@prenta/admin 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/__tests__/lib/page-audit-input.test.js +81 -0
  3. package/dist/__tests__/lib/page-audit-input.test.js.map +1 -1
  4. package/dist/__tests__/lib/version-history.test.js +18 -0
  5. package/dist/__tests__/lib/version-history.test.js.map +1 -1
  6. package/dist/__tests__/no-server-barrel-imports.test.js +3 -4
  7. package/dist/__tests__/no-server-barrel-imports.test.js.map +1 -1
  8. package/dist/__tests__/views/editor-top-bar.render.test.js +5 -0
  9. package/dist/__tests__/views/editor-top-bar.render.test.js.map +1 -1
  10. package/dist/__tests__/views/post-section-editor.test.js +38 -0
  11. package/dist/__tests__/views/post-section-editor.test.js.map +1 -1
  12. package/dist/__tests__/views/post-tab.render.test.d.ts +2 -0
  13. package/dist/__tests__/views/post-tab.render.test.d.ts.map +1 -0
  14. package/dist/__tests__/views/post-tab.render.test.js +86 -0
  15. package/dist/__tests__/views/post-tab.render.test.js.map +1 -0
  16. package/dist/components/seo/SeoEditorPane.d.ts +9 -1
  17. package/dist/components/seo/SeoEditorPane.d.ts.map +1 -1
  18. package/dist/components/seo/SeoEditorPane.js +5 -2
  19. package/dist/components/seo/SeoEditorPane.js.map +1 -1
  20. package/dist/hooks/usePageAudit.d.ts +4 -1
  21. package/dist/hooks/usePageAudit.d.ts.map +1 -1
  22. package/dist/hooks/usePageAudit.js +3 -3
  23. package/dist/hooks/usePageAudit.js.map +1 -1
  24. package/dist/lib/page-audit-input.d.ts +26 -1
  25. package/dist/lib/page-audit-input.d.ts.map +1 -1
  26. package/dist/lib/page-audit-input.js +48 -2
  27. package/dist/lib/page-audit-input.js.map +1 -1
  28. package/dist/lib/version-history.d.ts +5 -0
  29. package/dist/lib/version-history.d.ts.map +1 -1
  30. package/dist/lib/version-history.js +18 -0
  31. package/dist/lib/version-history.js.map +1 -1
  32. package/dist/views/page-editor/EditorTopBar.js +1 -1
  33. package/dist/views/page-editor/EditorTopBar.js.map +1 -1
  34. package/dist/views/post-editor/PostEditorCanvas.d.ts +14 -1
  35. package/dist/views/post-editor/PostEditorCanvas.d.ts.map +1 -1
  36. package/dist/views/post-editor/PostEditorCanvas.js +2 -2
  37. package/dist/views/post-editor/PostEditorCanvas.js.map +1 -1
  38. package/dist/views/post-editor/PostFieldsForm.d.ts +39 -0
  39. package/dist/views/post-editor/PostFieldsForm.d.ts.map +1 -0
  40. package/dist/views/post-editor/PostFieldsForm.js +85 -0
  41. package/dist/views/post-editor/PostFieldsForm.js.map +1 -0
  42. package/dist/views/post-editor/PostFieldsModal.d.ts +2 -14
  43. package/dist/views/post-editor/PostFieldsModal.d.ts.map +1 -1
  44. package/dist/views/post-editor/PostFieldsModal.js +20 -81
  45. package/dist/views/post-editor/PostFieldsModal.js.map +1 -1
  46. package/dist/views/post-editor/PostSectionEditor.d.ts.map +1 -1
  47. package/dist/views/post-editor/PostSectionEditor.js +122 -34
  48. package/dist/views/post-editor/PostSectionEditor.js.map +1 -1
  49. package/dist/views/post-editor/PostTab.d.ts +17 -0
  50. package/dist/views/post-editor/PostTab.d.ts.map +1 -0
  51. package/dist/views/post-editor/PostTab.js +23 -0
  52. package/dist/views/post-editor/PostTab.js.map +1 -0
  53. package/package.json +6 -6
  54. package/src/__tests__/lib/page-audit-input.test.ts +99 -0
  55. package/src/__tests__/lib/version-history.test.ts +20 -0
  56. package/src/__tests__/no-server-barrel-imports.test.ts +3 -4
  57. package/src/__tests__/views/editor-top-bar.render.test.tsx +6 -0
  58. package/src/__tests__/views/post-section-editor.test.tsx +59 -0
  59. package/src/__tests__/views/post-tab.render.test.tsx +116 -0
  60. package/src/components/seo/SeoEditorPane.tsx +16 -1
  61. package/src/hooks/usePageAudit.ts +9 -2
  62. package/src/lib/page-audit-input.ts +67 -1
  63. package/src/lib/version-history.ts +23 -0
  64. package/src/views/page-editor/EditorTopBar.tsx +2 -2
  65. package/src/views/post-editor/PostEditorCanvas.tsx +27 -5
  66. package/src/views/post-editor/PostFieldsForm.tsx +322 -0
  67. package/src/views/post-editor/PostFieldsModal.tsx +30 -281
  68. package/src/views/post-editor/PostSectionEditor.tsx +204 -59
  69. package/src/views/post-editor/PostTab.tsx +46 -0
