@actuate-media/cms-admin 0.9.0 → 0.11.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.
- package/dist/AdminRoot.d.ts.map +1 -1
- package/dist/AdminRoot.js +8 -5
- package/dist/AdminRoot.js.map +1 -1
- package/dist/__tests__/layout/primitives.test.d.ts +2 -0
- package/dist/__tests__/layout/primitives.test.d.ts.map +1 -0
- package/dist/__tests__/layout/primitives.test.js +34 -0
- package/dist/__tests__/layout/primitives.test.js.map +1 -0
- package/dist/__tests__/lib/cv.test.d.ts +2 -0
- package/dist/__tests__/lib/cv.test.d.ts.map +1 -0
- package/dist/__tests__/lib/cv.test.js +66 -0
- package/dist/__tests__/lib/cv.test.js.map +1 -0
- package/dist/actuate-admin.css +1 -1
- package/dist/assets/actuate-logo.d.ts +36 -0
- package/dist/assets/actuate-logo.d.ts.map +1 -0
- package/dist/assets/actuate-logo.js +15 -0
- package/dist/assets/actuate-logo.js.map +1 -0
- package/dist/components/Breadcrumbs.js +2 -2
- package/dist/components/CommandPalette.js +10 -10
- package/dist/components/ContentOverviewChart.js +3 -3
- package/dist/components/ErrorBoundary.js +1 -1
- package/dist/components/FocalPointPicker.js +2 -2
- package/dist/components/FolderTree.js +20 -20
- package/dist/components/LivePreview.js +3 -3
- package/dist/components/LocaleSwitcher.js +1 -1
- package/dist/components/MediaPickerModal.js +4 -4
- package/dist/components/PresenceIndicator.js +1 -1
- package/dist/components/SEOConfigPanel.d.ts +2 -0
- package/dist/components/SEOConfigPanel.d.ts.map +1 -0
- package/dist/components/SEOConfigPanel.js +174 -0
- package/dist/components/SEOConfigPanel.js.map +1 -0
- package/dist/components/SEOPanel.js +9 -9
- package/dist/components/SEOPerformance.js +2 -2
- package/dist/components/SchedulePublishDialog.d.ts +18 -0
- package/dist/components/SchedulePublishDialog.d.ts.map +1 -0
- package/dist/components/SchedulePublishDialog.js +106 -0
- package/dist/components/SchedulePublishDialog.js.map +1 -0
- package/dist/components/SharePreviewLinkDialog.d.ts +17 -0
- package/dist/components/SharePreviewLinkDialog.d.ts.map +1 -0
- package/dist/components/SharePreviewLinkDialog.js +83 -0
- package/dist/components/SharePreviewLinkDialog.js.map +1 -0
- package/dist/components/TipTapEditor.js +5 -5
- package/dist/components/VersionHistory.js +2 -2
- package/dist/components/ui/Badge.d.ts +33 -3
- package/dist/components/ui/Badge.d.ts.map +1 -1
- package/dist/components/ui/Badge.js +42 -8
- package/dist/components/ui/Badge.js.map +1 -1
- package/dist/components/ui/Button.d.ts +19 -8
- package/dist/components/ui/Button.d.ts.map +1 -1
- package/dist/components/ui/Button.js +35 -14
- package/dist/components/ui/Button.js.map +1 -1
- package/dist/components/ui/Card.d.ts +26 -0
- package/dist/components/ui/Card.d.ts.map +1 -0
- package/dist/components/ui/Card.js +45 -0
- package/dist/components/ui/Card.js.map +1 -0
- package/dist/components/ui/DataTable.js +1 -1
- package/dist/components/ui/Input.d.ts +15 -0
- package/dist/components/ui/Input.d.ts.map +1 -0
- package/dist/components/ui/Input.js +23 -0
- package/dist/components/ui/Input.js.map +1 -0
- package/dist/components/ui/SearchInput.js +1 -1
- package/dist/components/ui/Select.d.ts +16 -0
- package/dist/components/ui/Select.d.ts.map +1 -0
- package/dist/components/ui/Select.js +25 -0
- package/dist/components/ui/Select.js.map +1 -0
- package/dist/components/ui/Toast.js +1 -1
- package/dist/components/ui/index.d.ts +10 -4
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +5 -2
- package/dist/components/ui/index.js.map +1 -1
- package/dist/fields/BlockBuilderField.js +3 -3
- package/dist/fields/DateField.js +1 -1
- package/dist/fields/RelationshipField.js +3 -3
- package/dist/fields/TextField.js +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/layout/Header.js +1 -1
- package/dist/layout/Layout.d.ts +14 -0
- package/dist/layout/Layout.d.ts.map +1 -1
- package/dist/layout/Layout.js +17 -11
- package/dist/layout/Layout.js.map +1 -1
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/Sidebar.js +21 -11
- package/dist/layout/Sidebar.js.map +1 -1
- package/dist/layout/primitives/AdminShell.d.ts +43 -0
- package/dist/layout/primitives/AdminShell.d.ts.map +1 -0
- package/dist/layout/primitives/AdminShell.js +51 -0
- package/dist/layout/primitives/AdminShell.js.map +1 -0
- package/dist/layout/primitives/Box.d.ts +19 -0
- package/dist/layout/primitives/Box.d.ts.map +1 -0
- package/dist/layout/primitives/Box.js +12 -0
- package/dist/layout/primitives/Box.js.map +1 -0
- package/dist/layout/primitives/Cluster.d.ts +27 -0
- package/dist/layout/primitives/Cluster.d.ts.map +1 -0
- package/dist/layout/primitives/Cluster.js +37 -0
- package/dist/layout/primitives/Cluster.js.map +1 -0
- package/dist/layout/primitives/Grid.d.ts +45 -0
- package/dist/layout/primitives/Grid.d.ts.map +1 -0
- package/dist/layout/primitives/Grid.js +59 -0
- package/dist/layout/primitives/Grid.js.map +1 -0
- package/dist/layout/primitives/PageContainer.d.ts +36 -0
- package/dist/layout/primitives/PageContainer.d.ts.map +1 -0
- package/dist/layout/primitives/PageContainer.js +41 -0
- package/dist/layout/primitives/PageContainer.js.map +1 -0
- package/dist/layout/primitives/Split.d.ts +34 -0
- package/dist/layout/primitives/Split.d.ts.map +1 -0
- package/dist/layout/primitives/Split.js +27 -0
- package/dist/layout/primitives/Split.js.map +1 -0
- package/dist/layout/primitives/Stack.d.ts +23 -0
- package/dist/layout/primitives/Stack.d.ts.map +1 -0
- package/dist/layout/primitives/Stack.js +34 -0
- package/dist/layout/primitives/Stack.js.map +1 -0
- package/dist/layout/primitives/index.d.ts +30 -0
- package/dist/layout/primitives/index.d.ts.map +1 -0
- package/dist/layout/primitives/index.js +22 -0
- package/dist/layout/primitives/index.js.map +1 -0
- package/dist/layout/primitives/tokens.d.ts +48 -0
- package/dist/layout/primitives/tokens.d.ts.map +1 -0
- package/dist/layout/primitives/tokens.js +54 -0
- package/dist/layout/primitives/tokens.js.map +1 -0
- package/dist/lib/cv.d.ts +53 -0
- package/dist/lib/cv.d.ts.map +1 -0
- package/dist/lib/cv.js +39 -0
- package/dist/lib/cv.js.map +1 -0
- package/dist/views/ApiKeys.d.ts.map +1 -1
- package/dist/views/ApiKeys.js +13 -11
- package/dist/views/ApiKeys.js.map +1 -1
- package/dist/views/CollectionList.js +8 -8
- package/dist/views/Dashboard.d.ts.map +1 -1
- package/dist/views/Dashboard.js +333 -78
- package/dist/views/Dashboard.js.map +1 -1
- package/dist/views/DocumentEdit.d.ts.map +1 -1
- package/dist/views/DocumentEdit.js +17 -5
- package/dist/views/DocumentEdit.js.map +1 -1
- package/dist/views/ForgotPassword.js +2 -2
- package/dist/views/FormEditor.js +5 -5
- package/dist/views/FormSubmissions.js +6 -6
- package/dist/views/Forms.js +2 -2
- package/dist/views/Login.d.ts +16 -1
- package/dist/views/Login.d.ts.map +1 -1
- package/dist/views/Login.js +17 -7
- package/dist/views/Login.js.map +1 -1
- package/dist/views/MediaBrowser.js +16 -16
- package/dist/views/PageEditor.js +2 -2
- package/dist/views/Pages.js +10 -10
- package/dist/views/PostEditor.js +2 -2
- package/dist/views/Posts.js +4 -4
- package/dist/views/Redirects.js +4 -4
- package/dist/views/ResetPassword.js +2 -2
- package/dist/views/SEO.js +6 -6
- package/dist/views/ScriptTagEditor.js +4 -4
- package/dist/views/ScriptTags.js +2 -2
- package/dist/views/Settings.d.ts.map +1 -1
- package/dist/views/Settings.js +9 -8
- package/dist/views/Settings.js.map +1 -1
- package/dist/views/SetupWizard.js +2 -2
- package/dist/views/Users.js +4 -4
- package/dist/views/page-builder/AIBlockAssist.js +1 -1
- package/dist/views/page-builder/AIGenerateDialog.js +10 -10
- package/dist/views/page-builder/BlockEditor.js +10 -10
- package/dist/views/page-builder/BlockPicker.js +4 -4
- package/dist/views/page-builder/BottomBar.js +1 -1
- package/dist/views/page-builder/BuilderToolbar.js +2 -2
- package/dist/views/page-builder/ContextPanel.js +2 -2
- package/dist/views/page-builder/DesignScore.js +9 -9
- package/dist/views/page-builder/NodeSettings.js +8 -8
- package/dist/views/page-builder/PageBuilder.js +3 -3
- package/dist/views/page-builder/PageSettings.js +1 -1
- package/dist/views/page-builder/PageTemplates.js +2 -2
- package/dist/views/page-builder/SEOPanel.js +13 -13
- package/dist/views/page-builder/SavedSections.js +5 -5
- package/dist/views/page-builder/TemplatePicker.js +2 -2
- package/dist/views/page-builder/block-renderers/CTAPreview.js +5 -5
- package/dist/views/page-builder/block-renderers/CardsPreview.js +1 -1
- package/dist/views/page-builder/block-renderers/CodePreview.js +1 -1
- package/dist/views/page-builder/block-renderers/FAQPreview.js +3 -3
- package/dist/views/page-builder/block-renderers/FallbackPreview.js +1 -1
- package/dist/views/page-builder/block-renderers/FormPreview.js +3 -3
- package/dist/views/page-builder/block-renderers/GalleryPreview.js +5 -5
- package/dist/views/page-builder/block-renderers/HeroPreview.js +3 -3
- package/dist/views/page-builder/block-renderers/ImagePreview.js +3 -3
- package/dist/views/page-builder/block-renderers/TextPreview.js +3 -3
- package/dist/views/page-builder/block-renderers/VideoPreview.js +4 -4
- package/dist/views/page-builder/canvas/BlockRenderer.js +1 -1
- package/dist/views/page-builder/canvas/BuilderCanvas.js +3 -3
- package/dist/views/page-builder/canvas/ColumnRenderer.js +2 -2
- package/dist/views/page-builder/canvas/ContainerRenderer.js +2 -2
- package/dist/views/page-builder/canvas/RowRenderer.js +2 -2
- package/dist/views/page-builder/canvas/SectionRenderer.js +2 -2
- package/package.json +6 -2
- package/src/AdminRoot.tsx +21 -11
- package/src/__tests__/layout/primitives.test.ts +37 -0
- package/src/__tests__/lib/cv.test.ts +74 -0
- package/src/assets/actuate-logo.tsx +72 -0
- package/src/components/Breadcrumbs.tsx +6 -6
- package/src/components/CommandPalette.tsx +34 -34
- package/src/components/ContentOverviewChart.tsx +3 -3
- package/src/components/ErrorBoundary.tsx +3 -3
- package/src/components/FocalPointPicker.tsx +4 -4
- package/src/components/FolderTree.tsx +38 -38
- package/src/components/LivePreview.tsx +16 -16
- package/src/components/LocaleSwitcher.tsx +7 -7
- package/src/components/MediaPickerModal.tsx +21 -21
- package/src/components/PresenceIndicator.tsx +2 -2
- package/src/components/SEOConfigPanel.tsx +582 -0
- package/src/components/SEOPanel.tsx +46 -46
- package/src/components/SEOPerformance.tsx +21 -21
- package/src/components/SchedulePublishDialog.tsx +241 -0
- package/src/components/SharePreviewLinkDialog.tsx +227 -0
- package/src/components/TipTapEditor.tsx +33 -33
- package/src/components/VersionHistory.tsx +16 -16
- package/src/components/ui/Badge.tsx +66 -14
- package/src/components/ui/Button.tsx +70 -33
- package/src/components/ui/Card.tsx +101 -0
- package/src/components/ui/DataTable.tsx +1 -1
- package/src/components/ui/Input.tsx +35 -0
- package/src/components/ui/SearchInput.tsx +4 -4
- package/src/components/ui/Select.tsx +56 -0
- package/src/components/ui/Toast.tsx +1 -1
- package/src/components/ui/index.ts +18 -4
- package/src/fields/BlockBuilderField.tsx +3 -3
- package/src/fields/DateField.tsx +1 -1
- package/src/fields/RelationshipField.tsx +10 -10
- package/src/fields/TextField.tsx +1 -1
- package/src/index.ts +32 -0
- package/src/layout/Header.tsx +28 -28
- package/src/layout/Layout.tsx +39 -46
- package/src/layout/Sidebar.tsx +37 -64
- package/src/layout/primitives/AdminShell.tsx +118 -0
- package/src/layout/primitives/Box.tsx +30 -0
- package/src/layout/primitives/Cluster.tsx +74 -0
- package/src/layout/primitives/Grid.tsx +120 -0
- package/src/layout/primitives/PageContainer.tsx +96 -0
- package/src/layout/primitives/Split.tsx +73 -0
- package/src/layout/primitives/Stack.tsx +67 -0
- package/src/layout/primitives/index.ts +36 -0
- package/src/layout/primitives/tokens.ts +76 -0
- package/src/lib/cv.ts +96 -0
- package/src/styles/build-input.css +1 -1
- package/src/views/ApiKeys.tsx +57 -57
- package/src/views/CollectionList.tsx +30 -30
- package/src/views/Dashboard.tsx +737 -186
- package/src/views/DocumentEdit.tsx +90 -10
- package/src/views/ForgotPassword.tsx +18 -18
- package/src/views/FormEditor.tsx +75 -75
- package/src/views/FormSubmissions.tsx +76 -76
- package/src/views/Forms.tsx +27 -27
- package/src/views/Login.tsx +65 -25
- package/src/views/MediaBrowser.tsx +127 -127
- package/src/views/PageEditor.tsx +25 -25
- package/src/views/Pages.tsx +59 -59
- package/src/views/PostEditor.tsx +37 -37
- package/src/views/Posts.tsx +48 -48
- package/src/views/Redirects.tsx +21 -21
- package/src/views/ResetPassword.tsx +28 -28
- package/src/views/SEO.tsx +144 -144
- package/src/views/ScriptTagEditor.tsx +24 -24
- package/src/views/ScriptTags.tsx +10 -10
- package/src/views/Settings.tsx +88 -80
- package/src/views/SetupWizard.tsx +28 -28
- package/src/views/Users.tsx +20 -20
- package/src/views/page-builder/AIBlockAssist.tsx +1 -1
- package/src/views/page-builder/AIGenerateDialog.tsx +63 -63
- package/src/views/page-builder/BlockEditor.tsx +26 -26
- package/src/views/page-builder/BlockPicker.tsx +22 -22
- package/src/views/page-builder/BottomBar.tsx +8 -8
- package/src/views/page-builder/BuilderToolbar.tsx +17 -17
- package/src/views/page-builder/ContextPanel.tsx +3 -3
- package/src/views/page-builder/DesignScore.tsx +21 -21
- package/src/views/page-builder/NodeSettings.tsx +27 -27
- package/src/views/page-builder/PageBuilder.tsx +11 -11
- package/src/views/page-builder/PageSettings.tsx +4 -4
- package/src/views/page-builder/PageTemplates.tsx +18 -18
- package/src/views/page-builder/SEOPanel.tsx +53 -53
- package/src/views/page-builder/SavedSections.tsx +37 -37
- package/src/views/page-builder/TemplatePicker.tsx +17 -17
- package/src/views/page-builder/block-renderers/CTAPreview.tsx +13 -13
- package/src/views/page-builder/block-renderers/CardsPreview.tsx +5 -5
- package/src/views/page-builder/block-renderers/CodePreview.tsx +6 -6
- package/src/views/page-builder/block-renderers/FAQPreview.tsx +13 -13
- package/src/views/page-builder/block-renderers/FallbackPreview.tsx +3 -3
- package/src/views/page-builder/block-renderers/FormPreview.tsx +20 -20
- package/src/views/page-builder/block-renderers/GalleryPreview.tsx +8 -8
- package/src/views/page-builder/block-renderers/HeroPreview.tsx +16 -16
- package/src/views/page-builder/block-renderers/ImagePreview.tsx +4 -4
- package/src/views/page-builder/block-renderers/TextPreview.tsx +14 -14
- package/src/views/page-builder/block-renderers/VideoPreview.tsx +12 -12
- package/src/views/page-builder/canvas/BlockRenderer.tsx +4 -4
- package/src/views/page-builder/canvas/BuilderCanvas.tsx +6 -6
- package/src/views/page-builder/canvas/ColumnRenderer.tsx +3 -3
- package/src/views/page-builder/canvas/ContainerRenderer.tsx +2 -2
- package/src/views/page-builder/canvas/RowRenderer.tsx +2 -2
- package/src/views/page-builder/canvas/SectionRenderer.tsx +2 -2
|
@@ -29,13 +29,13 @@ export function BlockEditor({ node, onUpdateBlock, onUpdateSettings, onRemoveNod
|
|
|
29
29
|
}
|
|
30
30
|
}, [confirmDelete, node.id, onRemoveNode]);
|
|
31
31
|
if (!blockDef) {
|
|
32
|
-
return (_jsx("div", { className: "p-4", children: _jsxs("p", { className: "text-
|
|
32
|
+
return (_jsx("div", { className: "p-4", children: _jsxs("p", { className: "text-muted-foreground text-sm", children: ["Unknown block type: ", _jsx("code", { className: "text-xs", children: node.settings.blockType })] }) }));
|
|
33
33
|
}
|
|
34
|
-
return (_jsxs("div", { className: "flex flex-col
|
|
34
|
+
return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "border-border border-b p-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Star, { size: 16, className: "text-muted-foreground" }), _jsx("span", { className: "text-foreground flex-1 text-sm font-medium", children: blockDef.label }), _jsx(AIBlockAssist, { block: node, onUpdateData: (data) => onUpdateBlock(node.id, data) })] }), blockDef.description && (_jsx("p", { className: "text-muted-foreground mt-1 text-xs", children: blockDef.description }))] }), blockDef.variants.length > 1 && (_jsxs("div", { className: "border-border border-b p-4", children: [_jsx("p", { className: "text-muted-foreground mb-2 text-xs font-medium tracking-wider uppercase", children: "Variant" }), _jsx("div", { className: "grid grid-cols-2 gap-1.5", children: blockDef.variants.map((variant) => (_jsx("button", { type: "button", onClick: () => handleVariantChange(variant.name), className: `rounded-md border px-2 py-1.5 text-xs transition-colors ${node.settings.variant === variant.name
|
|
35
35
|
? 'bg-primary text-primary-foreground border-primary'
|
|
36
|
-
: 'bg-background border-input text-foreground hover:bg-accent'}`, children: variant.label }, variant.name))) })] })), _jsxs("div", { className: "space-y-4 p-4
|
|
36
|
+
: 'bg-background border-input text-foreground hover:bg-accent'}`, children: variant.label }, variant.name))) })] })), _jsxs("div", { className: "flex-1 space-y-4 p-4", children: [_jsx("p", { className: "text-muted-foreground mb-2 text-xs font-medium tracking-wider uppercase", children: "Fields" }), Object.entries(blockDef.fields).map(([fieldName, fieldDef]) => (_jsx(FieldRenderer, { name: fieldName, definition: fieldDef, value: node.data[fieldName], onChange: (value) => handleFieldChange(fieldName, value) }, fieldName)))] }), _jsxs("div", { className: "border-border space-y-2 border-t p-4", children: [_jsxs("button", { type: "button", onClick: () => onDuplicateNode(node.id), className: "bg-background border-input hover:bg-accent flex w-full items-center justify-center gap-2 rounded-md border px-3 py-2 text-sm font-medium transition-colors", children: [_jsx(Copy, { size: 14 }), "Duplicate"] }), _jsxs("button", { type: "button", onClick: handleDelete, onBlur: () => setConfirmDelete(false), className: `flex w-full items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors ${confirmDelete
|
|
37
37
|
? 'bg-destructive text-destructive-foreground'
|
|
38
|
-
: 'bg-background border
|
|
38
|
+
: 'bg-background border-destructive text-destructive hover:bg-destructive/10 border'}`, children: [_jsx(Trash2, { size: 14 }), confirmDelete ? 'Click again to confirm' : 'Delete'] })] })] }));
|
|
39
39
|
}
|
|
40
40
|
function FieldRenderer({ name, definition, value, onChange }) {
|
|
41
41
|
const label = definition.label || name;
|
|
@@ -43,13 +43,13 @@ function FieldRenderer({ name, definition, value, onChange }) {
|
|
|
43
43
|
case 'text':
|
|
44
44
|
return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("input", { type: "text", value: value ?? '', onChange: (e) => onChange(e.target.value), placeholder: definition.admin?.placeholder, className: INPUT_CLASS })] }));
|
|
45
45
|
case 'richText':
|
|
46
|
-
return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("div", { className: "
|
|
46
|
+
return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("div", { className: "border-input bg-background overflow-hidden rounded-md border", children: _jsx(TipTapEditor, { content: value ?? '', onChange: (html) => onChange(html), placeholder: definition.admin?.placeholder }) })] }));
|
|
47
47
|
case 'url':
|
|
48
48
|
return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("input", { type: "url", value: value ?? '', onChange: (e) => onChange(e.target.value), placeholder: definition.admin?.placeholder ?? 'https://', className: INPUT_CLASS })] }));
|
|
49
49
|
case 'number':
|
|
50
50
|
return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("input", { type: "number", value: value ?? '', onChange: (e) => onChange(e.target.value ? Number(e.target.value) : undefined), min: definition.min, max: definition.max, step: definition.step, className: INPUT_CLASS })] }));
|
|
51
51
|
case 'boolean':
|
|
52
|
-
return (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-sm font-medium
|
|
52
|
+
return (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-foreground text-sm font-medium", children: label }), _jsx(SwitchPrimitive.Root, { checked: !!value, onCheckedChange: (checked) => onChange(checked), className: "bg-input data-[state=checked]:bg-primary relative h-5 w-9 rounded-full transition-colors", "aria-label": label, children: _jsx(SwitchPrimitive.Thumb, { className: "bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[18px]" }) })] }));
|
|
53
53
|
case 'media':
|
|
54
54
|
return _jsx(MediaFieldRenderer, { label: label, value: value, onChange: onChange });
|
|
55
55
|
case 'select':
|
|
@@ -73,7 +73,7 @@ function FieldRenderer({ name, definition, value, onChange }) {
|
|
|
73
73
|
case 'email':
|
|
74
74
|
return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("input", { type: "email", value: value ?? '', onChange: (e) => onChange(e.target.value), placeholder: definition.admin?.placeholder ?? 'email@example.com', className: INPUT_CLASS })] }));
|
|
75
75
|
case 'color':
|
|
76
|
-
return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "color", value: value ?? '#000000', onChange: (e) => onChange(e.target.value), className: "h-9 w-9 rounded-md border
|
|
76
|
+
return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "color", value: value ?? '#000000', onChange: (e) => onChange(e.target.value), className: "border-input h-9 w-9 cursor-pointer rounded-md border" }), _jsx("input", { type: "text", value: value ?? '', onChange: (e) => onChange(e.target.value), placeholder: "#000000", className: `${INPUT_CLASS} flex-1` })] })] }));
|
|
77
77
|
default:
|
|
78
78
|
return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("input", { type: "text", value: String(value ?? ''), onChange: (e) => onChange(e.target.value), className: INPUT_CLASS })] }));
|
|
79
79
|
}
|
|
@@ -90,7 +90,7 @@ function MediaFieldRenderer({ label, value, onChange }) {
|
|
|
90
90
|
: value && typeof value === 'object' && 'url' in value
|
|
91
91
|
? String(value.url)
|
|
92
92
|
: '';
|
|
93
|
-
return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsxs("div", { className: "flex gap-2", children: [_jsx("input", { type: "text", value: url, onChange: (e) => onChange(e.target.value), placeholder: "https://...", className: `${INPUT_CLASS} flex-1` }), _jsx("button", { type: "button", onClick: () => setOpen(true), className: "
|
|
93
|
+
return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsxs("div", { className: "flex gap-2", children: [_jsx("input", { type: "text", value: url, onChange: (e) => onChange(e.target.value), placeholder: "https://...", className: `${INPUT_CLASS} flex-1` }), _jsx("button", { type: "button", onClick: () => setOpen(true), className: "bg-accent text-foreground border-input hover:bg-accent/80 rounded-md border px-3 py-2 text-xs font-medium transition-colors", children: "Browse" })] }), url && /\.(png|jpe?g|gif|webp|avif|svg)(\?|$)/i.test(url) && (_jsx("div", { className: "border-border bg-muted mt-2 overflow-hidden rounded-md border", children: _jsx("img", { src: url, alt: "", className: "bg-checkered h-32 w-full object-contain" }) })), _jsx(MediaPickerModal, { open: open, onClose: () => setOpen(false), onSelect: (selectedUrl) => {
|
|
94
94
|
onChange(selectedUrl);
|
|
95
95
|
setOpen(false);
|
|
96
96
|
} })] }));
|
|
@@ -131,7 +131,7 @@ function JsonFieldRenderer({ label, value, onChange }) {
|
|
|
131
131
|
setError(err instanceof Error ? err.message : 'Invalid JSON');
|
|
132
132
|
}
|
|
133
133
|
};
|
|
134
|
-
return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("textarea", { value: draft, onChange: (e) => handleChange(e.target.value), rows: 6, spellCheck: false, className: `${INPUT_CLASS} font-mono text-xs
|
|
134
|
+
return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsx("textarea", { value: draft, onChange: (e) => handleChange(e.target.value), rows: 6, spellCheck: false, className: `${INPUT_CLASS} resize-y font-mono text-xs` }), error && (_jsx("p", { className: "text-destructive mt-1 text-xs", role: "alert", children: error }))] }));
|
|
135
135
|
}
|
|
136
136
|
/**
|
|
137
137
|
* Lightweight array editor — supports homogenous arrays of strings or
|
|
@@ -153,6 +153,6 @@ function ArrayFieldRenderer({ label, value, onChange }) {
|
|
|
153
153
|
};
|
|
154
154
|
const addItem = () => onChange([...items, '']);
|
|
155
155
|
const removeItem = (idx) => onChange(items.filter((_, i) => i !== idx));
|
|
156
|
-
return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsxs("div", { className: "space-y-2", children: [items.map((item, idx) => (_jsxs("div", { className: "flex gap-2", children: [_jsx("input", { type: "text", value: typeof item === 'string' ? item : '', onChange: (e) => updateItem(idx, e.target.value), className: `${INPUT_CLASS} flex-1` }), _jsx("button", { type: "button", onClick: () => removeItem(idx), "aria-label": `Remove item ${idx + 1}`, className: "
|
|
156
|
+
return (_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: label }), _jsxs("div", { className: "space-y-2", children: [items.map((item, idx) => (_jsxs("div", { className: "flex gap-2", children: [_jsx("input", { type: "text", value: typeof item === 'string' ? item : '', onChange: (e) => updateItem(idx, e.target.value), className: `${INPUT_CLASS} flex-1` }), _jsx("button", { type: "button", onClick: () => removeItem(idx), "aria-label": `Remove item ${idx + 1}`, className: "text-destructive border-input hover:bg-destructive/10 rounded-md border px-2 py-2 text-xs transition-colors", children: _jsx(Trash2, { size: 14 }) })] }, idx))), _jsx("button", { type: "button", onClick: addItem, className: "bg-accent text-foreground border-input hover:bg-accent/80 w-full rounded-md border px-3 py-2 text-xs font-medium transition-colors", children: "+ Add item" })] })] }));
|
|
157
157
|
}
|
|
158
158
|
//# sourceMappingURL=BlockEditor.js.map
|
|
@@ -83,20 +83,20 @@ export function BlockPicker({ open, onClose, onSelect }) {
|
|
|
83
83
|
handleBack();
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
-
return (_jsx(Dialog.Root, { open: open, onOpenChange: (isOpen) => !isOpen && onClose(), children: _jsxs(Dialog.Portal, { children: [_jsx(Dialog.Overlay, { className: "
|
|
86
|
+
return (_jsx(Dialog.Root, { open: open, onOpenChange: (isOpen) => !isOpen && onClose(), children: _jsxs(Dialog.Portal, { children: [_jsx(Dialog.Overlay, { className: "motion-safe:animate-in motion-safe:fade-in-0 fixed inset-0 z-50 bg-black/50" }), _jsx(Dialog.Content, { className: "bg-card border-border fixed top-1/2 left-1/2 z-50 flex max-h-[80vh] w-full max-w-2xl -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border shadow-2xl", "aria-describedby": undefined, onEscapeKeyDown: () => {
|
|
87
87
|
if (selectedBlock) {
|
|
88
88
|
handleBack();
|
|
89
89
|
}
|
|
90
90
|
}, children: selectedBlock ? (_jsx(VariantView, { block: selectedBlock, variantListRef: variantListRef, onBack: handleBack, onVariantClick: handleVariantClick, onKeyDown: handleKeyDownOnVariants })) : (_jsx(BlockTypeGrid, { search: search, filteredBlocks: filteredBlocks, searchInputRef: searchInputRef, onSearchChange: setSearch, onBlockClick: handleBlockClick, onClose: onClose, onKeyDown: handleKeyDownOnGrid })) })] }) }));
|
|
91
91
|
}
|
|
92
92
|
function BlockTypeGrid({ search, filteredBlocks, searchInputRef, onSearchChange, onBlockClick, onClose, onKeyDown, }) {
|
|
93
|
-
return (_jsxs("div", { className: "flex flex-col
|
|
93
|
+
return (_jsxs("div", { className: "flex h-full flex-col", onKeyDown: onKeyDown, children: [_jsxs("div", { className: "flex items-center justify-between gap-3 px-5 pt-5 pb-3", children: [_jsx(Dialog.Title, { className: "text-foreground text-lg font-medium", children: "Add Block" }), _jsx(Dialog.Close, { asChild: true, children: _jsx("button", { type: "button", className: "text-muted-foreground hover:text-foreground hover:bg-accent rounded-md p-1.5 transition-colors", "aria-label": "Close", children: _jsx(X, { size: 18 }) }) })] }), _jsx("div", { className: "px-5 pb-3", children: _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "text-muted-foreground pointer-events-none absolute top-1/2 left-3 -translate-y-1/2", size: 16 }), _jsx("input", { ref: searchInputRef, type: "text", placeholder: "Search blocks...", value: search, onChange: (e) => onSearchChange(e.target.value), className: "bg-background border-input focus:ring-ring w-full rounded-md border py-2 pr-3 pl-9 text-sm focus:ring-2 focus:outline-none", "aria-label": "Search block types" })] }) }), _jsx("div", { className: "flex-1 overflow-y-auto px-5 pb-5", children: filteredBlocks.length === 0 ? (_jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [_jsx(Search, { size: 24, className: "text-muted-foreground mb-2" }), _jsxs("p", { className: "text-muted-foreground text-sm", children: ["No blocks match \u201C", search, "\u201D"] })] })) : (_jsx("div", { className: "grid grid-cols-2 gap-3", role: "list", "aria-label": "Available block types", children: filteredBlocks.map((block) => {
|
|
94
94
|
const Icon = resolveIcon(block.icon);
|
|
95
|
-
return (_jsxs("button", { type: "button", role: "listitem", onClick: () => onBlockClick(block), className: "
|
|
95
|
+
return (_jsxs("button", { type: "button", role: "listitem", onClick: () => onBlockClick(block), className: "border-border hover:border-primary bg-card group focus:ring-ring flex cursor-pointer items-start gap-3 rounded-lg border p-4 text-left transition-colors focus:ring-2 focus:outline-none", children: [_jsx("div", { className: "bg-accent text-foreground group-hover:bg-primary/10 group-hover:text-primary flex h-9 w-9 shrink-0 items-center justify-center rounded-md transition-colors", children: _jsx(Icon, { size: 18 }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-foreground truncate text-sm font-medium", children: block.label }), block.description && (_jsx("p", { className: "text-muted-foreground mt-0.5 line-clamp-2 text-xs", children: block.description }))] })] }, block.type));
|
|
96
96
|
}) })) })] }));
|
|
97
97
|
}
|
|
98
98
|
function VariantView({ block, variantListRef, onBack, onVariantClick, onKeyDown, }) {
|
|
99
99
|
const Icon = resolveIcon(block.icon);
|
|
100
|
-
return (_jsxs("div", { className: "flex flex-col
|
|
100
|
+
return (_jsxs("div", { className: "flex h-full flex-col", onKeyDown: onKeyDown, children: [_jsxs("div", { className: "flex items-center gap-3 px-5 pt-5 pb-3", children: [_jsx("button", { type: "button", onClick: onBack, className: "text-muted-foreground hover:text-foreground hover:bg-accent rounded-md p-1.5 transition-colors", "aria-label": "Back to block types", children: _jsx(ArrowLeft, { size: 18 }) }), _jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Icon, { size: 18, className: "text-foreground shrink-0" }), _jsx("h2", { className: "text-foreground truncate text-lg font-medium", children: block.label })] })] }), block.description && (_jsx("p", { className: "text-muted-foreground px-5 pb-3 text-sm", children: block.description })), _jsx("div", { className: "flex-1 overflow-y-auto px-5 pb-5", ref: variantListRef, children: _jsx("div", { className: "space-y-2", role: "list", "aria-label": `${block.label} variants`, children: block.variants.map((variant, index) => (_jsx("button", { type: "button", role: "listitem", "data-variant": variant.name, onClick: () => onVariantClick(variant), className: "border-border hover:border-primary bg-card group focus:ring-ring flex w-full cursor-pointer items-center gap-3 rounded-lg border p-4 text-left transition-colors focus:ring-2 focus:outline-none", children: _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("p", { className: "text-foreground text-sm font-medium", children: variant.label }), index === 0 && (_jsxs("span", { className: "text-primary bg-primary/10 inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs", children: [_jsx(Check, { size: 10 }), "Default"] }))] }), _jsx("p", { className: "text-muted-foreground mt-0.5 text-xs", children: variant.description })] }) }, variant.name))) }) })] }));
|
|
101
101
|
}
|
|
102
102
|
//# sourceMappingURL=BlockPicker.js.map
|
|
@@ -8,6 +8,6 @@ const DEVICE_LABELS = {
|
|
|
8
8
|
mobile: '375px',
|
|
9
9
|
};
|
|
10
10
|
export function BottomBar({ deviceMode, showGridOverlay, onAddSection, onToggleGrid, }) {
|
|
11
|
-
return (_jsxs("div", { className: "
|
|
11
|
+
return (_jsxs("div", { className: "bg-card border-border flex h-10 shrink-0 items-center gap-4 border-t px-4", role: "toolbar", "aria-label": "Builder actions", children: [_jsxs("button", { onClick: onAddSection, className: "text-muted-foreground hover:text-foreground flex items-center gap-1.5 px-3 py-2 text-sm transition-colors", "aria-label": "Add a new section", children: [_jsx(Plus, { size: 14 }), _jsx("span", { children: "Add Section" })] }), _jsx("div", { className: "bg-border h-5 w-px" }), _jsxs("label", { className: "flex cursor-pointer items-center gap-2", children: [_jsx(Grid3X3, { size: 14, className: "text-muted-foreground" }), _jsx(Switch.Root, { checked: showGridOverlay, onCheckedChange: onToggleGrid, className: "bg-input-background data-[state=checked]:bg-primary relative h-[18px] w-8 rounded-full transition-colors", "aria-label": "Toggle grid overlay", children: _jsx(Switch.Thumb, { className: "bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[14px]" }) }), _jsx("span", { className: "text-muted-foreground text-xs", children: "Grid" })] }), _jsx("div", { className: "flex-1" }), _jsx("span", { className: "text-muted-foreground text-xs tabular-nums", children: DEVICE_LABELS[deviceMode] })] }));
|
|
12
12
|
}
|
|
13
13
|
//# sourceMappingURL=BottomBar.js.map
|
|
@@ -8,10 +8,10 @@ const STATUS_STYLES = {
|
|
|
8
8
|
};
|
|
9
9
|
export function BuilderToolbar({ collectionSlug, pageSettings, status, dirty, saving, canUndo, canRedo, deviceMode, onNavigate, onTitleChange, onUndo, onRedo, onDeviceMode, onSave, onPublish, onOpenAI, }) {
|
|
10
10
|
const collectionLabel = collectionSlug.charAt(0).toUpperCase() + collectionSlug.slice(1);
|
|
11
|
-
return (_jsxs("div", { className: "
|
|
11
|
+
return (_jsxs("div", { className: "bg-card border-border flex h-14 shrink-0 items-center gap-3 border-b px-4", role: "toolbar", "aria-label": "Page builder toolbar", children: [_jsxs("button", { onClick: () => onNavigate(`/collections/${collectionSlug}`), className: "text-muted-foreground hover:text-foreground flex items-center gap-1 text-sm transition-colors", "aria-label": `Back to ${collectionLabel}`, children: [_jsx(ChevronLeft, { size: 16 }), _jsx("span", { className: "hidden sm:inline", children: collectionLabel })] }), _jsx("div", { className: "bg-border h-6 w-px" }), _jsx("input", { type: "text", value: pageSettings.title, onChange: (e) => onTitleChange(e.target.value), placeholder: "Untitled Page", className: "text-foreground focus-visible:ring-ring placeholder:text-muted-foreground min-w-0 flex-1 rounded-sm border-none bg-transparent text-sm font-medium outline-none focus-visible:ring-2 focus-visible:ring-offset-2", "aria-label": "Page title" }), _jsx("span", { className: `rounded-md px-2 py-0.5 text-xs font-medium whitespace-nowrap ${STATUS_STYLES[status] ?? STATUS_STYLES.DRAFT}`, children: status }), dirty && !saving && (_jsx("span", { className: "bg-destructive h-2 w-2 shrink-0 rounded-full", title: "Unsaved changes", "aria-label": "Unsaved changes" })), _jsx("div", { className: "bg-border h-6 w-px" }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { onClick: onUndo, disabled: !canUndo, className: "text-muted-foreground hover:text-foreground hover:bg-muted rounded-md p-1.5 transition-colors disabled:pointer-events-none disabled:opacity-30", "aria-label": "Undo", children: _jsx(Undo2, { size: 16 }) }), _jsx("button", { onClick: onRedo, disabled: !canRedo, className: "text-muted-foreground hover:text-foreground hover:bg-muted rounded-md p-1.5 transition-colors disabled:pointer-events-none disabled:opacity-30", "aria-label": "Redo", children: _jsx(Redo2, { size: 16 }) })] }), _jsx("div", { className: "bg-border h-6 w-px" }), _jsxs("div", { className: "bg-muted flex items-center gap-0.5 rounded-md p-0.5", children: [_jsx(DeviceButton, { active: deviceMode === 'desktop', onClick: () => onDeviceMode('desktop'), label: "Desktop view", children: _jsx(Monitor, { size: 16 }) }), _jsx(DeviceButton, { active: deviceMode === 'tablet', onClick: () => onDeviceMode('tablet'), label: "Tablet view", children: _jsx(Tablet, { size: 16 }) }), _jsx(DeviceButton, { active: deviceMode === 'mobile', onClick: () => onDeviceMode('mobile'), label: "Mobile view", children: _jsx(Smartphone, { size: 16 }) })] }), _jsx("div", { className: "bg-border h-6 w-px" }), onOpenAI && (_jsxs(_Fragment, { children: [_jsxs("button", { onClick: onOpenAI, className: "text-primary bg-primary/10 hover:bg-primary/20 flex items-center gap-1.5 rounded-md px-2.5 py-1.5 text-sm font-medium transition-colors", "aria-label": "Generate page with AI", children: [_jsx(Sparkles, { size: 14 }), _jsx("span", { className: "hidden sm:inline", children: "AI" })] }), _jsx("div", { className: "bg-border h-6 w-px" })] })), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("button", { onClick: onSave, disabled: saving || !dirty, className: "bg-muted text-muted-foreground hover:bg-muted/80 flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-colors disabled:pointer-events-none disabled:opacity-50", children: [saving && _jsx(Loader2, { size: 14, className: "animate-spin" }), saving ? 'Saving...' : 'Save'] }), _jsx("button", { onClick: onPublish, disabled: saving, className: "bg-primary text-primary-foreground hover:bg-primary/90 rounded-md px-3 py-1.5 text-sm font-medium transition-colors disabled:pointer-events-none disabled:opacity-50", children: "Publish" })] })] }));
|
|
12
12
|
}
|
|
13
13
|
function DeviceButton({ active, onClick, label, children, }) {
|
|
14
|
-
return (_jsx("button", { onClick: onClick, className: `p-1.5
|
|
14
|
+
return (_jsx("button", { onClick: onClick, className: `rounded-md p-1.5 transition-colors ${active
|
|
15
15
|
? 'bg-background text-foreground shadow-sm'
|
|
16
16
|
: 'text-muted-foreground hover:text-foreground'}`, "aria-label": label, "aria-pressed": active, children: children }));
|
|
17
17
|
}
|
|
@@ -32,9 +32,9 @@ export function ContextPanel({ activeTab, onTabChange, selectedNode, tree, pageS
|
|
|
32
32
|
return 'node';
|
|
33
33
|
return 'page';
|
|
34
34
|
}, [activeTab, availableTabs, selectedNode]);
|
|
35
|
-
return (_jsx("div", { className: "
|
|
35
|
+
return (_jsx("div", { className: "bg-card h-full w-full overflow-y-auto", children: _jsxs(Tabs.Root, { value: effectiveTab, onValueChange: (value) => onTabChange(value), children: [_jsx(Tabs.List, { className: "border-border bg-muted/30 flex border-b", children: availableTabs.map((tab) => {
|
|
36
36
|
const Icon = tab.icon;
|
|
37
|
-
return (_jsxs(Tabs.Trigger, { value: tab.value, className: "
|
|
37
|
+
return (_jsxs(Tabs.Trigger, { value: tab.value, className: "text-muted-foreground hover:text-foreground data-[state=active]:text-foreground data-[state=active]:border-primary data-[state=active]:bg-background flex flex-1 items-center justify-center gap-1.5 px-2 py-2.5 text-xs font-medium transition-colors data-[state=active]:border-b-2", children: [_jsx(Icon, { size: 14 }), _jsx("span", { children: tab.label })] }, tab.value));
|
|
38
38
|
}) }), _jsx(Tabs.Content, { value: "block", children: selectedNode?.type === 'block' && (_jsx(BlockEditor, { node: selectedNode, onUpdateBlock: onUpdateBlock, onUpdateSettings: onUpdateSettings, onRemoveNode: onRemoveNode, onDuplicateNode: onDuplicateNode, config: config })) }), _jsx(Tabs.Content, { value: "node", children: selectedNode &&
|
|
39
39
|
selectedNode.type !== 'block' &&
|
|
40
40
|
selectedNode.type !== 'page' &&
|
|
@@ -38,11 +38,11 @@ function getRingStrokeColor(score) {
|
|
|
38
38
|
function StatusIcon({ status }) {
|
|
39
39
|
switch (status) {
|
|
40
40
|
case 'good':
|
|
41
|
-
return _jsx(CheckCircle2, { size: 14, className: "text-green-500
|
|
41
|
+
return _jsx(CheckCircle2, { size: 14, className: "shrink-0 text-green-500" });
|
|
42
42
|
case 'warning':
|
|
43
|
-
return _jsx(AlertCircle, { size: 14, className: "text-amber-500
|
|
43
|
+
return _jsx(AlertCircle, { size: 14, className: "shrink-0 text-amber-500" });
|
|
44
44
|
case 'error':
|
|
45
|
-
return _jsx(XCircle, { size: 14, className: "text-red-500
|
|
45
|
+
return _jsx(XCircle, { size: 14, className: "shrink-0 text-red-500" });
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
function SeverityBadge({ severity }) {
|
|
@@ -51,7 +51,7 @@ function SeverityBadge({ severity }) {
|
|
|
51
51
|
suggestion: 'bg-amber-100 text-amber-700',
|
|
52
52
|
info: 'bg-blue-100 text-blue-700',
|
|
53
53
|
};
|
|
54
|
-
return (_jsx("span", { className: `inline-block px-1.5 py-0.5
|
|
54
|
+
return (_jsx("span", { className: `inline-block rounded px-1.5 py-0.5 text-xs font-medium ${classes[severity]}`, children: severity }));
|
|
55
55
|
}
|
|
56
56
|
function ScoreRing({ score }) {
|
|
57
57
|
const radius = 32;
|
|
@@ -60,11 +60,11 @@ function ScoreRing({ score }) {
|
|
|
60
60
|
const progress = Math.min(score, 100) / 100;
|
|
61
61
|
const dashOffset = circumference * (1 - progress);
|
|
62
62
|
const size = (radius + strokeWidth) * 2;
|
|
63
|
-
return (_jsxs("div", { className: "flex flex-col items-center gap-2", children: [_jsxs("div", { className: "relative", children: [_jsxs("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, className: "-rotate-90", children: [_jsx("circle", { cx: size / 2, cy: size / 2, r: radius, fill: "none", stroke: "var(--border)", strokeWidth: strokeWidth }), _jsx("circle", { cx: size / 2, cy: size / 2, r: radius, fill: "none", stroke: getRingStrokeColor(score), strokeWidth: strokeWidth, strokeDasharray: circumference, strokeDashoffset: dashOffset, strokeLinecap: "round", className: "transition-all duration-700 ease-out" })] }), _jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: _jsx("span", { className: `text-lg font-medium ${getScoreColor(score, 100)}`, children: score }) })] }), _jsx("span", { className: "text-
|
|
63
|
+
return (_jsxs("div", { className: "flex flex-col items-center gap-2", children: [_jsxs("div", { className: "relative", children: [_jsxs("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, className: "-rotate-90", children: [_jsx("circle", { cx: size / 2, cy: size / 2, r: radius, fill: "none", stroke: "var(--border)", strokeWidth: strokeWidth }), _jsx("circle", { cx: size / 2, cy: size / 2, r: radius, fill: "none", stroke: getRingStrokeColor(score), strokeWidth: strokeWidth, strokeDasharray: circumference, strokeDashoffset: dashOffset, strokeLinecap: "round", className: "transition-all duration-700 ease-out" })] }), _jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: _jsx("span", { className: `text-lg font-medium ${getScoreColor(score, 100)}`, children: score }) })] }), _jsx("span", { className: "text-muted-foreground text-xs", children: getScoreLabel(score) })] }));
|
|
64
64
|
}
|
|
65
65
|
function CategoryRow({ category, expanded, onToggle, }) {
|
|
66
66
|
const percentage = category.maxScore > 0 ? (category.score / category.maxScore) * 100 : 0;
|
|
67
|
-
return (_jsxs("div", { className: "border-
|
|
67
|
+
return (_jsxs("div", { className: "border-border border-b last:border-b-0", children: [_jsxs("button", { type: "button", className: "hover:bg-muted/50 flex w-full flex-col gap-2 px-4 py-3 text-left transition-colors", onClick: onToggle, "aria-expanded": expanded, children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-foreground text-xs font-medium", children: category.label }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("span", { className: "text-muted-foreground text-xs", children: [category.score, "/", category.maxScore] }), expanded ? (_jsx(ChevronUp, { size: 14, className: "text-muted-foreground" })) : (_jsx(ChevronDown, { size: 14, className: "text-muted-foreground" }))] })] }), _jsx("div", { className: "bg-muted h-1.5 w-full overflow-hidden rounded-full", children: _jsx("div", { className: `h-full rounded-full transition-all duration-500 ease-out ${getBarColor(category.score, category.maxScore)}`, style: { width: `${percentage}%` } }) })] }), expanded && category.checks.length > 0 && (_jsx("div", { className: "flex flex-col gap-2 px-4 pb-3", children: category.checks.map((check) => (_jsxs("div", { className: "flex items-start gap-2 pl-1", children: [_jsx(StatusIcon, { status: check.status }), _jsxs("div", { className: "flex flex-col", children: [_jsx("span", { className: "text-foreground text-xs font-medium", children: check.label }), _jsx("span", { className: "text-muted-foreground text-xs", children: check.detail })] })] }, check.id))) }))] }));
|
|
68
68
|
}
|
|
69
69
|
function SuggestionsList({ suggestions }) {
|
|
70
70
|
const sorted = useMemo(() => {
|
|
@@ -77,7 +77,7 @@ function SuggestionsList({ suggestions }) {
|
|
|
77
77
|
}, [suggestions]);
|
|
78
78
|
if (sorted.length === 0)
|
|
79
79
|
return null;
|
|
80
|
-
return (_jsxs("div", { className: "px-4 py-3
|
|
80
|
+
return (_jsxs("div", { className: "border-border border-t px-4 py-3", children: [_jsxs("div", { className: "mb-3 flex items-center gap-2", children: [_jsx(Lightbulb, { size: 14, className: "text-muted-foreground" }), _jsx("span", { className: "text-foreground text-xs font-medium", children: "Suggestions" })] }), _jsx("div", { className: "flex flex-col gap-2.5", children: sorted.map((suggestion) => (_jsxs("div", { className: "flex items-start gap-2", children: [_jsx(SeverityBadge, { severity: suggestion.severity }), _jsx("span", { className: "text-muted-foreground text-xs leading-relaxed", children: suggestion.message })] }, suggestion.id))) })] }));
|
|
81
81
|
}
|
|
82
82
|
export function DesignScorePanel({ tree }) {
|
|
83
83
|
const analysis = useMemo(() => analyzeDesign(tree), [tree]);
|
|
@@ -86,8 +86,8 @@ export function DesignScorePanel({ tree }) {
|
|
|
86
86
|
setExpandedCategories((prev) => prev.includes(name) ? prev.filter((n) => n !== name) : [...prev, name]);
|
|
87
87
|
};
|
|
88
88
|
if (!tree.children || tree.children.length === 0) {
|
|
89
|
-
return (_jsxs("div", { className: "
|
|
89
|
+
return (_jsxs("div", { className: "flex min-h-[200px] flex-col items-center justify-center p-6 text-center", children: [_jsx(Palette, { size: 32, className: "text-muted-foreground mb-3" }), _jsx("p", { className: "text-foreground mb-1 text-sm font-medium", children: "Design Score" }), _jsx("p", { className: "text-muted-foreground text-xs", children: "Add sections to your page to see the design analysis" })] }));
|
|
90
90
|
}
|
|
91
|
-
return (_jsxs("div", { className: "flex flex-col", children: [_jsx("div", { className: "flex flex-col items-center
|
|
91
|
+
return (_jsxs("div", { className: "flex flex-col", children: [_jsx("div", { className: "border-border flex flex-col items-center border-b py-5", children: _jsx(ScoreRing, { score: analysis.score }) }), _jsx("div", { className: "flex flex-col", children: analysis.categories.map((category) => (_jsx(CategoryRow, { category: category, expanded: expandedCategories.includes(category.name), onToggle: () => toggleCategory(category.name) }, category.name))) }), _jsx(SuggestionsList, { suggestions: analysis.suggestions })] }));
|
|
92
92
|
}
|
|
93
93
|
//# sourceMappingURL=DesignScore.js.map
|
|
@@ -36,19 +36,19 @@ export function NodeSettings({ node, onUpdateSettings, onRemoveNode, onDuplicate
|
|
|
36
36
|
: node.type === 'row'
|
|
37
37
|
? 'Row'
|
|
38
38
|
: 'Column';
|
|
39
|
-
return (_jsxs("div", { className: "flex flex-col
|
|
39
|
+
return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsx("div", { className: "border-border border-b p-4", children: _jsxs("p", { className: "text-foreground text-sm font-medium", children: [nodeLabel, " Settings"] }) }), _jsx("div", { className: "flex-1 overflow-y-auto", children: _jsxs("div", { className: "space-y-4 p-4", children: [node.type === 'section' && (_jsx(SectionFields, { node: node, updateSetting: updateSetting, onAddRow: onAddRow })), node.type === 'container' && (_jsx(ContainerFields, { node: node, updateSetting: updateSetting })), node.type === 'row' && _jsx(RowFields, { node: node, updateSetting: updateSetting }), node.type === 'column' && _jsx(ColumnFields, { node: node, updateSetting: updateSetting })] }) }), _jsxs("div", { className: "border-border space-y-2 border-t p-4", children: [_jsx("p", { className: SECTION_HEADING_CLASS, children: "Actions" }), _jsxs("div", { className: "flex gap-2", children: [_jsxs("button", { type: "button", onClick: () => onMoveNodeUp(node.id), "aria-label": "Move up", className: "bg-background border-input hover:bg-accent flex flex-1 items-center justify-center gap-1.5 rounded-md border px-3 py-2 text-sm transition-colors", children: [_jsx(ArrowUp, { size: 14 }), "Up"] }), _jsxs("button", { type: "button", onClick: () => onMoveNodeDown(node.id), "aria-label": "Move down", className: "bg-background border-input hover:bg-accent flex flex-1 items-center justify-center gap-1.5 rounded-md border px-3 py-2 text-sm transition-colors", children: [_jsx(ArrowDown, { size: 14 }), "Down"] })] }), _jsxs("button", { type: "button", onClick: () => onDuplicateNode(node.id), className: "bg-background border-input hover:bg-accent flex w-full items-center justify-center gap-2 rounded-md border px-3 py-2 text-sm font-medium transition-colors", children: [_jsx(Copy, { size: 14 }), "Duplicate"] }), _jsxs("button", { type: "button", onClick: handleDelete, onBlur: () => setConfirmDelete(false), className: `flex w-full items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors ${confirmDelete
|
|
40
40
|
? 'bg-destructive text-destructive-foreground'
|
|
41
|
-
: 'bg-background border
|
|
41
|
+
: 'bg-background border-destructive text-destructive hover:bg-destructive/10 border'}`, children: [_jsx(Trash2, { size: 14 }), confirmDelete ? 'Click again to confirm' : 'Delete'] })] })] }));
|
|
42
42
|
}
|
|
43
43
|
function SectionFields({ node, updateSetting, onAddRow, }) {
|
|
44
44
|
const s = node.settings;
|
|
45
|
-
return (_jsxs(_Fragment, { children: [_jsx("p", { className: SECTION_HEADING_CLASS, children: "Background" }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Background Color" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "color", value: s.background ?? '#ffffff', onChange: (e) => updateSetting('background', e.target.value), className: "h-9 w-9 rounded-md border
|
|
45
|
+
return (_jsxs(_Fragment, { children: [_jsx("p", { className: SECTION_HEADING_CLASS, children: "Background" }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Background Color" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "color", value: s.background ?? '#ffffff', onChange: (e) => updateSetting('background', e.target.value), className: "border-input h-9 w-9 cursor-pointer rounded-md border" }), _jsx("input", { type: "text", value: s.background ?? '', onChange: (e) => updateSetting('background', e.target.value), placeholder: "transparent", className: `${INPUT_CLASS} flex-1` })] })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "Spacing" }), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Padding Top" }), _jsx("input", { type: "text", value: s.paddingTop ?? '', onChange: (e) => updateSetting('paddingTop', e.target.value), placeholder: "0px", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Padding Bottom" }), _jsx("input", { type: "text", value: s.paddingBottom ?? '', onChange: (e) => updateSetting('paddingBottom', e.target.value), placeholder: "0px", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Margin Top" }), _jsx("input", { type: "text", value: s.marginTop ?? '', onChange: (e) => updateSetting('marginTop', e.target.value), placeholder: "0px", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Margin Bottom" }), _jsx("input", { type: "text", value: s.marginBottom ?? '', onChange: (e) => updateSetting('marginBottom', e.target.value), placeholder: "0px", className: INPUT_CLASS })] })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "Attributes" }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-foreground text-sm font-medium", children: "Visibility" }), _jsx(SwitchPrimitive.Root, { checked: s.visibility !== 'hidden', onCheckedChange: (checked) => updateSetting('visibility', checked ? 'visible' : 'hidden'), className: "bg-input data-[state=checked]:bg-primary relative h-5 w-9 rounded-full transition-colors", "aria-label": "Section visibility", children: _jsx(SwitchPrimitive.Thumb, { className: "bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[18px]" }) })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "HTML ID" }), _jsx("input", { type: "text", value: s.htmlId ?? '', onChange: (e) => updateSetting('htmlId', e.target.value), placeholder: "section-id", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "HTML Class" }), _jsx("input", { type: "text", value: s.htmlClass ?? '', onChange: (e) => updateSetting('htmlClass', e.target.value), placeholder: "my-class", className: INPUT_CLASS })] }), onAddRow && (_jsxs("button", { type: "button", onClick: () => onAddRow(node.id), className: "bg-primary text-primary-foreground hover:bg-primary/90 flex w-full items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors", children: [_jsx(Plus, { size: 14 }), "Add Row"] }))] }));
|
|
46
46
|
}
|
|
47
47
|
function ContainerFields({ node, updateSetting, }) {
|
|
48
48
|
const s = node.settings;
|
|
49
49
|
return (_jsxs(_Fragment, { children: [_jsx("p", { className: SECTION_HEADING_CLASS, children: "Layout" }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Max Width" }), _jsx("input", { type: "text", value: s.maxWidth ?? '', onChange: (e) => updateSetting('maxWidth', e.target.value), placeholder: "1200px", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Alignment" }), _jsx("div", { className: "flex gap-1", children: ['left', 'center', 'right'].map((align) => {
|
|
50
50
|
const Icon = align === 'left' ? AlignLeft : align === 'center' ? AlignCenter : AlignRight;
|
|
51
|
-
return (_jsx("button", { type: "button", onClick: () => updateSetting('alignment', align), "aria-label": `Align ${align}`, className: `flex-1
|
|
51
|
+
return (_jsx("button", { type: "button", onClick: () => updateSetting('alignment', align), "aria-label": `Align ${align}`, className: `flex flex-1 items-center justify-center rounded-md border py-2 transition-colors ${s.alignment === align
|
|
52
52
|
? 'bg-primary text-primary-foreground border-primary'
|
|
53
53
|
: 'bg-background border-input hover:bg-accent'}`, children: _jsx(Icon, { size: 14 }) }, align));
|
|
54
54
|
}) })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Padding" }), _jsx("input", { type: "text", value: s.padding ?? '', onChange: (e) => updateSetting('padding', e.target.value), placeholder: "0px", className: INPUT_CLASS })] })] }));
|
|
@@ -63,18 +63,18 @@ function RowFields({ node, updateSetting, }) {
|
|
|
63
63
|
: align === 'center'
|
|
64
64
|
? Minus
|
|
65
65
|
: AlignCenter;
|
|
66
|
-
return (_jsx("button", { type: "button", onClick: () => updateSetting('verticalAlign', align), "aria-label": `Align ${align}`, className: `flex-1
|
|
66
|
+
return (_jsx("button", { type: "button", onClick: () => updateSetting('verticalAlign', align), "aria-label": `Align ${align}`, className: `flex flex-1 items-center justify-center rounded-md border py-2 text-xs transition-colors ${s.verticalAlign === align
|
|
67
67
|
? 'bg-primary text-primary-foreground border-primary'
|
|
68
68
|
: 'bg-background border-input hover:bg-accent'}`, children: _jsx(Icon, { size: 14 }) }, align));
|
|
69
|
-
}) })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "Mobile" }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-sm font-medium
|
|
69
|
+
}) })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "Mobile" }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-foreground text-sm font-medium", children: "Reverse on Mobile" }), _jsx(SwitchPrimitive.Root, { checked: !!s.reverseOnMobile, onCheckedChange: (checked) => updateSetting('reverseOnMobile', checked), className: "bg-input data-[state=checked]:bg-primary relative h-5 w-9 rounded-full transition-colors", "aria-label": "Reverse column order on mobile", children: _jsx(SwitchPrimitive.Thumb, { className: "bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[18px]" }) })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-foreground text-sm font-medium", children: "Wrap on Mobile" }), _jsx(SwitchPrimitive.Root, { checked: !!s.wrapOnMobile, onCheckedChange: (checked) => updateSetting('wrapOnMobile', checked), className: "bg-input data-[state=checked]:bg-primary relative h-5 w-9 rounded-full transition-colors", "aria-label": "Wrap columns on mobile", children: _jsx(SwitchPrimitive.Thumb, { className: "bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[18px]" }) })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "Column Presets" }), _jsx("div", { className: "grid grid-cols-2 gap-1.5", children: COLUMN_PRESETS.map((preset) => (_jsxs("button", { type: "button", onClick: () => updateSetting('__columnPreset', preset.widths), className: "border-input bg-background hover:bg-accent rounded-md border px-2 py-2 transition-colors", children: [_jsx("div", { className: "flex h-4 gap-0.5", children: preset.widths.map((w, i) => (_jsx("div", { className: "bg-muted-foreground/30 rounded-sm", style: { flex: w } }, i))) }), _jsx("p", { className: "text-muted-foreground mt-1 text-center text-xs", children: preset.widths.join(' | ') })] }, preset.label))) })] }));
|
|
70
70
|
}
|
|
71
71
|
function ColumnFields({ node, updateSetting, }) {
|
|
72
72
|
const s = node.settings;
|
|
73
73
|
return (_jsxs(_Fragment, { children: [_jsx("p", { className: SECTION_HEADING_CLASS, children: "Size" }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Width (1-12)" }), _jsx("input", { type: "number", min: 1, max: 12, value: s.width, onChange: (e) => updateSetting('width', Number(e.target.value)), className: INPUT_CLASS })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "Layout" }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Vertical Align" }), _jsx("div", { className: "flex gap-1", children: ['top', 'center', 'bottom'].map((align) => {
|
|
74
74
|
const Icon = align === 'top' ? ArrowUpFromLine : align === 'bottom' ? ArrowDownToLine : Minus;
|
|
75
|
-
return (_jsx("button", { type: "button", onClick: () => updateSetting('verticalAlign', align), "aria-label": `Align ${align}`, className: `flex-1
|
|
75
|
+
return (_jsx("button", { type: "button", onClick: () => updateSetting('verticalAlign', align), "aria-label": `Align ${align}`, className: `flex flex-1 items-center justify-center rounded-md border py-2 transition-colors ${s.verticalAlign === align
|
|
76
76
|
? 'bg-primary text-primary-foreground border-primary'
|
|
77
77
|
: 'bg-background border-input hover:bg-accent'}`, children: _jsx(Icon, { size: 14 }) }, align));
|
|
78
|
-
}) })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Padding" }), _jsx("input", { type: "text", value: s.padding ?? '', onChange: (e) => updateSetting('padding', e.target.value), placeholder: "0px", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Background Color" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "color", value: s.background ?? '#ffffff', onChange: (e) => updateSetting('background', e.target.value), className: "h-9 w-9 rounded-md border
|
|
78
|
+
}) })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Padding" }), _jsx("input", { type: "text", value: s.padding ?? '', onChange: (e) => updateSetting('padding', e.target.value), placeholder: "0px", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Background Color" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "color", value: s.background ?? '#ffffff', onChange: (e) => updateSetting('background', e.target.value), className: "border-input h-9 w-9 cursor-pointer rounded-md border" }), _jsx("input", { type: "text", value: s.background ?? '', onChange: (e) => updateSetting('background', e.target.value), placeholder: "transparent", className: `${INPUT_CLASS} flex-1` })] })] })] }));
|
|
79
79
|
}
|
|
80
80
|
//# sourceMappingURL=NodeSettings.js.map
|
|
@@ -116,10 +116,10 @@ export function PageBuilder({ documentId, collectionSlug, config, onNavigate })
|
|
|
116
116
|
replaceTree(generatedTree);
|
|
117
117
|
}, [replaceTree]);
|
|
118
118
|
if (loading) {
|
|
119
|
-
return (_jsx("div", { className: "h-full
|
|
119
|
+
return (_jsx("div", { className: "bg-background flex h-full items-center justify-center", children: _jsx(Loader2, { className: "text-muted-foreground animate-spin", size: 24 }) }));
|
|
120
120
|
}
|
|
121
121
|
if (loadError) {
|
|
122
|
-
return (_jsx("div", { className: "h-full
|
|
122
|
+
return (_jsx("div", { className: "bg-background flex h-full items-center justify-center", children: _jsxs("div", { className: "border-destructive/30 bg-destructive/5 flex max-w-md items-center gap-3 rounded-lg border p-4", children: [_jsx(AlertTriangle, { className: "text-destructive shrink-0", size: 20 }), _jsxs("div", { children: [_jsx("p", { className: "text-foreground text-sm font-medium", children: "Failed to load page" }), _jsx("p", { className: "text-muted-foreground mt-1 text-sm", children: loadError })] })] }) }));
|
|
123
123
|
}
|
|
124
124
|
const canvasWidth = DEVICE_WIDTHS[deviceMode];
|
|
125
125
|
const isConstrained = deviceMode !== 'desktop';
|
|
@@ -143,6 +143,6 @@ export function PageBuilder({ documentId, collectionSlug, config, onNavigate })
|
|
|
143
143
|
...previewStyle,
|
|
144
144
|
fontFamily: previewTheme.fontFamily ?? undefined,
|
|
145
145
|
};
|
|
146
|
-
return (_jsxs(ErrorBoundary, { children: [_jsxs("div", { className: "h-full flex
|
|
146
|
+
return (_jsxs(ErrorBoundary, { children: [_jsxs("div", { className: "bg-background flex h-full flex-col overflow-hidden", children: [_jsx(BuilderToolbar, { collectionSlug: collectionSlug, pageSettings: pageSettings, status: status, dirty: dirty, saving: saving, canUndo: canUndo, canRedo: canRedo, deviceMode: deviceMode, onNavigate: onNavigate, onTitleChange: (title) => setPageSettings({ title }), onUndo: undo, onRedo: redo, onDeviceMode: setDeviceMode, onSave: handleSave, onPublish: handlePublish, onOpenAI: () => setAiDialogOpen(true) }), _jsxs("div", { className: "flex flex-1 overflow-hidden", children: [_jsx("div", { className: "bg-muted flex-1 overflow-auto", children: _jsx("div", { className: "mx-auto h-full max-w-full transition-all duration-200", style: { width: canvasWidth }, children: _jsx("div", { className: `bg-background page-builder-canvas-shell h-full ${isConstrained ? 'border-border border-x shadow-lg' : ''}`, style: canvasShellStyle, children: _jsx(BuilderCanvas, { tree: tree, selectedNodeId: selectedNodeId, showGridOverlay: showGridOverlay, deviceMode: deviceMode, onSelectNode: selectNode }) }) }) }), _jsx("div", { className: "border-border bg-card w-[35%] max-w-[420px] min-w-[280px] overflow-y-auto border-l", children: _jsx(ContextPanel, { activeTab: activeTab, onTabChange: setActiveTab, selectedNode: selectedNode, tree: tree, pageSettings: pageSettings, onUpdateSettings: updateSettings, onUpdateBlock: updateBlock, onRemoveNode: removeNodeById, onDuplicateNode: duplicateNode, onMoveNodeUp: moveNodeUp, onMoveNodeDown: moveNodeDown, onPageSettingsChange: setPageSettings, onAddRow: addRowToSection, config: config }) })] }), _jsx(BottomBar, { deviceMode: deviceMode, showGridOverlay: showGridOverlay, onAddSection: addSection, onToggleGrid: setShowGridOverlay })] }), _jsx(AIGenerateDialog, { open: aiDialogOpen, onClose: () => setAiDialogOpen(false), onAccept: handleAIAccept })] }));
|
|
147
147
|
}
|
|
148
148
|
//# sourceMappingURL=PageBuilder.js.map
|
|
@@ -22,6 +22,6 @@ export function PageSettingsEditor({ settings, onChange }) {
|
|
|
22
22
|
}, [onChange]);
|
|
23
23
|
const metaTitleLength = (settings.metaTitle ?? '').length;
|
|
24
24
|
const metaDescLength = (settings.metaDescription ?? '').length;
|
|
25
|
-
return (_jsxs("div", { className: "space-y-4 p-4", children: [_jsx("p", { className: SECTION_HEADING_CLASS, children: "General" }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Title" }), _jsx("input", { type: "text", value: settings.title, onChange: (e) => update('title', e.target.value), placeholder: "Page title", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Slug" }), _jsx("input", { type: "text", value: settings.slug, onChange: (e) => update('slug', e.target.value), placeholder: "/page-slug", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Template" }), _jsx("input", { type: "text", value: settings.template ?? '', onChange: (e) => update('template', e.target.value), placeholder: "default", className: INPUT_CLASS, readOnly: true })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "SEO" }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center justify-between
|
|
25
|
+
return (_jsxs("div", { className: "space-y-4 p-4", children: [_jsx("p", { className: SECTION_HEADING_CLASS, children: "General" }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Title" }), _jsx("input", { type: "text", value: settings.title, onChange: (e) => update('title', e.target.value), placeholder: "Page title", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Slug" }), _jsx("input", { type: "text", value: settings.slug, onChange: (e) => update('slug', e.target.value), placeholder: "/page-slug", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Template" }), _jsx("input", { type: "text", value: settings.template ?? '', onChange: (e) => update('template', e.target.value), placeholder: "default", className: INPUT_CLASS, readOnly: true })] }), _jsx("p", { className: SECTION_HEADING_CLASS, children: "SEO" }), _jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between", children: [_jsx("label", { className: "text-foreground text-sm font-medium", children: "Meta Title" }), _jsxs("span", { className: `text-xs ${metaTitleLength > 60 ? 'text-destructive' : 'text-muted-foreground'}`, children: [metaTitleLength, "/60"] })] }), _jsx("input", { type: "text", value: settings.metaTitle ?? '', onChange: (e) => update('metaTitle', e.target.value), placeholder: "SEO title", maxLength: 100, className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between", children: [_jsx("label", { className: "text-foreground text-sm font-medium", children: "Meta Description" }), _jsxs("span", { className: `text-xs ${metaDescLength > 160 ? 'text-destructive' : 'text-muted-foreground'}`, children: [metaDescLength, "/160"] })] }), _jsx("textarea", { value: settings.metaDescription ?? '', onChange: (e) => update('metaDescription', e.target.value), placeholder: "Brief description for search engines", rows: 3, maxLength: 250, className: `${INPUT_CLASS} resize-y` })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "OG Image" }), _jsx("input", { type: "text", value: settings.ogImage ?? '', onChange: (e) => update('ogImage', e.target.value), placeholder: "https://example.com/image.jpg", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Focus Keyphrase" }), _jsx("input", { type: "text", value: settings.focusKeyphrase ?? '', onChange: (e) => update('focusKeyphrase', e.target.value), placeholder: "primary keyword", className: INPUT_CLASS })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL_CLASS, children: "Schema Type" }), _jsxs("select", { value: settings.schemaType ?? '', onChange: (e) => update('schemaType', e.target.value), className: INPUT_CLASS, children: [_jsx("option", { value: "", children: "Select schema type..." }), SCHEMA_TYPES.map((type) => (_jsx("option", { value: type, children: type }, type)))] })] })] }));
|
|
26
26
|
}
|
|
27
27
|
//# sourceMappingURL=PageSettings.js.map
|
|
@@ -6,8 +6,8 @@ export function PageTemplates({ onNavigate }) {
|
|
|
6
6
|
const { data, loading, error, refetch } = useApiData('/page-templates');
|
|
7
7
|
const templates = data ?? [];
|
|
8
8
|
if (loading) {
|
|
9
|
-
return (_jsxs("div", { className: "flex h-64 items-center justify-center p-4", role: "status", "aria-live": "polite", children: [_jsx(Loader2, { className: "h-6 w-6 animate-spin
|
|
9
|
+
return (_jsxs("div", { className: "flex h-64 items-center justify-center p-4", role: "status", "aria-live": "polite", children: [_jsx(Loader2, { className: "text-primary h-6 w-6 animate-spin" }), _jsx("span", { className: "sr-only", children: "Loading page templates" })] }));
|
|
10
10
|
}
|
|
11
|
-
return (_jsxs("div", { className: "p-4 pr-8", children: [error && (_jsxs("div", { className: "mb-4 flex items-center gap-3 rounded-lg border
|
|
11
|
+
return (_jsxs("div", { className: "p-4 pr-8", children: [error && (_jsxs("div", { className: "border-border bg-card mb-4 flex items-center gap-3 rounded-lg border p-3", children: [_jsx(AlertTriangle, { className: "text-muted-foreground h-5 w-5 shrink-0" }), _jsx("span", { className: "text-foreground flex-1 text-sm", children: error }), _jsx("button", { type: "button", onClick: refetch, className: "border-border text-foreground hover:bg-accent rounded-md border px-3 py-1 text-sm", children: "Retry" })] })), _jsxs("div", { className: "mb-4 flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-foreground mb-1 text-2xl font-medium", children: "Page Templates" }), _jsxs("p", { className: "text-muted-foreground text-sm", children: [templates.length, " saved template", templates.length === 1 ? '' : 's'] })] }), _jsxs("button", { type: "button", onClick: refetch, className: "border-border text-foreground hover:bg-accent inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium", children: [_jsx(RefreshCw, { className: "h-4 w-4" }), "Refresh"] })] }), templates.length === 0 ? (_jsxs("div", { className: "border-border bg-card rounded-lg border p-8 text-center", children: [_jsx(Layers, { className: "text-muted-foreground mx-auto mb-3 h-8 w-8" }), _jsx("h2", { className: "text-foreground mb-1 text-lg font-medium", children: "No page templates yet" }), _jsx("p", { className: "text-muted-foreground mb-4 text-sm", children: "Built-in templates are seeded by the CMS when the templates API is available." }), _jsx("button", { type: "button", onClick: () => onNavigate?.('/saved-sections'), className: "bg-primary text-primary-foreground rounded-md px-4 py-2 text-sm font-medium hover:opacity-90", children: "View Saved Sections" })] })) : (_jsx("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3", children: templates.map((template) => (_jsxs("div", { className: "border-border bg-card rounded-lg border p-4", children: [_jsxs("div", { className: "mb-3 flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-foreground text-base font-medium", children: template.name ?? 'Untitled template' }), _jsx("p", { className: "text-muted-foreground mt-1 text-sm", children: template.description ?? 'No description provided.' })] }), template.builtIn && (_jsx("span", { className: "bg-muted text-muted-foreground rounded-full px-2 py-0.5 text-xs", children: "Built-in" }))] }), _jsxs("div", { className: "text-muted-foreground flex items-center justify-between text-sm", children: [_jsx("span", { children: template.category ?? 'content' }), _jsx("span", { children: template.updatedAt ? new Date(template.updatedAt).toLocaleDateString() : '' })] })] }, template.id))) }))] }));
|
|
12
12
|
}
|
|
13
13
|
//# sourceMappingURL=PageTemplates.js.map
|