@actuate-media/cms-admin 0.10.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.js +1 -1
- package/dist/components/SharePreviewLinkDialog.js +1 -1
- 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 +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -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.js +7 -7
- 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.js +3 -3
- 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 +4 -4
- package/src/components/SharePreviewLinkDialog.tsx +1 -1
- 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 +28 -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 +9 -9
- 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
|
@@ -86,9 +86,9 @@ export function NodeSettings({
|
|
|
86
86
|
: 'Column'
|
|
87
87
|
|
|
88
88
|
return (
|
|
89
|
-
<div className="flex flex-col
|
|
90
|
-
<div className="
|
|
91
|
-
<p className="text-sm font-medium
|
|
89
|
+
<div className="flex h-full flex-col">
|
|
90
|
+
<div className="border-border border-b p-4">
|
|
91
|
+
<p className="text-foreground text-sm font-medium">{nodeLabel} Settings</p>
|
|
92
92
|
</div>
|
|
93
93
|
|
|
94
94
|
<div className="flex-1 overflow-y-auto">
|
|
@@ -104,14 +104,14 @@ export function NodeSettings({
|
|
|
104
104
|
</div>
|
|
105
105
|
</div>
|
|
106
106
|
|
|
107
|
-
<div className="
|
|
107
|
+
<div className="border-border space-y-2 border-t p-4">
|
|
108
108
|
<p className={SECTION_HEADING_CLASS}>Actions</p>
|
|
109
109
|
<div className="flex gap-2">
|
|
110
110
|
<button
|
|
111
111
|
type="button"
|
|
112
112
|
onClick={() => onMoveNodeUp(node.id)}
|
|
113
113
|
aria-label="Move up"
|
|
114
|
-
className="flex-1
|
|
114
|
+
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"
|
|
115
115
|
>
|
|
116
116
|
<ArrowUp size={14} />
|
|
117
117
|
Up
|
|
@@ -120,7 +120,7 @@ export function NodeSettings({
|
|
|
120
120
|
type="button"
|
|
121
121
|
onClick={() => onMoveNodeDown(node.id)}
|
|
122
122
|
aria-label="Move down"
|
|
123
|
-
className="flex-1
|
|
123
|
+
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"
|
|
124
124
|
>
|
|
125
125
|
<ArrowDown size={14} />
|
|
126
126
|
Down
|
|
@@ -129,7 +129,7 @@ export function NodeSettings({
|
|
|
129
129
|
<button
|
|
130
130
|
type="button"
|
|
131
131
|
onClick={() => onDuplicateNode(node.id)}
|
|
132
|
-
className="w-full
|
|
132
|
+
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"
|
|
133
133
|
>
|
|
134
134
|
<Copy size={14} />
|
|
135
135
|
Duplicate
|
|
@@ -138,10 +138,10 @@ export function NodeSettings({
|
|
|
138
138
|
type="button"
|
|
139
139
|
onClick={handleDelete}
|
|
140
140
|
onBlur={() => setConfirmDelete(false)}
|
|
141
|
-
className={`w-full
|
|
141
|
+
className={`flex w-full items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors ${
|
|
142
142
|
confirmDelete
|
|
143
143
|
? 'bg-destructive text-destructive-foreground'
|
|
144
|
-
: 'bg-background border
|
|
144
|
+
: 'bg-background border-destructive text-destructive hover:bg-destructive/10 border'
|
|
145
145
|
}`}
|
|
146
146
|
>
|
|
147
147
|
<Trash2 size={14} />
|
|
@@ -172,7 +172,7 @@ function SectionFields({
|
|
|
172
172
|
type="color"
|
|
173
173
|
value={s.background ?? '#ffffff'}
|
|
174
174
|
onChange={(e) => updateSetting('background', e.target.value)}
|
|
175
|
-
className="h-9 w-9 rounded-md border
|
|
175
|
+
className="border-input h-9 w-9 cursor-pointer rounded-md border"
|
|
176
176
|
/>
|
|
177
177
|
<input
|
|
178
178
|
type="text"
|
|
@@ -230,14 +230,14 @@ function SectionFields({
|
|
|
230
230
|
|
|
231
231
|
<p className={SECTION_HEADING_CLASS}>Attributes</p>
|
|
232
232
|
<div className="flex items-center justify-between">
|
|
233
|
-
<label className="text-sm font-medium
|
|
233
|
+
<label className="text-foreground text-sm font-medium">Visibility</label>
|
|
234
234
|
<SwitchPrimitive.Root
|
|
235
235
|
checked={s.visibility !== 'hidden'}
|
|
236
236
|
onCheckedChange={(checked) => updateSetting('visibility', checked ? 'visible' : 'hidden')}
|
|
237
|
-
className="
|
|
237
|
+
className="bg-input data-[state=checked]:bg-primary relative h-5 w-9 rounded-full transition-colors"
|
|
238
238
|
aria-label="Section visibility"
|
|
239
239
|
>
|
|
240
|
-
<SwitchPrimitive.Thumb className="block h-3.5 w-3.5 rounded-full
|
|
240
|
+
<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]" />
|
|
241
241
|
</SwitchPrimitive.Root>
|
|
242
242
|
</div>
|
|
243
243
|
<div>
|
|
@@ -265,7 +265,7 @@ function SectionFields({
|
|
|
265
265
|
<button
|
|
266
266
|
type="button"
|
|
267
267
|
onClick={() => onAddRow(node.id)}
|
|
268
|
-
className="w-full
|
|
268
|
+
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"
|
|
269
269
|
>
|
|
270
270
|
<Plus size={14} />
|
|
271
271
|
Add Row
|
|
@@ -308,7 +308,7 @@ function ContainerFields({
|
|
|
308
308
|
type="button"
|
|
309
309
|
onClick={() => updateSetting('alignment', align)}
|
|
310
310
|
aria-label={`Align ${align}`}
|
|
311
|
-
className={`flex-1
|
|
311
|
+
className={`flex flex-1 items-center justify-center rounded-md border py-2 transition-colors ${
|
|
312
312
|
s.alignment === align
|
|
313
313
|
? 'bg-primary text-primary-foreground border-primary'
|
|
314
314
|
: 'bg-background border-input hover:bg-accent'
|
|
@@ -373,7 +373,7 @@ function RowFields({
|
|
|
373
373
|
type="button"
|
|
374
374
|
onClick={() => updateSetting('verticalAlign', align)}
|
|
375
375
|
aria-label={`Align ${align}`}
|
|
376
|
-
className={`flex-1
|
|
376
|
+
className={`flex flex-1 items-center justify-center rounded-md border py-2 text-xs transition-colors ${
|
|
377
377
|
s.verticalAlign === align
|
|
378
378
|
? 'bg-primary text-primary-foreground border-primary'
|
|
379
379
|
: 'bg-background border-input hover:bg-accent'
|
|
@@ -388,25 +388,25 @@ function RowFields({
|
|
|
388
388
|
|
|
389
389
|
<p className={SECTION_HEADING_CLASS}>Mobile</p>
|
|
390
390
|
<div className="flex items-center justify-between">
|
|
391
|
-
<label className="text-sm font-medium
|
|
391
|
+
<label className="text-foreground text-sm font-medium">Reverse on Mobile</label>
|
|
392
392
|
<SwitchPrimitive.Root
|
|
393
393
|
checked={!!s.reverseOnMobile}
|
|
394
394
|
onCheckedChange={(checked) => updateSetting('reverseOnMobile', checked)}
|
|
395
|
-
className="
|
|
395
|
+
className="bg-input data-[state=checked]:bg-primary relative h-5 w-9 rounded-full transition-colors"
|
|
396
396
|
aria-label="Reverse column order on mobile"
|
|
397
397
|
>
|
|
398
|
-
<SwitchPrimitive.Thumb className="block h-3.5 w-3.5 rounded-full
|
|
398
|
+
<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]" />
|
|
399
399
|
</SwitchPrimitive.Root>
|
|
400
400
|
</div>
|
|
401
401
|
<div className="flex items-center justify-between">
|
|
402
|
-
<label className="text-sm font-medium
|
|
402
|
+
<label className="text-foreground text-sm font-medium">Wrap on Mobile</label>
|
|
403
403
|
<SwitchPrimitive.Root
|
|
404
404
|
checked={!!s.wrapOnMobile}
|
|
405
405
|
onCheckedChange={(checked) => updateSetting('wrapOnMobile', checked)}
|
|
406
|
-
className="
|
|
406
|
+
className="bg-input data-[state=checked]:bg-primary relative h-5 w-9 rounded-full transition-colors"
|
|
407
407
|
aria-label="Wrap columns on mobile"
|
|
408
408
|
>
|
|
409
|
-
<SwitchPrimitive.Thumb className="block h-3.5 w-3.5 rounded-full
|
|
409
|
+
<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]" />
|
|
410
410
|
</SwitchPrimitive.Root>
|
|
411
411
|
</div>
|
|
412
412
|
|
|
@@ -417,14 +417,14 @@ function RowFields({
|
|
|
417
417
|
key={preset.label}
|
|
418
418
|
type="button"
|
|
419
419
|
onClick={() => updateSetting('__columnPreset', preset.widths)}
|
|
420
|
-
className="
|
|
420
|
+
className="border-input bg-background hover:bg-accent rounded-md border px-2 py-2 transition-colors"
|
|
421
421
|
>
|
|
422
|
-
<div className="flex gap-0.5
|
|
422
|
+
<div className="flex h-4 gap-0.5">
|
|
423
423
|
{preset.widths.map((w, i) => (
|
|
424
424
|
<div key={i} className="bg-muted-foreground/30 rounded-sm" style={{ flex: w }} />
|
|
425
425
|
))}
|
|
426
426
|
</div>
|
|
427
|
-
<p className="text-
|
|
427
|
+
<p className="text-muted-foreground mt-1 text-center text-xs">
|
|
428
428
|
{preset.widths.join(' | ')}
|
|
429
429
|
</p>
|
|
430
430
|
</button>
|
|
@@ -470,7 +470,7 @@ function ColumnFields({
|
|
|
470
470
|
type="button"
|
|
471
471
|
onClick={() => updateSetting('verticalAlign', align)}
|
|
472
472
|
aria-label={`Align ${align}`}
|
|
473
|
-
className={`flex-1
|
|
473
|
+
className={`flex flex-1 items-center justify-center rounded-md border py-2 transition-colors ${
|
|
474
474
|
s.verticalAlign === align
|
|
475
475
|
? 'bg-primary text-primary-foreground border-primary'
|
|
476
476
|
: 'bg-background border-input hover:bg-accent'
|
|
@@ -499,7 +499,7 @@ function ColumnFields({
|
|
|
499
499
|
type="color"
|
|
500
500
|
value={s.background ?? '#ffffff'}
|
|
501
501
|
onChange={(e) => updateSetting('background', e.target.value)}
|
|
502
|
-
className="h-9 w-9 rounded-md border
|
|
502
|
+
className="border-input h-9 w-9 cursor-pointer rounded-md border"
|
|
503
503
|
/>
|
|
504
504
|
<input
|
|
505
505
|
type="text"
|
|
@@ -184,20 +184,20 @@ export function PageBuilder({ documentId, collectionSlug, config, onNavigate }:
|
|
|
184
184
|
|
|
185
185
|
if (loading) {
|
|
186
186
|
return (
|
|
187
|
-
<div className="h-full
|
|
188
|
-
<Loader2 className="
|
|
187
|
+
<div className="bg-background flex h-full items-center justify-center">
|
|
188
|
+
<Loader2 className="text-muted-foreground animate-spin" size={24} />
|
|
189
189
|
</div>
|
|
190
190
|
)
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
if (loadError) {
|
|
194
194
|
return (
|
|
195
|
-
<div className="h-full
|
|
196
|
-
<div className="flex items-center gap-3 rounded-lg border
|
|
195
|
+
<div className="bg-background flex h-full items-center justify-center">
|
|
196
|
+
<div className="border-destructive/30 bg-destructive/5 flex max-w-md items-center gap-3 rounded-lg border p-4">
|
|
197
197
|
<AlertTriangle className="text-destructive shrink-0" size={20} />
|
|
198
198
|
<div>
|
|
199
|
-
<p className="text-sm font-medium
|
|
200
|
-
<p className="text-
|
|
199
|
+
<p className="text-foreground text-sm font-medium">Failed to load page</p>
|
|
200
|
+
<p className="text-muted-foreground mt-1 text-sm">{loadError}</p>
|
|
201
201
|
</div>
|
|
202
202
|
</div>
|
|
203
203
|
</div>
|
|
@@ -226,7 +226,7 @@ export function PageBuilder({ documentId, collectionSlug, config, onNavigate }:
|
|
|
226
226
|
|
|
227
227
|
return (
|
|
228
228
|
<ErrorBoundary>
|
|
229
|
-
<div className="h-full flex
|
|
229
|
+
<div className="bg-background flex h-full flex-col overflow-hidden">
|
|
230
230
|
<BuilderToolbar
|
|
231
231
|
collectionSlug={collectionSlug}
|
|
232
232
|
pageSettings={pageSettings}
|
|
@@ -246,15 +246,15 @@ export function PageBuilder({ documentId, collectionSlug, config, onNavigate }:
|
|
|
246
246
|
onOpenAI={() => setAiDialogOpen(true)}
|
|
247
247
|
/>
|
|
248
248
|
|
|
249
|
-
<div className="flex-1
|
|
249
|
+
<div className="flex flex-1 overflow-hidden">
|
|
250
250
|
{/* Canvas area */}
|
|
251
|
-
<div className="flex-1 overflow-auto
|
|
251
|
+
<div className="bg-muted flex-1 overflow-auto">
|
|
252
252
|
<div
|
|
253
253
|
className="mx-auto h-full max-w-full transition-all duration-200"
|
|
254
254
|
style={{ width: canvasWidth }}
|
|
255
255
|
>
|
|
256
256
|
<div
|
|
257
|
-
className={`
|
|
257
|
+
className={`bg-background page-builder-canvas-shell h-full ${isConstrained ? 'border-border border-x shadow-lg' : ''}`}
|
|
258
258
|
style={canvasShellStyle}
|
|
259
259
|
>
|
|
260
260
|
<BuilderCanvas
|
|
@@ -269,7 +269,7 @@ export function PageBuilder({ documentId, collectionSlug, config, onNavigate }:
|
|
|
269
269
|
</div>
|
|
270
270
|
|
|
271
271
|
{/* Context panel */}
|
|
272
|
-
<div className="w-[35%]
|
|
272
|
+
<div className="border-border bg-card w-[35%] max-w-[420px] min-w-[280px] overflow-y-auto border-l">
|
|
273
273
|
<ContextPanel
|
|
274
274
|
activeTab={activeTab}
|
|
275
275
|
onTabChange={setActiveTab}
|
|
@@ -79,8 +79,8 @@ export function PageSettingsEditor({ settings, onChange }: PageSettingsProps) {
|
|
|
79
79
|
<p className={SECTION_HEADING_CLASS}>SEO</p>
|
|
80
80
|
|
|
81
81
|
<div>
|
|
82
|
-
<div className="flex items-center justify-between
|
|
83
|
-
<label className="text-sm font-medium
|
|
82
|
+
<div className="mb-1 flex items-center justify-between">
|
|
83
|
+
<label className="text-foreground text-sm font-medium">Meta Title</label>
|
|
84
84
|
<span
|
|
85
85
|
className={`text-xs ${
|
|
86
86
|
metaTitleLength > 60 ? 'text-destructive' : 'text-muted-foreground'
|
|
@@ -100,8 +100,8 @@ export function PageSettingsEditor({ settings, onChange }: PageSettingsProps) {
|
|
|
100
100
|
</div>
|
|
101
101
|
|
|
102
102
|
<div>
|
|
103
|
-
<div className="flex items-center justify-between
|
|
104
|
-
<label className="text-sm font-medium
|
|
103
|
+
<div className="mb-1 flex items-center justify-between">
|
|
104
|
+
<label className="text-foreground text-sm font-medium">Meta Description</label>
|
|
105
105
|
<span
|
|
106
106
|
className={`text-xs ${
|
|
107
107
|
metaDescLength > 160 ? 'text-destructive' : 'text-muted-foreground'
|
|
@@ -23,7 +23,7 @@ export function PageTemplates({ onNavigate }: PageTemplatesProps) {
|
|
|
23
23
|
if (loading) {
|
|
24
24
|
return (
|
|
25
25
|
<div className="flex h-64 items-center justify-center p-4" role="status" aria-live="polite">
|
|
26
|
-
<Loader2 className="h-6 w-6 animate-spin
|
|
26
|
+
<Loader2 className="text-primary h-6 w-6 animate-spin" />
|
|
27
27
|
<span className="sr-only">Loading page templates</span>
|
|
28
28
|
</div>
|
|
29
29
|
)
|
|
@@ -32,13 +32,13 @@ export function PageTemplates({ onNavigate }: PageTemplatesProps) {
|
|
|
32
32
|
return (
|
|
33
33
|
<div className="p-4 pr-8">
|
|
34
34
|
{error && (
|
|
35
|
-
<div className="mb-4 flex items-center gap-3 rounded-lg border
|
|
36
|
-
<AlertTriangle className="h-5 w-5 shrink-0
|
|
37
|
-
<span className="flex-1 text-sm
|
|
35
|
+
<div className="border-border bg-card mb-4 flex items-center gap-3 rounded-lg border p-3">
|
|
36
|
+
<AlertTriangle className="text-muted-foreground h-5 w-5 shrink-0" />
|
|
37
|
+
<span className="text-foreground flex-1 text-sm">{error}</span>
|
|
38
38
|
<button
|
|
39
39
|
type="button"
|
|
40
40
|
onClick={refetch}
|
|
41
|
-
className="rounded-md border
|
|
41
|
+
className="border-border text-foreground hover:bg-accent rounded-md border px-3 py-1 text-sm"
|
|
42
42
|
>
|
|
43
43
|
Retry
|
|
44
44
|
</button>
|
|
@@ -47,15 +47,15 @@ export function PageTemplates({ onNavigate }: PageTemplatesProps) {
|
|
|
47
47
|
|
|
48
48
|
<div className="mb-4 flex items-center justify-between">
|
|
49
49
|
<div>
|
|
50
|
-
<h1 className="mb-1 text-2xl font-medium
|
|
51
|
-
<p className="text-
|
|
50
|
+
<h1 className="text-foreground mb-1 text-2xl font-medium">Page Templates</h1>
|
|
51
|
+
<p className="text-muted-foreground text-sm">
|
|
52
52
|
{templates.length} saved template{templates.length === 1 ? '' : 's'}
|
|
53
53
|
</p>
|
|
54
54
|
</div>
|
|
55
55
|
<button
|
|
56
56
|
type="button"
|
|
57
57
|
onClick={refetch}
|
|
58
|
-
className="inline-flex items-center gap-2 rounded-md border
|
|
58
|
+
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"
|
|
59
59
|
>
|
|
60
60
|
<RefreshCw className="h-4 w-4" />
|
|
61
61
|
Refresh
|
|
@@ -63,16 +63,16 @@ export function PageTemplates({ onNavigate }: PageTemplatesProps) {
|
|
|
63
63
|
</div>
|
|
64
64
|
|
|
65
65
|
{templates.length === 0 ? (
|
|
66
|
-
<div className="
|
|
67
|
-
<Layers className="mx-auto mb-3 h-8 w-8
|
|
68
|
-
<h2 className="mb-1 text-lg font-medium
|
|
69
|
-
<p className="mb-4 text-sm
|
|
66
|
+
<div className="border-border bg-card rounded-lg border p-8 text-center">
|
|
67
|
+
<Layers className="text-muted-foreground mx-auto mb-3 h-8 w-8" />
|
|
68
|
+
<h2 className="text-foreground mb-1 text-lg font-medium">No page templates yet</h2>
|
|
69
|
+
<p className="text-muted-foreground mb-4 text-sm">
|
|
70
70
|
Built-in templates are seeded by the CMS when the templates API is available.
|
|
71
71
|
</p>
|
|
72
72
|
<button
|
|
73
73
|
type="button"
|
|
74
74
|
onClick={() => onNavigate?.('/saved-sections')}
|
|
75
|
-
className="
|
|
75
|
+
className="bg-primary text-primary-foreground rounded-md px-4 py-2 text-sm font-medium hover:opacity-90"
|
|
76
76
|
>
|
|
77
77
|
View Saved Sections
|
|
78
78
|
</button>
|
|
@@ -80,23 +80,23 @@ export function PageTemplates({ onNavigate }: PageTemplatesProps) {
|
|
|
80
80
|
) : (
|
|
81
81
|
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3">
|
|
82
82
|
{templates.map((template) => (
|
|
83
|
-
<div key={template.id} className="
|
|
83
|
+
<div key={template.id} className="border-border bg-card rounded-lg border p-4">
|
|
84
84
|
<div className="mb-3 flex items-start justify-between gap-3">
|
|
85
85
|
<div>
|
|
86
|
-
<h2 className="text-base font-medium
|
|
86
|
+
<h2 className="text-foreground text-base font-medium">
|
|
87
87
|
{template.name ?? 'Untitled template'}
|
|
88
88
|
</h2>
|
|
89
|
-
<p className="mt-1 text-sm
|
|
89
|
+
<p className="text-muted-foreground mt-1 text-sm">
|
|
90
90
|
{template.description ?? 'No description provided.'}
|
|
91
91
|
</p>
|
|
92
92
|
</div>
|
|
93
93
|
{template.builtIn && (
|
|
94
|
-
<span className="
|
|
94
|
+
<span className="bg-muted text-muted-foreground rounded-full px-2 py-0.5 text-xs">
|
|
95
95
|
Built-in
|
|
96
96
|
</span>
|
|
97
97
|
)}
|
|
98
98
|
</div>
|
|
99
|
-
<div className="flex items-center justify-between text-sm
|
|
99
|
+
<div className="text-muted-foreground flex items-center justify-between text-sm">
|
|
100
100
|
<span>{template.category ?? 'content'}</span>
|
|
101
101
|
<span>
|
|
102
102
|
{template.updatedAt ? new Date(template.updatedAt).toLocaleDateString() : ''}
|
|
@@ -54,11 +54,11 @@ function getScoreLabel(score: number): string {
|
|
|
54
54
|
function StatusIcon({ status }: { status: BuilderSEOCheck['status'] }) {
|
|
55
55
|
switch (status) {
|
|
56
56
|
case 'good':
|
|
57
|
-
return <CheckCircle2 size={14} className="text-green-500
|
|
57
|
+
return <CheckCircle2 size={14} className="shrink-0 text-green-500" />
|
|
58
58
|
case 'warning':
|
|
59
|
-
return <AlertCircle size={14} className="text-amber-500
|
|
59
|
+
return <AlertCircle size={14} className="shrink-0 text-amber-500" />
|
|
60
60
|
case 'error':
|
|
61
|
-
return <XCircle size={14} className="text-red-500
|
|
61
|
+
return <XCircle size={14} className="shrink-0 text-red-500" />
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -110,15 +110,15 @@ function ScoreSummary({ checks }: { checks: BuilderSEOCheck[] }) {
|
|
|
110
110
|
<div className="flex flex-col gap-1">
|
|
111
111
|
<div className="flex items-center gap-1.5">
|
|
112
112
|
<CheckCircle2 size={12} className="text-green-500" />
|
|
113
|
-
<span className="text-
|
|
113
|
+
<span className="text-muted-foreground text-xs">{passed} passed</span>
|
|
114
114
|
</div>
|
|
115
115
|
<div className="flex items-center gap-1.5">
|
|
116
116
|
<AlertCircle size={12} className="text-amber-500" />
|
|
117
|
-
<span className="text-
|
|
117
|
+
<span className="text-muted-foreground text-xs">{warnings} warnings</span>
|
|
118
118
|
</div>
|
|
119
119
|
<div className="flex items-center gap-1.5">
|
|
120
120
|
<XCircle size={12} className="text-red-500" />
|
|
121
|
-
<span className="text-
|
|
121
|
+
<span className="text-muted-foreground text-xs">{errors} issues</span>
|
|
122
122
|
</div>
|
|
123
123
|
</div>
|
|
124
124
|
)
|
|
@@ -138,16 +138,16 @@ function CollapsibleSection({
|
|
|
138
138
|
children: React.ReactNode
|
|
139
139
|
}) {
|
|
140
140
|
return (
|
|
141
|
-
<div className="border-
|
|
141
|
+
<div className="border-border border-b last:border-b-0">
|
|
142
142
|
<button
|
|
143
143
|
type="button"
|
|
144
|
-
className="w-full
|
|
144
|
+
className="hover:bg-muted/50 flex w-full items-center justify-between px-4 py-3 text-left transition-colors"
|
|
145
145
|
onClick={onToggle}
|
|
146
146
|
aria-expanded={expanded}
|
|
147
147
|
>
|
|
148
148
|
<div className="flex items-center gap-2">
|
|
149
149
|
<Icon size={14} className="text-muted-foreground" />
|
|
150
|
-
<span className="text-xs font-medium
|
|
150
|
+
<span className="text-foreground text-xs font-medium">{title}</span>
|
|
151
151
|
</div>
|
|
152
152
|
{expanded ? (
|
|
153
153
|
<ChevronUp size={14} className="text-muted-foreground" />
|
|
@@ -167,8 +167,8 @@ function SEOChecksList({ checks }: { checks: BuilderSEOCheck[] }) {
|
|
|
167
167
|
<div key={check.id} className="flex items-start gap-2">
|
|
168
168
|
<StatusIcon status={check.status} />
|
|
169
169
|
<div className="flex flex-col">
|
|
170
|
-
<span className="text-xs font-medium
|
|
171
|
-
<span className="text-
|
|
170
|
+
<span className="text-foreground text-xs font-medium">{check.label}</span>
|
|
171
|
+
<span className="text-muted-foreground text-xs">{check.detail}</span>
|
|
172
172
|
</div>
|
|
173
173
|
</div>
|
|
174
174
|
))}
|
|
@@ -186,48 +186,48 @@ function ReadabilityGrid({ readability }: { readability: BuilderReadabilityResul
|
|
|
186
186
|
|
|
187
187
|
return (
|
|
188
188
|
<div className="grid grid-cols-2 gap-3">
|
|
189
|
-
<div className="bg-muted/50
|
|
189
|
+
<div className="bg-muted/50 flex flex-col gap-1 rounded-md p-3">
|
|
190
190
|
<div className="flex items-center gap-1.5">
|
|
191
191
|
<BarChart3 size={12} className="text-muted-foreground" />
|
|
192
|
-
<span className="text-
|
|
192
|
+
<span className="text-muted-foreground text-xs">Flesch Score</span>
|
|
193
193
|
</div>
|
|
194
194
|
<span className={`text-sm font-medium ${getScoreColor(readability.fleschScore)}`}>
|
|
195
195
|
{readability.fleschScore}
|
|
196
196
|
</span>
|
|
197
|
-
<span className="text-
|
|
197
|
+
<span className="text-muted-foreground text-xs">{fleschLabel}</span>
|
|
198
198
|
</div>
|
|
199
199
|
|
|
200
|
-
<div className="bg-muted/50
|
|
200
|
+
<div className="bg-muted/50 flex flex-col gap-1 rounded-md p-3">
|
|
201
201
|
<div className="flex items-center gap-1.5">
|
|
202
202
|
<Type size={12} className="text-muted-foreground" />
|
|
203
|
-
<span className="text-
|
|
203
|
+
<span className="text-muted-foreground text-xs">Word Count</span>
|
|
204
204
|
</div>
|
|
205
|
-
<span className="text-sm font-medium
|
|
206
|
-
<span className="text-
|
|
205
|
+
<span className="text-foreground text-sm font-medium">{readability.wordCount}</span>
|
|
206
|
+
<span className="text-muted-foreground text-xs">
|
|
207
207
|
{readability.wordCount >= 300 ? 'Good length' : 'Short'}
|
|
208
208
|
</span>
|
|
209
209
|
</div>
|
|
210
210
|
|
|
211
|
-
<div className="bg-muted/50
|
|
211
|
+
<div className="bg-muted/50 flex flex-col gap-1 rounded-md p-3">
|
|
212
212
|
<div className="flex items-center gap-1.5">
|
|
213
213
|
<FileText size={12} className="text-muted-foreground" />
|
|
214
|
-
<span className="text-
|
|
214
|
+
<span className="text-muted-foreground text-xs">Avg Sentence</span>
|
|
215
215
|
</div>
|
|
216
|
-
<span className="text-sm font-medium
|
|
216
|
+
<span className="text-foreground text-sm font-medium">
|
|
217
217
|
{readability.avgSentenceLength} words
|
|
218
218
|
</span>
|
|
219
|
-
<span className="text-
|
|
219
|
+
<span className="text-muted-foreground text-xs">
|
|
220
220
|
{readability.avgSentenceLength <= 20 ? 'Good' : 'Long'}
|
|
221
221
|
</span>
|
|
222
222
|
</div>
|
|
223
223
|
|
|
224
|
-
<div className="bg-muted/50
|
|
224
|
+
<div className="bg-muted/50 flex flex-col gap-1 rounded-md p-3">
|
|
225
225
|
<div className="flex items-center gap-1.5">
|
|
226
226
|
<Clock size={12} className="text-muted-foreground" />
|
|
227
|
-
<span className="text-
|
|
227
|
+
<span className="text-muted-foreground text-xs">Reading Time</span>
|
|
228
228
|
</div>
|
|
229
|
-
<span className="text-sm font-medium
|
|
230
|
-
<span className="text-
|
|
229
|
+
<span className="text-foreground text-sm font-medium">{readability.readingTime} min</span>
|
|
230
|
+
<span className="text-muted-foreground text-xs">~{readability.wordCount} words</span>
|
|
231
231
|
</div>
|
|
232
232
|
</div>
|
|
233
233
|
)
|
|
@@ -240,8 +240,8 @@ function PerBlockHints({ hints }: { hints: BuilderSEOCheck[] }) {
|
|
|
240
240
|
<div key={`${hint.id}-${index}`} className="flex items-start gap-2">
|
|
241
241
|
<StatusIcon status={hint.status} />
|
|
242
242
|
<div className="flex flex-col">
|
|
243
|
-
<span className="text-xs font-medium
|
|
244
|
-
<span className="text-
|
|
243
|
+
<span className="text-foreground text-xs font-medium">{hint.label}</span>
|
|
244
|
+
<span className="text-muted-foreground text-xs">{hint.detail}</span>
|
|
245
245
|
</div>
|
|
246
246
|
</div>
|
|
247
247
|
))}
|
|
@@ -263,7 +263,7 @@ function BasicSEOFields({
|
|
|
263
263
|
<div className="flex flex-col gap-4">
|
|
264
264
|
<div className="flex flex-col gap-1.5">
|
|
265
265
|
<div className="flex items-center justify-between">
|
|
266
|
-
<label className="text-xs font-medium
|
|
266
|
+
<label className="text-foreground text-xs font-medium">Meta Title</label>
|
|
267
267
|
<span
|
|
268
268
|
className={`text-xs ${metaTitleLength > 60 ? 'text-red-500' : metaTitleLength > 0 ? 'text-muted-foreground' : 'text-muted-foreground'}`}
|
|
269
269
|
>
|
|
@@ -275,13 +275,13 @@ function BasicSEOFields({
|
|
|
275
275
|
value={pageSettings.metaTitle || ''}
|
|
276
276
|
onChange={(e) => onPageSettingsChange({ metaTitle: e.target.value })}
|
|
277
277
|
placeholder="Page title for search engines"
|
|
278
|
-
className="
|
|
278
|
+
className="bg-input-background border-border text-foreground placeholder:text-muted-foreground focus:ring-primary w-full rounded-md border px-3 py-2 text-sm focus:ring-1 focus:outline-none"
|
|
279
279
|
/>
|
|
280
280
|
</div>
|
|
281
281
|
|
|
282
282
|
<div className="flex flex-col gap-1.5">
|
|
283
283
|
<div className="flex items-center justify-between">
|
|
284
|
-
<label className="text-xs font-medium
|
|
284
|
+
<label className="text-foreground text-xs font-medium">Meta Description</label>
|
|
285
285
|
<span
|
|
286
286
|
className={`text-xs ${metaDescLength > 160 ? 'text-red-500' : metaDescLength > 0 ? 'text-muted-foreground' : 'text-muted-foreground'}`}
|
|
287
287
|
>
|
|
@@ -293,18 +293,18 @@ function BasicSEOFields({
|
|
|
293
293
|
onChange={(e) => onPageSettingsChange({ metaDescription: e.target.value })}
|
|
294
294
|
placeholder="Brief description of the page content"
|
|
295
295
|
rows={3}
|
|
296
|
-
className="
|
|
296
|
+
className="bg-input-background border-border text-foreground placeholder:text-muted-foreground focus:ring-primary w-full resize-none rounded-md border px-3 py-2 text-sm focus:ring-1 focus:outline-none"
|
|
297
297
|
/>
|
|
298
298
|
</div>
|
|
299
299
|
|
|
300
300
|
<div className="flex flex-col gap-1.5">
|
|
301
|
-
<label className="text-xs font-medium
|
|
301
|
+
<label className="text-foreground text-xs font-medium">Focus Keyphrase</label>
|
|
302
302
|
<input
|
|
303
303
|
type="text"
|
|
304
304
|
value={pageSettings.focusKeyphrase || ''}
|
|
305
305
|
onChange={(e) => onPageSettingsChange({ focusKeyphrase: e.target.value })}
|
|
306
306
|
placeholder="Primary keyword or phrase"
|
|
307
|
-
className="
|
|
307
|
+
className="bg-input-background border-border text-foreground placeholder:text-muted-foreground focus:ring-primary w-full rounded-md border px-3 py-2 text-sm focus:ring-1 focus:outline-none"
|
|
308
308
|
/>
|
|
309
309
|
</div>
|
|
310
310
|
</div>
|
|
@@ -317,12 +317,12 @@ function SearchPreview({ pageSettings }: { pageSettings: PageSettings }) {
|
|
|
317
317
|
const slug = pageSettings.slug || 'page'
|
|
318
318
|
|
|
319
319
|
return (
|
|
320
|
-
<div className="bg-background rounded-md border
|
|
321
|
-
<p className="text-
|
|
320
|
+
<div className="bg-background border-border rounded-md border p-4">
|
|
321
|
+
<p className="text-muted-foreground mb-2 text-xs">Google Search Preview</p>
|
|
322
322
|
<div className="flex flex-col gap-1">
|
|
323
|
-
<p className="text-
|
|
324
|
-
<p className="text-xs text-green-600
|
|
325
|
-
<p className="text-
|
|
323
|
+
<p className="text-primary truncate text-sm">{title}</p>
|
|
324
|
+
<p className="truncate text-xs text-green-600">example.com/{slug}</p>
|
|
325
|
+
<p className="text-muted-foreground line-clamp-2 text-xs">{description}</p>
|
|
326
326
|
</div>
|
|
327
327
|
</div>
|
|
328
328
|
)
|
|
@@ -333,22 +333,22 @@ function SocialPreview({ pageSettings }: { pageSettings: PageSettings }) {
|
|
|
333
333
|
const description = pageSettings.metaDescription || 'No description set'
|
|
334
334
|
|
|
335
335
|
return (
|
|
336
|
-
<div className="bg-background
|
|
337
|
-
<p className="text-
|
|
336
|
+
<div className="bg-background border-border overflow-hidden rounded-md border">
|
|
337
|
+
<p className="text-muted-foreground px-4 pt-3 pb-2 text-xs">Open Graph Preview</p>
|
|
338
338
|
{pageSettings.ogImage && (
|
|
339
|
-
<div className="
|
|
340
|
-
<img src={pageSettings.ogImage} alt="OG preview" className="
|
|
339
|
+
<div className="bg-muted flex h-32 w-full items-center justify-center overflow-hidden">
|
|
340
|
+
<img src={pageSettings.ogImage} alt="OG preview" className="h-full w-full object-cover" />
|
|
341
341
|
</div>
|
|
342
342
|
)}
|
|
343
343
|
{!pageSettings.ogImage && (
|
|
344
|
-
<div className="
|
|
344
|
+
<div className="bg-muted flex h-32 w-full items-center justify-center">
|
|
345
345
|
<Globe size={24} className="text-muted-foreground" />
|
|
346
346
|
</div>
|
|
347
347
|
)}
|
|
348
|
-
<div className="
|
|
349
|
-
<p className="text-
|
|
350
|
-
<p className="text-sm font-medium
|
|
351
|
-
<p className="text-
|
|
348
|
+
<div className="flex flex-col gap-1 p-3">
|
|
349
|
+
<p className="text-muted-foreground text-xs uppercase">example.com</p>
|
|
350
|
+
<p className="text-foreground truncate text-sm font-medium">{title}</p>
|
|
351
|
+
<p className="text-muted-foreground line-clamp-2 text-xs">{description}</p>
|
|
352
352
|
</div>
|
|
353
353
|
</div>
|
|
354
354
|
)
|
|
@@ -380,10 +380,10 @@ export function BuilderSEOPanel({
|
|
|
380
380
|
|
|
381
381
|
if (!tree.children || tree.children.length === 0) {
|
|
382
382
|
return (
|
|
383
|
-
<div className="
|
|
383
|
+
<div className="flex min-h-[200px] flex-col items-center justify-center p-6 text-center">
|
|
384
384
|
<Search size={32} className="text-muted-foreground mb-3" />
|
|
385
|
-
<p className="text-
|
|
386
|
-
<p className="text-
|
|
385
|
+
<p className="text-foreground mb-1 text-sm font-medium">SEO Analysis</p>
|
|
386
|
+
<p className="text-muted-foreground text-xs">
|
|
387
387
|
Add content to your page to see SEO analysis
|
|
388
388
|
</p>
|
|
389
389
|
</div>
|
|
@@ -392,10 +392,10 @@ export function BuilderSEOPanel({
|
|
|
392
392
|
|
|
393
393
|
return (
|
|
394
394
|
<div className="flex flex-col">
|
|
395
|
-
<div className="flex items-center gap-4 px-4 py-5
|
|
395
|
+
<div className="border-border flex items-center gap-4 border-b px-4 py-5">
|
|
396
396
|
<ScoreRing score={analysis.score} />
|
|
397
397
|
<div className="flex flex-col gap-1">
|
|
398
|
-
<span className="text-xs font-medium
|
|
398
|
+
<span className="text-foreground text-xs font-medium">
|
|
399
399
|
{getScoreLabel(analysis.score)}
|
|
400
400
|
</span>
|
|
401
401
|
<ScoreSummary checks={analysis.checks} />
|