@ampless/admin 1.0.0-alpha.85 → 1.0.0-beta.101

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.ja.md +2 -2
  2. package/README.md +2 -2
  3. package/dist/api/index.d.ts +1 -1
  4. package/dist/api/index.js +4 -2
  5. package/dist/{chunk-SQ6LFPXH.js → chunk-2TBGPB5H.js} +2 -2
  6. package/dist/{chunk-K44QF3MV.js → chunk-4OFRX6QX.js} +1 -1
  7. package/dist/{chunk-HANIMWMN.js → chunk-4WYMEUYU.js} +301 -222
  8. package/dist/chunk-7HSWOQWV.js +172 -0
  9. package/dist/{chunk-J6R356H3.js → chunk-7OZ23MLD.js} +1 -1
  10. package/dist/{chunk-OFPNBZKP.js → chunk-7W7LAQXY.js} +76 -8
  11. package/dist/{chunk-HN3UFHP7.js → chunk-ANME5KDN.js} +1 -1
  12. package/dist/{chunk-GGHN2RKQ.js → chunk-E5VF3Y65.js} +69 -3
  13. package/dist/{chunk-7LT6YPIT.js → chunk-JLCTF5HY.js} +8 -2
  14. package/dist/{chunk-R3TEJ32M.js → chunk-LXY3BRKQ.js} +2 -2
  15. package/dist/{chunk-MKWYNK4J.js → chunk-NHMG2MRJ.js} +2 -2
  16. package/dist/{chunk-AYESATAM.js → chunk-OPVLQOOB.js} +44 -13
  17. package/dist/{chunk-SMI7Y77B.js → chunk-ORXOMW7M.js} +265 -190
  18. package/dist/{chunk-W4VHP2JW.js → chunk-SYAEM5DM.js} +1 -1
  19. package/dist/{chunk-7NQERXNY.js → chunk-TJZ4FTU6.js} +1 -1
  20. package/dist/{chunk-CFIOUXVE.js → chunk-V5XORHKX.js} +1 -1
  21. package/dist/chunk-ZDIDJCSU.js +40 -0
  22. package/dist/components/account-view.d.ts +8 -0
  23. package/dist/components/account-view.js +10 -0
  24. package/dist/components/admin-dashboard.js +3 -3
  25. package/dist/components/edit-post-view.js +5 -5
  26. package/dist/components/index.d.ts +4 -2
  27. package/dist/components/index.js +7 -7
  28. package/dist/components/login-view.d.ts +3 -1
  29. package/dist/components/login-view.js +4 -3
  30. package/dist/components/mcp-tokens-view.js +3 -3
  31. package/dist/components/media-view.js +5 -5
  32. package/dist/components/new-post-view.js +5 -5
  33. package/dist/components/plugin-settings-form.d.ts +2 -10
  34. package/dist/components/plugin-settings-form.js +5 -7
  35. package/dist/components/posts-list-view.js +3 -3
  36. package/dist/components/users-list-view.js +3 -3
  37. package/dist/{i18n-DA-aakRX.d.ts → i18n-Bd8q9aTl.d.ts} +108 -5
  38. package/dist/index.d.ts +2 -2
  39. package/dist/index.js +1 -1
  40. package/dist/metafile-esm.json +1 -1
  41. package/dist/pages/index.d.ts +21 -4
  42. package/dist/pages/index.js +54 -24
  43. package/package.json +5 -6
@@ -4,7 +4,7 @@ import {
4
4
  getAdminCmsConfig,
5
5
  getMediaProcessingDefaults,
6
6
  uploadProcessedImage
7
- } from "./chunk-HN3UFHP7.js";
7
+ } from "./chunk-ANME5KDN.js";
8
8
  import {
9
9
  getAdminEditorExtensions,
10
10
  getAdminTiptapNodeHtml,
@@ -15,7 +15,7 @@ import {
15
15
  } from "./chunk-2ITWLRYF.js";
16
16
  import {
17
17
  useT
18
- } from "./chunk-K44QF3MV.js";
18
+ } from "./chunk-4OFRX6QX.js";
19
19
 
20
20
  // src/components/media-picker.tsx
21
21
  import { useEffect, useRef, useState } from "react";
@@ -160,7 +160,7 @@ function MediaPicker({ trigger, onSelect }) {
160
160
  }
161
161
 
162
162
  // src/components/post-form.tsx
163
- import { useEffect as useEffect4, useRef as useRef3, useState as useState5 } from "react";
163
+ import { useEffect as useEffect5, useRef as useRef4, useState as useState6 } from "react";
164
164
  import { useRouter } from "next/navigation";
165
165
  import { Image as ImageIcon3 } from "lucide-react";
166
166
  import {
@@ -169,7 +169,7 @@ import {
169
169
  deletePost,
170
170
  formatDate
171
171
  } from "ampless";
172
- import { Button as Button7, Input, Label, Textarea } from "@ampless/runtime/ui";
172
+ import { Button as Button7, Input as Input2, Label, Textarea } from "@ampless/runtime/ui";
173
173
 
174
174
  // src/editor/tiptap-editor.tsx
175
175
  import { useEditor, EditorContent } from "@tiptap/react";
@@ -325,8 +325,77 @@ function TableControls({ editor }) {
325
325
  ] });
326
326
  }
327
327
 
