@ampless/admin 1.0.0-alpha.85 → 1.0.0-beta.100
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.
- package/README.ja.md +2 -2
- package/README.md +2 -2
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.js +4 -2
- package/dist/{chunk-SQ6LFPXH.js → chunk-2TBGPB5H.js} +2 -2
- package/dist/{chunk-K44QF3MV.js → chunk-4OFRX6QX.js} +1 -1
- package/dist/{chunk-HANIMWMN.js → chunk-4WYMEUYU.js} +301 -222
- package/dist/chunk-7HSWOQWV.js +172 -0
- package/dist/{chunk-J6R356H3.js → chunk-7OZ23MLD.js} +1 -1
- package/dist/{chunk-OFPNBZKP.js → chunk-7W7LAQXY.js} +76 -8
- package/dist/{chunk-HN3UFHP7.js → chunk-ANME5KDN.js} +1 -1
- package/dist/{chunk-GGHN2RKQ.js → chunk-E5VF3Y65.js} +69 -3
- package/dist/{chunk-7LT6YPIT.js → chunk-JLCTF5HY.js} +8 -2
- package/dist/{chunk-R3TEJ32M.js → chunk-LXY3BRKQ.js} +2 -2
- package/dist/{chunk-MKWYNK4J.js → chunk-NHMG2MRJ.js} +2 -2
- package/dist/{chunk-AYESATAM.js → chunk-OPVLQOOB.js} +44 -13
- package/dist/{chunk-SMI7Y77B.js → chunk-ORXOMW7M.js} +265 -190
- package/dist/{chunk-W4VHP2JW.js → chunk-SYAEM5DM.js} +1 -1
- package/dist/{chunk-7NQERXNY.js → chunk-TJZ4FTU6.js} +1 -1
- package/dist/{chunk-CFIOUXVE.js → chunk-V5XORHKX.js} +1 -1
- package/dist/chunk-ZDIDJCSU.js +40 -0
- package/dist/components/account-view.d.ts +8 -0
- package/dist/components/account-view.js +10 -0
- package/dist/components/admin-dashboard.js +3 -3
- package/dist/components/edit-post-view.js +5 -5
- package/dist/components/index.d.ts +4 -2
- package/dist/components/index.js +7 -7
- package/dist/components/login-view.d.ts +3 -1
- package/dist/components/login-view.js +4 -3
- package/dist/components/mcp-tokens-view.js +3 -3
- package/dist/components/media-view.js +5 -5
- package/dist/components/new-post-view.js +5 -5
- package/dist/components/plugin-settings-form.d.ts +2 -10
- package/dist/components/plugin-settings-form.js +5 -7
- package/dist/components/posts-list-view.js +3 -3
- package/dist/components/users-list-view.js +3 -3
- package/dist/{i18n-DA-aakRX.d.ts → i18n-Bd8q9aTl.d.ts} +108 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/metafile-esm.json +1 -1
- package/dist/pages/index.d.ts +21 -4
- package/dist/pages/index.js +54 -24
- package/package.json +5 -6
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
getAdminCmsConfig,
|
|
5
5
|
getMediaProcessingDefaults,
|
|
6
6
|
uploadProcessedImage
|
|
7
|
-
} from "./chunk-
|
|
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-
|
|
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
|
|
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/
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
445
|
+
children: /* @__PURE__ */ jsx4(Icon, { className: "h-4 w-4" })
|
|
377
446
|
},
|
|
378
447
|
tool.name
|
|
379
448
|
);
|
|
380
449
|
}),
|
|
381
|
-
/* @__PURE__ */
|
|
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__ */
|
|
458
|
+
children: /* @__PURE__ */ jsx4(LinkIcon, { className: "h-4 w-4" })
|
|
390
459
|
}
|
|
391
460
|
),
|
|
392
|
-
/* @__PURE__ */
|
|
461
|
+
/* @__PURE__ */ jsx4(
|
|
393
462
|
MediaPicker,
|
|
394
463
|
{
|
|
395
464
|
onSelect: insertImage,
|
|
396
|
-
trigger: /* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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__ */
|
|
432
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
463
|
-
/* @__PURE__ */
|
|
464
|
-
/* @__PURE__ */
|
|
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__ */
|
|
468
|
-
/* @__PURE__ */
|
|
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
|
|
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__ */
|
|
621
|
-
/* @__PURE__ */
|
|
622
|
-
/* @__PURE__ */
|
|
623
|
-
editor && /* @__PURE__ */
|
|
624
|
-
/* @__PURE__ */
|
|
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
|
|
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
|
|
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] =
|
|
732
|
-
const [loaded, setLoaded] =
|
|
733
|
-
const [loading, setLoading] =
|
|
734
|
-
const [error, setError] =
|
|
735
|
-
const [revisions, setRevisions] =
|
|
736
|
-
const [nextToken, setNextToken] =
|
|
737
|
-
const [selected, setSelected] =
|
|
738
|
-
const [previewHtml, setPreviewHtml] =
|
|
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
|
-
|
|
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
|
-
|
|
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__ */
|
|
784
|
-
/* @__PURE__ */
|
|
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__ */
|
|
793
|
-
/* @__PURE__ */
|
|
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__ */
|
|
798
|
-
error && /* @__PURE__ */
|
|
799
|
-
loading && revisions.length === 0 ? /* @__PURE__ */
|
|
800
|
-
/* @__PURE__ */
|
|
801
|
-
/* @__PURE__ */
|
|
802
|
-
/* @__PURE__ */
|
|
803
|
-
/* @__PURE__ */
|
|
804
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
812
|
-
/* @__PURE__ */
|
|
813
|
-
/* @__PURE__ */
|
|
814
|
-
/* @__PURE__ */
|
|
815
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
855
|
-
/* @__PURE__ */
|
|
856
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
871
|
-
/* @__PURE__ */
|
|
872
|
-
selected.slug && /* @__PURE__ */
|
|
873
|
-
/* @__PURE__ */
|
|
874
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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
|
-
|
|
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
|
|
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] =
|
|
1012
|
-
const [issues, setIssues] =
|
|
1013
|
-
const [busy, setBusy] =
|
|
1014
|
-
const [error, setError] =
|
|
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
|
|
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
|
|
1073
|
-
if (!
|
|
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 (
|
|
1076
|
-
void handleZip(
|
|
1154
|
+
if (files.length === 1 && files[0].name.toLowerCase().endsWith(".zip")) {
|
|
1155
|
+
void handleZip(files[0]);
|
|
1077
1156
|
} else {
|
|
1078
|
-
void handleLooseFiles(
|
|
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__ */
|
|
1089
|
-
/* @__PURE__ */
|
|
1090
|
-
/* @__PURE__ */
|
|
1091
|
-
/* @__PURE__ */
|
|
1092
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1181
|
+
/* @__PURE__ */ jsx8("span", { className: "text-xs text-muted-foreground", children: t("posts.form.static.pickHint") })
|
|
1103
1182
|
] }),
|
|
1104
|
-
busy && /* @__PURE__ */
|
|
1105
|
-
error && /* @__PURE__ */
|
|
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__ */
|
|
1108
|
-
pending && /* @__PURE__ */
|
|
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__ */
|
|
1121
|
-
/* @__PURE__ */
|
|
1122
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1139
|
-
/* @__PURE__ */
|
|
1140
|
-
/* @__PURE__ */
|
|
1141
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1148
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1153
|
-
/* @__PURE__ */
|
|
1154
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1158
|
-
issues.slice(0, 20).map((issue, idx) => /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1248
|
+
/* @__PURE__ */ jsx8("p", { className: "mt-2 text-xs text-muted-foreground", children: t("posts.form.static.issuesHint") })
|
|
1170
1249
|
] }),
|
|
1171
|
-
/* @__PURE__ */
|
|
1250
|
+
/* @__PURE__ */ jsx8(FileList, { files: files.map((f) => f.path) })
|
|
1172
1251
|
] });
|
|
1173
1252
|
}
|
|
1174
1253
|
function FileList({ files }) {
|
|
1175
|
-
return /* @__PURE__ */
|
|
1176
|
-
files.slice(0, 40).map((path) => /* @__PURE__ */
|
|
1177
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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 =
|
|
1421
|
-
const [title, setTitle] =
|
|
1422
|
-
const [slug, setSlug] =
|
|
1423
|
-
const [excerpt, setExcerpt] =
|
|
1424
|
-
const [format, setFormat] =
|
|
1425
|
-
const [body, setBody] =
|
|
1426
|
-
const [status, setStatus] =
|
|
1427
|
-
const [tagsInput, setTagsInput] =
|
|
1428
|
-
const [noLayout, setNoLayout] =
|
|
1429
|
-
const [publishedAtInput, setPublishedAtInput] =
|
|
1430
|
-
const [saving, setSaving] =
|
|
1431
|
-
const [error, setError] =
|
|
1432
|
-
const [view, setView] =
|
|
1433
|
-
const [previewHtml, setPreviewHtml] =
|
|
1434
|
-
const [editorEpoch, setEditorEpoch] =
|
|
1435
|
-
const dirtyRef =
|
|
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] =
|
|
1440
|
-
const [restoredHint, setRestoredHint] =
|
|
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] =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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__ */
|
|
1740
|
-
/* @__PURE__ */
|
|
1741
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1763
|
-
/* @__PURE__ */
|
|
1764
|
-
/* @__PURE__ */
|
|
1765
|
-
/* @__PURE__ */
|
|
1766
|
-
previewPost.publishedAt ? /* @__PURE__ */
|
|
1767
|
-
/* @__PURE__ */
|
|
1768
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1849
|
+
excerpt && /* @__PURE__ */ jsx9("p", { className: "mt-3 text-base text-muted-foreground", children: excerpt })
|
|
1771
1850
|
] }),
|
|
1772
|
-
format === "static" ? /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1910
|
+
/* @__PURE__ */ jsx9("p", { className: "text-xs text-muted-foreground", children: t("posts.form.previewHint") })
|
|
1832
1911
|
] }),
|
|
1833
|
-
/* @__PURE__ */
|
|
1834
|
-
recovery && /* @__PURE__ */
|
|
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__ */
|
|
1841
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1847
|
-
/* @__PURE__ */
|
|
1848
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1854
|
-
isStaticFormat && /* @__PURE__ */
|
|
1855
|
-
/* @__PURE__ */
|
|
1856
|
-
/* @__PURE__ */
|
|
1857
|
-
/* @__PURE__ */
|
|
1858
|
-
|
|
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__ */
|
|
1872
|
-
/* @__PURE__ */
|
|
1873
|
-
/* @__PURE__ */
|
|
1874
|
-
|
|
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__ */
|
|
1887
|
-
/* @__PURE__ */
|
|
1888
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1902
|
-
/* @__PURE__ */
|
|
1903
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1912
|
-
/* @__PURE__ */
|
|
1913
|
-
/* @__PURE__ */
|
|
1914
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1997
|
+
/* @__PURE__ */ jsx9("p", { className: "text-xs text-muted-foreground", children: t("posts.form.formatHint") })
|
|
1919
1998
|
] }),
|
|
1920
|
-
/* @__PURE__ */
|
|
1921
|
-
/* @__PURE__ */
|
|
1922
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2006
|
+
/* @__PURE__ */ jsx9(
|
|
1928
2007
|
MediaPicker,
|
|
1929
2008
|
{
|
|
1930
2009
|
onSelect: insertMediaSnippet,
|
|
1931
|
-
trigger: /* @__PURE__ */
|
|
1932
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1968
|
-
/* @__PURE__ */
|
|
1969
|
-
/* @__PURE__ */
|
|
1970
|
-
|
|
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__ */
|
|
2060
|
+
/* @__PURE__ */ jsx9("p", { className: "text-xs text-muted-foreground", children: t("posts.form.tagsHint") })
|
|
1982
2061
|
] }),
|
|
1983
|
-
/* @__PURE__ */
|
|
1984
|
-
/* @__PURE__ */
|
|
1985
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1997
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2003
|
-
/* @__PURE__ */
|
|
2004
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2018
|
-
status === "published" && isFuture(resolvedPublishedAt) && /* @__PURE__ */
|
|
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__ */
|
|
2021
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2034
|
-
/* @__PURE__ */
|
|
2035
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2039
|
-
/* @__PURE__ */
|
|
2040
|
-
/* @__PURE__ */
|
|
2041
|
-
isEdit && /* @__PURE__ */
|
|
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__ */
|
|
2122
|
+
isEdit && post && /* @__PURE__ */ jsx9(
|
|
2044
2123
|
PostHistoryPanel,
|
|
2045
2124
|
{
|
|
2046
2125
|
postId: post.postId,
|