@@ -0,0 +1,85 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import { Loader2, Sparkles } from 'lucide-react';
5
+ import { toast } from 'sonner';
6
+ import { normalizeSlug, validateSlug } from '@prenta/core/client';
7
+ import { MediaPickerModal } from '../../components/MediaPickerModal.js';
8
+ import { TagInput } from '../../components/TagInput.js';
9
+ import { coauthorText } from '../../lib/coauthor-client.js';
10
+ const LABEL = 'text-foreground mb-1 block text-xs font-medium';
11
+ /** Match TipTap body editor borders — `border-input` is transparent in theme.css. */
12
+ const INPUT = 'border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none';
13
+ const slugify = normalizeSlug;
14
+ function stripHtml(html) {
15
+ return html
16
+ .replace(/<[^>]*>/g, ' ')
17
+ .replace(/\s+/g, ' ')
18
+ .trim();
19
+ }
20
+ function buildContentContext(title, body, excerpt) {
21
+ const plain = stripHtml(body);
22
+ const parts = [title.trim(), excerpt.trim(), plain].filter(Boolean);
23
+ return parts.join('\n\n');
24
+ }
25
+ function AiFieldButton({ label, busy, disabled, onClick, }) {
26
+ return (_jsxs("button", { type: "button", "aria-label": label, title: label, disabled: disabled || busy, onClick: onClick, className: "inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[11px] font-medium text-[var(--acc)] transition-colors duration-[var(--motion-fast)] hover:bg-[var(--acc-l)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:outline-none disabled:opacity-60", children: [busy ? (_jsx(Loader2, { className: "h-3 w-3 animate-spin", "aria-hidden": true })) : (_jsx(Sparkles, { className: "h-3 w-3", "aria-hidden": true })), busy ? 'Generating…' : 'AI'] }));
27
+ }
28
+ /** Title, slug, excerpt, featured image, category, and tags. SEO lives in the SEO tab. */
29
+ export function PostFieldsForm({ values, canEdit, fields, postType, bodyHtml = '', slugTouched, onSlugTouched, onChange, titleRef, idPrefix = 'pf', }) {
30
+ const [mediaOpen, setMediaOpen] = useState(false);
31
+ const [aiBusy, setAiBusy] = useState(false);
32
+ const categoryField = fields?.category;
33
+ const categoryOptions = categoryField?.type === 'select' && Array.isArray(categoryField.options)
34
+ ? categoryField.options
35
+ : null;
36
+ const tagsField = fields?.tags;
37
+ const hasTags = tagsField?.type === 'array';
38
+ const slugError = validateSlug(values.slug);
39
+ function handleTitle(next) {
40
+ const patch = { title: next };
41
+ if (!slugTouched)
42
+ patch.slug = slugify(next);
43
+ onChange(patch);
44
+ }
45
+ async function handleAiGenerateExcerpt() {
46
+ const context = buildContentContext(values.title, bodyHtml, values.excerpt);
47
+ if (!context.trim()) {
48
+ toast.error('Add a title or write body content in the Article Body section before generating with AI.');
49
+ return;
50
+ }
51
+ setAiBusy(true);
52
+ try {
53
+ const outcome = await coauthorText('compress', context, {
54
+ instructions: 'Write a 1–2 sentence excerpt for blog listings and cards. Return only the excerpt text.',
55
+ targetLength: 45,
56
+ });
57
+ if (!outcome.ok) {
58
+ toast.error(outcome.error);
59
+ return;
60
+ }
61
+ onChange({ excerpt: outcome.result.text.trim() });
62
+ toast.success('Excerpt generated — review before saving.');
63
+ }
64
+ catch {
65
+ toast.error('AI request failed.');
66
+ }
67
+ finally {
68
+ setAiBusy(false);
69
+ }
70
+ }
71
+ const titleId = `${idPrefix}-title`;
72
+ const slugId = `${idPrefix}-slug`;
73
+ const categoryId = `${idPrefix}-category`;
74
+ const tagsId = `${idPrefix}-tags`;
75
+ const excerptId = `${idPrefix}-excerpt`;
76
+ const imageId = `${idPrefix}-image`;
77
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { children: [_jsxs("label", { className: LABEL, htmlFor: titleId, children: ["Title ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx("input", { id: titleId, ref: titleRef, className: INPUT, value: values.title, disabled: !canEdit, placeholder: "e.g. Announcing our new product", onChange: (e) => handleTitle(e.target.value) })] }), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { children: [_jsxs("label", { className: LABEL, htmlFor: slugId, children: ["Slug ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx("input", { id: slugId, className: INPUT, value: values.slug, disabled: !canEdit, placeholder: slugTouched ? undefined : 'Generated from title…', "aria-invalid": Boolean(slugError), "aria-describedby": slugError ? `${slugId}-error` : undefined, onChange: (e) => {
78
+ onSlugTouched();
79
+ onChange({ slug: slugify(e.target.value) });
80
+ } }), slugError && (_jsx("p", { id: `${slugId}-error`, className: "text-destructive mt-1 text-xs", children: slugError }))] }), _jsxs("div", { children: [_jsx("label", { className: LABEL, htmlFor: categoryId, children: "Category" }), categoryOptions ? (_jsxs("select", { id: categoryId, className: INPUT, value: values.category, disabled: !canEdit, onChange: (e) => onChange({ category: e.target.value }), children: [_jsx("option", { value: "", children: "No category" }), categoryOptions.map((o) => (_jsx("option", { value: o.value, children: o.label }, o.value))), values.category && !categoryOptions.some((o) => o.value === values.category) && (_jsx("option", { value: values.category, children: values.category }))] })) : (_jsx("input", { id: categoryId, className: INPUT, value: values.category, disabled: !canEdit, placeholder: "e.g. Product", onChange: (e) => onChange({ category: e.target.value }) }))] })] }), hasTags && (_jsxs("div", { children: [_jsx("label", { className: LABEL, htmlFor: tagsId, children: "Tags" }), _jsx(TagInput, { id: tagsId, value: values.tags, onChange: (tags) => onChange({ tags }), collection: postType, field: "tags", disabled: !canEdit, maxTags: tagsField?.maxRows })] })), _jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between gap-2", children: [_jsx("label", { className: `${LABEL} mb-0`, htmlFor: excerptId, children: "Excerpt" }), _jsx(AiFieldButton, { label: "Generate excerpt from content", busy: aiBusy, disabled: !canEdit, onClick: () => void handleAiGenerateExcerpt() })] }), _jsx("textarea", { id: excerptId, className: `${INPUT} min-h-[72px] resize-y`, value: values.excerpt, disabled: !canEdit, placeholder: "A short summary shown in listings and the header.", onChange: (e) => onChange({ excerpt: e.target.value }) })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL, htmlFor: imageId, children: "Featured image" }), _jsxs("div", { className: "flex gap-2", children: [_jsx("input", { id: imageId, className: `${INPUT} min-w-0 flex-1`, value: values.featuredImage, disabled: !canEdit, placeholder: "https://\u2026 or pick from the media library", onChange: (e) => onChange({ featuredImage: e.target.value }) }), _jsx("button", { type: "button", disabled: !canEdit, onClick: () => setMediaOpen(true), className: "bg-accent text-foreground border-border hover:bg-accent/80 shrink-0 rounded-md border px-3 py-1.5 text-xs font-medium disabled:opacity-50", children: "Browse" })] }), values.featuredImage && (_jsx("div", { className: "border-border bg-muted mt-2 overflow-hidden rounded-md border", children: _jsx("img", { src: values.featuredImage, alt: "", className: "h-28 w-full object-cover" }) }))] })] }), _jsx(MediaPickerModal, { open: mediaOpen, onClose: () => setMediaOpen(false), onSelect: (url) => {
81
+ onChange({ featuredImage: url });
82
+ setMediaOpen(false);
83
+ }, accept: "image/*" })] }));
84
+ }
85
+ //# sourceMappingURL=PostFieldsForm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PostFieldsForm.js","sourceRoot":"","sources":["../../../src/views/post-editor/PostFieldsForm.tsx"],"names":[],"mappings":"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"}
@@ -1,17 +1,6 @@
1
1
  import type { EditorPost } from '../../lib/post-editor-service.js';