328
- // src/editor/toolbar.tsx
328
+ // src/editor/code-block-language-control.tsx
329
+ import { useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
330
+ import { Braces } from "lucide-react";
331
+ import { Input } from "@ampless/runtime/ui";
332
+
333
+ // src/editor/code-language.ts
334
+ var TOKEN = /^[a-z0-9][a-z0-9_-]{0,63}$/;
335
+ function normalizeCodeLanguage(value) {
336
+ const cleaned = value.toLowerCase().replace(/[^a-z0-9_-]/g, "");
337
+ return TOKEN.test(cleaned) ? cleaned : null;
338
+ }
339
+
340
+ // src/editor/code-block-language-control.tsx
329
341
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
342
+ function CodeBlockLanguageControl({ editor }) {
343
+ const t = useT();
344
+ const [state, setState] = useState3({ active: false, language: "" });
345
+ const [localValue, setLocalValue] = useState3("");
346
+ const focusedRef = useRef3(false);
347
+ const lastSeededLanguageRef = useRef3("");
348
+ useEffect3(() => {
349
+ const sync = () => {
350
+ const active = editor.isActive("codeBlock");
351
+ const language = editor.getAttributes("codeBlock").language ?? "";
352
+ setState({ active, language });
353
+ if (!focusedRef.current || language !== lastSeededLanguageRef.current) {
354
+ setLocalValue(language);
355
+ lastSeededLanguageRef.current = language;
356
+ }
357
+ };
358
+ sync();
359
+ editor.on("selectionUpdate", sync);
360
+ editor.on("transaction", sync);
361
+ return () => {
362
+ editor.off("selectionUpdate", sync);
363
+ editor.off("transaction", sync);
364
+ };
365
+ }, [editor]);
366
+ if (!state.active) return null;
367
+ return /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-1", children: [
368
+ /* @__PURE__ */ jsx3(Braces, { className: "h-4 w-4 shrink-0 text-muted-foreground", "aria-hidden": "true" }),
369
+ /* @__PURE__ */ jsx3(
370
+ Input,
371
+ {
372
+ type: "text",
373
+ className: "h-8 w-32 text-xs",
374
+ value: localValue,
375
+ title: t("editor.codeBlock.languageLabel"),
376
+ placeholder: t("editor.codeBlock.languagePlaceholder"),
377
+ "aria-label": t("editor.codeBlock.languageLabel"),
378
+ onFocus: () => {
379
+ focusedRef.current = true;
380
+ },
381
+ onBlur: () => {
382
+ focusedRef.current = false;
383
+ const committed = editor.getAttributes("codeBlock").language ?? "";
384
+ setLocalValue(committed);
385
+ lastSeededLanguageRef.current = committed;
386
+ },
387
+ onChange: (e) => {
388
+ const raw = e.target.value;
389
+ setLocalValue(raw);
390
+ editor.chain().updateAttributes("codeBlock", { language: normalizeCodeLanguage(raw) }).run();
391
+ }
392
+ }
393
+ )
394
+ ] });
395
+ }
396
+
397
+ // src/editor/toolbar.tsx
398
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
330
399
  function Toolbar({ editor }) {
331
400
  const t = useT();
332
401
  if (!editor) return null;
@@ -362,10 +431,10 @@ function Toolbar({ editor }) {
362
431
  const insertImage = (url) => {
363
432
  editor.chain().focus().setImage({ src: url }).run();
364
433
  };
365
- return /* @__PURE__ */ jsxs3("div", { className: "flex flex-wrap gap-1 border-b p-2", children: [
434
+ return /* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap gap-1 border-b p-2", children: [
366
435
  tools.map((tool) => {
367
436
  const Icon = tool.icon;
368
- return /* @__PURE__ */ jsx3(
437
+ return /* @__PURE__ */ jsx4(
369
438
  Button3,
370
439
  {
371
440
  type: "button",
@@ -373,12 +442,12 @@ function Toolbar({ editor }) {
373
442
  size: "icon",
374
443
  onClick: tool.action,
375
444
  className: cn2(tool.isActive() && "bg-accent text-accent-foreground"),
376
- children: /* @__PURE__ */ jsx3(Icon, { className: "h-4 w-4" })
445
+ children: /* @__PURE__ */ jsx4(Icon, { className: "h-4 w-4" })
377
446
  },
378
447
  tool.name
379
448
  );
380
449
  }),
381
- /* @__PURE__ */ jsx3(
450
+ /* @__PURE__ */ jsx4(
382
451
  Button3,
383
452
  {
384
453
  type: "button",
@@ -386,17 +455,18 @@ function Toolbar({ editor }) {
386
455
  size: "icon",
387
456
  onClick: setLink,
388
457
  className: cn2(editor.isActive("link") && "bg-accent text-accent-foreground"),
389
- children: /* @__PURE__ */ jsx3(LinkIcon, { className: "h-4 w-4" })
458
+ children: /* @__PURE__ */ jsx4(LinkIcon, { className: "h-4 w-4" })
390
459
  }
391
460
  ),
392
- /* @__PURE__ */ jsx3(
461
+ /* @__PURE__ */ jsx4(
393
462
  MediaPicker,
394
463
  {
395
464
  onSelect: insertImage,
396
- trigger: /* @__PURE__ */ jsx3(Button3, { type: "button", variant: "ghost", size: "icon", children: /* @__PURE__ */ jsx3(ImageIcon, { className: "h-4 w-4" }) })
465
+ trigger: /* @__PURE__ */ jsx4(Button3, { type: "button", variant: "ghost", size: "icon", children: /* @__PURE__ */ jsx4(ImageIcon, { className: "h-4 w-4" }) })
397
466
  }
398
467
  ),
399
- /* @__PURE__ */ jsx3(TableControls, { editor })
468
+ /* @__PURE__ */ jsx4(TableControls, { editor }),
469
+ /* @__PURE__ */ jsx4(CodeBlockLanguageControl, { editor })
400
470
  ] });
401
471
  }
402
472
 
@@ -404,7 +474,7 @@ function Toolbar({ editor }) {
404
474
  import { BubbleMenu } from "@tiptap/react/menus";
405
475
  import { Trash2, Pencil, ImageIcon as ImageIcon2, Maximize2 } from "lucide-react";
406
476
  import { Button as Button4, cn as cn3 } from "@ampless/runtime/ui";
407
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
477
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
408
478
  function ImageBubbleMenu({ editor }) {
409
479
  const t = useT();
410
480
  const editAlt = () => {
@@ -422,14 +492,14 @@ function ImageBubbleMenu({ editor }) {
422
492
  editor.chain().focus().updateAttributes("image", { display: next }).run();
423
493
  };
424
494
  const currentDisplay = editor.getAttributes("image").display ?? null;
425
- return /* @__PURE__ */ jsx4(
495
+ return /* @__PURE__ */ jsx5(
426
496
  BubbleMenu,
427
497
  {
428
498
  editor,
429
499
  shouldShow: ({ editor: editor2 }) => editor2.isActive("image"),
430
500
  options: { placement: "top" },
431
- children: /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-1 rounded-md border bg-popover p-1 shadow", children: [
432
- /* @__PURE__ */ jsxs4(
501
+ children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1 rounded-md border bg-popover p-1 shadow", children: [
502
+ /* @__PURE__ */ jsxs5(
433
503
  Button4,
434
504
  {
435
505
  type: "button",
@@ -439,12 +509,12 @@ function ImageBubbleMenu({ editor }) {
439
509
  className: cn3(currentDisplay === "inline" && "bg-accent text-accent-foreground"),
440
510
  title: t("editor.image.inlineTitle"),
441
511
  children: [
442
- /* @__PURE__ */ jsx4(ImageIcon2, { className: "mr-1 h-3 w-3" }),
512
+ /* @__PURE__ */ jsx5(ImageIcon2, { className: "mr-1 h-3 w-3" }),
443
513
  t("editor.image.inline")
444
514
  ]
445
515
  }
446
516
  ),
447
- /* @__PURE__ */ jsxs4(
517
+ /* @__PURE__ */ jsxs5(
448
518
  Button4,
449
519
  {
450
520
  type: "button",
@@ -454,18 +524,18 @@ function ImageBubbleMenu({ editor }) {
454
524
  className: cn3(currentDisplay === "lightbox" && "bg-accent text-accent-foreground"),
455
525
  title: t("editor.image.lightboxTitle"),
456
526
  children: [
457
- /* @__PURE__ */ jsx4(Maximize2, { className: "mr-1 h-3 w-3" }),
527
+ /* @__PURE__ */ jsx5(Maximize2, { className: "mr-1 h-3 w-3" }),
458
528
  t("editor.image.lightbox")
459
529
  ]
460
530
  }
461
531
  ),
462
- /* @__PURE__ */ jsx4("span", { className: "mx-1 h-4 w-px bg-border" }),
463
- /* @__PURE__ */ jsxs4(Button4, { type: "button", variant: "ghost", size: "sm", onClick: editAlt, children: [
464
- /* @__PURE__ */ jsx4(Pencil, { className: "mr-1 h-3 w-3" }),
532
+ /* @__PURE__ */ jsx5("span", { className: "mx-1 h-4 w-px bg-border" }),
533
+ /* @__PURE__ */ jsxs5(Button4, { type: "button", variant: "ghost", size: "sm", onClick: editAlt, children: [
534
+ /* @__PURE__ */ jsx5(Pencil, { className: "mr-1 h-3 w-3" }),
465
535
  t("editor.image.alt")
466
536
  ] }),
467
- /* @__PURE__ */ jsxs4(Button4, { type: "button", variant: "ghost", size: "sm", onClick: remove2, children: [
468
- /* @__PURE__ */ jsx4(Trash2, { className: "mr-1 h-3 w-3" }),
537
+ /* @__PURE__ */ jsxs5(Button4, { type: "button", variant: "ghost", size: "sm", onClick: remove2, children: [
538
+ /* @__PURE__ */ jsx5(Trash2, { className: "mr-1 h-3 w-3" }),
469
539
  t("editor.image.delete")
470
540
  ] })
471
541
  ] })
@@ -517,7 +587,7 @@ var BASE_TIPTAP_EXTENSIONS = [
517
587
  ];
518
588
 
519
589
  // src/editor/tiptap-editor.tsx
520
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
590
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
521
591
  var EDITOR_STYLES = `
522
592
  .ProseMirror .tiptap-table,
523
593
  .ProseMirror table {
@@ -617,16 +687,16 @@ function TiptapEditor({ initialContent, onChange, onUserEdit }) {
617
687
  onUserEdit?.();
618
688
  }
619
689
  });
620
- return /* @__PURE__ */ jsxs5("div", { className: "rounded-md border", children: [
621
- /* @__PURE__ */ jsx5("style", { children: EDITOR_STYLES }),
622
- /* @__PURE__ */ jsx5(Toolbar, { editor }),
623
- editor && /* @__PURE__ */ jsx5(ImageBubbleMenu, { editor }),
624
- /* @__PURE__ */ jsx5(EditorContent, { editor })
690
+ return /* @__PURE__ */ jsxs6("div", { className: "rounded-md border", children: [
691
+ /* @__PURE__ */ jsx6("style", { children: EDITOR_STYLES }),
692
+ /* @__PURE__ */ jsx6(Toolbar, { editor }),
693
+ editor && /* @__PURE__ */ jsx6(ImageBubbleMenu, { editor }),
694
+ /* @__PURE__ */ jsx6(EditorContent, { editor })
625
695
  ] });
626
696
  }
627
697
 
628
698
  // src/components/post-history-panel.tsx
629
- import { useCallback, useEffect as useEffect3, useState as useState3 } from "react";
699
+ import { useCallback, useEffect as useEffect4, useState as useState4 } from "react";
630
700
  import { listPostHistory } from "ampless";
631
701
  import { Button as Button5 } from "@ampless/runtime/ui";
632
702
 
@@ -687,7 +757,7 @@ function buildPreviewSrcDoc(html) {
687
757
  }
688
758
 
689
759
  // src/components/post-history-panel.tsx
690
- import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
760
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
691
761
  var PAGE_SIZE = 20;
692
762
  function formatRevisedAt(iso, timezone, locale) {
693
763
  const d = new Date(iso);
@@ -728,17 +798,17 @@ function PostHistoryPanel({
728
798
  const config = getAdminCmsConfig();
729
799
  const timezone = config?.timezone ?? "UTC";
730
800
  const locale = config?.locale ?? "en";
731
- const [open, setOpen] = useState3(false);
732
- const [loaded, setLoaded] = useState3(false);
733
- const [loading, setLoading] = useState3(false);
734
- const [error, setError] = useState3(null);
735
- const [revisions, setRevisions] = useState3([]);
736
- const [nextToken, setNextToken] = useState3(void 0);
737
- const [selected, setSelected] = useState3(null);
738
- const [previewHtml, setPreviewHtml] = useState3("");
801
+ const [open, setOpen] = useState4(false);
802
+ const [loaded, setLoaded] = useState4(false);
803
+ const [loading, setLoading] = useState4(false);
804
+ const [error, setError] = useState4(null);
805
+ const [revisions, setRevisions] = useState4([]);
806
+ const [nextToken, setNextToken] = useState4(void 0);
807
+ const [selected, setSelected] = useState4(null);
808
+ const [previewHtml, setPreviewHtml] = useState4("");
739
809
  const selectedHistoryId = selected?.postHistoryId;
740
810
  const selectedFormat = selected?.format;
741
- useEffect3(() => {
811
+ useEffect4(() => {
742
812
  if (!selected) return;
743
813
  if (selected.format === "static") return;
744
814
  const ctrl = new AbortController();
@@ -774,14 +844,14 @@ function PostHistoryPanel({
774
844
  },
775
845
  [postId]
776
846
  );
777
- useEffect3(() => {
847
+ useEffect4(() => {
778
848
  if (open && !loaded) {
779
849
  setLoaded(true);
780
850
  void loadPage();
781
851
  }
782
852
  }, [open, loaded, loadPage]);
783
- return /* @__PURE__ */ jsxs6("section", { className: "rounded-md border", children: [
784
- /* @__PURE__ */ jsxs6(
853
+ return /* @__PURE__ */ jsxs7("section", { className: "rounded-md border", children: [
854
+ /* @__PURE__ */ jsxs7(
785
855
  "button",
786
856
  {
787
857
  type: "button",
@@ -789,30 +859,30 @@ function PostHistoryPanel({
789
859
  "aria-expanded": open,
790
860
  className: "flex w-full items-center justify-between px-4 py-3 text-left text-sm font-medium",
791
861
  children: [
792
- /* @__PURE__ */ jsx6("span", { children: t("posts.history.title") }),
793
- /* @__PURE__ */ jsx6("span", { className: "text-muted-foreground", "aria-hidden": "true", children: open ? "\u2212" : "+" })
862
+ /* @__PURE__ */ jsx7("span", { children: t("posts.history.title") }),
863
+ /* @__PURE__ */ jsx7("span", { className: "text-muted-foreground", "aria-hidden": "true", children: open ? "\u2212" : "+" })
794
864
  ]
795
865
  }
796
866
  ),
797
- open && /* @__PURE__ */ jsxs6("div", { className: "space-y-4 border-t px-4 py-4", children: [
798
- error && /* @__PURE__ */ jsx6("p", { className: "text-sm text-destructive", children: error }),
799
- loading && revisions.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "text-sm text-muted-foreground", children: t("common.loading") }) : revisions.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "text-sm text-muted-foreground", children: t("posts.history.empty") }) : /* @__PURE__ */ jsx6("div", { className: "overflow-x-auto rounded-md border", children: /* @__PURE__ */ jsxs6("table", { className: "w-full text-sm", children: [
800
- /* @__PURE__ */ jsx6("thead", { children: /* @__PURE__ */ jsxs6("tr", { className: "border-b text-left text-xs text-muted-foreground", children: [
801
- /* @__PURE__ */ jsx6("th", { className: "px-3 py-2 font-medium", children: t("posts.history.columnRevisedAt") }),
802
- /* @__PURE__ */ jsx6("th", { className: "px-3 py-2 font-medium", children: t("posts.history.columnStatus") }),
803
- /* @__PURE__ */ jsx6("th", { className: "px-3 py-2 font-medium", children: t("posts.history.columnTitle") }),
804
- /* @__PURE__ */ jsx6("th", { className: "px-3 py-2 font-medium text-right", children: t("common.actions") })
867
+ open && /* @__PURE__ */ jsxs7("div", { className: "space-y-4 border-t px-4 py-4", children: [
868
+ error && /* @__PURE__ */ jsx7("p", { className: "text-sm text-destructive", children: error }),
869
+ loading && revisions.length === 0 ? /* @__PURE__ */ jsx7("p", { className: "text-sm text-muted-foreground", children: t("common.loading") }) : revisions.length === 0 ? /* @__PURE__ */ jsx7("p", { className: "text-sm text-muted-foreground", children: t("posts.history.empty") }) : /* @__PURE__ */ jsx7("div", { className: "overflow-x-auto rounded-md border", children: /* @__PURE__ */ jsxs7("table", { className: "w-full text-sm", children: [
870
+ /* @__PURE__ */ jsx7("thead", { children: /* @__PURE__ */ jsxs7("tr", { className: "border-b text-left text-xs text-muted-foreground", children: [
871
+ /* @__PURE__ */ jsx7("th", { className: "px-3 py-2 font-medium", children: t("posts.history.columnRevisedAt") }),
872
+ /* @__PURE__ */ jsx7("th", { className: "px-3 py-2 font-medium", children: t("posts.history.columnStatus") }),
873
+ /* @__PURE__ */ jsx7("th", { className: "px-3 py-2 font-medium", children: t("posts.history.columnTitle") }),
874
+ /* @__PURE__ */ jsx7("th", { className: "px-3 py-2 font-medium text-right", children: t("common.actions") })
805
875
  ] }) }),
806
- /* @__PURE__ */ jsx6("tbody", { children: revisions.map((rev) => /* @__PURE__ */ jsxs6(
876
+ /* @__PURE__ */ jsx7("tbody", { children: revisions.map((rev) => /* @__PURE__ */ jsxs7(
807
877
  "tr",
808
878
  {
809
879
  className: selected?.postHistoryId === rev.postHistoryId ? "border-b bg-muted/50" : "border-b",
810
880
  children: [
811
- /* @__PURE__ */ jsx6("td", { className: "whitespace-nowrap px-3 py-2 font-mono text-xs", children: formatRevisedAt(rev.revisedAt, timezone, locale) }),
812
- /* @__PURE__ */ jsx6("td", { className: "px-3 py-2", children: /* @__PURE__ */ jsx6("span", { className: "text-xs text-muted-foreground", children: rev.status ? t(`common.${rev.status}`) : "\u2014" }) }),
813
- /* @__PURE__ */ jsx6("td", { className: "px-3 py-2", children: rev.title || "\u2014" }),
814
- /* @__PURE__ */ jsx6("td", { className: "px-3 py-2 text-right", children: /* @__PURE__ */ jsxs6("div", { className: "flex justify-end gap-2", children: [
815
- /* @__PURE__ */ jsx6(
881
+ /* @__PURE__ */ jsx7("td", { className: "whitespace-nowrap px-3 py-2 font-mono text-xs", children: formatRevisedAt(rev.revisedAt, timezone, locale) }),
882
+ /* @__PURE__ */ jsx7("td", { className: "px-3 py-2", children: /* @__PURE__ */ jsx7("span", { className: "text-xs text-muted-foreground", children: rev.status ? t(`common.${rev.status}`) : "\u2014" }) }),
883
+ /* @__PURE__ */ jsx7("td", { className: "px-3 py-2", children: rev.title || "\u2014" }),
884
+ /* @__PURE__ */ jsx7("td", { className: "px-3 py-2 text-right", children: /* @__PURE__ */ jsxs7("div", { className: "flex justify-end gap-2", children: [
885
+ /* @__PURE__ */ jsx7(
816
886
  Button5,
817
887
  {
818
888
  type: "button",
@@ -822,7 +892,7 @@ function PostHistoryPanel({
822
892
  children: t("posts.history.view")
823
893
  }
824
894
  ),
825
- /* @__PURE__ */ jsx6(
895
+ /* @__PURE__ */ jsx7(
826
896
  Button5,
827
897
  {
828
898
  type: "button",
@@ -840,7 +910,7 @@ function PostHistoryPanel({
840
910
  rev.postHistoryId
841
911
  )) })
842
912
  ] }) }),
843
- nextToken && /* @__PURE__ */ jsx6("div", { children: /* @__PURE__ */ jsx6(
913
+ nextToken && /* @__PURE__ */ jsx7("div", { children: /* @__PURE__ */ jsx7(
844
914
  Button5,
845
915
  {
846
916
  type: "button",
@@ -851,12 +921,12 @@ function PostHistoryPanel({
851
921
  children: loading ? t("common.loading") : t("posts.history.loadMore")
852
922
  }
853
923
  ) }),
854
- selected && /* @__PURE__ */ jsxs6("div", { className: "space-y-3 rounded-md border p-4", children: [
855
- /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between", children: [
856
- /* @__PURE__ */ jsx6("h4", { className: "text-sm font-semibold", children: t("posts.history.viewing", {
924
+ selected && /* @__PURE__ */ jsxs7("div", { className: "space-y-3 rounded-md border p-4", children: [
925
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between", children: [
926
+ /* @__PURE__ */ jsx7("h4", { className: "text-sm font-semibold", children: t("posts.history.viewing", {
857
927
  date: formatRevisedAt(selected.revisedAt, timezone, locale)
858
928
  }) }),
859
- /* @__PURE__ */ jsx6(
929
+ /* @__PURE__ */ jsx7(
860
930
  Button5,
861
931
  {
862
932
  type: "button",
@@ -867,14 +937,14 @@ function PostHistoryPanel({
867
937
  }
868
938
  )
869
939
  ] }),
870
- /* @__PURE__ */ jsxs6("p", { className: "text-xs text-muted-foreground", children: [
871
- /* @__PURE__ */ jsx6("span", { className: "font-mono uppercase", children: selected.format ?? "\u2014" }),
872
- selected.slug && /* @__PURE__ */ jsxs6(Fragment2, { children: [
873
- /* @__PURE__ */ jsx6("span", { className: "mx-2", children: "\xB7" }),
874
- /* @__PURE__ */ jsx6("span", { className: "font-mono", children: selected.slug })
940
+ /* @__PURE__ */ jsxs7("p", { className: "text-xs text-muted-foreground", children: [
941
+ /* @__PURE__ */ jsx7("span", { className: "font-mono uppercase", children: selected.format ?? "\u2014" }),
942
+ selected.slug && /* @__PURE__ */ jsxs7(Fragment2, { children: [
943
+ /* @__PURE__ */ jsx7("span", { className: "mx-2", children: "\xB7" }),
944
+ /* @__PURE__ */ jsx7("span", { className: "font-mono", children: selected.slug })
875
945
  ] })
876
946
  ] }),
877
- selected.format === "static" ? /* @__PURE__ */ jsx6("p", { className: "rounded-md bg-amber-50 p-2 text-xs text-amber-700 dark:bg-amber-950 dark:text-amber-400", children: t("posts.history.staticCaveat") }) : (
947
+ selected.format === "static" ? /* @__PURE__ */ jsx7("p", { className: "rounded-md bg-amber-50 p-2 text-xs text-amber-700 dark:bg-amber-950 dark:text-amber-400", children: t("posts.history.staticCaveat") }) : (
878
948
  // Sandbox is `allow-scripts allow-same-origin`. With
879
949
  // srcDoc, this gives the iframe the admin's origin so
880
950
  // 3rd-party embed widgets (YouTube SDK, x.com widgets.js)
@@ -901,7 +971,7 @@ function PostHistoryPanel({
901
971
  // don't style its srcDoc contents. Typography comes from
902
972
  // the full document the preview route now returns
903
973
  // (PREVIEW_BASE_CSS + theme vars in createPreviewRouteHandler).
904
- /* @__PURE__ */ jsx6(
974
+ /* @__PURE__ */ jsx7(
905
975
  "iframe",
906
976
  {
907
977
  title: "revision-preview",
@@ -917,7 +987,7 @@ function PostHistoryPanel({
917
987
  }
918
988
 
919
989
  // src/components/static-uploader.tsx
920
- import { useState as useState4 } from "react";
990
+ import { useState as useState5 } from "react";
921
991
  import { FileText, AlertTriangle, FileArchive, X } from "lucide-react";
922
992
  import { Button as Button6 } from "@ampless/runtime/ui";
923
993
 
@@ -967,7 +1037,15 @@ async function uploadBundle(opts) {
967
1037
  if (!opts.files.some((f) => f.path === entrypoint)) {
968
1038
  throw new Error(`Entrypoint "${entrypoint}" is not present in the bundle.`);
969
1039
  }
970
- await deleteBundle(opts.slug).catch(() => void 0);
1040
+ try {
1041
+ await deleteBundle(opts.slug);
1042
+ } catch (err) {
1043
+ console.error(
1044
+ "[ampless static-bundle] failed to clear existing bundle before replace:",
1045
+ err
1046
+ );
1047
+ throw err;
1048
+ }
971
1049
  const prefix = bundlePrefix(opts.slug);
972
1050
  let uploaded = 0;
973
1051
  const filesMeta = {};
@@ -1005,13 +1083,13 @@ async function deleteBundle(slug) {
1005
1083
  }
1006
1084
 
1007
1085
  // src/components/static-uploader.tsx
1008
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1086
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1009
1087
  function StaticUploader({ initial, onFilesReady, onClear }) {
1010
1088
  const t = useT();
1011
- const [pending, setPending] = useState4(null);
1012
- const [issues, setIssues] = useState4([]);
1013
- const [busy, setBusy] = useState4(false);
1014
- const [error, setError] = useState4(null);
1089
+ const [pending, setPending] = useState5(null);
1090
+ const [issues, setIssues] = useState5([]);
1091
+ const [busy, setBusy] = useState5(false);
1092
+ const [error, setError] = useState5(null);
1015
1093
  async function handleZip(file) {
1016
1094
  setBusy(true);
1017
1095
  setError(null);
@@ -1041,7 +1119,7 @@ function StaticUploader({ initial, onFilesReady, onClear }) {
1041
1119
  const extracted = [];
1042
1120
  const structural = [];
1043
1121
  for (const f of Array.from(files)) {
1044
- const rel = f.webkitRelativePath ?? f.name;
1122
+ const rel = f.webkitRelativePath || f.name;
1045
1123
  const stripped = rel.includes("/") ? rel.slice(rel.indexOf("/") + 1) : rel;
1046
1124
  const reason = validateBundlePath(stripped);
1047
1125
  if (reason) {
@@ -1069,13 +1147,14 @@ function StaticUploader({ initial, onFilesReady, onClear }) {
1069
1147
  }
1070
1148
  }
1071
1149
  function onPickerChange(e) {
1072
- const fl = e.target.files;
1073
- if (!fl || fl.length === 0) return;
1150
+ const picked = e.target.files;
1151
+ if (!picked || picked.length === 0) return;
1152
+ const files = Array.from(picked);
1074
1153
  e.target.value = "";
1075
- if (fl.length === 1 && fl[0].name.toLowerCase().endsWith(".zip")) {
1076
- void handleZip(fl[0]);
1154
+ if (files.length === 1 && files[0].name.toLowerCase().endsWith(".zip")) {
1155
+ void handleZip(files[0]);
1077
1156
  } else {
1078
- void handleLooseFiles(fl);
1157
+ void handleLooseFiles(files);
1079
1158
  }
1080
1159
  }
1081
1160
  function clearPending() {
@@ -1085,11 +1164,11 @@ function StaticUploader({ initial, onFilesReady, onClear }) {
1085
1164
  onClear();
1086
1165
  }
1087
1166
  const showCurrent = !pending && initial && initial.files.length > 0;
1088
- return /* @__PURE__ */ jsxs7("div", { className: "space-y-4", children: [
1089
- /* @__PURE__ */ jsxs7("div", { className: "rounded-md border border-dashed p-4", children: [
1090
- /* @__PURE__ */ jsxs7("label", { className: "flex flex-col items-start gap-2 text-sm", children: [
1091
- /* @__PURE__ */ jsx7("span", { className: "font-medium", children: t("posts.form.static.pick") }),
1092
- /* @__PURE__ */ jsx7(
1167
+ return /* @__PURE__ */ jsxs8("div", { className: "space-y-4", children: [
1168
+ /* @__PURE__ */ jsxs8("div", { className: "rounded-md border border-dashed p-4", children: [
1169
+ /* @__PURE__ */ jsxs8("label", { className: "flex flex-col items-start gap-2 text-sm", children: [
1170
+ /* @__PURE__ */ jsx8("span", { className: "font-medium", children: t("posts.form.static.pick") }),
1171
+ /* @__PURE__ */ jsx8(
1093
1172
  "input",
1094
1173
  {
1095
1174
  type: "file",
@@ -1099,13 +1178,13 @@ function StaticUploader({ initial, onFilesReady, onClear }) {
1099
1178
  disabled: busy
1100
1179
  }
1101
1180
  ),
1102
- /* @__PURE__ */ jsx7("span", { className: "text-xs text-muted-foreground", children: t("posts.form.static.pickHint") })
1181
+ /* @__PURE__ */ jsx8("span", { className: "text-xs text-muted-foreground", children: t("posts.form.static.pickHint") })
1103
1182
  ] }),
1104
- busy && /* @__PURE__ */ jsx7("p", { className: "mt-2 text-sm text-muted-foreground", children: t("common.loading") }),
1105
- error && /* @__PURE__ */ jsx7("p", { className: "mt-2 text-sm text-destructive", children: error })
1183
+ busy && /* @__PURE__ */ jsx8("p", { className: "mt-2 text-sm text-muted-foreground", children: t("common.loading") }),
1184
+ error && /* @__PURE__ */ jsx8("p", { className: "mt-2 text-sm text-destructive", children: error })
1106
1185
  ] }),
1107
- showCurrent && /* @__PURE__ */ jsx7(CurrentBundle, { body: initial }),
1108
- pending && /* @__PURE__ */ jsx7(
1186
+ showCurrent && /* @__PURE__ */ jsx8(CurrentBundle, { body: initial }),
1187
+ pending && /* @__PURE__ */ jsx8(
1109
1188
  PendingBundle,
1110
1189
  {
1111
1190
  files: pending,
@@ -1117,15 +1196,15 @@ function StaticUploader({ initial, onFilesReady, onClear }) {
1117
1196
  }
1118
1197
  function CurrentBundle({ body }) {
1119
1198
  const t = useT();
1120
- return /* @__PURE__ */ jsxs7("div", { className: "rounded-md border bg-muted/30 p-3", children: [
1121
- /* @__PURE__ */ jsxs7("div", { className: "mb-2 flex items-center gap-2 text-sm font-medium", children: [
1122
- /* @__PURE__ */ jsx7(FileArchive, { className: "h-4 w-4" }),
1199
+ return /* @__PURE__ */ jsxs8("div", { className: "rounded-md border bg-muted/30 p-3", children: [
1200
+ /* @__PURE__ */ jsxs8("div", { className: "mb-2 flex items-center gap-2 text-sm font-medium", children: [
1201
+ /* @__PURE__ */ jsx8(FileArchive, { className: "h-4 w-4" }),
1123
1202
  t("posts.form.static.currentBundle", {
1124
1203
  count: body.files.length,
1125
1204
  entrypoint: body.entrypoint
1126
1205
  })
1127
1206
  ] }),
1128
- /* @__PURE__ */ jsx7(FileList, { files: body.files })
1207
+ /* @__PURE__ */ jsx8(FileList, { files: body.files })
1129
1208
  ] });
1130
1209
  }
1131
1210
  function PendingBundle({
@@ -1135,49 +1214,49 @@ function PendingBundle({
1135
1214
  }) {
1136
1215
  const t = useT();
1137
1216
  const totalBytes = files.reduce((sum, f) => sum + f.data.byteLength, 0);
1138
- return /* @__PURE__ */ jsxs7("div", { className: "rounded-md border p-3", children: [
1139
- /* @__PURE__ */ jsxs7("div", { className: "mb-2 flex items-center justify-between gap-2 text-sm font-medium", children: [
1140
- /* @__PURE__ */ jsxs7("span", { className: "flex items-center gap-2", children: [
1141
- /* @__PURE__ */ jsx7(FileArchive, { className: "h-4 w-4" }),
1217
+ return /* @__PURE__ */ jsxs8("div", { className: "rounded-md border p-3", children: [
1218
+ /* @__PURE__ */ jsxs8("div", { className: "mb-2 flex items-center justify-between gap-2 text-sm font-medium", children: [
1219
+ /* @__PURE__ */ jsxs8("span", { className: "flex items-center gap-2", children: [
1220
+ /* @__PURE__ */ jsx8(FileArchive, { className: "h-4 w-4" }),
1142
1221
  t("posts.form.static.pendingBundle", {
1143
1222
  count: files.length,
1144
1223
  size: formatBytes(totalBytes)
1145
1224
  })
1146
1225
  ] }),
1147
- /* @__PURE__ */ jsxs7(Button6, { type: "button", variant: "ghost", size: "sm", onClick: onClear, children: [
1148
- /* @__PURE__ */ jsx7(X, { className: "mr-1 h-3 w-3" }),
1226
+ /* @__PURE__ */ jsxs8(Button6, { type: "button", variant: "ghost", size: "sm", onClick: onClear, children: [
1227
+ /* @__PURE__ */ jsx8(X, { className: "mr-1 h-3 w-3" }),
1149
1228
  t("common.cancel")
1150
1229
  ] })
1151
1230
  ] }),
1152
- issues.length > 0 && /* @__PURE__ */ jsxs7("div", { className: "mb-3 rounded-md border border-destructive/40 bg-destructive/5 p-2 text-sm", children: [
1153
- /* @__PURE__ */ jsxs7("div", { className: "mb-1 flex items-center gap-2 font-medium text-destructive", children: [
1154
- /* @__PURE__ */ jsx7(AlertTriangle, { className: "h-4 w-4" }),
1231
+ issues.length > 0 && /* @__PURE__ */ jsxs8("div", { className: "mb-3 rounded-md border border-destructive/40 bg-destructive/5 p-2 text-sm", children: [
1232
+ /* @__PURE__ */ jsxs8("div", { className: "mb-1 flex items-center gap-2 font-medium text-destructive", children: [
1233
+ /* @__PURE__ */ jsx8(AlertTriangle, { className: "h-4 w-4" }),
1155
1234
  t("posts.form.static.issuesTitle", { count: issues.length })
1156
1235
  ] }),
1157
- /* @__PURE__ */ jsxs7("ul", { className: "space-y-0.5 text-xs", children: [
1158
- issues.slice(0, 20).map((issue, idx) => /* @__PURE__ */ jsxs7("li", { className: "font-mono", children: [
1236
+ /* @__PURE__ */ jsxs8("ul", { className: "space-y-0.5 text-xs", children: [
1237
+ issues.slice(0, 20).map((issue, idx) => /* @__PURE__ */ jsxs8("li", { className: "font-mono", children: [
1159
1238
  issue.path,
1160
1239
  ": ",
1161
1240
  issue.reason
1162
1241
  ] }, `${issue.path}-${idx}`)),
1163
- issues.length > 20 && /* @__PURE__ */ jsxs7("li", { className: "font-mono text-muted-foreground", children: [
1242
+ issues.length > 20 && /* @__PURE__ */ jsxs8("li", { className: "font-mono text-muted-foreground", children: [
1164
1243
  "\u2026 ",
1165
1244
  issues.length - 20,
1166
1245
  " more"
1167
1246
  ] })
1168
1247
  ] }),
1169
- /* @__PURE__ */ jsx7("p", { className: "mt-2 text-xs text-muted-foreground", children: t("posts.form.static.issuesHint") })
1248
+ /* @__PURE__ */ jsx8("p", { className: "mt-2 text-xs text-muted-foreground", children: t("posts.form.static.issuesHint") })
1170
1249
  ] }),
1171
- /* @__PURE__ */ jsx7(FileList, { files: files.map((f) => f.path) })
1250
+ /* @__PURE__ */ jsx8(FileList, { files: files.map((f) => f.path) })
1172
1251
  ] });
1173
1252
  }
1174
1253
  function FileList({ files }) {
1175
- return /* @__PURE__ */ jsxs7("ul", { className: "space-y-0.5 text-xs", children: [
1176
- files.slice(0, 40).map((path) => /* @__PURE__ */ jsxs7("li", { className: "flex items-center gap-1.5 font-mono text-muted-foreground", children: [
1177
- /* @__PURE__ */ jsx7(FileText, { className: "h-3 w-3 shrink-0" }),
1254
+ return /* @__PURE__ */ jsxs8("ul", { className: "space-y-0.5 text-xs", children: [
1255
+ files.slice(0, 40).map((path) => /* @__PURE__ */ jsxs8("li", { className: "flex items-center gap-1.5 font-mono text-muted-foreground", children: [
1256
+ /* @__PURE__ */ jsx8(FileText, { className: "h-3 w-3 shrink-0" }),
1178
1257
  path
1179
1258
  ] }, path)),
1180
- files.length > 40 && /* @__PURE__ */ jsxs7("li", { className: "font-mono text-xs text-muted-foreground", children: [
1259
+ files.length > 40 && /* @__PURE__ */ jsxs8("li", { className: "font-mono text-xs text-muted-foreground", children: [
1181
1260
  "\u2026 ",
1182
1261
  files.length - 40,
1183
1262
  " more"
@@ -1371,7 +1450,7 @@ function convertBodyFormat(body, from, to, registries) {
1371
1450
  }
1372
1451
 
1373
1452
  // src/components/post-form.tsx
1374
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1453
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1375
1454
  var EMPTY_TIPTAP_DOC = { type: "doc", content: [{ type: "paragraph" }] };
1376
1455
  var IMAGE_URL_RE = /\.(jpe?g|png|gif|webp|avif|svg|bmp|tiff?)(\?|$)/i;
1377
1456
  var STYLESHEET_URL_RE = /\.css(\?|$)/i;
@@ -1417,27 +1496,27 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1417
1496
  const router = useRouter();
1418
1497
  const t = useT();
1419
1498
  const isEdit = !!post;
1420
- const bodyTextareaRef = useRef3(null);
1421
- const [title, setTitle] = useState5(post?.title ?? "");
1422
- const [slug, setSlug] = useState5(post?.slug ?? "");
1423
- const [excerpt, setExcerpt] = useState5(post?.excerpt ?? "");
1424
- const [format, setFormat] = useState5(post?.format ?? "tiptap");
1425
- const [body, setBody] = useState5(post?.body ?? EMPTY_TIPTAP_DOC);
1426
- const [status, setStatus] = useState5(post?.status ?? "draft");
1427
- const [tagsInput, setTagsInput] = useState5((post?.tags ?? []).join(", "));
1428
- const [noLayout, setNoLayout] = useState5(post?.metadata?.no_layout === true);
1429
- const [publishedAtInput, setPublishedAtInput] = useState5(isoToLocalInput(post?.publishedAt));
1430
- const [saving, setSaving] = useState5(false);
1431
- const [error, setError] = useState5(null);
1432
- const [view, setView] = useState5("edit");
1433
- const [previewHtml, setPreviewHtml] = useState5("");
1434
- const [editorEpoch, setEditorEpoch] = useState5(0);
1435
- const dirtyRef = useRef3(false);
1499
+ const bodyTextareaRef = useRef4(null);
1500
+ const [title, setTitle] = useState6(post?.title ?? "");
1501
+ const [slug, setSlug] = useState6(post?.slug ?? "");
1502
+ const [excerpt, setExcerpt] = useState6(post?.excerpt ?? "");
1503
+ const [format, setFormat] = useState6(post?.format ?? "tiptap");
1504
+ const [body, setBody] = useState6(post?.body ?? EMPTY_TIPTAP_DOC);
1505
+ const [status, setStatus] = useState6(post?.status ?? "draft");
1506
+ const [tagsInput, setTagsInput] = useState6((post?.tags ?? []).join(", "));
1507
+ const [noLayout, setNoLayout] = useState6(post?.metadata?.no_layout === true);
1508
+ const [publishedAtInput, setPublishedAtInput] = useState6(isoToLocalInput(post?.publishedAt));
1509
+ const [saving, setSaving] = useState6(false);
1510
+ const [error, setError] = useState6(null);
1511
+ const [view, setView] = useState6("edit");
1512
+ const [previewHtml, setPreviewHtml] = useState6("");
1513
+ const [editorEpoch, setEditorEpoch] = useState6(0);
1514
+ const dirtyRef = useRef4(false);
1436
1515
  function markDirty() {
1437
1516
  dirtyRef.current = true;
1438
1517
  }
1439
- const [recovery, setRecovery] = useState5(null);
1440
- const [restoredHint, setRestoredHint] = useState5(false);
1518
+ const [recovery, setRecovery] = useState6(null);
1519
+ const [restoredHint, setRestoredHint] = useState6(false);
1441
1520
  const draftId = post?.postId ?? NEW_POST_DRAFT_ID;
1442
1521
  const isStaticFormat = format === "static";
1443
1522
  const cmsConfig = getAdminCmsConfig();
@@ -1450,7 +1529,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1450
1529
  initialInput: initialPublishedAtInput,
1451
1530
  existing: post?.publishedAt
1452
1531
  });
1453
- const [pendingBundle, setPendingBundle] = useState5(null);
1532
+ const [pendingBundle, setPendingBundle] = useState6(null);
1454
1533
  const initialStaticBody = isStaticBody(post?.body) ? post.body : null;
1455
1534
  function buildMetadata() {
1456
1535
  const next = { ...post?.metadata ?? {} };
@@ -1518,7 +1597,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1518
1597
  dirtyRef.current = false;
1519
1598
  setRecovery(null);
1520
1599
  }
1521
- useEffect4(() => {
1600
+ useEffect5(() => {
1522
1601
  if (loadedState.format === "static") return;
1523
1602
  const draft = readDraft(draftId);
1524
1603
  if (!draft) return;
@@ -1533,7 +1612,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1533
1612
  }
1534
1613
  setRecovery({ draft, decision });
1535
1614
  }, []);
1536
- useEffect4(() => {
1615
+ useEffect5(() => {
1537
1616
  if (isStaticFormat) return;
1538
1617
  if (!dirtyRef.current) return;
1539
1618
  const handle = setTimeout(() => {
@@ -1641,13 +1720,13 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1641
1720
  await updatePost(post.postId, {
1642
1721
  title,
1643
1722
  slug: finalSlug,
1644
- excerpt: excerpt || void 0,
1723
+ excerpt,
1645
1724
  format,
1646
1725
  body: nextBody,
1647
1726
  status,
1648
1727
  publishedAt,
1649
1728
  tags,
1650
- metadata
1729
+ metadata: metadata ?? {}
1651
1730
  });
1652
1731
  } else {
1653
1732
  await createPost({
@@ -1700,7 +1779,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1700
1779
  publishedAt: resolvedPublishedAt,
1701
1780
  tags: parseTags(tagsInput)
1702
1781
  };
1703
- useEffect4(() => {
1782
+ useEffect5(() => {
1704
1783
  if (view !== "preview") return;
1705
1784
  if (format === "static") return;
1706
1785
  const ctrl = new AbortController();
@@ -1736,9 +1815,9 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1736
1815
  resolvedPublishedAt,
1737
1816
  tagsInput
1738
1817
  ]);
1739
- return /* @__PURE__ */ jsxs8("form", { onSubmit: save, className: "space-y-6", children: [
1740
- /* @__PURE__ */ jsxs8("div", { className: "flex gap-1 border-b", children: [
1741
- /* @__PURE__ */ jsx8(
1818
+ return /* @__PURE__ */ jsxs9("form", { onSubmit: save, className: "space-y-6", children: [
1819
+ /* @__PURE__ */ jsxs9("div", { className: "flex gap-1 border-b", children: [
1820
+ /* @__PURE__ */ jsx9(
1742
1821
  "button",
1743
1822
  {
1744
1823
  type: "button",
@@ -1748,7 +1827,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1748
1827
  children: t("posts.form.tabEdit")
1749
1828
  }
1750
1829
  ),
1751
- /* @__PURE__ */ jsx8(
1830
+ /* @__PURE__ */ jsx9(
1752
1831
  "button",
1753
1832
  {
1754
1833
  type: "button",
@@ -1759,17 +1838,17 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1759
1838
  }
1760
1839
  )
1761
1840
  ] }),
1762
- view === "preview" && /* @__PURE__ */ jsxs8("article", { className: "space-y-4", children: [
1763
- /* @__PURE__ */ jsxs8("header", { className: "border-b pb-4", children: [
1764
- /* @__PURE__ */ jsx8("h1", { className: "text-3xl font-bold tracking-tight", children: title || /* @__PURE__ */ jsx8("span", { className: "text-muted-foreground italic", children: t("posts.form.previewNoTitle") }) }),
1765
- /* @__PURE__ */ jsxs8("p", { className: "mt-2 text-sm text-muted-foreground", children: [
1766
- previewPost.publishedAt ? /* @__PURE__ */ jsx8("time", { dateTime: previewPost.publishedAt, children: formatDate(previewPost.publishedAt) }) : /* @__PURE__ */ jsx8("span", { children: t("common.draft") }),
1767
- /* @__PURE__ */ jsx8("span", { className: "mx-2", children: "\xB7" }),
1768
- /* @__PURE__ */ jsx8("span", { className: "font-mono text-xs uppercase", children: format })
1841
+ view === "preview" && /* @__PURE__ */ jsxs9("article", { className: "space-y-4", children: [
1842
+ /* @__PURE__ */ jsxs9("header", { className: "border-b pb-4", children: [
1843
+ /* @__PURE__ */ jsx9("h1", { className: "text-3xl font-bold tracking-tight", children: title || /* @__PURE__ */ jsx9("span", { className: "text-muted-foreground italic", children: t("posts.form.previewNoTitle") }) }),
1844
+ /* @__PURE__ */ jsxs9("p", { className: "mt-2 text-sm text-muted-foreground", children: [
1845
+ previewPost.publishedAt ? /* @__PURE__ */ jsx9("time", { dateTime: previewPost.publishedAt, children: formatDate(previewPost.publishedAt) }) : /* @__PURE__ */ jsx9("span", { children: t("common.draft") }),
1846
+ /* @__PURE__ */ jsx9("span", { className: "mx-2", children: "\xB7" }),
1847
+ /* @__PURE__ */ jsx9("span", { className: "font-mono text-xs uppercase", children: format })
1769
1848
  ] }),
1770
- excerpt && /* @__PURE__ */ jsx8("p", { className: "mt-3 text-base text-muted-foreground", children: excerpt })
1849
+ excerpt && /* @__PURE__ */ jsx9("p", { className: "mt-3 text-base text-muted-foreground", children: excerpt })
1771
1850
  ] }),
1772
- format === "static" ? /* @__PURE__ */ jsx8("p", { className: "text-sm text-muted-foreground", children: t("posts.form.static.previewHint") }) : (
1851
+ format === "static" ? /* @__PURE__ */ jsx9("p", { className: "text-sm text-muted-foreground", children: t("posts.form.static.previewHint") }) : (
1773
1852
  // Phase 7: preview HTML is fetched from the template's
1774
1853
  // `/admin/preview` Route Handler so `ampless.renderBody`
1775
1854
  // (async ReactNode) + `ampless.publicPostScriptsForPage(
@@ -1807,7 +1886,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1807
1886
  // document — an iframe srcDoc does not inherit the parent page's
1808
1887
  // CSS. Typography is now applied inside the document returned by
1809
1888
  // createPreviewRouteHandler (PREVIEW_BASE_CSS + theme cssVars).
1810
- /* @__PURE__ */ jsx8(
1889
+ /* @__PURE__ */ jsx9(
1811
1890
  "iframe",
1812
1891
  {
1813
1892
  title: "post-preview",
@@ -1817,7 +1896,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1817
1896
  }
1818
1897
  )
1819
1898
  ),
1820
- previewPost.tags && previewPost.tags.length > 0 && /* @__PURE__ */ jsx8("div", { className: "flex flex-wrap gap-2 border-t pt-4 text-sm", children: previewPost.tags.map((tag) => /* @__PURE__ */ jsxs8(
1899
+ previewPost.tags && previewPost.tags.length > 0 && /* @__PURE__ */ jsx9("div", { className: "flex flex-wrap gap-2 border-t pt-4 text-sm", children: previewPost.tags.map((tag) => /* @__PURE__ */ jsxs9(
1821
1900
  "span",
1822
1901
  {
1823
1902
  className: "rounded-full border px-2 py-0.5 text-xs text-muted-foreground",
@@ -1828,34 +1907,34 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1828
1907
  },
1829
1908
  tag
1830
1909
  )) }),
1831
- /* @__PURE__ */ jsx8("p", { className: "text-xs text-muted-foreground", children: t("posts.form.previewHint") })
1910
+ /* @__PURE__ */ jsx9("p", { className: "text-xs text-muted-foreground", children: t("posts.form.previewHint") })
1832
1911
  ] }),
1833
- /* @__PURE__ */ jsxs8("div", { className: view === "edit" ? "space-y-6" : "hidden", children: [
1834
- recovery && /* @__PURE__ */ jsxs8(
1912
+ /* @__PURE__ */ jsxs9("div", { className: view === "edit" ? "space-y-6" : "hidden", children: [
1913
+ recovery && /* @__PURE__ */ jsxs9(
1835
1914
  "div",
1836
1915
  {
1837
1916
  role: "alert",
1838
1917
  className: recovery.decision === "stale" ? "space-y-2 rounded-md border border-amber-300 bg-amber-50 p-4 text-sm dark:border-amber-800 dark:bg-amber-950" : "space-y-2 rounded-md border border-[var(--primary)]/40 bg-[var(--primary)]/5 p-4 text-sm",
1839
1918
  children: [
1840
- /* @__PURE__ */ jsx8("p", { className: "font-medium", children: recovery.decision === "stale" ? t("posts.draft.staleTitle") : t("posts.draft.recoverTitle") }),
1841
- /* @__PURE__ */ jsx8("p", { className: "text-muted-foreground", children: recovery.decision === "stale" ? t("posts.draft.staleBody", {
1919
+ /* @__PURE__ */ jsx9("p", { className: "font-medium", children: recovery.decision === "stale" ? t("posts.draft.staleTitle") : t("posts.draft.recoverTitle") }),
1920
+ /* @__PURE__ */ jsx9("p", { className: "text-muted-foreground", children: recovery.decision === "stale" ? t("posts.draft.staleBody", {
1842
1921
  when: formatDraftTime(recovery.draft.savedAt, draftTimezone, draftLocale)
1843
1922
  }) : t("posts.draft.recoverBody", {
1844
1923
  when: formatDraftTime(recovery.draft.savedAt, draftTimezone, draftLocale)
1845
1924
  }) }),
1846
- /* @__PURE__ */ jsxs8("div", { className: "flex gap-2", children: [
1847
- /* @__PURE__ */ jsx8(Button7, { type: "button", size: "sm", onClick: acceptRecovery, children: recovery.decision === "stale" ? t("posts.draft.restoreAnyway") : t("posts.draft.restore") }),
1848
- /* @__PURE__ */ jsx8(Button7, { type: "button", size: "sm", variant: "outline", onClick: discardRecovery, children: t("posts.draft.discard") })
1925
+ /* @__PURE__ */ jsxs9("div", { className: "flex gap-2", children: [
1926
+ /* @__PURE__ */ jsx9(Button7, { type: "button", size: "sm", onClick: acceptRecovery, children: recovery.decision === "stale" ? t("posts.draft.restoreAnyway") : t("posts.draft.restore") }),
1927
+ /* @__PURE__ */ jsx9(Button7, { type: "button", size: "sm", variant: "outline", onClick: discardRecovery, children: t("posts.draft.discard") })
1849
1928
  ] })
1850
1929
  ]
1851
1930
  }
1852
1931
  ),
1853
- restoredHint && !recovery && /* @__PURE__ */ jsx8("p", { className: "rounded-md border border-[var(--primary)]/40 bg-[var(--primary)]/5 px-3 py-2 text-xs text-muted-foreground", children: t("posts.draft.restored") }),
1854
- isStaticFormat && /* @__PURE__ */ jsx8("p", { className: "rounded-md border bg-muted/40 px-3 py-2 text-xs text-muted-foreground", children: t("posts.draft.staticUnsupported") }),
1855
- /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
1856
- /* @__PURE__ */ jsx8(Label, { htmlFor: "title", children: t("posts.form.title") }),
1857
- /* @__PURE__ */ jsx8(
1858
- Input,
1932
+ restoredHint && !recovery && /* @__PURE__ */ jsx9("p", { className: "rounded-md border border-[var(--primary)]/40 bg-[var(--primary)]/5 px-3 py-2 text-xs text-muted-foreground", children: t("posts.draft.restored") }),
1933
+ isStaticFormat && /* @__PURE__ */ jsx9("p", { className: "rounded-md border bg-muted/40 px-3 py-2 text-xs text-muted-foreground", children: t("posts.draft.staticUnsupported") }),
1934
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
1935
+ /* @__PURE__ */ jsx9(Label, { htmlFor: "title", children: t("posts.form.title") }),
1936
+ /* @__PURE__ */ jsx9(
1937
+ Input2,
1859
1938
  {
1860
1939
  id: "title",
1861
1940
  required: true,
@@ -1868,10 +1947,10 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1868
1947
  }
1869
1948
  )
1870
1949
  ] }),
1871
- /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
1872
- /* @__PURE__ */ jsx8(Label, { htmlFor: "slug", children: t("posts.form.slug") }),
1873
- /* @__PURE__ */ jsx8(
1874
- Input,
1950
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
1951
+ /* @__PURE__ */ jsx9(Label, { htmlFor: "slug", children: t("posts.form.slug") }),
1952
+ /* @__PURE__ */ jsx9(
1953
+ Input2,
1875
1954
  {
1876
1955
  id: "slug",
1877
1956
  value: slug,
@@ -1883,9 +1962,9 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1883
1962
  }
1884
1963
  )
1885
1964
  ] }),
1886
- /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
1887
- /* @__PURE__ */ jsx8(Label, { htmlFor: "excerpt", children: t("posts.form.excerpt") }),
1888
- /* @__PURE__ */ jsx8(
1965
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
1966
+ /* @__PURE__ */ jsx9(Label, { htmlFor: "excerpt", children: t("posts.form.excerpt") }),
1967
+ /* @__PURE__ */ jsx9(
1889
1968
  Textarea,
1890
1969
  {
1891
1970
  id: "excerpt",
@@ -1898,9 +1977,9 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1898
1977
  }
1899
1978
  )
1900
1979
  ] }),
1901
- /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
1902
- /* @__PURE__ */ jsx8(Label, { htmlFor: "format", children: t("posts.form.format") }),
1903
- /* @__PURE__ */ jsxs8(
1980
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
1981
+ /* @__PURE__ */ jsx9(Label, { htmlFor: "format", children: t("posts.form.format") }),
1982
+ /* @__PURE__ */ jsxs9(
1904
1983
  "select",
1905
1984
  {
1906
1985
  id: "format",
@@ -1908,34 +1987,34 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1908
1987
  onChange: (e) => changeFormat(e.target.value),
1909
1988
  className: "flex h-9 w-full max-w-xs rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm",
1910
1989
  children: [
1911
- /* @__PURE__ */ jsx8("option", { value: "tiptap", children: "Tiptap (rich editor)" }),
1912
- /* @__PURE__ */ jsx8("option", { value: "markdown", children: "Markdown" }),
1913
- /* @__PURE__ */ jsx8("option", { value: "html", children: "HTML" }),
1914
- /* @__PURE__ */ jsx8("option", { value: "static", children: t("posts.form.formatStaticLabel") })
1990
+ /* @__PURE__ */ jsx9("option", { value: "tiptap", children: "Tiptap (rich editor)" }),
1991
+ /* @__PURE__ */ jsx9("option", { value: "markdown", children: "Markdown" }),
1992
+ /* @__PURE__ */ jsx9("option", { value: "html", children: "HTML" }),
1993
+ /* @__PURE__ */ jsx9("option", { value: "static", children: t("posts.form.formatStaticLabel") })
1915
1994
  ]
1916
1995
  }
1917
1996
  ),
1918
- /* @__PURE__ */ jsx8("p", { className: "text-xs text-muted-foreground", children: t("posts.form.formatHint") })
1997
+ /* @__PURE__ */ jsx9("p", { className: "text-xs text-muted-foreground", children: t("posts.form.formatHint") })
1919
1998
  ] }),
1920
- /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
1921
- /* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between", children: [
1922
- /* @__PURE__ */ jsx8(Label, { children: t("posts.form.body") }),
1999
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
2000
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between", children: [
2001
+ /* @__PURE__ */ jsx9(Label, { children: t("posts.form.body") }),
1923
2002
  format !== "tiptap" && format !== "static" && // For textarea-based formats (markdown / html) there's no
1924
2003
  // embedded toolbar, so we surface the MediaPicker as a
1925
2004
  // standalone button. Selecting an asset inserts a
1926
2005
  // format-aware snippet at the cursor.
1927
- /* @__PURE__ */ jsx8(
2006
+ /* @__PURE__ */ jsx9(
1928
2007
  MediaPicker,
1929
2008
  {
1930
2009
  onSelect: insertMediaSnippet,
1931
- trigger: /* @__PURE__ */ jsxs8(Button7, { type: "button", variant: "outline", size: "sm", children: [
1932
- /* @__PURE__ */ jsx8(ImageIcon3, { className: "mr-2 h-3 w-3" }),
2010
+ trigger: /* @__PURE__ */ jsxs9(Button7, { type: "button", variant: "outline", size: "sm", children: [
2011
+ /* @__PURE__ */ jsx9(ImageIcon3, { className: "mr-2 h-3 w-3" }),
1933
2012
  t("posts.form.insertMedia")
1934
2013
  ] })
1935
2014
  }
1936
2015
  )
1937
2016
  ] }),
1938
- format === "tiptap" ? /* @__PURE__ */ jsx8(
2017
+ format === "tiptap" ? /* @__PURE__ */ jsx9(
1939
2018
  TiptapEditor,
1940
2019
  {
1941
2020
  initialContent: body,
@@ -1943,14 +2022,14 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1943
2022
  onUserEdit: markDirty
1944
2023
  },
1945
2024
  editorEpoch
1946
- ) : format === "static" ? /* @__PURE__ */ jsx8(
2025
+ ) : format === "static" ? /* @__PURE__ */ jsx9(
1947
2026
  StaticUploader,
1948
2027
  {
1949
2028
  initial: initialStaticBody,
1950
2029
  onFilesReady: (files, entrypoint) => setPendingBundle({ files, entrypoint }),
1951
2030
  onClear: () => setPendingBundle(null)
1952
2031
  }
1953
- ) : /* @__PURE__ */ jsx8(
2032
+ ) : /* @__PURE__ */ jsx9(
1954
2033
  Textarea,
1955
2034
  {
1956
2035
  ref: bodyTextareaRef,
@@ -1964,10 +2043,10 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1964
2043
  }
1965
2044
  )
1966
2045
  ] }),
1967
- /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
1968
- /* @__PURE__ */ jsx8(Label, { htmlFor: "tags", children: t("posts.form.tags") }),
1969
- /* @__PURE__ */ jsx8(
1970
- Input,
2046
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
2047
+ /* @__PURE__ */ jsx9(Label, { htmlFor: "tags", children: t("posts.form.tags") }),
2048
+ /* @__PURE__ */ jsx9(
2049
+ Input2,
1971
2050
  {
1972
2051
  id: "tags",
1973
2052
  value: tagsInput,
@@ -1978,11 +2057,11 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1978
2057
  placeholder: t("posts.form.tagsPlaceholder")
1979
2058
  }
1980
2059
  ),
1981
- /* @__PURE__ */ jsx8("p", { className: "text-xs text-muted-foreground", children: t("posts.form.tagsHint") })
2060
+ /* @__PURE__ */ jsx9("p", { className: "text-xs text-muted-foreground", children: t("posts.form.tagsHint") })
1982
2061
  ] }),
1983
- /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
1984
- /* @__PURE__ */ jsx8(Label, { htmlFor: "status", children: t("posts.form.status") }),
1985
- /* @__PURE__ */ jsxs8(
2062
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
2063
+ /* @__PURE__ */ jsx9(Label, { htmlFor: "status", children: t("posts.form.status") }),
2064
+ /* @__PURE__ */ jsxs9(
1986
2065
  "select",
1987
2066
  {
1988
2067
  id: "status",
@@ -1993,15 +2072,15 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1993
2072
  },
1994
2073
  className: "flex h-9 w-full max-w-xs rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm",
1995
2074
  children: [
1996
- /* @__PURE__ */ jsx8("option", { value: "draft", children: t("common.draft") }),
1997
- /* @__PURE__ */ jsx8("option", { value: "published", children: t("common.published") })
2075
+ /* @__PURE__ */ jsx9("option", { value: "draft", children: t("common.draft") }),
2076
+ /* @__PURE__ */ jsx9("option", { value: "published", children: t("common.published") })
1998
2077
  ]
1999
2078
  }
2000
2079
  )
2001
2080
  ] }),
2002
- /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
2003
- /* @__PURE__ */ jsx8(Label, { htmlFor: "publishedAt", children: t("posts.form.publishedAt") }),
2004
- /* @__PURE__ */ jsx8(
2081
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
2082
+ /* @__PURE__ */ jsx9(Label, { htmlFor: "publishedAt", children: t("posts.form.publishedAt") }),
2083
+ /* @__PURE__ */ jsx9(
2005
2084
  "input",
2006
2085
  {
2007
2086
  id: "publishedAt",
@@ -2014,11 +2093,11 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
2014
2093
  className: "flex h-9 w-full max-w-xs rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm"
2015
2094
  }
2016
2095
  ),
2017
- /* @__PURE__ */ jsx8("p", { className: "text-xs text-muted-foreground", children: t("posts.form.publishedAtHint") }),
2018
- status === "published" && isFuture(resolvedPublishedAt) && /* @__PURE__ */ jsx8("p", { className: "text-xs text-amber-600 dark:text-amber-400", children: t("posts.form.scheduledNotice", { date: publishedAtInput }) })
2096
+ /* @__PURE__ */ jsx9("p", { className: "text-xs text-muted-foreground", children: t("posts.form.publishedAtHint") }),
2097
+ status === "published" && isFuture(resolvedPublishedAt) && /* @__PURE__ */ jsx9("p", { className: "text-xs text-amber-600 dark:text-amber-400", children: t("posts.form.scheduledNotice", { date: publishedAtInput }) })
2019
2098
  ] }),
2020
- format === "html" && /* @__PURE__ */ jsx8("div", { className: "space-y-2", children: /* @__PURE__ */ jsxs8("label", { className: "flex items-start gap-2 text-sm", children: [
2021
- /* @__PURE__ */ jsx8(
2099
+ format === "html" && /* @__PURE__ */ jsx9("div", { className: "space-y-2", children: /* @__PURE__ */ jsxs9("label", { className: "flex items-start gap-2 text-sm", children: [
2100
+ /* @__PURE__ */ jsx9(
2022
2101
  "input",
2023
2102
  {
2024
2103
  type: "checkbox",
@@ -2030,17 +2109,17 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
2030
2109
  className: "mt-1"
2031
2110
  }
2032
2111
  ),
2033
- /* @__PURE__ */ jsxs8("span", { children: [
2034
- /* @__PURE__ */ jsx8("span", { className: "font-medium", children: t("posts.form.noLayout") }),
2035
- /* @__PURE__ */ jsx8("span", { className: "block text-xs text-muted-foreground", children: t("posts.form.noLayoutHint") })
2112
+ /* @__PURE__ */ jsxs9("span", { children: [
2113
+ /* @__PURE__ */ jsx9("span", { className: "font-medium", children: t("posts.form.noLayout") }),
2114
+ /* @__PURE__ */ jsx9("span", { className: "block text-xs text-muted-foreground", children: t("posts.form.noLayoutHint") })
2036
2115
  ] })
2037
2116
  ] }) }),
2038
- error && /* @__PURE__ */ jsx8("p", { className: "text-sm text-destructive", children: error }),
2039
- /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
2040
- /* @__PURE__ */ jsx8(Button7, { type: "submit", disabled: saving, children: saving ? t("common.saving") : isEdit ? t("posts.form.saveChanges") : t("posts.form.createPost") }),
2041
- isEdit && /* @__PURE__ */ jsx8(Button7, { type: "button", variant: "destructive", onClick: handleDelete, disabled: saving, children: t("posts.form.delete") })
2117
+ error && /* @__PURE__ */ jsx9("p", { className: "text-sm text-destructive", children: error }),
2118
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
2119
+ /* @__PURE__ */ jsx9(Button7, { type: "submit", disabled: saving, children: saving ? t("common.saving") : isEdit ? t("posts.form.saveChanges") : t("posts.form.createPost") }),
2120
+ isEdit && /* @__PURE__ */ jsx9(Button7, { type: "button", variant: "destructive", onClick: handleDelete, disabled: saving, children: t("posts.form.delete") })
2042
2121
  ] }),
2043
- isEdit && post && /* @__PURE__ */ jsx8(
2122
+ isEdit && post && /* @__PURE__ */ jsx9(
2044
2123
  PostHistoryPanel,
2045
2124
  {
2046
2125
  postId: post.postId,