@ampless/admin 1.0.0-beta.92 → 1.0.0-beta.93

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 (36) hide show
  1. package/dist/api/index.d.ts +1 -1
  2. package/dist/{chunk-FVHQJCH4.js → chunk-26ZRUSES.js} +2 -2
  3. package/dist/{chunk-IBFNFTJ6.js → chunk-2GFTMGIZ.js} +1 -1
  4. package/dist/{chunk-M5QQJHM7.js → chunk-4UIDGQ2L.js} +8 -0
  5. package/dist/{chunk-TMOFUAU7.js → chunk-5KUAGEQW.js} +1 -1
  6. package/dist/{chunk-6275N7HG.js → chunk-5L2ICOCA.js} +1 -1
  7. package/dist/{chunk-2Y5SRSCZ.js → chunk-6EGOUZXY.js} +1 -1
  8. package/dist/{chunk-OPHSYQQV.js → chunk-ASEYWSR6.js} +2 -2
  9. package/dist/{chunk-OAG4NI7Q.js → chunk-BU7YQ5MS.js} +1 -1
  10. package/dist/{chunk-FVGWVH6Q.js → chunk-ISE2LXLA.js} +3 -3
  11. package/dist/{chunk-VJ5SDYVW.js → chunk-JTPEKM5J.js} +1 -1
  12. package/dist/{chunk-HRCUFIGW.js → chunk-LHHWZQDN.js} +2 -2
  13. package/dist/{chunk-HKMHNEFV.js → chunk-P7NMQTSQ.js} +1 -1
  14. package/dist/{chunk-QO73C7VC.js → chunk-PQU342OC.js} +1 -1
  15. package/dist/{chunk-TEMSFG34.js → chunk-QTU63B4K.js} +2 -2
  16. package/dist/{chunk-UUZAKCZZ.js → chunk-TDXYTNZB.js} +283 -213
  17. package/dist/{chunk-3AQGYUVP.js → chunk-UYT6WMWV.js} +1 -1
  18. package/dist/components/account-view.js +3 -3
  19. package/dist/components/admin-dashboard.js +3 -3
  20. package/dist/components/edit-post-view.js +5 -5
  21. package/dist/components/index.d.ts +1 -1
  22. package/dist/components/index.js +6 -6
  23. package/dist/components/login-view.js +3 -3
  24. package/dist/components/mcp-tokens-view.js +3 -3
  25. package/dist/components/media-view.js +5 -5
  26. package/dist/components/new-post-view.js +5 -5
  27. package/dist/components/plugin-settings-form.js +3 -3
  28. package/dist/components/posts-list-view.js +3 -3
  29. package/dist/components/users-list-view.js +3 -3
  30. package/dist/{i18n-CecqYBeP.d.ts → i18n-BOuZ2Yhb.d.ts} +12 -0
  31. package/dist/index.d.ts +2 -2
  32. package/dist/index.js +1 -1
  33. package/dist/metafile-esm.json +1 -1
  34. package/dist/pages/index.d.ts +1 -1
  35. package/dist/pages/index.js +16 -16
  36. package/package.json +3 -3
@@ -4,7 +4,7 @@ import {
4
4
  getAdminCmsConfig,
5
5
  getMediaProcessingDefaults,
6
6
  uploadProcessedImage
7
- } from "./chunk-6275N7HG.js";
7
+ } from "./chunk-5L2ICOCA.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-IBFNFTJ6.js";
18
+ } from "./chunk-2GFTMGIZ.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
 
@@ -1005,13 +1075,13 @@ async function deleteBundle(slug) {
1005
1075
  }
1006
1076
 
1007
1077
  // src/components/static-uploader.tsx
1008
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1078
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1009
1079
  function StaticUploader({ initial, onFilesReady, onClear }) {
1010
1080
  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);