2
- /**
3
- * The slice of a collection's field config the modal reads to pick controls:
4
- * a `select` category renders a dropdown (structured vocabulary), an `array`
5
- * tags field renders the chip input with autocomplete.
6
- */
7
- export interface PostFieldConfig {
8
- type?: string;
9
- options?: Array<{
10
- label: string;
11
- value: string;
12
- }>;
13
- maxRows?: number;
14
- }
2
+ import { type PostFieldConfig } from './PostFieldsForm.js';
3
+ export type { PostFieldConfig };
15
4
  interface PostFieldsModalProps {
16
5
  open: boolean;
17
6
  post: EditorPost;
@@ -23,5 +12,4 @@ interface PostFieldsModalProps {
23
12
  }
24
13
  /** Edits post metadata: title, slug, excerpt, featured image, category, and tags. SEO lives in the SEO tab. */
25
14
  export declare function PostFieldsModal({ open, post, canEdit, fields, onClose, onSave, }: PostFieldsModalProps): import("react/jsx-runtime").JSX.Element;
26
- export {};
27
15
  //# sourceMappingURL=PostFieldsModal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PostFieldsModal.d.ts","sourceRoot":"","sources":["../../../src/views/post-editor/PostFieldsModal.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAElE;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACjD,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,UAAU,oBAAoB;IAC5B,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,UAAU,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAAC,CAAA;IACpD,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,CAAA;CAC7C;AAsFD,+GAA+G;AAC/G,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,MAAM,EACN,OAAO,EACP,MAAM,GACP,EAAE,oBAAoB,2CAuStB"}
1
+ {"version":3,"file":"PostFieldsModal.d.ts","sourceRoot":"","sources":["../../../src/views/post-editor/PostFieldsModal.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAClE,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,qBAAqB,CAAA;AAE5B,YAAY,EAAE,eAAe,EAAE,CAAA;AAE/B,UAAU,oBAAoB;IAC5B,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,UAAU,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAAC,CAAA;IACpD,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,CAAA;CAC7C;AA6BD,+GAA+G;AAC/G,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,MAAM,EACN,OAAO,EACP,MAAM,GACP,EAAE,oBAAoB,2CA8GtB"}
@@ -1,19 +1,11 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useMemo, useRef, useState } from 'react';
4
- import { Loader2, Sparkles } from 'lucide-react';
5
- import { toast } from 'sonner';
6
- import { normalizeSlug, validateSlug } from '@prenta/core/client';
4
+ import { validateSlug } from '@prenta/core/client';
7
5
  import { Modal } from '../../components/ui/Modal.js';
8
6
  import { Button } from '../../components/ui/Button.js';
9
7
  import { ConfirmDialog } from '../../components/ui/ConfirmDialog.js';
10
- import { MediaPickerModal } from '../../components/MediaPickerModal.js';
11
- import { TagInput } from '../../components/TagInput.js';
12
- import { coauthorText } from '../../lib/coauthor-client.js';
13
- const LABEL = 'text-foreground mb-1 block text-xs font-medium';
14
- /** Match TipTap body editor borders — `border-input` is transparent in theme.css. */
15
- const INPUT = 'border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none';
16
- const slugify = normalizeSlug;
8
+ import { PostFieldsForm, } from './PostFieldsForm.js';
17
9
  function snapshotFromPost(post) {
18
10
  return {
19
11
  title: post.title,
@@ -30,20 +22,6 @@ function snapshotFromFields(input) {
30
22
  tags: [...input.tags].sort().join('\0'),
31
23
  };
32
24
  }
33
- function stripHtml(html) {
34
- return html
35
- .replace(/<[^>]*>/g, ' ')
36
- .replace(/\s+/g, ' ')
37
- .trim();
38
- }
39
- function buildContentContext(title, body, excerpt) {
40
- const plain = stripHtml(body);
41
- const parts = [title.trim(), excerpt.trim(), plain].filter(Boolean);
42
- return parts.join('\n\n');
43
- }
44
- function AiFieldButton({ label, busy, disabled, onClick, }) {
45
- return (_jsxs("button", { type: "button", "aria-label": label, title: label, disabled: disabled || busy, onClick: onClick, className: "inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[11px] font-medium text-[var(--acc)] transition-colors duration-[var(--motion-fast)] hover:bg-[var(--acc-l)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:outline-none disabled:opacity-60", children: [busy ? (_jsx(Loader2, { className: "h-3 w-3 animate-spin", "aria-hidden": true })) : (_jsx(Sparkles, { className: "h-3 w-3", "aria-hidden": true })), busy ? 'Generating…' : 'AI'] }));
46
- }
47
25
  /** Edits post metadata: title, slug, excerpt, featured image, category, and tags. SEO lives in the SEO tab. */
48
26
  export function PostFieldsModal({ open, post, canEdit, fields, onClose, onSave, }) {
49
27
  const [title, setTitle] = useState(post.title);
@@ -53,18 +31,10 @@ export function PostFieldsModal({ open, post, canEdit, fields, onClose, onSave,
53
31
  const [category, setCategory] = useState(post.category);
54
32
  const [tags, setTags] = useState(post.tags);
55
33
  const [slugTouched, setSlugTouched] = useState(Boolean(post.slug));
56
- const [mediaOpen, setMediaOpen] = useState(false);
57
- const [aiBusy, setAiBusy] = useState(false);
58
34
  const [confirmDiscard, setConfirmDiscard] = useState(false);
59
35
  const baselineRef = useRef(null);
60
36
  // Land the user in the Title field (name-it-first flow for new posts).
61
37
  const titleRef = useRef(null);
62
- const categoryField = fields?.category;
63
- const categoryOptions = categoryField?.type === 'select' && Array.isArray(categoryField.options)
64
- ? categoryField.options
65
- : null;
66
- const tagsField = fields?.tags;
67
- const hasTags = tagsField?.type === 'array';
68
38
  useEffect(() => {
69
39
  if (!open) {
70
40
  baselineRef.current = null;
@@ -78,22 +48,14 @@ export function PostFieldsModal({ open, post, canEdit, fields, onClose, onSave,
78
48
  setCategory(post.category);
79
49
  setTags(post.tags);
80
50
  setSlugTouched(Boolean(post.slug));
81
- setAiBusy(false);
82
51
  baselineRef.current = snapshotFromPost(post);
83
52
  }, [open, post]);
53
+ const values = { title, slug, excerpt, featuredImage, category, tags };
84
54
  const isDirty = useMemo(() => {
85
55
  if (!open || !baselineRef.current)
86
56
  return false;
87
- const current = snapshotFromFields({
88
- title,
89
- slug,
90
- excerpt,
91
- featuredImage,
92
- category,
93
- tags,
94
- });
95
- return JSON.stringify(current) !== JSON.stringify(baselineRef.current);
96
- }, [open, title, slug, excerpt, featuredImage, category, tags]);
57
+ return JSON.stringify(snapshotFromFields(values)) !== JSON.stringify(baselineRef.current);
58
+ }, [open, values]);
97
59
  function requestDismiss() {
98
60
  if (isDirty) {
99
61
  setConfirmDiscard(true);
@@ -101,50 +63,27 @@ export function PostFieldsModal({ open, post, canEdit, fields, onClose, onSave,
101
63
  }
102
64
  onClose();
103
65
  }
104
- function handleTitle(next) {
105
- setTitle(next);
106
- if (!slugTouched)
107
- setSlug(slugify(next));
66
+ function handleChange(patch) {
67
+ if (patch.title !== undefined)
68
+ setTitle(patch.title);
69
+ if (patch.slug !== undefined)
70
+ setSlug(patch.slug);
71
+ if (patch.excerpt !== undefined)
72
+ setExcerpt(patch.excerpt);
73
+ if (patch.featuredImage !== undefined)
74
+ setFeaturedImage(patch.featuredImage);
75
+ if (patch.category !== undefined)
76
+ setCategory(patch.category);
77
+ if (patch.tags !== undefined)
78
+ setTags(patch.tags);
108
79
  }
109
80
  const slugError = validateSlug(slug);
110
- async function handleAiGenerateExcerpt() {
111
- const context = buildContentContext(title, post.body, excerpt);
112
- if (!context.trim()) {
113
- toast.error('Add a title or write body content in the Article Body section before generating with AI.');
114
- return;
115
- }
116
- setAiBusy(true);
117
- try {
118
- const outcome = await coauthorText('compress', context, {
119
- instructions: 'Write a 1–2 sentence excerpt for blog listings and cards. Return only the excerpt text.',
120
- targetLength: 45,
121
- });
122
- if (!outcome.ok) {
123
- toast.error(outcome.error);
124
- return;
125
- }
126
- setExcerpt(outcome.result.text.trim());
127
- toast.success('Excerpt generated — review before saving.');
128
- }
129
- catch {
130
- toast.error('AI request failed.');
131
- }
132
- finally {
133
- setAiBusy(false);
134
- }
135
- }
136
81
  function handleSave() {
137
82
  if (slugError)
138
83
  return;
139
84
  onSave({ title, slug, excerpt, featuredImage, category, tags });
140
85
  onClose();
141
86
  }
142
- return (_jsxs(_Fragment, { children: [_jsx(Modal, { open: open, onClose: onClose, onDismiss: requestDismiss, title: "Post details", size: "lg", initialFocusRef: titleRef, actions: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "ghost", onClick: requestDismiss, children: "Cancel" }), _jsx(Button, { variant: "primary", onClick: handleSave, disabled: !canEdit || Boolean(slugError), children: "Done" })] }), children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { children: [_jsxs("label", { className: LABEL, htmlFor: "pf-title", children: ["Title ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx("input", { id: "pf-title", ref: titleRef, className: INPUT, value: title, disabled: !canEdit, placeholder: "e.g. Announcing our new product", onChange: (e) => handleTitle(e.target.value) })] }), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { children: [_jsxs("label", { className: LABEL, htmlFor: "pf-slug", children: ["Slug ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx("input", { id: "pf-slug", className: INPUT, value: slug, disabled: !canEdit, placeholder: slugTouched ? undefined : 'Generated from title…', "aria-invalid": Boolean(slugError), "aria-describedby": slugError ? 'pf-slug-error' : undefined, onChange: (e) => {
143
- setSlugTouched(true);
144
- setSlug(slugify(e.target.value));
145
- } }), slugError && (_jsx("p", { id: "pf-slug-error", className: "text-destructive mt-1 text-xs", children: slugError }))] }), _jsxs("div", { children: [_jsx("label", { className: LABEL, htmlFor: "pf-category", children: "Category" }), categoryOptions ? (_jsxs("select", { id: "pf-category", className: INPUT, value: category, disabled: !canEdit, onChange: (e) => setCategory(e.target.value), children: [_jsx("option", { value: "", children: "No category" }), categoryOptions.map((o) => (_jsx("option", { value: o.value, children: o.label }, o.value))), category && !categoryOptions.some((o) => o.value === category) && (_jsx("option", { value: category, children: category }))] })) : (_jsx("input", { id: "pf-category", className: INPUT, value: category, disabled: !canEdit, placeholder: "e.g. Product", onChange: (e) => setCategory(e.target.value) }))] })] }), hasTags && (_jsxs("div", { children: [_jsx("label", { className: LABEL, htmlFor: "pf-tags", children: "Tags" }), _jsx(TagInput, { id: "pf-tags", value: tags, onChange: setTags, collection: post.postType, field: "tags", disabled: !canEdit, maxTags: tagsField?.maxRows })] })), _jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between gap-2", children: [_jsx("label", { className: `${LABEL} mb-0`, htmlFor: "pf-excerpt", children: "Excerpt" }), _jsx(AiFieldButton, { label: "Generate excerpt from content", busy: aiBusy, disabled: !canEdit, onClick: () => void handleAiGenerateExcerpt() })] }), _jsx("textarea", { id: "pf-excerpt", className: `${INPUT} min-h-[72px] resize-y`, value: excerpt, disabled: !canEdit, placeholder: "A short summary shown in listings and the header.", onChange: (e) => setExcerpt(e.target.value) })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL, htmlFor: "pf-image", children: "Featured image" }), _jsxs("div", { className: "flex gap-2", children: [_jsx("input", { id: "pf-image", className: `${INPUT} min-w-0 flex-1`, value: featuredImage, disabled: !canEdit, placeholder: "https://\u2026 or pick from the media library", onChange: (e) => setFeaturedImage(e.target.value) }), _jsx("button", { type: "button", disabled: !canEdit, onClick: () => setMediaOpen(true), className: "bg-accent text-foreground border-border hover:bg-accent/80 shrink-0 rounded-md border px-3 py-1.5 text-xs font-medium disabled:opacity-50", children: "Browse" })] }), featuredImage && (_jsx("div", { className: "border-border bg-muted mt-2 overflow-hidden rounded-md border", children: _jsx("img", { src: featuredImage, alt: "", className: "h-28 w-full object-cover" }) }))] })] }) }), _jsx(MediaPickerModal, { open: mediaOpen, onClose: () => setMediaOpen(false), onSelect: (url) => {
146
- setFeaturedImage(url);
147
- setMediaOpen(false);
148
- }, accept: "image/*" }), _jsx(ConfirmDialog, { open: confirmDiscard, onClose: () => setConfirmDiscard(false), onConfirm: onClose, title: "Discard unsaved changes?", description: "You have unsaved post details. Closing now will discard them.", confirmLabel: "Discard", cancelLabel: "Keep editing", destructive: true })] }));
87
+ return (_jsxs(_Fragment, { children: [_jsx(Modal, { open: open, onClose: onClose, onDismiss: requestDismiss, title: "Post details", size: "lg", initialFocusRef: titleRef, actions: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "ghost", onClick: requestDismiss, children: "Cancel" }), _jsx(Button, { variant: "primary", onClick: handleSave, disabled: !canEdit || Boolean(slugError), children: "Done" })] }), children: _jsx(PostFieldsForm, { values: values, canEdit: canEdit, fields: fields, postType: post.postType, bodyHtml: post.body, slugTouched: slugTouched, onSlugTouched: () => setSlugTouched(true), onChange: handleChange, titleRef: titleRef }) }), _jsx(ConfirmDialog, { open: confirmDiscard, onClose: () => setConfirmDiscard(false), onConfirm: onClose, title: "Discard unsaved changes?", description: "You have unsaved post details. Closing now will discard them.", confirmLabel: "Discard", cancelLabel: "Keep editing", destructive: true })] }));
149
88
  }
