@ampless/admin 1.0.0-alpha.84 → 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 +34 -7
- package/dist/api/index.js +8 -3
- package/dist/{chunk-SQ6LFPXH.js → chunk-2TBGPB5H.js} +2 -2
- package/dist/{chunk-K44QF3MV.js → chunk-4OFRX6QX.js} +1 -1
- package/dist/{chunk-BRTC5O3E.js → chunk-4WYMEUYU.js} +361 -224
- 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-V6JNTCPS.js → chunk-JLCTF5HY.js} +8 -2
- package/dist/{chunk-YU5MPQXB.js → chunk-LXY3BRKQ.js} +2 -2
- package/dist/{chunk-MKWYNK4J.js → chunk-NHMG2MRJ.js} +2 -2
- package/dist/{chunk-WXIYV2PO.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,19 +687,77 @@ 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
|
+
|
|
703
|
+
// src/lib/preview-srcdoc.ts
|
|
704
|
+
function buildPreviewSrcDoc(html) {
|
|
705
|
+
if (typeof document === "undefined") return html;
|
|
706
|
+
if (!html.includes("<head>")) return html;
|
|
707
|
+
const linkTags = [];
|
|
708
|
+
const styleTags = [];
|
|
709
|
+
const linkEls = document.querySelectorAll('link[rel="stylesheet"]');
|
|
710
|
+
for (const el of linkEls) {
|
|
711
|
+
if (el.href) {
|
|
712
|
+
linkTags.push(`<link rel="stylesheet" href="${el.href}">`);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
const styleEls = document.querySelectorAll("style");
|
|
716
|
+
for (const el of styleEls) {
|
|
717
|
+
const content = el.textContent ?? "";
|
|
718
|
+
if (content.trim()) {
|
|
719
|
+
styleTags.push(`<style>${content}</style>`);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
const collected = [...linkTags, ...styleTags];
|
|
723
|
+
let result = html;
|
|
724
|
+
if (collected.length > 0) {
|
|
725
|
+
result = result.replace("<head>", `<head>${collected.join("")}`);
|
|
726
|
+
}
|
|
727
|
+
const bodyDataAttrs = [];
|
|
728
|
+
for (const attr of document.body.attributes) {
|
|
729
|
+
if (attr.name.startsWith("data-")) {
|
|
730
|
+
const escaped = attr.value.replace(/"/g, """);
|
|
731
|
+
bodyDataAttrs.push(`${attr.name}="${escaped}"`);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
if (bodyDataAttrs.length > 0) {
|
|
735
|
+
result = result.replace(
|
|
736
|
+
/(<body\b[^>]*)(>)/,
|
|
737
|
+
`$1 ${bodyDataAttrs.join(" ")}$2`
|
|
738
|
+
);
|
|
739
|
+
}
|
|
740
|
+
const htmlClass = document.documentElement.className;
|
|
741
|
+
if (htmlClass) {
|
|
742
|
+
const escaped = htmlClass.replace(/"/g, """);
|
|
743
|
+
result = result.replace(
|
|
744
|
+
/(<html\b)([^>]*)(>)/,
|
|
745
|
+
(_, open, attrs, close) => {
|
|
746
|
+
if (/class=/.test(attrs)) {
|
|
747
|
+
return `${open}${attrs.replace(/class="([^"]*)"/, `class="$1 ${escaped}`)}${close}`;
|
|
748
|
+
}
|
|
749
|
+
return `${open}${attrs} class="${escaped}"${close}`;
|
|
750
|
+
}
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
if (collected.length > 0) {
|
|
754
|
+
result = result.replace(/<style\s+id="ampless-preview-base">[\s\S]*?<\/style>/, "");
|
|
755
|
+
}
|
|
756
|
+
return result;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// src/components/post-history-panel.tsx
|
|
760
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
633
761
|
var PAGE_SIZE = 20;
|
|
634
762
|
function formatRevisedAt(iso, timezone, locale) {
|
|
635
763
|
const d = new Date(iso);
|
|
@@ -670,17 +798,17 @@ function PostHistoryPanel({
|
|
|
670
798
|
const config = getAdminCmsConfig();
|
|
671
799
|
const timezone = config?.timezone ?? "UTC";
|
|
672
800
|
const locale = config?.locale ?? "en";
|
|
673
|
-
const [open, setOpen] =
|
|
674
|
-
const [loaded, setLoaded] =
|
|
675
|
-
const [loading, setLoading] =
|
|
676
|
-
const [error, setError] =
|
|
677
|
-
const [revisions, setRevisions] =
|
|
678
|
-
const [nextToken, setNextToken] =
|
|
679
|
-
const [selected, setSelected] =
|
|
680
|
-
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("");
|
|
681
809
|
const selectedHistoryId = selected?.postHistoryId;
|
|
682
810
|
const selectedFormat = selected?.format;
|
|
683
|
-
|
|
811
|
+
useEffect4(() => {
|
|
684
812
|
if (!selected) return;
|
|
685
813
|
if (selected.format === "static") return;
|
|
686
814
|
const ctrl = new AbortController();
|
|
@@ -693,7 +821,7 @@ function PostHistoryPanel({
|
|
|
693
821
|
if (!r.ok) throw new Error(`preview ${r.status}`);
|
|
694
822
|
return r.text();
|
|
695
823
|
}).then((html) => {
|
|
696
|
-
if (!ctrl.signal.aborted) setPreviewHtml(html);
|
|
824
|
+
if (!ctrl.signal.aborted) setPreviewHtml(buildPreviewSrcDoc(html));
|
|
697
825
|
}).catch((err) => {
|
|
698
826
|
if (ctrl.signal.aborted) return;
|
|
699
827
|
console.error("[ampless admin] revision preview fetch failed:", err);
|
|
@@ -716,14 +844,14 @@ function PostHistoryPanel({
|
|
|
716
844
|
},
|
|
717
845
|
[postId]
|
|
718
846
|
);
|
|
719
|
-
|
|
847
|
+
useEffect4(() => {
|
|
720
848
|
if (open && !loaded) {
|
|
721
849
|
setLoaded(true);
|
|
722
850
|
void loadPage();
|
|
723
851
|
}
|
|
724
852
|
}, [open, loaded, loadPage]);
|
|
725
|
-
return /* @__PURE__ */
|
|
726
|
-
/* @__PURE__ */
|
|
853
|
+
return /* @__PURE__ */ jsxs7("section", { className: "rounded-md border", children: [
|
|
854
|
+
/* @__PURE__ */ jsxs7(
|
|
727
855
|
"button",
|
|
728
856
|
{
|
|
729
857
|
type: "button",
|
|
@@ -731,30 +859,30 @@ function PostHistoryPanel({
|
|
|
731
859
|
"aria-expanded": open,
|
|
732
860
|
className: "flex w-full items-center justify-between px-4 py-3 text-left text-sm font-medium",
|
|
733
861
|
children: [
|
|
734
|
-
/* @__PURE__ */
|
|
735
|
-
/* @__PURE__ */
|
|
862
|
+
/* @__PURE__ */ jsx7("span", { children: t("posts.history.title") }),
|
|
863
|
+
/* @__PURE__ */ jsx7("span", { className: "text-muted-foreground", "aria-hidden": "true", children: open ? "\u2212" : "+" })
|
|
736
864
|
]
|
|
737
865
|
}
|
|
738
866
|
),
|
|
739
|
-
open && /* @__PURE__ */
|
|
740
|
-
error && /* @__PURE__ */
|
|
741
|
-
loading && revisions.length === 0 ? /* @__PURE__ */
|
|
742
|
-
/* @__PURE__ */
|
|
743
|
-
/* @__PURE__ */
|
|
744
|
-
/* @__PURE__ */
|
|
745
|
-
/* @__PURE__ */
|
|
746
|
-
/* @__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") })
|
|
747
875
|
] }) }),
|
|
748
|
-
/* @__PURE__ */
|
|
876
|
+
/* @__PURE__ */ jsx7("tbody", { children: revisions.map((rev) => /* @__PURE__ */ jsxs7(
|
|
749
877
|
"tr",
|
|
750
878
|
{
|
|
751
879
|
className: selected?.postHistoryId === rev.postHistoryId ? "border-b bg-muted/50" : "border-b",
|
|
752
880
|
children: [
|
|
753
|
-
/* @__PURE__ */
|
|
754
|
-
/* @__PURE__ */
|
|
755
|
-
/* @__PURE__ */
|
|
756
|
-
/* @__PURE__ */
|
|
757
|
-
/* @__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(
|
|
758
886
|
Button5,
|
|
759
887
|
{
|
|
760
888
|
type: "button",
|
|
@@ -764,7 +892,7 @@ function PostHistoryPanel({
|
|
|
764
892
|
children: t("posts.history.view")
|
|
765
893
|
}
|
|
766
894
|
),
|
|
767
|
-
/* @__PURE__ */
|
|
895
|
+
/* @__PURE__ */ jsx7(
|
|
768
896
|
Button5,
|
|
769
897
|
{
|
|
770
898
|
type: "button",
|
|
@@ -782,7 +910,7 @@ function PostHistoryPanel({
|
|
|
782
910
|
rev.postHistoryId
|
|
783
911
|
)) })
|
|
784
912
|
] }) }),
|
|
785
|
-
nextToken && /* @__PURE__ */
|
|
913
|
+
nextToken && /* @__PURE__ */ jsx7("div", { children: /* @__PURE__ */ jsx7(
|
|
786
914
|
Button5,
|
|
787
915
|
{
|
|
788
916
|
type: "button",
|
|
@@ -793,12 +921,12 @@ function PostHistoryPanel({
|
|
|
793
921
|
children: loading ? t("common.loading") : t("posts.history.loadMore")
|
|
794
922
|
}
|
|
795
923
|
) }),
|
|
796
|
-
selected && /* @__PURE__ */
|
|
797
|
-
/* @__PURE__ */
|
|
798
|
-
/* @__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", {
|
|
799
927
|
date: formatRevisedAt(selected.revisedAt, timezone, locale)
|
|
800
928
|
}) }),
|
|
801
|
-
/* @__PURE__ */
|
|
929
|
+
/* @__PURE__ */ jsx7(
|
|
802
930
|
Button5,
|
|
803
931
|
{
|
|
804
932
|
type: "button",
|
|
@@ -809,14 +937,14 @@ function PostHistoryPanel({
|
|
|
809
937
|
}
|
|
810
938
|
)
|
|
811
939
|
] }),
|
|
812
|
-
/* @__PURE__ */
|
|
813
|
-
/* @__PURE__ */
|
|
814
|
-
selected.slug && /* @__PURE__ */
|
|
815
|
-
/* @__PURE__ */
|
|
816
|
-
/* @__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 })
|
|
817
945
|
] })
|
|
818
946
|
] }),
|
|
819
|
-
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") }) : (
|
|
820
948
|
// Sandbox is `allow-scripts allow-same-origin`. With
|
|
821
949
|
// srcDoc, this gives the iframe the admin's origin so
|
|
822
950
|
// 3rd-party embed widgets (YouTube SDK, x.com widgets.js)
|
|
@@ -843,7 +971,7 @@ function PostHistoryPanel({
|
|
|
843
971
|
// don't style its srcDoc contents. Typography comes from
|
|
844
972
|
// the full document the preview route now returns
|
|
845
973
|
// (PREVIEW_BASE_CSS + theme vars in createPreviewRouteHandler).
|
|
846
|
-
/* @__PURE__ */
|
|
974
|
+
/* @__PURE__ */ jsx7(
|
|
847
975
|
"iframe",
|
|
848
976
|
{
|
|
849
977
|
title: "revision-preview",
|
|
@@ -859,7 +987,7 @@ function PostHistoryPanel({
|
|
|
859
987
|
}
|
|
860
988
|
|
|
861
989
|
// src/components/static-uploader.tsx
|
|
862
|
-
import { useState as
|
|
990
|
+
import { useState as useState5 } from "react";
|
|
863
991
|
import { FileText, AlertTriangle, FileArchive, X } from "lucide-react";
|
|
864
992
|
import { Button as Button6 } from "@ampless/runtime/ui";
|
|
865
993
|
|
|
@@ -909,7 +1037,15 @@ async function uploadBundle(opts) {
|
|
|
909
1037
|
if (!opts.files.some((f) => f.path === entrypoint)) {
|
|
910
1038
|
throw new Error(`Entrypoint "${entrypoint}" is not present in the bundle.`);
|
|
911
1039
|
}
|
|
912
|
-
|
|
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
|
+
}
|
|
913
1049
|
const prefix = bundlePrefix(opts.slug);
|
|
914
1050
|
let uploaded = 0;
|
|
915
1051
|
const filesMeta = {};
|
|
@@ -947,13 +1083,13 @@ async function deleteBundle(slug) {
|
|
|
947
1083
|
}
|
|
948
1084
|
|
|
949
1085
|
// src/components/static-uploader.tsx
|
|
950
|
-
import { jsx as
|
|
1086
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
951
1087
|
function StaticUploader({ initial, onFilesReady, onClear }) {
|
|
952
1088
|
const t = useT();
|
|
953
|
-
const [pending, setPending] =
|
|
954
|
-
const [issues, setIssues] =
|
|
955
|
-
const [busy, setBusy] =
|
|
956
|
-
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);
|
|
957
1093
|
async function handleZip(file) {
|
|
958
1094
|
setBusy(true);
|
|
959
1095
|
setError(null);
|
|
@@ -983,7 +1119,7 @@ function StaticUploader({ initial, onFilesReady, onClear }) {
|
|
|
983
1119
|
const extracted = [];
|
|
984
1120
|
const structural = [];
|
|
985
1121
|
for (const f of Array.from(files)) {
|
|
986
|
-
const rel = f.webkitRelativePath
|
|
1122
|
+
const rel = f.webkitRelativePath || f.name;
|
|
987
1123
|
const stripped = rel.includes("/") ? rel.slice(rel.indexOf("/") + 1) : rel;
|
|
988
1124
|
const reason = validateBundlePath(stripped);
|
|
989
1125
|
if (reason) {
|
|
@@ -1011,13 +1147,14 @@ function StaticUploader({ initial, onFilesReady, onClear }) {
|
|
|
1011
1147
|
}
|
|
1012
1148
|
}
|
|
1013
1149
|
function onPickerChange(e) {
|
|
1014
|
-
const
|
|
1015
|
-
if (!
|
|
1150
|
+
const picked = e.target.files;
|
|
1151
|
+
if (!picked || picked.length === 0) return;
|
|
1152
|
+
const files = Array.from(picked);
|
|
1016
1153
|
e.target.value = "";
|
|
1017
|
-
if (
|
|
1018
|
-
void handleZip(
|
|
1154
|
+
if (files.length === 1 && files[0].name.toLowerCase().endsWith(".zip")) {
|
|
1155
|
+
void handleZip(files[0]);
|
|
1019
1156
|
} else {
|
|
1020
|
-
void handleLooseFiles(
|
|
1157
|
+
void handleLooseFiles(files);
|
|
1021
1158
|
}
|
|
1022
1159
|
}
|
|
1023
1160
|
function clearPending() {
|
|
@@ -1027,11 +1164,11 @@ function StaticUploader({ initial, onFilesReady, onClear }) {
|
|
|
1027
1164
|
onClear();
|
|
1028
1165
|
}
|
|
1029
1166
|
const showCurrent = !pending && initial && initial.files.length > 0;
|
|
1030
|
-
return /* @__PURE__ */
|
|
1031
|
-
/* @__PURE__ */
|
|
1032
|
-
/* @__PURE__ */
|
|
1033
|
-
/* @__PURE__ */
|
|
1034
|
-
/* @__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(
|
|
1035
1172
|
"input",
|
|
1036
1173
|
{
|
|
1037
1174
|
type: "file",
|
|
@@ -1041,13 +1178,13 @@ function StaticUploader({ initial, onFilesReady, onClear }) {
|
|
|
1041
1178
|
disabled: busy
|
|
1042
1179
|
}
|
|
1043
1180
|
),
|
|
1044
|
-
/* @__PURE__ */
|
|
1181
|
+
/* @__PURE__ */ jsx8("span", { className: "text-xs text-muted-foreground", children: t("posts.form.static.pickHint") })
|
|
1045
1182
|
] }),
|
|
1046
|
-
busy && /* @__PURE__ */
|
|
1047
|
-
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 })
|
|
1048
1185
|
] }),
|
|
1049
|
-
showCurrent && /* @__PURE__ */
|
|
1050
|
-
pending && /* @__PURE__ */
|
|
1186
|
+
showCurrent && /* @__PURE__ */ jsx8(CurrentBundle, { body: initial }),
|
|
1187
|
+
pending && /* @__PURE__ */ jsx8(
|
|
1051
1188
|
PendingBundle,
|
|
1052
1189
|
{
|
|
1053
1190
|
files: pending,
|
|
@@ -1059,15 +1196,15 @@ function StaticUploader({ initial, onFilesReady, onClear }) {
|
|
|
1059
1196
|
}
|
|
1060
1197
|
function CurrentBundle({ body }) {
|
|
1061
1198
|
const t = useT();
|
|
1062
|
-
return /* @__PURE__ */
|
|
1063
|
-
/* @__PURE__ */
|
|
1064
|
-
/* @__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" }),
|
|
1065
1202
|
t("posts.form.static.currentBundle", {
|
|
1066
1203
|
count: body.files.length,
|
|
1067
1204
|
entrypoint: body.entrypoint
|
|
1068
1205
|
})
|
|
1069
1206
|
] }),
|
|
1070
|
-
/* @__PURE__ */
|
|
1207
|
+
/* @__PURE__ */ jsx8(FileList, { files: body.files })
|
|
1071
1208
|
] });
|
|
1072
1209
|
}
|
|
1073
1210
|
function PendingBundle({
|
|
@@ -1077,49 +1214,49 @@ function PendingBundle({
|
|
|
1077
1214
|
}) {
|
|
1078
1215
|
const t = useT();
|
|
1079
1216
|
const totalBytes = files.reduce((sum, f) => sum + f.data.byteLength, 0);
|
|
1080
|
-
return /* @__PURE__ */
|
|
1081
|
-
/* @__PURE__ */
|
|
1082
|
-
/* @__PURE__ */
|
|
1083
|
-
/* @__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" }),
|
|
1084
1221
|
t("posts.form.static.pendingBundle", {
|
|
1085
1222
|
count: files.length,
|
|
1086
1223
|
size: formatBytes(totalBytes)
|
|
1087
1224
|
})
|
|
1088
1225
|
] }),
|
|
1089
|
-
/* @__PURE__ */
|
|
1090
|
-
/* @__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" }),
|
|
1091
1228
|
t("common.cancel")
|
|
1092
1229
|
] })
|
|
1093
1230
|
] }),
|
|
1094
|
-
issues.length > 0 && /* @__PURE__ */
|
|
1095
|
-
/* @__PURE__ */
|
|
1096
|
-
/* @__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" }),
|
|
1097
1234
|
t("posts.form.static.issuesTitle", { count: issues.length })
|
|
1098
1235
|
] }),
|
|
1099
|
-
/* @__PURE__ */
|
|
1100
|
-
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: [
|
|
1101
1238
|
issue.path,
|
|
1102
1239
|
": ",
|
|
1103
1240
|
issue.reason
|
|
1104
1241
|
] }, `${issue.path}-${idx}`)),
|
|
1105
|
-
issues.length > 20 && /* @__PURE__ */
|
|
1242
|
+
issues.length > 20 && /* @__PURE__ */ jsxs8("li", { className: "font-mono text-muted-foreground", children: [
|
|
1106
1243
|
"\u2026 ",
|
|
1107
1244
|
issues.length - 20,
|
|
1108
1245
|
" more"
|
|
1109
1246
|
] })
|
|
1110
1247
|
] }),
|
|
1111
|
-
/* @__PURE__ */
|
|
1248
|
+
/* @__PURE__ */ jsx8("p", { className: "mt-2 text-xs text-muted-foreground", children: t("posts.form.static.issuesHint") })
|
|
1112
1249
|
] }),
|
|
1113
|
-
/* @__PURE__ */
|
|
1250
|
+
/* @__PURE__ */ jsx8(FileList, { files: files.map((f) => f.path) })
|
|
1114
1251
|
] });
|
|
1115
1252
|
}
|
|
1116
1253
|
function FileList({ files }) {
|
|
1117
|
-
return /* @__PURE__ */
|
|
1118
|
-
files.slice(0, 40).map((path) => /* @__PURE__ */
|
|
1119
|
-
/* @__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" }),
|
|
1120
1257
|
path
|
|
1121
1258
|
] }, path)),
|
|
1122
|
-
files.length > 40 && /* @__PURE__ */
|
|
1259
|
+
files.length > 40 && /* @__PURE__ */ jsxs8("li", { className: "font-mono text-xs text-muted-foreground", children: [
|
|
1123
1260
|
"\u2026 ",
|
|
1124
1261
|
files.length - 40,
|
|
1125
1262
|
" more"
|
|
@@ -1313,7 +1450,7 @@ function convertBodyFormat(body, from, to, registries) {
|
|
|
1313
1450
|
}
|
|
1314
1451
|
|
|
1315
1452
|
// src/components/post-form.tsx
|
|
1316
|
-
import { jsx as
|
|
1453
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1317
1454
|
var EMPTY_TIPTAP_DOC = { type: "doc", content: [{ type: "paragraph" }] };
|
|
1318
1455
|
var IMAGE_URL_RE = /\.(jpe?g|png|gif|webp|avif|svg|bmp|tiff?)(\?|$)/i;
|
|
1319
1456
|
var STYLESHEET_URL_RE = /\.css(\?|$)/i;
|
|
@@ -1359,27 +1496,27 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1359
1496
|
const router = useRouter();
|
|
1360
1497
|
const t = useT();
|
|
1361
1498
|
const isEdit = !!post;
|
|
1362
|
-
const bodyTextareaRef =
|
|
1363
|
-
const [title, setTitle] =
|
|
1364
|
-
const [slug, setSlug] =
|
|
1365
|
-
const [excerpt, setExcerpt] =
|
|
1366
|
-
const [format, setFormat] =
|
|
1367
|
-
const [body, setBody] =
|
|
1368
|
-
const [status, setStatus] =
|
|
1369
|
-
const [tagsInput, setTagsInput] =
|
|
1370
|
-
const [noLayout, setNoLayout] =
|
|
1371
|
-
const [publishedAtInput, setPublishedAtInput] =
|
|
1372
|
-
const [saving, setSaving] =
|
|
1373
|
-
const [error, setError] =
|
|
1374
|
-
const [view, setView] =
|
|
1375
|
-
const [previewHtml, setPreviewHtml] =
|
|
1376
|
-
const [editorEpoch, setEditorEpoch] =
|
|
1377
|
-
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);
|
|
1378
1515
|
function markDirty() {
|
|
1379
1516
|
dirtyRef.current = true;
|
|
1380
1517
|
}
|
|
1381
|
-
const [recovery, setRecovery] =
|
|
1382
|
-
const [restoredHint, setRestoredHint] =
|
|
1518
|
+
const [recovery, setRecovery] = useState6(null);
|
|
1519
|
+
const [restoredHint, setRestoredHint] = useState6(false);
|
|
1383
1520
|
const draftId = post?.postId ?? NEW_POST_DRAFT_ID;
|
|
1384
1521
|
const isStaticFormat = format === "static";
|
|
1385
1522
|
const cmsConfig = getAdminCmsConfig();
|
|
@@ -1392,7 +1529,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1392
1529
|
initialInput: initialPublishedAtInput,
|
|
1393
1530
|
existing: post?.publishedAt
|
|
1394
1531
|
});
|
|
1395
|
-
const [pendingBundle, setPendingBundle] =
|
|
1532
|
+
const [pendingBundle, setPendingBundle] = useState6(null);
|
|
1396
1533
|
const initialStaticBody = isStaticBody(post?.body) ? post.body : null;
|
|
1397
1534
|
function buildMetadata() {
|
|
1398
1535
|
const next = { ...post?.metadata ?? {} };
|
|
@@ -1460,7 +1597,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1460
1597
|
dirtyRef.current = false;
|
|
1461
1598
|
setRecovery(null);
|
|
1462
1599
|
}
|
|
1463
|
-
|
|
1600
|
+
useEffect5(() => {
|
|
1464
1601
|
if (loadedState.format === "static") return;
|
|
1465
1602
|
const draft = readDraft(draftId);
|
|
1466
1603
|
if (!draft) return;
|
|
@@ -1475,7 +1612,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1475
1612
|
}
|
|
1476
1613
|
setRecovery({ draft, decision });
|
|
1477
1614
|
}, []);
|
|
1478
|
-
|
|
1615
|
+
useEffect5(() => {
|
|
1479
1616
|
if (isStaticFormat) return;
|
|
1480
1617
|
if (!dirtyRef.current) return;
|
|
1481
1618
|
const handle = setTimeout(() => {
|
|
@@ -1583,13 +1720,13 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1583
1720
|
await updatePost(post.postId, {
|
|
1584
1721
|
title,
|
|
1585
1722
|
slug: finalSlug,
|
|
1586
|
-
excerpt
|
|
1723
|
+
excerpt,
|
|
1587
1724
|
format,
|
|
1588
1725
|
body: nextBody,
|
|
1589
1726
|
status,
|
|
1590
1727
|
publishedAt,
|
|
1591
1728
|
tags,
|
|
1592
|
-
metadata
|
|
1729
|
+
metadata: metadata ?? {}
|
|
1593
1730
|
});
|
|
1594
1731
|
} else {
|
|
1595
1732
|
await createPost({
|
|
@@ -1642,7 +1779,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1642
1779
|
publishedAt: resolvedPublishedAt,
|
|
1643
1780
|
tags: parseTags(tagsInput)
|
|
1644
1781
|
};
|
|
1645
|
-
|
|
1782
|
+
useEffect5(() => {
|
|
1646
1783
|
if (view !== "preview") return;
|
|
1647
1784
|
if (format === "static") return;
|
|
1648
1785
|
const ctrl = new AbortController();
|
|
@@ -1656,7 +1793,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1656
1793
|
if (!r.ok) throw new Error(`preview ${r.status}`);
|
|
1657
1794
|
return r.text();
|
|
1658
1795
|
}).then((html) => {
|
|
1659
|
-
if (!ctrl.signal.aborted) setPreviewHtml(html);
|
|
1796
|
+
if (!ctrl.signal.aborted) setPreviewHtml(buildPreviewSrcDoc(html));
|
|
1660
1797
|
}).catch((err) => {
|
|
1661
1798
|
if (ctrl.signal.aborted) return;
|
|
1662
1799
|
console.error("[ampless admin] preview fetch failed:", err);
|
|
@@ -1678,9 +1815,9 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1678
1815
|
resolvedPublishedAt,
|
|
1679
1816
|
tagsInput
|
|
1680
1817
|
]);
|
|
1681
|
-
return /* @__PURE__ */
|
|
1682
|
-
/* @__PURE__ */
|
|
1683
|
-
/* @__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(
|
|
1684
1821
|
"button",
|
|
1685
1822
|
{
|
|
1686
1823
|
type: "button",
|
|
@@ -1690,7 +1827,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1690
1827
|
children: t("posts.form.tabEdit")
|
|
1691
1828
|
}
|
|
1692
1829
|
),
|
|
1693
|
-
/* @__PURE__ */
|
|
1830
|
+
/* @__PURE__ */ jsx9(
|
|
1694
1831
|
"button",
|
|
1695
1832
|
{
|
|
1696
1833
|
type: "button",
|
|
@@ -1701,17 +1838,17 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1701
1838
|
}
|
|
1702
1839
|
)
|
|
1703
1840
|
] }),
|
|
1704
|
-
view === "preview" && /* @__PURE__ */
|
|
1705
|
-
/* @__PURE__ */
|
|
1706
|
-
/* @__PURE__ */
|
|
1707
|
-
/* @__PURE__ */
|
|
1708
|
-
previewPost.publishedAt ? /* @__PURE__ */
|
|
1709
|
-
/* @__PURE__ */
|
|
1710
|
-
/* @__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 })
|
|
1711
1848
|
] }),
|
|
1712
|
-
excerpt && /* @__PURE__ */
|
|
1849
|
+
excerpt && /* @__PURE__ */ jsx9("p", { className: "mt-3 text-base text-muted-foreground", children: excerpt })
|
|
1713
1850
|
] }),
|
|
1714
|
-
format === "static" ? /* @__PURE__ */
|
|
1851
|
+
format === "static" ? /* @__PURE__ */ jsx9("p", { className: "text-sm text-muted-foreground", children: t("posts.form.static.previewHint") }) : (
|
|
1715
1852
|
// Phase 7: preview HTML is fetched from the template's
|
|
1716
1853
|
// `/admin/preview` Route Handler so `ampless.renderBody`
|
|
1717
1854
|
// (async ReactNode) + `ampless.publicPostScriptsForPage(
|
|
@@ -1749,7 +1886,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1749
1886
|
// document — an iframe srcDoc does not inherit the parent page's
|
|
1750
1887
|
// CSS. Typography is now applied inside the document returned by
|
|
1751
1888
|
// createPreviewRouteHandler (PREVIEW_BASE_CSS + theme cssVars).
|
|
1752
|
-
/* @__PURE__ */
|
|
1889
|
+
/* @__PURE__ */ jsx9(
|
|
1753
1890
|
"iframe",
|
|
1754
1891
|
{
|
|
1755
1892
|
title: "post-preview",
|
|
@@ -1759,7 +1896,7 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1759
1896
|
}
|
|
1760
1897
|
)
|
|
1761
1898
|
),
|
|
1762
|
-
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(
|
|
1763
1900
|
"span",
|
|
1764
1901
|
{
|
|
1765
1902
|
className: "rounded-full border px-2 py-0.5 text-xs text-muted-foreground",
|
|
@@ -1770,34 +1907,34 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1770
1907
|
},
|
|
1771
1908
|
tag
|
|
1772
1909
|
)) }),
|
|
1773
|
-
/* @__PURE__ */
|
|
1910
|
+
/* @__PURE__ */ jsx9("p", { className: "text-xs text-muted-foreground", children: t("posts.form.previewHint") })
|
|
1774
1911
|
] }),
|
|
1775
|
-
/* @__PURE__ */
|
|
1776
|
-
recovery && /* @__PURE__ */
|
|
1912
|
+
/* @__PURE__ */ jsxs9("div", { className: view === "edit" ? "space-y-6" : "hidden", children: [
|
|
1913
|
+
recovery && /* @__PURE__ */ jsxs9(
|
|
1777
1914
|
"div",
|
|
1778
1915
|
{
|
|
1779
1916
|
role: "alert",
|
|
1780
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",
|
|
1781
1918
|
children: [
|
|
1782
|
-
/* @__PURE__ */
|
|
1783
|
-
/* @__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", {
|
|
1784
1921
|
when: formatDraftTime(recovery.draft.savedAt, draftTimezone, draftLocale)
|
|
1785
1922
|
}) : t("posts.draft.recoverBody", {
|
|
1786
1923
|
when: formatDraftTime(recovery.draft.savedAt, draftTimezone, draftLocale)
|
|
1787
1924
|
}) }),
|
|
1788
|
-
/* @__PURE__ */
|
|
1789
|
-
/* @__PURE__ */
|
|
1790
|
-
/* @__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") })
|
|
1791
1928
|
] })
|
|
1792
1929
|
]
|
|
1793
1930
|
}
|
|
1794
1931
|
),
|
|
1795
|
-
restoredHint && !recovery && /* @__PURE__ */
|
|
1796
|
-
isStaticFormat && /* @__PURE__ */
|
|
1797
|
-
/* @__PURE__ */
|
|
1798
|
-
/* @__PURE__ */
|
|
1799
|
-
/* @__PURE__ */
|
|
1800
|
-
|
|
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,
|
|
1801
1938
|
{
|
|
1802
1939
|
id: "title",
|
|
1803
1940
|
required: true,
|
|
@@ -1810,10 +1947,10 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1810
1947
|
}
|
|
1811
1948
|
)
|
|
1812
1949
|
] }),
|
|
1813
|
-
/* @__PURE__ */
|
|
1814
|
-
/* @__PURE__ */
|
|
1815
|
-
/* @__PURE__ */
|
|
1816
|
-
|
|
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,
|
|
1817
1954
|
{
|
|
1818
1955
|
id: "slug",
|
|
1819
1956
|
value: slug,
|
|
@@ -1825,9 +1962,9 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1825
1962
|
}
|
|
1826
1963
|
)
|
|
1827
1964
|
] }),
|
|
1828
|
-
/* @__PURE__ */
|
|
1829
|
-
/* @__PURE__ */
|
|
1830
|
-
/* @__PURE__ */
|
|
1965
|
+
/* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
|
|
1966
|
+
/* @__PURE__ */ jsx9(Label, { htmlFor: "excerpt", children: t("posts.form.excerpt") }),
|
|
1967
|
+
/* @__PURE__ */ jsx9(
|
|
1831
1968
|
Textarea,
|
|
1832
1969
|
{
|
|
1833
1970
|
id: "excerpt",
|
|
@@ -1840,9 +1977,9 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1840
1977
|
}
|
|
1841
1978
|
)
|
|
1842
1979
|
] }),
|
|
1843
|
-
/* @__PURE__ */
|
|
1844
|
-
/* @__PURE__ */
|
|
1845
|
-
/* @__PURE__ */
|
|
1980
|
+
/* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
|
|
1981
|
+
/* @__PURE__ */ jsx9(Label, { htmlFor: "format", children: t("posts.form.format") }),
|
|
1982
|
+
/* @__PURE__ */ jsxs9(
|
|
1846
1983
|
"select",
|
|
1847
1984
|
{
|
|
1848
1985
|
id: "format",
|
|
@@ -1850,34 +1987,34 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1850
1987
|
onChange: (e) => changeFormat(e.target.value),
|
|
1851
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",
|
|
1852
1989
|
children: [
|
|
1853
|
-
/* @__PURE__ */
|
|
1854
|
-
/* @__PURE__ */
|
|
1855
|
-
/* @__PURE__ */
|
|
1856
|
-
/* @__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") })
|
|
1857
1994
|
]
|
|
1858
1995
|
}
|
|
1859
1996
|
),
|
|
1860
|
-
/* @__PURE__ */
|
|
1997
|
+
/* @__PURE__ */ jsx9("p", { className: "text-xs text-muted-foreground", children: t("posts.form.formatHint") })
|
|
1861
1998
|
] }),
|
|
1862
|
-
/* @__PURE__ */
|
|
1863
|
-
/* @__PURE__ */
|
|
1864
|
-
/* @__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") }),
|
|
1865
2002
|
format !== "tiptap" && format !== "static" && // For textarea-based formats (markdown / html) there's no
|
|
1866
2003
|
// embedded toolbar, so we surface the MediaPicker as a
|
|
1867
2004
|
// standalone button. Selecting an asset inserts a
|
|
1868
2005
|
// format-aware snippet at the cursor.
|
|
1869
|
-
/* @__PURE__ */
|
|
2006
|
+
/* @__PURE__ */ jsx9(
|
|
1870
2007
|
MediaPicker,
|
|
1871
2008
|
{
|
|
1872
2009
|
onSelect: insertMediaSnippet,
|
|
1873
|
-
trigger: /* @__PURE__ */
|
|
1874
|
-
/* @__PURE__ */
|
|
2010
|
+
trigger: /* @__PURE__ */ jsxs9(Button7, { type: "button", variant: "outline", size: "sm", children: [
|
|
2011
|
+
/* @__PURE__ */ jsx9(ImageIcon3, { className: "mr-2 h-3 w-3" }),
|
|
1875
2012
|
t("posts.form.insertMedia")
|
|
1876
2013
|
] })
|
|
1877
2014
|
}
|
|
1878
2015
|
)
|
|
1879
2016
|
] }),
|
|
1880
|
-
format === "tiptap" ? /* @__PURE__ */
|
|
2017
|
+
format === "tiptap" ? /* @__PURE__ */ jsx9(
|
|
1881
2018
|
TiptapEditor,
|
|
1882
2019
|
{
|
|
1883
2020
|
initialContent: body,
|
|
@@ -1885,14 +2022,14 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1885
2022
|
onUserEdit: markDirty
|
|
1886
2023
|
},
|
|
1887
2024
|
editorEpoch
|
|
1888
|
-
) : format === "static" ? /* @__PURE__ */
|
|
2025
|
+
) : format === "static" ? /* @__PURE__ */ jsx9(
|
|
1889
2026
|
StaticUploader,
|
|
1890
2027
|
{
|
|
1891
2028
|
initial: initialStaticBody,
|
|
1892
2029
|
onFilesReady: (files, entrypoint) => setPendingBundle({ files, entrypoint }),
|
|
1893
2030
|
onClear: () => setPendingBundle(null)
|
|
1894
2031
|
}
|
|
1895
|
-
) : /* @__PURE__ */
|
|
2032
|
+
) : /* @__PURE__ */ jsx9(
|
|
1896
2033
|
Textarea,
|
|
1897
2034
|
{
|
|
1898
2035
|
ref: bodyTextareaRef,
|
|
@@ -1906,10 +2043,10 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1906
2043
|
}
|
|
1907
2044
|
)
|
|
1908
2045
|
] }),
|
|
1909
|
-
/* @__PURE__ */
|
|
1910
|
-
/* @__PURE__ */
|
|
1911
|
-
/* @__PURE__ */
|
|
1912
|
-
|
|
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,
|
|
1913
2050
|
{
|
|
1914
2051
|
id: "tags",
|
|
1915
2052
|
value: tagsInput,
|
|
@@ -1920,11 +2057,11 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1920
2057
|
placeholder: t("posts.form.tagsPlaceholder")
|
|
1921
2058
|
}
|
|
1922
2059
|
),
|
|
1923
|
-
/* @__PURE__ */
|
|
2060
|
+
/* @__PURE__ */ jsx9("p", { className: "text-xs text-muted-foreground", children: t("posts.form.tagsHint") })
|
|
1924
2061
|
] }),
|
|
1925
|
-
/* @__PURE__ */
|
|
1926
|
-
/* @__PURE__ */
|
|
1927
|
-
/* @__PURE__ */
|
|
2062
|
+
/* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
|
|
2063
|
+
/* @__PURE__ */ jsx9(Label, { htmlFor: "status", children: t("posts.form.status") }),
|
|
2064
|
+
/* @__PURE__ */ jsxs9(
|
|
1928
2065
|
"select",
|
|
1929
2066
|
{
|
|
1930
2067
|
id: "status",
|
|
@@ -1935,15 +2072,15 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1935
2072
|
},
|
|
1936
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",
|
|
1937
2074
|
children: [
|
|
1938
|
-
/* @__PURE__ */
|
|
1939
|
-
/* @__PURE__ */
|
|
2075
|
+
/* @__PURE__ */ jsx9("option", { value: "draft", children: t("common.draft") }),
|
|
2076
|
+
/* @__PURE__ */ jsx9("option", { value: "published", children: t("common.published") })
|
|
1940
2077
|
]
|
|
1941
2078
|
}
|
|
1942
2079
|
)
|
|
1943
2080
|
] }),
|
|
1944
|
-
/* @__PURE__ */
|
|
1945
|
-
/* @__PURE__ */
|
|
1946
|
-
/* @__PURE__ */
|
|
2081
|
+
/* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
|
|
2082
|
+
/* @__PURE__ */ jsx9(Label, { htmlFor: "publishedAt", children: t("posts.form.publishedAt") }),
|
|
2083
|
+
/* @__PURE__ */ jsx9(
|
|
1947
2084
|
"input",
|
|
1948
2085
|
{
|
|
1949
2086
|
id: "publishedAt",
|
|
@@ -1956,11 +2093,11 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1956
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"
|
|
1957
2094
|
}
|
|
1958
2095
|
),
|
|
1959
|
-
/* @__PURE__ */
|
|
1960
|
-
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 }) })
|
|
1961
2098
|
] }),
|
|
1962
|
-
format === "html" && /* @__PURE__ */
|
|
1963
|
-
/* @__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(
|
|
1964
2101
|
"input",
|
|
1965
2102
|
{
|
|
1966
2103
|
type: "checkbox",
|
|
@@ -1972,17 +2109,17 @@ function PostForm({ post, previewEndpoint = "/admin/preview" }) {
|
|
|
1972
2109
|
className: "mt-1"
|
|
1973
2110
|
}
|
|
1974
2111
|
),
|
|
1975
|
-
/* @__PURE__ */
|
|
1976
|
-
/* @__PURE__ */
|
|
1977
|
-
/* @__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") })
|
|
1978
2115
|
] })
|
|
1979
2116
|
] }) }),
|
|
1980
|
-
error && /* @__PURE__ */
|
|
1981
|
-
/* @__PURE__ */
|
|
1982
|
-
/* @__PURE__ */
|
|
1983
|
-
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") })
|
|
1984
2121
|
] }),
|
|
1985
|
-
isEdit && post && /* @__PURE__ */
|
|
2122
|
+
isEdit && post && /* @__PURE__ */ jsx9(
|
|
1986
2123
|
PostHistoryPanel,
|
|
1987
2124
|
{
|
|
1988
2125
|
postId: post.postId,
|