1081
+ const [pending, setPending] = useState5(null);
1082
+ const [issues, setIssues] = useState5([]);
1083
+ const [busy, setBusy] = useState5(false);
1084
+ const [error, setError] = useState5(null);
1015
1085
  async function handleZip(file) {
1016
1086
  setBusy(true);
1017
1087
  setError(null);
@@ -1085,11 +1155,11 @@ function StaticUploader({ initial, onFilesReady, onClear }) {
1085
1155
  onClear();
1086
1156
  }
1087
1157
  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(
1158
+ return /* @__PURE__ */ jsxs8("div", { className: "space-y-4", children: [
1159
+ /* @__PURE__ */ jsxs8("div", { className: "rounded-md border border-dashed p-4", children: [
1160
+ /* @__PURE__ */ jsxs8("label", { className: "flex flex-col items-start gap-2 text-sm", children: [
1161
+ /* @__PURE__ */ jsx8("span", { className: "font-medium", children: t("posts.form.static.pick") }),
1162
+ /* @__PURE__ */ jsx8(
1093
1163
  "input",
1094
1164
  {
1095
1165
  type: "file",
@@ -1099,13 +1169,13 @@ function StaticUploader({ initial, onFilesReady, onClear }) {
1099
1169
  disabled: busy
1100
1170
  }
1101
1171
  ),
1102
- /* @__PURE__ */ jsx7("span", { className: "text-xs text-muted-foreground", children: t("posts.form.static.pickHint") })
1172
+ /* @__PURE__ */ jsx8("span", { className: "text-xs text-muted-foreground", children: t("posts.form.static.pickHint") })
1103
1173
  ] }),
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 })
1174
+ busy && /* @__PURE__ */ jsx8("p", { className: "mt-2 text-sm text-muted-foreground", children: t("common.loading") }),
1175
+ error && /* @__PURE__ */ jsx8("p", { className: "mt-2 text-sm text-destructive", children: error })
1106
1176
  ] }),
1107
- showCurrent && /* @__PURE__ */ jsx7(CurrentBundle, { body: initial }),
1108
- pending && /* @__PURE__ */ jsx7(
1177
+ showCurrent && /* @__PURE__ */ jsx8(CurrentBundle, { body: initial }),
1178
+ pending && /* @__PURE__ */ jsx8(
1109
1179
  PendingBundle,
1110
1180
  {
1111
1181
  files: pending,
@@ -1117,15 +1187,15 @@ function StaticUploader({ initial, onFilesReady, onClear }) {
1117
1187
  }
1118
1188
  function CurrentBundle({ body }) {
1119
1189
  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" }),
1190
+ return /* @__PURE__ */ jsxs8("div", { className: "rounded-md border bg-muted/30 p-3", children: [
1191
+ /* @__PURE__ */ jsxs8("div", { className: "mb-2 flex items-center gap-2 text-sm font-medium", children: [
1192
+ /* @__PURE__ */ jsx8(FileArchive, { className: "h-4 w-4" }),
1123
1193
  t("posts.form.static.currentBundle", {
1124
1194
  count: body.files.length,
1125
1195
  entrypoint: body.entrypoint
1126
1196
  })
1127
1197
  ] }),
1128
- /* @__PURE__ */ jsx7(FileList, { files: body.files })
1198
+ /* @__PURE__ */ jsx8(FileList, { files: body.files })
1129
1199
  ] });
1130
1200
  }
1131
1201
  function PendingBundle({
@@ -1135,49 +1205,49 @@ function PendingBundle({
1135
1205
  }) {
1136
1206
  const t = useT();
1137
1207
  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" }),
1208
+ return /* @__PURE__ */ jsxs8("div", { className: "rounded-md border p-3", children: [
1209
+ /* @__PURE__ */ jsxs8("div", { className: "mb-2 flex items-center justify-between gap-2 text-sm font-medium", children: [
1210
+ /* @__PURE__ */ jsxs8("span", { className: "flex items-center gap-2", children: [
1211
+ /* @__PURE__ */ jsx8(FileArchive, { className: "h-4 w-4" }),
1142
1212
  t("posts.form.static.pendingBundle", {
1143
1213
  count: files.length,
1144
1214
  size: formatBytes(totalBytes)
1145
1215
  })
1146
1216
  ] }),
1147
- /* @__PURE__ */ jsxs7(Button6, { type: "button", variant: "ghost", size: "sm", onClick: onClear, children: [
1148
- /* @__PURE__ */ jsx7(X, { className: "mr-1 h-3 w-3" }),
1217
+ /* @__PURE__ */ jsxs8(Button6, { type: "button", variant: "ghost", size: "sm", onClick: onClear, children: [
1218
+ /* @__PURE__ */ jsx8(X, { className: "mr-1 h-3 w-3" }),
1149
1219
  t("common.cancel")
1150
1220
  ] })
1151
1221
  ] }),
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" }),
1222
+ issues.length > 0 && /* @__PURE__ */ jsxs8("div", { className: "mb-3 rounded-md border border-destructive/40 bg-destructive/5 p-2 text-sm", children: [
1223
+ /* @__PURE__ */ jsxs8("div", { className: "mb-1 flex items-center gap-2 font-medium text-destructive", children: [
1224
+ /* @__PURE__ */ jsx8(AlertTriangle, { className: "h-4 w-4" }),
1155
1225
  t("posts.form.static.issuesTitle", { count: issues.length })
1156
1226
  ] }),
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: [
1227
+ /* @__PURE__ */ jsxs8("ul", { className: "space-y-0.5 text-xs", children: [
1228
+ issues.slice(0, 20).map((issue, idx) => /* @__PURE__ */ jsxs8("li", { className: "font-mono", children: [
1159
1229
  issue.path,
1160
1230
  ": ",
1161
1231
  issue.reason
1162
1232
  ] }, `${issue.path}-${idx}`)),
1163
- issues.length > 20 && /* @__PURE__ */ jsxs7("li", { className: "font-mono text-muted-foreground", children: [
1233
+ issues.length > 20 && /* @__PURE__ */ jsxs8("li", { className: "font-mono text-muted-foreground", children: [
1164
1234
  "\u2026 ",
1165
1235
  issues.length - 20,
1166
1236
  " more"
1167
1237
  ] })
1168
1238
  ] }),
1169
- /* @__PURE__ */ jsx7("p", { className: "mt-2 text-xs text-muted-foreground", children: t("posts.form.static.issuesHint") })
1239
+ /* @__PURE__ */ jsx8("p", { className: "mt-2 text-xs text-muted-foreground", children: t("posts.form.static.issuesHint") })
1170
1240
  ] }),
1171
- /* @__PURE__ */ jsx7(FileList, { files: files.map((f) => f.path) })
1241
+ /* @__PURE__ */ jsx8(FileList, { files: files.map((f) => f.path) })
1172
1242
  ] });
1173
1243
  }
1174
1244
  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" }),
1245
+ return /* @__PURE__ */ jsxs8("ul", { className: "space-y-0.5 text-xs", children: [
1246
+ files.slice(0, 40).map((path) => /* @__PURE__ */ jsxs8("li", { className: "flex items-center gap-1.5 font-mono text-muted-foreground", children: [
1247
+ /* @__PURE__ */ jsx8(FileText, { className: "h-3 w-3 shrink-0" }),
1178
1248
  path
1179
1249
  ] }, path)),
1180
- files.length > 40 && /* @__PURE__ */ jsxs7("li", { className: "font-mono text-xs text-muted-foreground", children: [
1250
+ files.length > 40 && /* @__PURE__ */ jsxs8("li", { className: "font-mono text-xs text-muted-foreground", children: [
1181
1251
  "\u2026 ",
1182
1252
  files.length - 40,
1183
1253
  " more"
@@ -1371,7 +1441,7 @@ function convertBodyFormat(body, from, to, registries) {
1371
1441
  }
1372
1442
 
1373
1443
  // src/components/post-form.tsx
1374
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1444
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1375
1445
  var EMPTY_TIPTAP_DOC = { type: "doc", content: [{ type: "paragraph" }] };
1376
1446
  var IMAGE_URL_RE = /\.(jpe?g|png|gif|webp|avif|svg|bmp|tiff?)(\?|$)/i;
1377
1447
  var STYLESHEET_URL_RE = /\.css(\?|$)/i;
@@ -1417,27 +1487,27 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1417
1487
  const router = useRouter();
1418
1488
  const t = useT();
1419
1489
  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);
1490
+ const bodyTextareaRef = useRef4(null);
1491
+ const [title, setTitle] = useState6(post?.title ?? "");
1492
+ const [slug, setSlug] = useState6(post?.slug ?? "");
1493
+ const [excerpt, setExcerpt] = useState6(post?.excerpt ?? "");
1494
+ const [format, setFormat] = useState6(post?.format ?? "tiptap");
1495
+ const [body, setBody] = useState6(post?.body ?? EMPTY_TIPTAP_DOC);
1496
+ const [status, setStatus] = useState6(post?.status ?? "draft");
1497
+ const [tagsInput, setTagsInput] = useState6((post?.tags ?? []).join(", "));
1498
+ const [noLayout, setNoLayout] = useState6(post?.metadata?.no_layout === true);
1499
+ const [publishedAtInput, setPublishedAtInput] = useState6(isoToLocalInput(post?.publishedAt));
1500
+ const [saving, setSaving] = useState6(false);
1501
+ const [error, setError] = useState6(null);
1502
+ const [view, setView] = useState6("edit");
1503
+ const [previewHtml, setPreviewHtml] = useState6("");
1504
+ const [editorEpoch, setEditorEpoch] = useState6(0);
1505
+ const dirtyRef = useRef4(false);
1436
1506
  function markDirty() {
1437
1507
  dirtyRef.current = true;
1438
1508
  }
1439
- const [recovery, setRecovery] = useState5(null);
1440
- const [restoredHint, setRestoredHint] = useState5(false);
1509
+ const [recovery, setRecovery] = useState6(null);
1510
+ const [restoredHint, setRestoredHint] = useState6(false);
1441
1511
  const draftId = post?.postId ?? NEW_POST_DRAFT_ID;
1442
1512
  const isStaticFormat = format === "static";
1443
1513
  const cmsConfig = getAdminCmsConfig();
@@ -1450,7 +1520,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1450
1520
  initialInput: initialPublishedAtInput,
1451
1521
  existing: post?.publishedAt
1452
1522
  });
1453
- const [pendingBundle, setPendingBundle] = useState5(null);
1523
+ const [pendingBundle, setPendingBundle] = useState6(null);
1454
1524
  const initialStaticBody = isStaticBody(post?.body) ? post.body : null;
1455
1525
  function buildMetadata() {
1456
1526
  const next = { ...post?.metadata ?? {} };
@@ -1518,7 +1588,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1518
1588
  dirtyRef.current = false;
1519
1589
  setRecovery(null);
1520
1590
  }
1521
- useEffect4(() => {
1591
+ useEffect5(() => {
1522
1592
  if (loadedState.format === "static") return;
1523
1593
  const draft = readDraft(draftId);
1524
1594
  if (!draft) return;
@@ -1533,7 +1603,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1533
1603
  }
1534
1604
  setRecovery({ draft, decision });
1535
1605
  }, []);
1536
- useEffect4(() => {
1606
+ useEffect5(() => {
1537
1607
  if (isStaticFormat) return;
1538
1608
  if (!dirtyRef.current) return;
1539
1609
  const handle = setTimeout(() => {
@@ -1700,7 +1770,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1700
1770
  publishedAt: resolvedPublishedAt,
1701
1771
  tags: parseTags(tagsInput)
1702
1772
  };
1703
- useEffect4(() => {
1773
+ useEffect5(() => {
1704
1774
  if (view !== "preview") return;
1705
1775
  if (format === "static") return;
1706
1776
  const ctrl = new AbortController();
@@ -1736,9 +1806,9 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1736
1806
  resolvedPublishedAt,
1737
1807
  tagsInput
1738
1808
  ]);
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(
1809
+ return /* @__PURE__ */ jsxs9("form", { onSubmit: save, className: "space-y-6", children: [
1810
+ /* @__PURE__ */ jsxs9("div", { className: "flex gap-1 border-b", children: [
1811
+ /* @__PURE__ */ jsx9(
1742
1812
  "button",
1743
1813
  {
1744
1814
  type: "button",
@@ -1748,7 +1818,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1748
1818
  children: t("posts.form.tabEdit")
1749
1819
  }
1750
1820
  ),
1751
- /* @__PURE__ */ jsx8(
1821
+ /* @__PURE__ */ jsx9(
1752
1822
  "button",
1753
1823
  {
1754
1824
  type: "button",
@@ -1759,17 +1829,17 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1759
1829
  }
1760
1830
  )
1761
1831
  ] }),
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 })
1832
+ view === "preview" && /* @__PURE__ */ jsxs9("article", { className: "space-y-4", children: [
1833
+ /* @__PURE__ */ jsxs9("header", { className: "border-b pb-4", children: [
1834
+ /* @__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") }) }),
1835
+ /* @__PURE__ */ jsxs9("p", { className: "mt-2 text-sm text-muted-foreground", children: [
1836
+ previewPost.publishedAt ? /* @__PURE__ */ jsx9("time", { dateTime: previewPost.publishedAt, children: formatDate(previewPost.publishedAt) }) : /* @__PURE__ */ jsx9("span", { children: t("common.draft") }),
1837
+ /* @__PURE__ */ jsx9("span", { className: "mx-2", children: "\xB7" }),
1838
+ /* @__PURE__ */ jsx9("span", { className: "font-mono text-xs uppercase", children: format })
1769
1839
  ] }),
1770
- excerpt && /* @__PURE__ */ jsx8("p", { className: "mt-3 text-base text-muted-foreground", children: excerpt })
1840
+ excerpt && /* @__PURE__ */ jsx9("p", { className: "mt-3 text-base text-muted-foreground", children: excerpt })
1771
1841
  ] }),
1772
- format === "static" ? /* @__PURE__ */ jsx8("p", { className: "text-sm text-muted-foreground", children: t("posts.form.static.previewHint") }) : (
1842
+ format === "static" ? /* @__PURE__ */ jsx9("p", { className: "text-sm text-muted-foreground", children: t("posts.form.static.previewHint") }) : (
1773
1843
  // Phase 7: preview HTML is fetched from the template's
1774
1844
  // `/admin/preview` Route Handler so `ampless.renderBody`
1775
1845
  // (async ReactNode) + `ampless.publicPostScriptsForPage(
@@ -1807,7 +1877,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1807
1877
  // document — an iframe srcDoc does not inherit the parent page's
1808
1878
  // CSS. Typography is now applied inside the document returned by
1809
1879
  // createPreviewRouteHandler (PREVIEW_BASE_CSS + theme cssVars).
1810
- /* @__PURE__ */ jsx8(
1880
+ /* @__PURE__ */ jsx9(
1811
1881
  "iframe",
1812
1882
  {
1813
1883
  title: "post-preview",
@@ -1817,7 +1887,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1817
1887
  }
1818
1888
  )
1819
1889
  ),
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(
1890
+ 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
1891
  "span",
1822
1892
  {
1823
1893
  className: "rounded-full border px-2 py-0.5 text-xs text-muted-foreground",
@@ -1828,34 +1898,34 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1828
1898
  },
1829
1899
  tag
1830
1900
  )) }),
1831
- /* @__PURE__ */ jsx8("p", { className: "text-xs text-muted-foreground", children: t("posts.form.previewHint") })
1901
+ /* @__PURE__ */ jsx9("p", { className: "text-xs text-muted-foreground", children: t("posts.form.previewHint") })
1832
1902
  ] }),
1833
- /* @__PURE__ */ jsxs8("div", { className: view === "edit" ? "space-y-6" : "hidden", children: [
1834
- recovery && /* @__PURE__ */ jsxs8(
1903
+ /* @__PURE__ */ jsxs9("div", { className: view === "edit" ? "space-y-6" : "hidden", children: [
1904
+ recovery && /* @__PURE__ */ jsxs9(
1835
1905
  "div",
1836
1906
  {
1837
1907
  role: "alert",
1838
1908
  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
1909
  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", {
1910
+ /* @__PURE__ */ jsx9("p", { className: "font-medium", children: recovery.decision === "stale" ? t("posts.draft.staleTitle") : t("posts.draft.recoverTitle") }),
1911
+ /* @__PURE__ */ jsx9("p", { className: "text-muted-foreground", children: recovery.decision === "stale" ? t("posts.draft.staleBody", {
1842
1912
  when: formatDraftTime(recovery.draft.savedAt, draftTimezone, draftLocale)
1843
1913
  }) : t("posts.draft.recoverBody", {
1844
1914
  when: formatDraftTime(recovery.draft.savedAt, draftTimezone, draftLocale)
1845
1915
  }) }),
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") })
1916
+ /* @__PURE__ */ jsxs9("div", { className: "flex gap-2", children: [
1917
+ /* @__PURE__ */ jsx9(Button7, { type: "button", size: "sm", onClick: acceptRecovery, children: recovery.decision === "stale" ? t("posts.draft.restoreAnyway") : t("posts.draft.restore") }),
1918
+ /* @__PURE__ */ jsx9(Button7, { type: "button", size: "sm", variant: "outline", onClick: discardRecovery, children: t("posts.draft.discard") })
1849
1919
  ] })
1850
1920
  ]
1851
1921
  }
1852
1922
  ),
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,
1923
+ 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") }),
1924
+ 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") }),
1925
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
1926
+ /* @__PURE__ */ jsx9(Label, { htmlFor: "title", children: t("posts.form.title") }),
1927
+ /* @__PURE__ */ jsx9(
1928
+ Input2,
1859
1929
  {
1860
1930
  id: "title",
1861
1931
  required: true,
@@ -1868,10 +1938,10 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1868
1938
  }
1869
1939
  )
1870
1940
  ] }),
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,
1941
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
1942
+ /* @__PURE__ */ jsx9(Label, { htmlFor: "slug", children: t("posts.form.slug") }),
1943
+ /* @__PURE__ */ jsx9(
1944
+ Input2,
1875
1945
  {
1876
1946
  id: "slug",
1877
1947
  value: slug,
@@ -1883,9 +1953,9 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1883
1953
  }
1884
1954
  )
1885
1955
  ] }),
1886
- /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
1887
- /* @__PURE__ */ jsx8(Label, { htmlFor: "excerpt", children: t("posts.form.excerpt") }),
1888
- /* @__PURE__ */ jsx8(
1956
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
1957
+ /* @__PURE__ */ jsx9(Label, { htmlFor: "excerpt", children: t("posts.form.excerpt") }),
1958
+ /* @__PURE__ */ jsx9(
1889
1959
  Textarea,
1890
1960
  {
1891
1961
  id: "excerpt",
@@ -1898,9 +1968,9 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1898
1968
  }
1899
1969
  )
1900
1970
  ] }),
1901
- /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
1902
- /* @__PURE__ */ jsx8(Label, { htmlFor: "format", children: t("posts.form.format") }),
1903
- /* @__PURE__ */ jsxs8(
1971
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
1972
+ /* @__PURE__ */ jsx9(Label, { htmlFor: "format", children: t("posts.form.format") }),
1973
+ /* @__PURE__ */ jsxs9(
1904
1974
  "select",
1905
1975
  {
1906
1976
  id: "format",
@@ -1908,34 +1978,34 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1908
1978
  onChange: (e) => changeFormat(e.target.value),
1909
1979
  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
1980
  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") })
1981
+ /* @__PURE__ */ jsx9("option", { value: "tiptap", children: "Tiptap (rich editor)" }),
1982
+ /* @__PURE__ */ jsx9("option", { value: "markdown", children: "Markdown" }),
1983
+ /* @__PURE__ */ jsx9("option", { value: "html", children: "HTML" }),
1984
+ /* @__PURE__ */ jsx9("option", { value: "static", children: t("posts.form.formatStaticLabel") })
1915
1985
  ]
1916
1986
  }
1917
1987
  ),
1918
- /* @__PURE__ */ jsx8("p", { className: "text-xs text-muted-foreground", children: t("posts.form.formatHint") })
1988
+ /* @__PURE__ */ jsx9("p", { className: "text-xs text-muted-foreground", children: t("posts.form.formatHint") })
1919
1989
  ] }),
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") }),
1990
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
1991
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between", children: [
1992
+ /* @__PURE__ */ jsx9(Label, { children: t("posts.form.body") }),
1923
1993
  format !== "tiptap" && format !== "static" && // For textarea-based formats (markdown / html) there's no
1924
1994
  // embedded toolbar, so we surface the MediaPicker as a
1925
1995
  // standalone button. Selecting an asset inserts a
1926
1996
  // format-aware snippet at the cursor.
1927
- /* @__PURE__ */ jsx8(
1997
+ /* @__PURE__ */ jsx9(
1928
1998
  MediaPicker,
1929
1999
  {
1930
2000
  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" }),
2001
+ trigger: /* @__PURE__ */ jsxs9(Button7, { type: "button", variant: "outline", size: "sm", children: [
2002
+ /* @__PURE__ */ jsx9(ImageIcon3, { className: "mr-2 h-3 w-3" }),
1933
2003
  t("posts.form.insertMedia")
1934
2004
  ] })
1935
2005
  }
1936
2006
  )
1937
2007
  ] }),
1938
- format === "tiptap" ? /* @__PURE__ */ jsx8(
2008
+ format === "tiptap" ? /* @__PURE__ */ jsx9(
1939
2009
  TiptapEditor,
1940
2010
  {
1941
2011
  initialContent: body,
@@ -1943,14 +2013,14 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1943
2013
  onUserEdit: markDirty
1944
2014
  },
1945
2015
  editorEpoch
1946
- ) : format === "static" ? /* @__PURE__ */ jsx8(
2016
+ ) : format === "static" ? /* @__PURE__ */ jsx9(
1947
2017
  StaticUploader,
1948
2018
  {
1949
2019
  initial: initialStaticBody,
1950
2020
  onFilesReady: (files, entrypoint) => setPendingBundle({ files, entrypoint }),
1951
2021
  onClear: () => setPendingBundle(null)
1952
2022
  }
1953
- ) : /* @__PURE__ */ jsx8(
2023
+ ) : /* @__PURE__ */ jsx9(
1954
2024
  Textarea,
1955
2025
  {
1956
2026
  ref: bodyTextareaRef,
@@ -1964,10 +2034,10 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1964
2034
  }
1965
2035
  )
1966
2036
  ] }),
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,
2037
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
2038
+ /* @__PURE__ */ jsx9(Label, { htmlFor: "tags", children: t("posts.form.tags") }),
2039
+ /* @__PURE__ */ jsx9(
2040
+ Input2,
1971
2041
  {
1972
2042
  id: "tags",
1973
2043
  value: tagsInput,
@@ -1978,11 +2048,11 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1978
2048
  placeholder: t("posts.form.tagsPlaceholder")
1979
2049
  }
1980
2050
  ),
1981
- /* @__PURE__ */ jsx8("p", { className: "text-xs text-muted-foreground", children: t("posts.form.tagsHint") })
2051
+ /* @__PURE__ */ jsx9("p", { className: "text-xs text-muted-foreground", children: t("posts.form.tagsHint") })
1982
2052
  ] }),
1983
- /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
1984
- /* @__PURE__ */ jsx8(Label, { htmlFor: "status", children: t("posts.form.status") }),
1985
- /* @__PURE__ */ jsxs8(
2053
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
2054
+ /* @__PURE__ */ jsx9(Label, { htmlFor: "status", children: t("posts.form.status") }),
2055
+ /* @__PURE__ */ jsxs9(
1986
2056
  "select",
1987
2057
  {
1988
2058
  id: "status",
@@ -1993,15 +2063,15 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
1993
2063
  },
1994
2064
  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
2065
  children: [
1996
- /* @__PURE__ */ jsx8("option", { value: "draft", children: t("common.draft") }),
1997
- /* @__PURE__ */ jsx8("option", { value: "published", children: t("common.published") })
2066
+ /* @__PURE__ */ jsx9("option", { value: "draft", children: t("common.draft") }),
2067
+ /* @__PURE__ */ jsx9("option", { value: "published", children: t("common.published") })
1998
2068
  ]
1999
2069
  }
2000
2070
  )
2001
2071
  ] }),
2002
- /* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
2003
- /* @__PURE__ */ jsx8(Label, { htmlFor: "publishedAt", children: t("posts.form.publishedAt") }),
2004
- /* @__PURE__ */ jsx8(
2072
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
2073
+ /* @__PURE__ */ jsx9(Label, { htmlFor: "publishedAt", children: t("posts.form.publishedAt") }),
2074
+ /* @__PURE__ */ jsx9(
2005
2075
  "input",
2006
2076
  {
2007
2077
  id: "publishedAt",
@@ -2014,11 +2084,11 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
2014
2084
  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
2085
  }
2016
2086
  ),
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 }) })
2087
+ /* @__PURE__ */ jsx9("p", { className: "text-xs text-muted-foreground", children: t("posts.form.publishedAtHint") }),
2088
+ 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
2089
  ] }),
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(
2090
+ format === "html" && /* @__PURE__ */ jsx9("div", { className: "space-y-2", children: /* @__PURE__ */ jsxs9("label", { className: "flex items-start gap-2 text-sm", children: [
2091
+ /* @__PURE__ */ jsx9(
2022
2092
  "input",
2023
2093
  {
2024
2094
  type: "checkbox",
@@ -2030,17 +2100,17 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
2030
2100
  className: "mt-1"
2031
2101
  }
2032
2102
  ),
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") })
2103
+ /* @__PURE__ */ jsxs9("span", { children: [
2104
+ /* @__PURE__ */ jsx9("span", { className: "font-medium", children: t("posts.form.noLayout") }),
2105
+ /* @__PURE__ */ jsx9("span", { className: "block text-xs text-muted-foreground", children: t("posts.form.noLayoutHint") })
2036
2106
  ] })
2037
2107
  ] }) }),
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") })
2108
+ error && /* @__PURE__ */ jsx9("p", { className: "text-sm text-destructive", children: error }),
2109
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
2110
+ /* @__PURE__ */ jsx9(Button7, { type: "submit", disabled: saving, children: saving ? t("common.saving") : isEdit ? t("posts.form.saveChanges") : t("posts.form.createPost") }),
2111
+ isEdit && /* @__PURE__ */ jsx9(Button7, { type: "button", variant: "destructive", onClick: handleDelete, disabled: saving, children: t("posts.form.delete") })
2042
2112
  ] }),
2043
- isEdit && post && /* @__PURE__ */ jsx8(
2113
+ isEdit && post && /* @__PURE__ */ jsx9(
2044
2114
  PostHistoryPanel,
2045
2115
  {
2046
2116
  postId: post.postId,