150
89
  //# sourceMappingURL=PostFieldsModal.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PostFieldsModal.js","sourceRoot":"","sources":["../../../src/views/post-editor/PostFieldsModal.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PostFieldsModal.js","sourceRoot":"","sources":["../../../src/views/post-editor/PostFieldsModal.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PostSectionEditor.d.ts","sourceRoot":"","sources":["../../../src/views/post-editor/PostSectionEditor.tsx"],"names":[],"mappings":"AAiDA,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAE5E,8DAA8D;AAC9D,UAAU,YAAY;IACpB,WAAW,CAAC,EAAE,MAAM,CAClB,MAAM,EACJ;QACE,MAAM,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;QAC9B,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAAC,CAAA;KACrD,GACD,SAAS,CACZ,CAAA;IACD,GAAG,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAC3B;AAED,wDAAwD;AACxD,UAAU,aAAa;IACrB,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CACxD;AAED,UAAU,sBAAsB;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACnC;AAgBD,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,UAAU,EACV,MAAM,EACN,OAAO,EACP,UAAU,GACX,EAAE,sBAAsB,2CAqrBxB"}
1
+ {"version":3,"file":"PostSectionEditor.d.ts","sourceRoot":"","sources":["../../../src/views/post-editor/PostSectionEditor.tsx"],"names":[],"mappings":"AA0DA,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAc5E,8DAA8D;AAC9D,UAAU,YAAY;IACpB,WAAW,CAAC,EAAE,MAAM,CAClB,MAAM,EACJ;QACE,MAAM,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;QAC9B,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAAC,CAAA;KACrD,GACD,SAAS,CACZ,CAAA;IACD,GAAG,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAC3B;AAED,wDAAwD;AACxD,UAAU,aAAa;IACrB,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CACxD;AAED,UAAU,sBAAsB;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACnC;AAgBD,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,UAAU,EACV,MAAM,EACN,OAAO,EACP,UAAU,GACX,EAAE,sBAAsB,2CAizBxB"}
@@ -10,7 +10,12 @@ import { EditorRail, RailHeader } from '../../components/EditorRail.js';
10
10
  import { EditorRailTabs } from '../../components/EditorRailTabs.js';
11
11
  import { SeoEditorPane } from '../../components/seo/SeoEditorPane.js';
12
12
  import { ErrorBoundary } from '../../components/ErrorBoundary.js';
13
- import { VersionHistory } from '../../components/VersionHistory.js';
13
+ import { VersionHistoryPanel } from '../page-editor/VersionHistoryPanel.js';
14
+ import { ReviewBar } from '../page-editor/ReviewBar.js';
15
+ import { fetchPageVersions, restorePageVersion, } from '../../lib/version-history.js';
16
+ import { changedSectionIds, diffVersions } from '../../lib/version-diff.js';
17
+ import { scoreBand } from '@prenta/core/seo/page-audit';
18
+ import { usePageAudit } from '../../hooks/usePageAudit.js';
14
19
  import { emptyPostFromTemplate, fetchPostForEditor, fetchTemplateForEditor, missingPostFields, publishPost, savePostDraft, toggleSectionVisibility, updateSectionContent, updateSectionMeta, validatePost, } from '../../lib/post-editor-service.js';
15
20
  import { SharePreviewLinkDialog } from '../../components/SharePreviewLinkDialog.js';
16
21
  import { defaultPostHeader } from '@prenta/core/page-sections';
@@ -22,12 +27,24 @@ import { EditorTopBar } from '../page-editor/EditorTopBar.js';
22
27
  import { SectionsList } from '../page-editor/SectionsPanel.js';
23
28
  import { SectionEditForm } from '../page-editor/SectionEditForm.js';
24
29
  import { ValidationSummary } from '../page-editor/ValidationSummary.js';
25
- import { buildEditorContentHtml, computeLiveSeoScore } from '../../lib/editor-seo-content.js';
30
+ import { buildEditorContentHtml } from '../../lib/editor-seo-content.js';
26
31
  import { snapshotBaseline } from '../../lib/reflow-baseline.js';
27
32
  import { ReflowContext } from '../page-editor/reflow-context.js';
28
33
  import { inspectorIdFromFieldPath } from '../../lib/preview-bridge.js';
29
34
  import { PostEditorCanvas } from './PostEditorCanvas.js';
30
35
  import { PostFieldsModal } from './PostFieldsModal.js';
36
+ import { PostTab } from './PostTab.js';
37
+ /**
38
+ * The lower of the two audit scores — the tab dot should reflect the half that
39
+ * needs work, not an average that hides it. Same three-valued contract as the
40
+ * page editor: undefined = not reported yet, null = gated off, number = score.
41
+ */
42
+ function weakestAuditScore(audit) {
43
+ if (!audit)
44
+ return undefined;
45
+ const scores = [audit.seo.score, audit.geo.score].filter((s) => s !== null);
46
+ return scores.length ? Math.min(...scores) : null;
47
+ }
31
48
  function deriveCan(session) {
32
49
  const role = session?.user?.role;
33
50
  // Default closed: when we can't identify a role, hide the edit/publish
@@ -67,6 +84,18 @@ export function PostSectionEditor({ postType, documentId, config, session, onNav
67
84
  const [railTab, setRailTab] = useState('sections');
68
85
  const seoOpen = railTab === 'seo';
69
86
  const [historyOpen, setHistoryOpen] = useState(false);
87
+ const [versions, setVersions] = useState([]);
88
+ const [versionsLoading, setVersionsLoading] = useState(false);
89
+ const [versionsError, setVersionsError] = useState(null);
90
+ /** Index into `versions`; 0 is the newest, which is the current content. */
91
+ const [versionIndex, setVersionIndex] = useState(0);
92
+ const [restoring, setRestoring] = useState(false);
93
+ /**
94
+ * Live audit reported by the SEO pane, built from unsaved form state. Null
95
+ * until that pane has mounted — `audit` below falls back to the saved-record
96
+ * audit so the header chip and tab dot always have a number.
97
+ */
98
+ const [liveAudit, setLiveAudit] = useState(null);
70
99
  const [confirmPublish, setConfirmPublish] = useState(false);
71
100
  const [scheduleOpen, setScheduleOpen] = useState(false);
72
101
  const [shareOpen, setShareOpen] = useState(false);
@@ -108,6 +137,19 @@ export function PostSectionEditor({ postType, documentId, config, session, onNav
108
137
  }, [config, postType]);
109
138
  const publishCheck = useMemo(() => (post ? validatePost(post, true) : { errors: [''], warnings: [] }), [post]);
110
139
  const publishReady = Boolean(post) && publishCheck.errors.length === 0;
140
+ const { audit: savedAudit } = usePageAudit({
141
+ entityType: 'post',
142
+ entityId: post?.id ?? null,
143
+ sections: post?.sections ?? [],
144
+ slug: post?.slug ?? '',
145
+ fallback: { title: post?.seoTitle, description: post?.seoDescription },
146
+ post: {
147
+ title: post?.title,
148
+ bodyHtml: post?.body,
149
+ featuredImage: post?.featuredImage,
150
+ },
151
+ });
152
+ const audit = liveAudit ?? savedAudit;
111
153
  const railTabs = useMemo(() => [
112
154
  {
113
155
  id: 'sections',
@@ -115,12 +157,18 @@ export function PostSectionEditor({ postType, documentId, config, session, onNav
115
157
  title: 'Post content',
116
158
  count: post?.sections.length ?? 0,
117
159
  },
118
- // No score dot yet. The page editor's comes from the page audit, which
119
- // is page-scoped; wiring a number here from `computeLiveSeoScore` would
120
- // put a different model's score on a tab, which is the disagreement the
121
- // page editor was rewired to remove.
122
- { id: 'seo', label: 'SEO & GEO', title: 'Search & AI readiness' },
123
- ], [post?.sections.length]);
160
+ {
161
+ id: 'seo',
162
+ label: 'SEO & GEO',
163
+ title: 'Search & AI readiness',
164
+ score: weakestAuditScore(audit),
165
+ },
166
+ {
167
+ id: 'page',
168
+ label: 'Post',
169
+ title: 'Post settings',
170
+ },
171
+ ], [post?.sections.length, audit]);
124
172
  const activeRailTab = railTabs.find((tab) => tab.id === railTab) ?? railTabs[0];
125
173
  // Content the SEO pane analyses — sections plus the post body.
126
174
  const seoContentHtml = useMemo(() => buildEditorContentHtml(post?.sections ?? [], post?.body ?? ''), [post?.sections, post?.body]);
@@ -135,18 +183,6 @@ export function PostSectionEditor({ postType, documentId, config, session, onNav
135
183
  device: viewport,
136
184
  onProof: setViewport,
137
185
  }), [canvasEl, selectedId, baseline, viewport]);
138
- const liveSeoScore = useMemo(() => {
139
- if (!post)
140
- return 0;
141
- return computeLiveSeoScore({
142
- title: post.title,
143
- slug: post.slug,
144
- seoTitle: post.seoTitle,
145
- seoDescription: post.seoDescription,
146
- sections: post.sections,
147
- bodyHtml: post.body,
148
- });
149
- }, [post]);
150
186
  const publishDisabledReason = publishCheck.errors[0];
151
187
  // ─── Load ──────────────────────────────────────────────────────────
152
188
  useEffect(() => {
@@ -332,24 +368,66 @@ export function PostSectionEditor({ postType, documentId, config, session, onNav
332
368
  setPublishing(false);
333
369
  }
334
370
  }, [post, documentId, postType, onNavigate]);
335
- // After a version restore the server has already written the restored
336
- // data refetch so the editor reflects it instead of the stale state.
337
- const handleRestored = useCallback(() => {
371
+ // ─── Version history ─────────────────────────────────────────────────
372
+ // History is a MODE, not a dialog: it overlays the rail and drives the
373
+ // canvas, so the version being reviewed is editor state rather than
374
+ // something owned by a panel that can be unmounted.
375
+ const loadVersions = useCallback(async (postId) => {
376
+ setVersionsLoading(true);
377
+ setVersionsError(null);
378
+ try {
379
+ setVersions(await fetchPageVersions(postType, postId));
380
+ }
381
+ catch (err) {
382
+ setVersions([]);
383
+ setVersionsError(err instanceof Error ? err.message : 'Failed to load version history');
384
+ }
385
+ finally {
386
+ setVersionsLoading(false);
387
+ }
388
+ }, [postType]);
389
+ const openHistory = useCallback(() => {
338
390
  if (!post?.id)
339
391
  return;
340
- fetchPostForEditor(postType, post.id)
341
- .then((p) => {
342
- acceptPost(p);
392
+ setHistoryOpen(true);
393
+ setVersionIndex(0);
394
+ void loadVersions(post.id);
395
+ }, [post?.id, loadVersions]);
396
+ const closeHistory = useCallback(() => {
397
+ setHistoryOpen(false);
398
+ setVersionIndex(0);
399
+ }, []);
400
+ const reviewing = historyOpen && versionIndex > 0;
401
+ const reviewVersion = reviewing ? (versions[versionIndex] ?? null) : null;
402
+ const reviewChanges = useMemo(() => reviewVersion
403
+ ? diffVersions(reviewVersion.sections, versions[versionIndex + 1]?.sections)
404
+ : [], [reviewVersion, versions, versionIndex]);
405
+ const reviewChangedIds = useMemo(() => changedSectionIds(reviewChanges), [reviewChanges]);
406
+ const handleRestoreVersion = useCallback(async (version) => {
407
+ if (!post?.id)
408
+ return;
409
+ setRestoring(true);
410
+ try {
411
+ await restorePageVersion(postType, post.id, version.id);
412
+ const restored = await fetchPostForEditor(postType, post.id);
413
+ acceptPost(restored);
343
414
  setSelectedId(null);
344
- setRailTab('sections');
345
415
  setDirty(false);
346
416
  setSaveState('idle');
347
417
  setValidation(null);
348
- })
349
- .catch(() => {
350
- toast.error('Version restored — refresh the page to see it.');
351
- });
352
- }, [postType, post?.id]);
418
+ closeHistory();
419
+ void loadVersions(post.id);
420
+ toast.success('Version restored');
421
+ }
422
+ catch (err) {
423
+ toast.error(err instanceof Error ? err.message : 'Failed to restore version');
424
+ }
425
+ finally {
426
+ setRestoring(false);
427
+ }
428
+ }, [post?.id, postType, acceptPost, closeHistory, loadVersions]);
429
+ const effectiveCanEdit = canEdit && !reviewing;
430
+ const canRestoreVersion = canEdit;
353
431
  const handleSeoSaved = useCallback(() => {
354
432
  if (!post?.id)
355
433
  return;
@@ -438,10 +516,20 @@ export function PostSectionEditor({ postType, documentId, config, session, onNav
438
516
  const structuralTypes = Array.from(new Set(post.sections
439
517
  .filter((s) => !hasCanvasRenderer(s.sectionType) && !customRenderers[s.sectionType])
440
518
  .map((s) => s.sectionType)));
441
- return (_jsxs(ErrorBoundary, { children: [_jsxs("div", { className: "bg-background flex h-full flex-col overflow-hidden", children: [_jsx(EditorTopBar, { title: post.title || `New ${typeLabel}`, status: post.status, dirty: dirty, saveState: saveState, publishing: publishing, canEdit: canEdit, canPublish: canPublish && canEdit, publishReady: publishReady, publishDisabledReason: publishDisabledReason, viewport: viewport, backLabel: "Posts", onViewport: setViewport, zoom: zoom, canvasScale: canvasScale, onZoom: setZoom, onBack: () => guardedNavigate('/posts'), onViewOnSite: post.id && post.slug ? handleViewOnSite : undefined, onShare: post.id ? handleShare : undefined, hasPublicSiteUrl: Boolean(publicSiteUrl), matchesAdminOrigin: matchesAdminOrigin, onHistory: post.id ? () => setHistoryOpen(true) : undefined, onOpenSettings: () => setFieldsOpen(true), onOpenSeo: handleToggleSeo, seoOpen: seoOpen, seoScore: liveSeoScore, onSaveDraft: handleSaveDraft, onPublish: requestPublish, onSchedule: post.id ? requestSchedule : undefined, scheduleReady: Boolean(post.id), scheduledAt: post.scheduledAt, scheduledUnpublishAt: post.scheduledUnpublishAt, structuralTypes: structuralTypes }), unmanagedTypes.length > 0 && (_jsxs("div", { role: "status", className: "border-border bg-muted/50 flex items-start gap-3 border-b px-4 py-2.5", children: [_jsx(Lock, { className: "text-muted-foreground mt-0.5 shrink-0", size: 16, "aria-hidden": true }), _jsxs("p", { className: "text-muted-foreground flex-1 text-sm", children: ["This post has", ' ', _jsxs("span", { className: "text-foreground font-medium", children: [unmanagedTypes.length, " section type", unmanagedTypes.length > 1 ? 's' : ''] }), ' ', "managed outside the editor (", unmanagedTypes.join(', '), "). They are preserved on save but edited in your seed script or code, not here."] })] })), validation && (_jsx(ValidationSummary, { errors: validation.errors, warnings: validation.warnings, onDismiss: () => setValidation(null) })), _jsx(ReflowContext.Provider, { value: reflowContext, children: _jsxs("div", { className: "prenta-editor-body relative flex flex-1 overflow-hidden", children: [_jsx(EditorRail, { collapsedLabel: activeRailTab.label, children: ({ width, dragging, collapse }) => (_jsxs(_Fragment, { children: [_jsx(EditorRailTabs, { tabs: railTabs, active: railTab, onChange: setRailTab }), _jsx(RailHeader, { title: activeRailTab.title, width: width, dragging: dragging, onCollapse: collapse }), _jsx("div", { role: "tabpanel", id: `rail-panel-${railTab}`, "aria-labelledby": `rail-tab-${railTab}`, className: "flex min-h-0 flex-1 flex-col", children: railTab === 'sections' ? (_jsx(SectionsList, { sections: post.sections, selectedId: selectedId, canEdit: canEdit, onSelect: handleSelectSection, onToggleVisibility: handleToggleVisibility, renderEditor: (section) => (_jsx(SectionEditForm, { section: section, canEdit: canEdit, onContentChange: handleContentChange, onMetaChange: handleMetaChange, postBody: post.body, onPostBodyChange: handlePostBodyChange })) })) : (_jsx(SeoEditorPane, { entityType: "post", entityId: post.id, slug: post.slug, auditSections: post.sections, contentHtml: seoContentHtml, draftMeta: {
519
+ return (_jsxs(ErrorBoundary, { children: [_jsxs("div", { className: "bg-background flex h-full flex-col overflow-hidden", children: [_jsx(EditorTopBar, { title: post.title || `New ${typeLabel}`, status: post.status, dirty: dirty, saveState: saveState, publishing: publishing, canEdit: effectiveCanEdit, canPublish: canPublish && effectiveCanEdit, publishReady: publishReady, publishDisabledReason: publishDisabledReason, viewport: viewport, backLabel: "Posts", onViewport: setViewport, zoom: zoom, canvasScale: canvasScale, onZoom: setZoom, onBack: () => guardedNavigate('/posts'), onViewOnSite: post.id && post.slug ? handleViewOnSite : undefined, onShare: post.id ? handleShare : undefined, hasPublicSiteUrl: Boolean(publicSiteUrl), matchesAdminOrigin: matchesAdminOrigin, historyOpen: historyOpen, onHistory: post.id ? () => (historyOpen ? closeHistory() : openHistory()) : undefined, onOpenSettings: () => setFieldsOpen(true), onOpenSeo: handleToggleSeo, seoOpen: seoOpen, seoScore: audit?.seo.score ?? undefined, seoScoreBand: typeof audit?.seo.score === 'number' ? scoreBand(audit.seo.score) : undefined, onSaveDraft: handleSaveDraft, onPublish: requestPublish, onSchedule: post.id ? requestSchedule : undefined, scheduleReady: Boolean(post.id), scheduledAt: post.scheduledAt, scheduledUnpublishAt: post.scheduledUnpublishAt, structuralTypes: structuralTypes }), unmanagedTypes.length > 0 && (_jsxs("div", { role: "status", className: "border-border bg-muted/50 flex items-start gap-3 border-b px-4 py-2.5", children: [_jsx(Lock, { className: "text-muted-foreground mt-0.5 shrink-0", size: 16, "aria-hidden": true }), _jsxs("p", { className: "text-muted-foreground flex-1 text-sm", children: ["This post has", ' ', _jsxs("span", { className: "text-foreground font-medium", children: [unmanagedTypes.length, " section type", unmanagedTypes.length > 1 ? 's' : ''] }), ' ', "managed outside the editor (", unmanagedTypes.join(', '), "). They are preserved on save but edited in your seed script or code, not here."] })] })), validation && (_jsx(ValidationSummary, { errors: validation.errors, warnings: validation.warnings, onDismiss: () => setValidation(null) })), _jsx(ReflowContext.Provider, { value: reflowContext, children: _jsxs("div", { className: "prenta-editor-body relative flex flex-1 overflow-hidden", children: [_jsx(EditorRail, { collapsedLabel: activeRailTab.label, children: ({ width, dragging, collapse }) => (_jsxs(_Fragment, { children: [_jsx(EditorRailTabs, { tabs: railTabs, active: railTab, onChange: setRailTab }), _jsx(RailHeader, { title: activeRailTab.title, width: width, dragging: dragging, onCollapse: collapse }), _jsx("div", { role: "tabpanel", id: `rail-panel-${railTab}`, "aria-labelledby": `rail-tab-${railTab}`, className: "flex min-h-0 flex-1 flex-col", children: railTab === 'sections' ? (_jsx(SectionsList, { sections: post.sections, selectedId: selectedId, canEdit: effectiveCanEdit, onSelect: handleSelectSection, onToggleVisibility: handleToggleVisibility, renderEditor: reviewing
520
+ ? undefined
521
+ : (section) => (_jsx(SectionEditForm, { section: section, canEdit: effectiveCanEdit, onContentChange: handleContentChange, onMetaChange: handleMetaChange, postBody: post.body, onPostBodyChange: handlePostBodyChange })) })) : railTab === 'page' ? (_jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", children: _jsx(PostTab, { post: post, canEdit: effectiveCanEdit, fields: config?.collections?.[postType]?.fields, onChange: handleFields }) })) : (_jsx(SeoEditorPane, { entityType: "post", entityId: post.id, slug: post.slug, auditSections: post.sections, onAuditChange: setLiveAudit, contentHtml: seoContentHtml, title: post.title, bodyHtml: post.body, featuredImage: post.featuredImage, draftMeta: {
442
522
  seoTitle: post.seoTitle,
443
523
  seoDescription: post.seoDescription,
444
- }, onDraftChange: handleFields, onClose: () => setRailTab('sections'), onSaved: handleSeoSaved })) })] })) }), _jsx("div", { className: "flex-1 overflow-hidden", children: _jsx(PostEditorCanvas, { sections: post.sections, header: header, context: context, selectedId: selectedId, viewport: viewport, zoom: zoom, onScaleChange: setCanvasScale, onCanvasElement: setCanvasEl, onSelect: handleSelectSection, structuralTypes: structuralTypes }) })] }) })] }), post.id && (_jsx(VersionHistory, { collectionSlug: postType, documentId: post.id, open: historyOpen, onClose: () => setHistoryOpen(false), onRestore: handleRestored })), _jsx(PostFieldsModal, { open: fieldsOpen, post: post, canEdit: canEdit, fields: config?.collections?.[postType]?.fields, onClose: () => setFieldsOpen(false), onSave: handleFields }), _jsx(ConfirmDialog, { open: confirmPublish, onClose: () => setConfirmPublish(false), onConfirm: doPublish, title: "Publish this post?", description: "The current content will go live and replace the published version.", confirmLabel: "Publish" }), post.id && (_jsx(SchedulePublishDialog, { collectionSlug: postType, documentId: post.id, scheduledAt: post.scheduledAt, scheduledUnpublishAt: post.scheduledUnpublishAt, open: scheduleOpen, onClose: () => setScheduleOpen(false), onScheduled: handleScheduled })), post.id && (_jsx(SharePreviewLinkDialog, { collectionSlug: postType, documentId: post.id, documentSlug: post.slug, documentPath: post.path, siteUrl: publicSiteUrl, urlPrefix: urlPrefix, open: shareOpen, onClose: () => setShareOpen(false) })), _jsx(ConfirmDialog, { open: leaveTarget !== null, onClose: () => setLeaveTarget(null), onConfirm: () => {
524
+ }, onDraftChange: handleFields, onClose: () => setRailTab('sections'), onSaved: handleSeoSaved })) }), historyOpen && (_jsx(VersionHistoryPanel, { versions: versions, loading: versionsLoading, error: versionsError, selectedIndex: versionIndex, onSelect: setVersionIndex, onClose: closeHistory, onRestore: handleRestoreVersion, restoring: restoring, canRestore: canRestoreVersion }))] })) }), _jsx("div", { className: "flex-1 overflow-hidden", children: _jsx(PostEditorCanvas, { sections: reviewVersion ? reviewVersion.sections : post.sections, header: header, context: reviewVersion
525
+ ? {
526
+ ...context,
527
+ title: reviewVersion.title ?? context.title,
528
+ excerpt: reviewVersion.excerpt ?? context.excerpt,
529
+ body: reviewVersion.body ?? context.body,
530
+ featuredImageUrl: reviewVersion.featuredImage ?? context.featuredImageUrl,
531
+ }
532
+ : context, selectedId: selectedId, viewport: viewport, zoom: zoom, onScaleChange: setCanvasScale, onCanvasElement: setCanvasEl, onSelect: handleSelectSection, structuralTypes: structuralTypes, reviewing: reviewing, changedSectionIds: reviewChangedIds, reviewBar: reviewVersion ? (_jsx(ReviewBar, { version: reviewVersion, changedCount: reviewChangedIds.size, onRestore: () => void handleRestoreVersion(reviewVersion), onBackToCurrent: () => setVersionIndex(0), restoring: restoring, canRestore: canRestoreVersion })) : null }) })] }) })] }), _jsx(PostFieldsModal, { open: fieldsOpen, post: post, canEdit: effectiveCanEdit, fields: config?.collections?.[postType]?.fields, onClose: () => setFieldsOpen(false), onSave: handleFields }), _jsx(ConfirmDialog, { open: confirmPublish, onClose: () => setConfirmPublish(false), onConfirm: doPublish, title: "Publish this post?", description: "The current content will go live and replace the published version.", confirmLabel: "Publish" }), post.id && (_jsx(SchedulePublishDialog, { collectionSlug: postType, documentId: post.id, scheduledAt: post.scheduledAt, scheduledUnpublishAt: post.scheduledUnpublishAt, open: scheduleOpen, onClose: () => setScheduleOpen(false), onScheduled: handleScheduled })), post.id && (_jsx(SharePreviewLinkDialog, { collectionSlug: postType, documentId: post.id, documentSlug: post.slug, documentPath: post.path, siteUrl: publicSiteUrl, urlPrefix: urlPrefix, open: shareOpen, onClose: () => setShareOpen(false) })), _jsx(ConfirmDialog, { open: leaveTarget !== null, onClose: () => setLeaveTarget(null), onConfirm: () => {
445
533
  const target = leaveTarget;
446
534
  setLeaveTarget(null);
447
535
  setDirty(false);