@prenta/admin 0.98.1 → 1.1.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/CHANGELOG.md +12 -0
- package/dist/AdminRoot.d.ts.map +1 -1
- package/dist/AdminRoot.js +22 -84
- package/dist/AdminRoot.js.map +1 -1
- package/dist/__tests__/components/breakpoint-controls.render.test.js +4 -4
- package/dist/__tests__/components/breakpoint-controls.render.test.js.map +1 -1
- package/dist/__tests__/components/seo-score-bands.test.js +0 -3
- package/dist/__tests__/components/seo-score-bands.test.js.map +1 -1
- package/dist/__tests__/layout/sidebar-posts.test.js +6 -11
- package/dist/__tests__/layout/sidebar-posts.test.js.map +1 -1
- package/dist/__tests__/layout/sidebar-submenu.render.test.js +3 -2
- package/dist/__tests__/layout/sidebar-submenu.render.test.js.map +1 -1
- package/dist/__tests__/lib/open-public-site-tab.test.d.ts +2 -0
- package/dist/__tests__/lib/open-public-site-tab.test.d.ts.map +1 -0
- package/dist/__tests__/lib/open-public-site-tab.test.js +64 -0
- package/dist/__tests__/lib/open-public-site-tab.test.js.map +1 -0
- package/dist/__tests__/lib/page-editor-service-api.test.js +26 -23
- package/dist/__tests__/lib/page-editor-service-api.test.js.map +1 -1
- package/dist/__tests__/lib/view-site-chrome.test.d.ts +2 -0
- package/dist/__tests__/lib/view-site-chrome.test.d.ts.map +1 -0
- package/dist/__tests__/lib/view-site-chrome.test.js +59 -0
- package/dist/__tests__/lib/view-site-chrome.test.js.map +1 -0
- package/dist/__tests__/router/admin-routes.test.js +4 -0
- package/dist/__tests__/router/admin-routes.test.js.map +1 -1
- package/dist/__tests__/views/canvas-surface-shared.test.js +0 -16
- package/dist/__tests__/views/canvas-surface-shared.test.js.map +1 -1
- package/dist/__tests__/views/editor-top-bar.render.test.js +44 -22
- package/dist/__tests__/views/editor-top-bar.render.test.js.map +1 -1
- package/dist/__tests__/views/page-section-editor.test.js +30 -10
- package/dist/__tests__/views/page-section-editor.test.js.map +1 -1
- package/dist/__tests__/views/page-tab.render.test.js +0 -1
- package/dist/__tests__/views/page-tab.render.test.js.map +1 -1
- package/dist/__tests__/views/post-section-editor.test.js +23 -0
- package/dist/__tests__/views/post-section-editor.test.js.map +1 -1
- package/dist/components/BreakpointPicker.d.ts +3 -2
- package/dist/components/BreakpointPicker.d.ts.map +1 -1
- package/dist/components/BreakpointPicker.js +5 -3
- package/dist/components/BreakpointPicker.js.map +1 -1
- package/dist/components/CanvasEditTip.js +1 -1
- package/dist/components/CanvasEditTip.js.map +1 -1
- package/dist/index.d.ts +1 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/layout/Sidebar.d.ts +3 -4
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/Sidebar.js +7 -38
- package/dist/layout/Sidebar.js.map +1 -1
- package/dist/lib/editor-preview.d.ts +4 -1
- package/dist/lib/editor-preview.d.ts.map +1 -1
- package/dist/lib/editor-preview.js +4 -1
- package/dist/lib/editor-preview.js.map +1 -1
- package/dist/lib/open-public-site-tab.d.ts +14 -0
- package/dist/lib/open-public-site-tab.d.ts.map +1 -0
- package/dist/lib/open-public-site-tab.js +46 -0
- package/dist/lib/open-public-site-tab.js.map +1 -0
- package/dist/lib/page-editor-service.d.ts +0 -7
- package/dist/lib/page-editor-service.d.ts.map +1 -1
- package/dist/lib/page-editor-service.js +9 -9
- package/dist/lib/page-editor-service.js.map +1 -1
- package/dist/lib/view-site-chrome.d.ts +16 -0
- package/dist/lib/view-site-chrome.d.ts.map +1 -0
- package/dist/lib/view-site-chrome.js +15 -0
- package/dist/lib/view-site-chrome.js.map +1 -0
- package/dist/prenta-admin.css +1 -1
- package/dist/router/admin-routes.d.ts.map +1 -1
- package/dist/router/admin-routes.js +0 -2
- package/dist/router/admin-routes.js.map +1 -1
- package/dist/views/PageEditor.d.ts +2 -2
- package/dist/views/PageEditor.js +2 -2
- package/dist/views/page-editor/EditorCanvas.d.ts +1 -2
- package/dist/views/page-editor/EditorCanvas.d.ts.map +1 -1
- package/dist/views/page-editor/EditorCanvas.js +2 -2
- package/dist/views/page-editor/EditorCanvas.js.map +1 -1
- package/dist/views/page-editor/EditorTopBar.d.ts +13 -17
- package/dist/views/page-editor/EditorTopBar.d.ts.map +1 -1
- package/dist/views/page-editor/EditorTopBar.js +19 -21
- package/dist/views/page-editor/EditorTopBar.js.map +1 -1
- package/dist/views/page-editor/PageSectionEditor.d.ts +1 -7
- package/dist/views/page-editor/PageSectionEditor.d.ts.map +1 -1
- package/dist/views/page-editor/PageSectionEditor.js +38 -110
- package/dist/views/page-editor/PageSectionEditor.js.map +1 -1
- package/dist/views/page-editor/StructureNotice.d.ts +2 -5
- package/dist/views/page-editor/StructureNotice.d.ts.map +1 -1
- package/dist/views/page-editor/StructureNotice.js +6 -10
- package/dist/views/page-editor/StructureNotice.js.map +1 -1
- package/dist/views/post-editor/PostEditorCanvas.d.ts +1 -3
- package/dist/views/post-editor/PostEditorCanvas.d.ts.map +1 -1
- package/dist/views/post-editor/PostEditorCanvas.js +3 -3
- package/dist/views/post-editor/PostEditorCanvas.js.map +1 -1
- package/dist/views/post-editor/PostSectionEditor.d.ts +1 -15
- package/dist/views/post-editor/PostSectionEditor.d.ts.map +1 -1
- package/dist/views/post-editor/PostSectionEditor.js +30 -88
- package/dist/views/post-editor/PostSectionEditor.js.map +1 -1
- package/package.json +3 -3
- package/src/AdminRoot.tsx +18 -138
- package/src/__tests__/components/breakpoint-controls.render.test.tsx +6 -4
- package/src/__tests__/components/seo-score-bands.test.ts +0 -3
- package/src/__tests__/layout/sidebar-posts.test.ts +6 -11
- package/src/__tests__/layout/sidebar-submenu.render.test.tsx +3 -2
- package/src/__tests__/lib/open-public-site-tab.test.ts +74 -0
- package/src/__tests__/lib/page-editor-service-api.test.ts +27 -25
- package/src/__tests__/lib/view-site-chrome.test.ts +65 -0
- package/src/__tests__/router/admin-routes.test.ts +5 -0
- package/src/__tests__/views/canvas-surface-shared.test.ts +0 -19
- package/src/__tests__/views/editor-top-bar.render.test.tsx +85 -22
- package/src/__tests__/views/page-section-editor.test.tsx +42 -10
- package/src/__tests__/views/page-tab.render.test.tsx +0 -1
- package/src/__tests__/views/post-section-editor.test.tsx +35 -0
- package/src/components/BreakpointPicker.tsx +6 -3
- package/src/components/CanvasEditTip.tsx +2 -2
- package/src/index.ts +1 -11
- package/src/layout/Sidebar.tsx +6 -41
- package/src/lib/editor-preview.ts +4 -1
- package/src/lib/open-public-site-tab.ts +57 -0
- package/src/lib/page-editor-service.ts +9 -16
- package/src/lib/view-site-chrome.ts +34 -0
- package/src/router/admin-routes.ts +0 -2
- package/src/styles/theme.css +4 -4
- package/src/views/PageEditor.tsx +2 -2
- package/src/views/page-editor/EditorCanvas.tsx +1 -6
- package/src/views/page-editor/EditorTopBar.tsx +81 -82
- package/src/views/page-editor/PageSectionEditor.tsx +85 -194
- package/src/views/page-editor/StructureNotice.tsx +7 -42
- package/src/views/post-editor/PostEditorCanvas.tsx +2 -8
- package/src/views/post-editor/PostSectionEditor.tsx +66 -138
- package/dist/__tests__/views/page-builder-block-renderer.render.test.d.ts +0 -2
- package/dist/__tests__/views/page-builder-block-renderer.render.test.d.ts.map +0 -1
- package/dist/__tests__/views/page-builder-block-renderer.render.test.js +0 -48
- package/dist/__tests__/views/page-builder-block-renderer.render.test.js.map +0 -1
- package/dist/__tests__/views/page-builder-form-picker.render.test.d.ts +0 -2
- package/dist/__tests__/views/page-builder-form-picker.render.test.d.ts.map +0 -1
- package/dist/__tests__/views/page-builder-form-picker.render.test.js +0 -44
- package/dist/__tests__/views/page-builder-form-picker.render.test.js.map +0 -1
- package/dist/__tests__/views/page-builder-sections-panel.render.test.d.ts +0 -2
- package/dist/__tests__/views/page-builder-sections-panel.render.test.d.ts.map +0 -1
- package/dist/__tests__/views/page-builder-sections-panel.render.test.js +0 -121
- package/dist/__tests__/views/page-builder-sections-panel.render.test.js.map +0 -1
- package/dist/__tests__/views/page-builder-seo-panel.render.test.d.ts +0 -2
- package/dist/__tests__/views/page-builder-seo-panel.render.test.d.ts.map +0 -1
- package/dist/__tests__/views/page-builder-seo-panel.render.test.js +0 -65
- package/dist/__tests__/views/page-builder-seo-panel.render.test.js.map +0 -1
- package/dist/__tests__/views/page-builder-template-seed.render.test.d.ts +0 -2
- package/dist/__tests__/views/page-builder-template-seed.render.test.d.ts.map +0 -1
- package/dist/__tests__/views/page-builder-template-seed.render.test.js +0 -48
- package/dist/__tests__/views/page-builder-template-seed.render.test.js.map +0 -1
- package/dist/__tests__/views/page-templates.render.test.d.ts +0 -2
- package/dist/__tests__/views/page-templates.render.test.d.ts.map +0 -1
- package/dist/__tests__/views/page-templates.render.test.js +0 -126
- package/dist/__tests__/views/page-templates.render.test.js.map +0 -1
- package/dist/__tests__/views/use-site-preview.render.test.d.ts +0 -2
- package/dist/__tests__/views/use-site-preview.render.test.d.ts.map +0 -1
- package/dist/__tests__/views/use-site-preview.render.test.js +0 -120
- package/dist/__tests__/views/use-site-preview.render.test.js.map +0 -1
- package/dist/hooks/useBuilderState.d.ts +0 -49
- package/dist/hooks/useBuilderState.d.ts.map +0 -1
- package/dist/hooks/useBuilderState.js +0 -238
- package/dist/hooks/useBuilderState.js.map +0 -1
- package/dist/views/page-builder/AIBlockAssist.d.ts +0 -9
- package/dist/views/page-builder/AIBlockAssist.d.ts.map +0 -1
- package/dist/views/page-builder/AIBlockAssist.js +0 -40
- package/dist/views/page-builder/AIBlockAssist.js.map +0 -1
- package/dist/views/page-builder/AIGenerateDialog.d.ts +0 -8
- package/dist/views/page-builder/AIGenerateDialog.d.ts.map +0 -1
- package/dist/views/page-builder/AIGenerateDialog.js +0 -173
- package/dist/views/page-builder/AIGenerateDialog.js.map +0 -1
- package/dist/views/page-builder/BlockEditor.d.ts +0 -11
- package/dist/views/page-builder/BlockEditor.d.ts.map +0 -1
- package/dist/views/page-builder/BlockEditor.js +0 -159
- package/dist/views/page-builder/BlockEditor.js.map +0 -1
- package/dist/views/page-builder/BlockPicker.d.ts +0 -7
- package/dist/views/page-builder/BlockPicker.d.ts.map +0 -1
- package/dist/views/page-builder/BlockPicker.js +0 -103
- package/dist/views/page-builder/BlockPicker.js.map +0 -1
- package/dist/views/page-builder/BottomBar.d.ts +0 -9
- package/dist/views/page-builder/BottomBar.d.ts.map +0 -1
- package/dist/views/page-builder/BottomBar.js +0 -13
- package/dist/views/page-builder/BottomBar.js.map +0 -1
- package/dist/views/page-builder/BuilderSectionsPanel.d.ts +0 -20
- package/dist/views/page-builder/BuilderSectionsPanel.d.ts.map +0 -1
- package/dist/views/page-builder/BuilderSectionsPanel.js +0 -105
- package/dist/views/page-builder/BuilderSectionsPanel.js.map +0 -1
- package/dist/views/page-builder/BuilderToolbar.d.ts +0 -21
- package/dist/views/page-builder/BuilderToolbar.d.ts.map +0 -1
- package/dist/views/page-builder/BuilderToolbar.js +0 -18
- package/dist/views/page-builder/BuilderToolbar.js.map +0 -1
- package/dist/views/page-builder/ContextPanel.d.ts +0 -20
- package/dist/views/page-builder/ContextPanel.d.ts.map +0 -1
- package/dist/views/page-builder/ContextPanel.js +0 -43
- package/dist/views/page-builder/ContextPanel.js.map +0 -1
- package/dist/views/page-builder/DesignScore.d.ts +0 -6
- package/dist/views/page-builder/DesignScore.d.ts.map +0 -1
- package/dist/views/page-builder/DesignScore.js +0 -93
- package/dist/views/page-builder/DesignScore.js.map +0 -1
- package/dist/views/page-builder/NodeSettings.d.ts +0 -12
- package/dist/views/page-builder/NodeSettings.d.ts.map +0 -1
- package/dist/views/page-builder/NodeSettings.js +0 -80
- package/dist/views/page-builder/NodeSettings.js.map +0 -1
- package/dist/views/page-builder/PageBuilder.d.ts +0 -10
- package/dist/views/page-builder/PageBuilder.d.ts.map +0 -1
- package/dist/views/page-builder/PageBuilder.js +0 -222
- package/dist/views/page-builder/PageBuilder.js.map +0 -1
- package/dist/views/page-builder/PageSettings.d.ts +0 -7
- package/dist/views/page-builder/PageSettings.d.ts.map +0 -1
- package/dist/views/page-builder/PageSettings.js +0 -27
- package/dist/views/page-builder/PageSettings.js.map +0 -1
- package/dist/views/page-builder/PageTemplates.d.ts +0 -5
- package/dist/views/page-builder/PageTemplates.d.ts.map +0 -1
- package/dist/views/page-builder/PageTemplates.js +0 -146
- package/dist/views/page-builder/PageTemplates.js.map +0 -1
- package/dist/views/page-builder/RelationshipField.d.ts +0 -15
- package/dist/views/page-builder/RelationshipField.d.ts.map +0 -1
- package/dist/views/page-builder/RelationshipField.js +0 -65
- package/dist/views/page-builder/RelationshipField.js.map +0 -1
- package/dist/views/page-builder/SEOPanel.d.ts +0 -9
- package/dist/views/page-builder/SEOPanel.d.ts.map +0 -1
- package/dist/views/page-builder/SEOPanel.js +0 -38
- package/dist/views/page-builder/SEOPanel.js.map +0 -1
- package/dist/views/page-builder/SavedSections.d.ts +0 -6
- package/dist/views/page-builder/SavedSections.d.ts.map +0 -1
- package/dist/views/page-builder/SavedSections.js +0 -141
- package/dist/views/page-builder/SavedSections.js.map +0 -1
- package/dist/views/page-builder/TemplatePicker.d.ts +0 -7
- package/dist/views/page-builder/TemplatePicker.d.ts.map +0 -1
- package/dist/views/page-builder/TemplatePicker.js +0 -68
- package/dist/views/page-builder/TemplatePicker.js.map +0 -1
- package/dist/views/page-builder/Widgets.d.ts +0 -13
- package/dist/views/page-builder/Widgets.d.ts.map +0 -1
- package/dist/views/page-builder/Widgets.js +0 -15
- package/dist/views/page-builder/Widgets.js.map +0 -1
- package/dist/views/page-builder/block-renderers/CTAPreview.d.ts +0 -3
- package/dist/views/page-builder/block-renderers/CTAPreview.d.ts.map +0 -1
- package/dist/views/page-builder/block-renderers/CTAPreview.js +0 -19
- package/dist/views/page-builder/block-renderers/CTAPreview.js.map +0 -1
- package/dist/views/page-builder/block-renderers/CardsPreview.d.ts +0 -3
- package/dist/views/page-builder/block-renderers/CardsPreview.d.ts.map +0 -1
- package/dist/views/page-builder/block-renderers/CardsPreview.js +0 -22
- package/dist/views/page-builder/block-renderers/CardsPreview.js.map +0 -1
- package/dist/views/page-builder/block-renderers/CodePreview.d.ts +0 -3
- package/dist/views/page-builder/block-renderers/CodePreview.d.ts.map +0 -1
- package/dist/views/page-builder/block-renderers/CodePreview.js +0 -12
- package/dist/views/page-builder/block-renderers/CodePreview.js.map +0 -1
- package/dist/views/page-builder/block-renderers/FAQPreview.d.ts +0 -3
- package/dist/views/page-builder/block-renderers/FAQPreview.d.ts.map +0 -1
- package/dist/views/page-builder/block-renderers/FAQPreview.js +0 -27
- package/dist/views/page-builder/block-renderers/FAQPreview.js.map +0 -1
- package/dist/views/page-builder/block-renderers/FallbackPreview.d.ts +0 -6
- package/dist/views/page-builder/block-renderers/FallbackPreview.d.ts.map +0 -1
- package/dist/views/page-builder/block-renderers/FallbackPreview.js +0 -7
- package/dist/views/page-builder/block-renderers/FallbackPreview.js.map +0 -1
- package/dist/views/page-builder/block-renderers/FormPreview.d.ts +0 -9
- package/dist/views/page-builder/block-renderers/FormPreview.d.ts.map +0 -1
- package/dist/views/page-builder/block-renderers/FormPreview.js +0 -52
- package/dist/views/page-builder/block-renderers/FormPreview.js.map +0 -1
- package/dist/views/page-builder/block-renderers/GalleryPreview.d.ts +0 -3
- package/dist/views/page-builder/block-renderers/GalleryPreview.d.ts.map +0 -1
- package/dist/views/page-builder/block-renderers/GalleryPreview.js +0 -19
- package/dist/views/page-builder/block-renderers/GalleryPreview.js.map +0 -1
- package/dist/views/page-builder/block-renderers/HeroPreview.d.ts +0 -3
- package/dist/views/page-builder/block-renderers/HeroPreview.d.ts.map +0 -1
- package/dist/views/page-builder/block-renderers/HeroPreview.js +0 -19
- package/dist/views/page-builder/block-renderers/HeroPreview.js.map +0 -1
- package/dist/views/page-builder/block-renderers/ImagePreview.d.ts +0 -3
- package/dist/views/page-builder/block-renderers/ImagePreview.d.ts.map +0 -1
- package/dist/views/page-builder/block-renderers/ImagePreview.js +0 -17
- package/dist/views/page-builder/block-renderers/ImagePreview.js.map +0 -1
- package/dist/views/page-builder/block-renderers/TextPreview.d.ts +0 -3
- package/dist/views/page-builder/block-renderers/TextPreview.d.ts.map +0 -1
- package/dist/views/page-builder/block-renderers/TextPreview.js +0 -22
- package/dist/views/page-builder/block-renderers/TextPreview.js.map +0 -1
- package/dist/views/page-builder/block-renderers/VideoPreview.d.ts +0 -3
- package/dist/views/page-builder/block-renderers/VideoPreview.d.ts.map +0 -1
- package/dist/views/page-builder/block-renderers/VideoPreview.js +0 -18
- package/dist/views/page-builder/block-renderers/VideoPreview.js.map +0 -1
- package/dist/views/page-builder/block-renderers/index.d.ts +0 -9
- package/dist/views/page-builder/block-renderers/index.d.ts.map +0 -1
- package/dist/views/page-builder/block-renderers/index.js +0 -25
- package/dist/views/page-builder/block-renderers/index.js.map +0 -1
- package/dist/views/page-builder/canvas/BlockRenderer.d.ts +0 -8
- package/dist/views/page-builder/canvas/BlockRenderer.d.ts.map +0 -1
- package/dist/views/page-builder/canvas/BlockRenderer.js +0 -20
- package/dist/views/page-builder/canvas/BlockRenderer.js.map +0 -1
- package/dist/views/page-builder/canvas/BuilderCanvas.d.ts +0 -10
- package/dist/views/page-builder/canvas/BuilderCanvas.d.ts.map +0 -1
- package/dist/views/page-builder/canvas/BuilderCanvas.js +0 -26
- package/dist/views/page-builder/canvas/BuilderCanvas.js.map +0 -1
- package/dist/views/page-builder/canvas/ColumnRenderer.d.ts +0 -8
- package/dist/views/page-builder/canvas/ColumnRenderer.d.ts.map +0 -1
- package/dist/views/page-builder/canvas/ColumnRenderer.js +0 -32
- package/dist/views/page-builder/canvas/ColumnRenderer.js.map +0 -1
- package/dist/views/page-builder/canvas/ContainerRenderer.d.ts +0 -8
- package/dist/views/page-builder/canvas/ContainerRenderer.d.ts.map +0 -1
- package/dist/views/page-builder/canvas/ContainerRenderer.js +0 -29
- package/dist/views/page-builder/canvas/ContainerRenderer.js.map +0 -1
- package/dist/views/page-builder/canvas/RowRenderer.d.ts +0 -8
- package/dist/views/page-builder/canvas/RowRenderer.d.ts.map +0 -1
- package/dist/views/page-builder/canvas/RowRenderer.js +0 -28
- package/dist/views/page-builder/canvas/RowRenderer.js.map +0 -1
- package/dist/views/page-builder/canvas/SectionRenderer.d.ts +0 -8
- package/dist/views/page-builder/canvas/SectionRenderer.d.ts.map +0 -1
- package/dist/views/page-builder/canvas/SectionRenderer.js +0 -50
- package/dist/views/page-builder/canvas/SectionRenderer.js.map +0 -1
- package/dist/views/page-builder/canvas/index.d.ts +0 -3
- package/dist/views/page-builder/canvas/index.d.ts.map +0 -1
- package/dist/views/page-builder/canvas/index.js +0 -2
- package/dist/views/page-builder/canvas/index.js.map +0 -1
- package/dist/views/page-editor/PagePreview.d.ts +0 -13
- package/dist/views/page-editor/PagePreview.d.ts.map +0 -1
- package/dist/views/page-editor/PagePreview.js +0 -46
- package/dist/views/page-editor/PagePreview.js.map +0 -1
- package/dist/views/page-editor/SitePreviewFrame.d.ts +0 -43
- package/dist/views/page-editor/SitePreviewFrame.d.ts.map +0 -1
- package/dist/views/page-editor/SitePreviewFrame.js +0 -165
- package/dist/views/page-editor/SitePreviewFrame.js.map +0 -1
- package/dist/views/page-editor/useSitePreview.d.ts +0 -47
- package/dist/views/page-editor/useSitePreview.d.ts.map +0 -1
- package/dist/views/page-editor/useSitePreview.js +0 -96
- package/dist/views/page-editor/useSitePreview.js.map +0 -1
- package/dist/views/post-editor/PostPreview.d.ts +0 -14
- package/dist/views/post-editor/PostPreview.d.ts.map +0 -1
- package/dist/views/post-editor/PostPreview.js +0 -63
- package/dist/views/post-editor/PostPreview.js.map +0 -1
- package/src/__tests__/views/page-builder-block-renderer.render.test.tsx +0 -66
- package/src/__tests__/views/page-builder-form-picker.render.test.tsx +0 -54
- package/src/__tests__/views/page-builder-sections-panel.render.test.tsx +0 -138
- package/src/__tests__/views/page-builder-seo-panel.render.test.tsx +0 -77
- package/src/__tests__/views/page-builder-template-seed.render.test.tsx +0 -59
- package/src/__tests__/views/page-templates.render.test.tsx +0 -182
- package/src/__tests__/views/use-site-preview.render.test.tsx +0 -164
- package/src/hooks/useBuilderState.ts +0 -361
- package/src/views/page-builder/AIBlockAssist.tsx +0 -64
- package/src/views/page-builder/AIGenerateDialog.tsx +0 -593
- package/src/views/page-builder/BlockEditor.tsx +0 -523
- package/src/views/page-builder/BlockPicker.tsx +0 -324
- package/src/views/page-builder/BottomBar.tsx +0 -65
- package/src/views/page-builder/BuilderSectionsPanel.tsx +0 -304
- package/src/views/page-builder/BuilderToolbar.tsx +0 -221
- package/src/views/page-builder/ContextPanel.tsx +0 -144
- package/src/views/page-builder/DesignScore.tsx +0 -251
- package/src/views/page-builder/NodeSettings.tsx +0 -500
- package/src/views/page-builder/PageBuilder.tsx +0 -405
- package/src/views/page-builder/PageSettings.tsx +0 -162
- package/src/views/page-builder/PageTemplates.tsx +0 -435
- package/src/views/page-builder/RelationshipField.tsx +0 -113
- package/src/views/page-builder/SEOPanel.tsx +0 -222
- package/src/views/page-builder/SavedSections.tsx +0 -480
- package/src/views/page-builder/TemplatePicker.tsx +0 -197
- package/src/views/page-builder/Widgets.tsx +0 -44
- package/src/views/page-builder/block-renderers/CTAPreview.tsx +0 -79
- package/src/views/page-builder/block-renderers/CardsPreview.tsx +0 -69
- package/src/views/page-builder/block-renderers/CodePreview.tsx +0 -46
- package/src/views/page-builder/block-renderers/FAQPreview.tsx +0 -87
- package/src/views/page-builder/block-renderers/FallbackPreview.tsx +0 -18
- package/src/views/page-builder/block-renderers/FormPreview.tsx +0 -117
- package/src/views/page-builder/block-renderers/GalleryPreview.tsx +0 -87
- package/src/views/page-builder/block-renderers/HeroPreview.tsx +0 -90
- package/src/views/page-builder/block-renderers/ImagePreview.tsx +0 -54
- package/src/views/page-builder/block-renderers/TextPreview.tsx +0 -81
- package/src/views/page-builder/block-renderers/VideoPreview.tsx +0 -73
- package/src/views/page-builder/block-renderers/index.ts +0 -34
- package/src/views/page-builder/canvas/BlockRenderer.tsx +0 -56
- package/src/views/page-builder/canvas/BuilderCanvas.tsx +0 -87
- package/src/views/page-builder/canvas/ColumnRenderer.tsx +0 -82
- package/src/views/page-builder/canvas/ContainerRenderer.tsx +0 -67
- package/src/views/page-builder/canvas/RowRenderer.tsx +0 -68
- package/src/views/page-builder/canvas/SectionRenderer.tsx +0 -93
- package/src/views/page-builder/canvas/index.ts +0 -2
- package/src/views/page-editor/PagePreview.tsx +0 -105
- package/src/views/page-editor/SitePreviewFrame.tsx +0 -250
- package/src/views/page-editor/useSitePreview.ts +0 -158
- package/src/views/post-editor/PostPreview.tsx +0 -125
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useMemo, useState } from 'react'
|
|
4
|
-
import type { PageNode } from '@prenta/core'
|
|
5
|
-
import { auditPage } from '@prenta/core/seo/page-audit'
|
|
6
|
-
import { ChevronDown, ChevronUp, Eye, FileText, Globe, Search } from 'lucide-react'
|
|
7
|
-
import { PageAuditPanel } from '../../components/seo/PageAuditPanel.js'
|
|
8
|
-
import { buildPageAuditInputFromBuilder } from '../../lib/page-audit-input.js'
|
|
9
|
-
import type { PageSettings } from '../../hooks/useBuilderState.js'
|
|
10
|
-
|
|
11
|
-
export interface BuilderSEOPanelProps {
|
|
12
|
-
tree: PageNode
|
|
13
|
-
pageSettings: PageSettings
|
|
14
|
-
onPageSettingsChange: (settings: Partial<PageSettings>) => void
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function CollapsibleSection({
|
|
18
|
-
title,
|
|
19
|
-
icon: Icon,
|
|
20
|
-
expanded,
|
|
21
|
-
onToggle,
|
|
22
|
-
children,
|
|
23
|
-
}: {
|
|
24
|
-
title: string
|
|
25
|
-
icon: typeof Search
|
|
26
|
-
expanded: boolean
|
|
27
|
-
onToggle: () => void
|
|
28
|
-
children: React.ReactNode
|
|
29
|
-
}) {
|
|
30
|
-
return (
|
|
31
|
-
<div className="border-border border-b last:border-b-0">
|
|
32
|
-
<button
|
|
33
|
-
type="button"
|
|
34
|
-
className="hover:bg-muted/50 flex w-full items-center justify-between px-4 py-3 text-left transition-colors"
|
|
35
|
-
onClick={onToggle}
|
|
36
|
-
aria-expanded={expanded}
|
|
37
|
-
>
|
|
38
|
-
<div className="flex items-center gap-2">
|
|
39
|
-
<Icon size={14} className="text-muted-foreground" />
|
|
40
|
-
<span className="text-foreground text-xs font-medium">{title}</span>
|
|
41
|
-
</div>
|
|
42
|
-
{expanded ? (
|
|
43
|
-
<ChevronUp size={14} className="text-muted-foreground" />
|
|
44
|
-
) : (
|
|
45
|
-
<ChevronDown size={14} className="text-muted-foreground" />
|
|
46
|
-
)}
|
|
47
|
-
</button>
|
|
48
|
-
{expanded && <div className="px-4 pb-4">{children}</div>}
|
|
49
|
-
</div>
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function BasicSEOFields({
|
|
54
|
-
pageSettings,
|
|
55
|
-
onPageSettingsChange,
|
|
56
|
-
}: {
|
|
57
|
-
pageSettings: PageSettings
|
|
58
|
-
onPageSettingsChange: (settings: Partial<PageSettings>) => void
|
|
59
|
-
}) {
|
|
60
|
-
const metaTitleLength = (pageSettings.metaTitle || '').length
|
|
61
|
-
const metaDescLength = (pageSettings.metaDescription || '').length
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<div className="flex flex-col gap-4">
|
|
65
|
-
<div className="flex flex-col gap-1.5">
|
|
66
|
-
<div className="flex items-center justify-between">
|
|
67
|
-
<label htmlFor="builder-meta-title" className="text-foreground text-xs font-medium">
|
|
68
|
-
Meta Title
|
|
69
|
-
</label>
|
|
70
|
-
<span
|
|
71
|
-
className={`text-xs ${metaTitleLength > 60 ? 'text-destructive' : metaTitleLength > 0 ? 'text-muted-foreground' : 'text-muted-foreground'}`}
|
|
72
|
-
>
|
|
73
|
-
{metaTitleLength}/60
|
|
74
|
-
</span>
|
|
75
|
-
</div>
|
|
76
|
-
<input
|
|
77
|
-
id="builder-meta-title"
|
|
78
|
-
type="text"
|
|
79
|
-
value={pageSettings.metaTitle || ''}
|
|
80
|
-
onChange={(e) => onPageSettingsChange({ metaTitle: e.target.value })}
|
|
81
|
-
placeholder="Page title for search engines"
|
|
82
|
-
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"
|
|
83
|
-
/>
|
|
84
|
-
</div>
|
|
85
|
-
|
|
86
|
-
<div className="flex flex-col gap-1.5">
|
|
87
|
-
<div className="flex items-center justify-between">
|
|
88
|
-
<label className="text-foreground text-xs font-medium">Meta Description</label>
|
|
89
|
-
<span
|
|
90
|
-
className={`text-xs ${metaDescLength > 160 ? 'text-destructive' : metaDescLength > 0 ? 'text-muted-foreground' : 'text-muted-foreground'}`}
|
|
91
|
-
>
|
|
92
|
-
{metaDescLength}/160
|
|
93
|
-
</span>
|
|
94
|
-
</div>
|
|
95
|
-
<textarea
|
|
96
|
-
value={pageSettings.metaDescription || ''}
|
|
97
|
-
onChange={(e) => onPageSettingsChange({ metaDescription: e.target.value })}
|
|
98
|
-
placeholder="Brief description of the page content"
|
|
99
|
-
rows={3}
|
|
100
|
-
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"
|
|
101
|
-
/>
|
|
102
|
-
</div>
|
|
103
|
-
|
|
104
|
-
<div className="flex flex-col gap-1.5">
|
|
105
|
-
<label className="text-foreground text-xs font-medium">Focus Keyphrase</label>
|
|
106
|
-
<input
|
|
107
|
-
type="text"
|
|
108
|
-
value={pageSettings.focusKeyphrase || ''}
|
|
109
|
-
onChange={(e) => onPageSettingsChange({ focusKeyphrase: e.target.value })}
|
|
110
|
-
placeholder="Primary keyword or phrase"
|
|
111
|
-
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"
|
|
112
|
-
/>
|
|
113
|
-
</div>
|
|
114
|
-
</div>
|
|
115
|
-
)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function SearchPreview({ pageSettings }: { pageSettings: PageSettings }) {
|
|
119
|
-
const title = pageSettings.metaTitle || pageSettings.title || 'Untitled Page'
|
|
120
|
-
const description = pageSettings.metaDescription || 'No description set'
|
|
121
|
-
const slug = pageSettings.slug || 'page'
|
|
122
|
-
|
|
123
|
-
return (
|
|
124
|
-
<div className="bg-background border-border rounded-md border p-4">
|
|
125
|
-
<p className="text-muted-foreground mb-2 text-xs">Google Search Preview</p>
|
|
126
|
-
<div className="flex flex-col gap-1">
|
|
127
|
-
<p className="text-primary truncate text-sm">{title}</p>
|
|
128
|
-
<p className="text-success truncate text-xs">example.com/{slug}</p>
|
|
129
|
-
<p className="text-muted-foreground line-clamp-2 text-xs">{description}</p>
|
|
130
|
-
</div>
|
|
131
|
-
</div>
|
|
132
|
-
)
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function SocialPreview({ pageSettings }: { pageSettings: PageSettings }) {
|
|
136
|
-
const title = pageSettings.metaTitle || pageSettings.title || 'Untitled Page'
|
|
137
|
-
const description = pageSettings.metaDescription || 'No description set'
|
|
138
|
-
|
|
139
|
-
return (
|
|
140
|
-
<div className="bg-background border-border overflow-hidden rounded-md border">
|
|
141
|
-
<p className="text-muted-foreground px-4 pt-3 pb-2 text-xs">Open Graph Preview</p>
|
|
142
|
-
{pageSettings.ogImage && (
|
|
143
|
-
<div className="bg-muted flex h-32 w-full items-center justify-center overflow-hidden">
|
|
144
|
-
<img src={pageSettings.ogImage} alt="OG preview" className="h-full w-full object-cover" />
|
|
145
|
-
</div>
|
|
146
|
-
)}
|
|
147
|
-
{!pageSettings.ogImage && (
|
|
148
|
-
<div className="bg-muted flex h-32 w-full items-center justify-center">
|
|
149
|
-
<Globe size={24} className="text-muted-foreground" />
|
|
150
|
-
</div>
|
|
151
|
-
)}
|
|
152
|
-
<div className="flex flex-col gap-1 p-3">
|
|
153
|
-
<p className="text-muted-foreground text-xs uppercase">example.com</p>
|
|
154
|
-
<p className="text-foreground truncate text-sm font-medium">{title}</p>
|
|
155
|
-
<p className="text-muted-foreground line-clamp-2 text-xs">{description}</p>
|
|
156
|
-
</div>
|
|
157
|
-
</div>
|
|
158
|
-
)
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export function BuilderSEOPanel({
|
|
162
|
-
tree,
|
|
163
|
-
pageSettings,
|
|
164
|
-
onPageSettingsChange,
|
|
165
|
-
}: BuilderSEOPanelProps) {
|
|
166
|
-
const audit = useMemo(
|
|
167
|
-
() => auditPage(buildPageAuditInputFromBuilder({ tree, pageSettings })),
|
|
168
|
-
[tree, pageSettings],
|
|
169
|
-
)
|
|
170
|
-
const [expandedSections, setExpandedSections] = useState<string[]>(['basicSeo'])
|
|
171
|
-
|
|
172
|
-
const toggleSection = (section: string) => {
|
|
173
|
-
setExpandedSections((prev) =>
|
|
174
|
-
prev.includes(section) ? prev.filter((s) => s !== section) : [...prev, section],
|
|
175
|
-
)
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (!tree.children || tree.children.length === 0) {
|
|
179
|
-
return (
|
|
180
|
-
<div className="flex min-h-[200px] flex-col items-center justify-center p-6 text-center">
|
|
181
|
-
<Search size={32} className="text-muted-foreground mb-3" />
|
|
182
|
-
<p className="text-foreground mb-1 text-sm font-medium">SEO Analysis</p>
|
|
183
|
-
<p className="text-muted-foreground text-xs">
|
|
184
|
-
Add content to your page to see SEO analysis
|
|
185
|
-
</p>
|
|
186
|
-
</div>
|
|
187
|
-
)
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return (
|
|
191
|
-
<div className="flex flex-col">
|
|
192
|
-
<PageAuditPanel audit={audit} />
|
|
193
|
-
|
|
194
|
-
<CollapsibleSection
|
|
195
|
-
title="Basic SEO"
|
|
196
|
-
icon={FileText}
|
|
197
|
-
expanded={expandedSections.includes('basicSeo')}
|
|
198
|
-
onToggle={() => toggleSection('basicSeo')}
|
|
199
|
-
>
|
|
200
|
-
<BasicSEOFields pageSettings={pageSettings} onPageSettingsChange={onPageSettingsChange} />
|
|
201
|
-
</CollapsibleSection>
|
|
202
|
-
|
|
203
|
-
<CollapsibleSection
|
|
204
|
-
title="Search Preview"
|
|
205
|
-
icon={Eye}
|
|
206
|
-
expanded={expandedSections.includes('searchPreview')}
|
|
207
|
-
onToggle={() => toggleSection('searchPreview')}
|
|
208
|
-
>
|
|
209
|
-
<SearchPreview pageSettings={pageSettings} />
|
|
210
|
-
</CollapsibleSection>
|
|
211
|
-
|
|
212
|
-
<CollapsibleSection
|
|
213
|
-
title="Social Preview"
|
|
214
|
-
icon={Globe}
|
|
215
|
-
expanded={expandedSections.includes('socialPreview')}
|
|
216
|
-
onToggle={() => toggleSection('socialPreview')}
|
|
217
|
-
>
|
|
218
|
-
<SocialPreview pageSettings={pageSettings} />
|
|
219
|
-
</CollapsibleSection>
|
|
220
|
-
</div>
|
|
221
|
-
)
|
|
222
|
-
}
|
|
@@ -1,480 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState, useEffect, useCallback } from 'react'
|
|
4
|
-
import {
|
|
5
|
-
Plus,
|
|
6
|
-
ArrowLeft,
|
|
7
|
-
Edit,
|
|
8
|
-
Trash2,
|
|
9
|
-
Copy,
|
|
10
|
-
Layers,
|
|
11
|
-
Loader2,
|
|
12
|
-
AlertTriangle,
|
|
13
|
-
Calendar,
|
|
14
|
-
Hash,
|
|
15
|
-
} from 'lucide-react'
|
|
16
|
-
import { toast } from 'sonner'
|
|
17
|
-
import { cmsApi } from '../../lib/api.js'
|
|
18
|
-
import { createSection, createContainer, createRow, createColumn } from '@prenta/core/page-builder'
|
|
19
|
-
|
|
20
|
-
export interface SavedSectionsProps {
|
|
21
|
-
onNavigate: (path: string) => void
|
|
22
|
-
config: any
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface SavedSection {
|
|
26
|
-
id: string
|
|
27
|
-
name: string
|
|
28
|
-
description: string
|
|
29
|
-
category: string
|
|
30
|
-
tree: Record<string, unknown> | null
|
|
31
|
-
usageCount: number
|
|
32
|
-
createdAt: string
|
|
33
|
-
updatedAt: string
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
type ViewState = { mode: 'list' } | { mode: 'create' } | { mode: 'edit'; section: SavedSection }
|
|
37
|
-
|
|
38
|
-
const CATEGORIES = ['header', 'footer', 'content', 'sidebar'] as const
|
|
39
|
-
type Category = (typeof CATEGORIES)[number]
|
|
40
|
-
|
|
41
|
-
const CATEGORY_COLORS: Record<string, string> = {
|
|
42
|
-
header: 'bg-primary/10 text-primary',
|
|
43
|
-
footer: 'bg-accent text-foreground',
|
|
44
|
-
content: 'bg-muted text-muted-foreground',
|
|
45
|
-
sidebar: 'bg-primary/10 text-primary',
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function formatDate(dateStr: string): string {
|
|
49
|
-
return new Date(dateStr).toLocaleDateString(undefined, {
|
|
50
|
-
month: 'short',
|
|
51
|
-
day: 'numeric',
|
|
52
|
-
year: 'numeric',
|
|
53
|
-
})
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function createEmptySectionTree(): Record<string, unknown> {
|
|
57
|
-
const col = createColumn(100)
|
|
58
|
-
const row = createRow([col])
|
|
59
|
-
const container = createContainer()
|
|
60
|
-
;(container as unknown as { children: unknown[] }).children = [row]
|
|
61
|
-
const section = createSection()
|
|
62
|
-
;(section as unknown as { children: unknown[] }).children = [container]
|
|
63
|
-
return section as unknown as Record<string, unknown>
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function SavedSections({ onNavigate, config }: SavedSectionsProps) {
|
|
67
|
-
const [sections, setSections] = useState<SavedSection[]>([])
|
|
68
|
-
const [loading, setLoading] = useState(true)
|
|
69
|
-
const [error, setError] = useState<string | null>(null)
|
|
70
|
-
const [viewState, setViewState] = useState<ViewState>({ mode: 'list' })
|
|
71
|
-
const [activeCategory, setActiveCategory] = useState<Category | 'all'>('all')
|
|
72
|
-
const [deleteConfirmId, setDeleteConfirmId] = useState<string | null>(null)
|
|
73
|
-
const [saving, setSaving] = useState(false)
|
|
74
|
-
|
|
75
|
-
const fetchSections = useCallback(async () => {
|
|
76
|
-
setLoading(true)
|
|
77
|
-
setError(null)
|
|
78
|
-
const res = await cmsApi<SavedSection[]>('/saved-sections')
|
|
79
|
-
if (res.error) {
|
|
80
|
-
setError(res.error)
|
|
81
|
-
} else {
|
|
82
|
-
setSections(res.data ?? [])
|
|
83
|
-
}
|
|
84
|
-
setLoading(false)
|
|
85
|
-
}, [])
|
|
86
|
-
|
|
87
|
-
useEffect(() => {
|
|
88
|
-
fetchSections()
|
|
89
|
-
}, [fetchSections])
|
|
90
|
-
|
|
91
|
-
const filteredSections =
|
|
92
|
-
activeCategory === 'all' ? sections : sections.filter((s) => s.category === activeCategory)
|
|
93
|
-
|
|
94
|
-
async function handleDelete(id: string) {
|
|
95
|
-
const res = await cmsApi(`/saved-sections/${id}`, { method: 'DELETE' })
|
|
96
|
-
if (res.error) {
|
|
97
|
-
toast.error(res.error)
|
|
98
|
-
} else {
|
|
99
|
-
toast.success('Section deleted')
|
|
100
|
-
setSections((prev) => prev.filter((s) => s.id !== id))
|
|
101
|
-
}
|
|
102
|
-
setDeleteConfirmId(null)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async function handleDuplicate(section: SavedSection) {
|
|
106
|
-
const res = await cmsApi<SavedSection>('/saved-sections', {
|
|
107
|
-
method: 'POST',
|
|
108
|
-
body: JSON.stringify({
|
|
109
|
-
name: `${section.name} (Copy)`,
|
|
110
|
-
description: section.description,
|
|
111
|
-
category: section.category,
|
|
112
|
-
tree: section.tree,
|
|
113
|
-
}),
|
|
114
|
-
})
|
|
115
|
-
if (res.error) {
|
|
116
|
-
toast.error(res.error)
|
|
117
|
-
} else {
|
|
118
|
-
toast.success('Section duplicated')
|
|
119
|
-
fetchSections()
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (viewState.mode === 'create' || viewState.mode === 'edit') {
|
|
124
|
-
return (
|
|
125
|
-
<SectionForm
|
|
126
|
-
initial={viewState.mode === 'edit' ? viewState.section : undefined}
|
|
127
|
-
saving={saving}
|
|
128
|
-
onSave={async (data) => {
|
|
129
|
-
setSaving(true)
|
|
130
|
-
if (viewState.mode === 'create') {
|
|
131
|
-
const res = await cmsApi<SavedSection>('/saved-sections', {
|
|
132
|
-
method: 'POST',
|
|
133
|
-
body: JSON.stringify({ ...data, tree: createEmptySectionTree() }),
|
|
134
|
-
})
|
|
135
|
-
setSaving(false)
|
|
136
|
-
if (res.error) {
|
|
137
|
-
toast.error(res.error)
|
|
138
|
-
} else {
|
|
139
|
-
toast.success('Section created')
|
|
140
|
-
setViewState({ mode: 'list' })
|
|
141
|
-
fetchSections()
|
|
142
|
-
}
|
|
143
|
-
} else {
|
|
144
|
-
const res = await cmsApi<SavedSection>(`/saved-sections/${viewState.section.id}`, {
|
|
145
|
-
method: 'PUT',
|
|
146
|
-
body: JSON.stringify(data),
|
|
147
|
-
})
|
|
148
|
-
setSaving(false)
|
|
149
|
-
if (res.error) {
|
|
150
|
-
toast.error(res.error)
|
|
151
|
-
} else {
|
|
152
|
-
toast.success('Section updated')
|
|
153
|
-
setViewState({ mode: 'list' })
|
|
154
|
-
fetchSections()
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}}
|
|
158
|
-
onCancel={() => setViewState({ mode: 'list' })}
|
|
159
|
-
/>
|
|
160
|
-
)
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return (
|
|
164
|
-
<div className="p-4 pr-8">
|
|
165
|
-
<div className="mb-6 flex items-center justify-between">
|
|
166
|
-
<div>
|
|
167
|
-
<h1 className="text-foreground">Saved Sections</h1>
|
|
168
|
-
<p className="text-muted-foreground mt-1 text-sm">
|
|
169
|
-
Reusable sections for the page builder
|
|
170
|
-
</p>
|
|
171
|
-
</div>
|
|
172
|
-
<button
|
|
173
|
-
type="button"
|
|
174
|
-
onClick={() => setViewState({ mode: 'create' })}
|
|
175
|
-
className="bg-primary text-primary-foreground hover:bg-primary/90 flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-colors"
|
|
176
|
-
>
|
|
177
|
-
<Plus size={16} />
|
|
178
|
-
Create Section
|
|
179
|
-
</button>
|
|
180
|
-
</div>
|
|
181
|
-
|
|
182
|
-
<div className="border-border mb-4 flex items-center gap-1 border-b">
|
|
183
|
-
<CategoryTab
|
|
184
|
-
label="All"
|
|
185
|
-
active={activeCategory === 'all'}
|
|
186
|
-
onClick={() => setActiveCategory('all')}
|
|
187
|
-
/>
|
|
188
|
-
{CATEGORIES.map((cat) => (
|
|
189
|
-
<CategoryTab
|
|
190
|
-
key={cat}
|
|
191
|
-
label={cat.charAt(0).toUpperCase() + cat.slice(1)}
|
|
192
|
-
active={activeCategory === cat}
|
|
193
|
-
onClick={() => setActiveCategory(cat)}
|
|
194
|
-
/>
|
|
195
|
-
))}
|
|
196
|
-
</div>
|
|
197
|
-
|
|
198
|
-
{loading && (
|
|
199
|
-
<div className="flex items-center justify-center py-16">
|
|
200
|
-
<Loader2 className="text-muted-foreground h-6 w-6 animate-spin" />
|
|
201
|
-
</div>
|
|
202
|
-
)}
|
|
203
|
-
|
|
204
|
-
{error && !loading && (
|
|
205
|
-
<div className="flex flex-col items-center justify-center py-12 text-center">
|
|
206
|
-
<AlertTriangle size={24} className="text-destructive mb-2" />
|
|
207
|
-
<p className="text-muted-foreground mb-3 text-sm">{error}</p>
|
|
208
|
-
<button
|
|
209
|
-
type="button"
|
|
210
|
-
onClick={fetchSections}
|
|
211
|
-
className="text-foreground border-border hover:bg-accent rounded-md border px-3 py-1.5 text-sm font-medium transition-colors"
|
|
212
|
-
>
|
|
213
|
-
Retry
|
|
214
|
-
</button>
|
|
215
|
-
</div>
|
|
216
|
-
)}
|
|
217
|
-
|
|
218
|
-
{!loading && !error && filteredSections.length === 0 && (
|
|
219
|
-
<div className="flex flex-col items-center justify-center py-16 text-center">
|
|
220
|
-
<Layers size={32} className="text-muted-foreground mb-3" />
|
|
221
|
-
<p className="text-foreground mb-1 text-sm font-medium">No saved sections</p>
|
|
222
|
-
<p className="text-muted-foreground mb-4 text-xs">
|
|
223
|
-
{activeCategory === 'all'
|
|
224
|
-
? 'Create your first reusable section to get started.'
|
|
225
|
-
: `No sections in the "${activeCategory}" category.`}
|
|
226
|
-
</p>
|
|
227
|
-
{activeCategory === 'all' && (
|
|
228
|
-
<button
|
|
229
|
-
type="button"
|
|
230
|
-
onClick={() => setViewState({ mode: 'create' })}
|
|
231
|
-
className="bg-primary text-primary-foreground hover:bg-primary/90 flex items-center gap-2 rounded-md px-3 py-1.5 text-sm font-medium transition-colors"
|
|
232
|
-
>
|
|
233
|
-
<Plus size={14} />
|
|
234
|
-
Create Section
|
|
235
|
-
</button>
|
|
236
|
-
)}
|
|
237
|
-
</div>
|
|
238
|
-
)}
|
|
239
|
-
|
|
240
|
-
{!loading && !error && filteredSections.length > 0 && (
|
|
241
|
-
<div className="grid grid-cols-1 gap-3 lg:grid-cols-2">
|
|
242
|
-
{filteredSections.map((section) => (
|
|
243
|
-
<div
|
|
244
|
-
key={section.id}
|
|
245
|
-
className="border-border bg-card hover:border-primary/50 rounded-lg border p-4 transition-colors"
|
|
246
|
-
>
|
|
247
|
-
<div className="flex items-start justify-between gap-3">
|
|
248
|
-
<div className="min-w-0 flex-1">
|
|
249
|
-
<p className="text-foreground truncate text-sm font-medium">{section.name}</p>
|
|
250
|
-
{section.description && (
|
|
251
|
-
<p className="text-muted-foreground mt-0.5 line-clamp-2 text-xs">
|
|
252
|
-
{section.description}
|
|
253
|
-
</p>
|
|
254
|
-
)}
|
|
255
|
-
</div>
|
|
256
|
-
<span
|
|
257
|
-
className={`shrink-0 rounded-full px-2 py-0.5 text-xs ${CATEGORY_COLORS[section.category] ?? 'bg-muted text-muted-foreground'}`}
|
|
258
|
-
>
|
|
259
|
-
{section.category}
|
|
260
|
-
</span>
|
|
261
|
-
</div>
|
|
262
|
-
|
|
263
|
-
<div className="text-muted-foreground mt-3 flex items-center gap-4 text-xs">
|
|
264
|
-
<span className="flex items-center gap-1">
|
|
265
|
-
<Hash size={12} />
|
|
266
|
-
{section.usageCount} use{section.usageCount !== 1 ? 's' : ''}
|
|
267
|
-
</span>
|
|
268
|
-
<span className="flex items-center gap-1">
|
|
269
|
-
<Calendar size={12} />
|
|
270
|
-
{formatDate(section.createdAt)}
|
|
271
|
-
</span>
|
|
272
|
-
{section.tree && (
|
|
273
|
-
<span className="flex items-center gap-1">
|
|
274
|
-
<Layers size={12} />
|
|
275
|
-
{JSON.stringify(section.tree).length > 1000 ? 'Complex' : 'Simple'}
|
|
276
|
-
</span>
|
|
277
|
-
)}
|
|
278
|
-
</div>
|
|
279
|
-
|
|
280
|
-
<div className="border-border mt-3 flex items-center gap-1 border-t pt-3">
|
|
281
|
-
<button
|
|
282
|
-
type="button"
|
|
283
|
-
onClick={() => setViewState({ mode: 'edit', section })}
|
|
284
|
-
className="text-foreground hover:bg-accent flex items-center gap-1.5 rounded-md px-2.5 py-1.5 text-xs font-medium transition-colors"
|
|
285
|
-
aria-label={`Edit ${section.name}`}
|
|
286
|
-
>
|
|
287
|
-
<Edit size={13} />
|
|
288
|
-
Edit
|
|
289
|
-
</button>
|
|
290
|
-
<button
|
|
291
|
-
type="button"
|
|
292
|
-
onClick={() => handleDuplicate(section)}
|
|
293
|
-
className="text-foreground hover:bg-accent flex items-center gap-1.5 rounded-md px-2.5 py-1.5 text-xs font-medium transition-colors"
|
|
294
|
-
aria-label={`Duplicate ${section.name}`}
|
|
295
|
-
>
|
|
296
|
-
<Copy size={13} />
|
|
297
|
-
Duplicate
|
|
298
|
-
</button>
|
|
299
|
-
{deleteConfirmId === section.id ? (
|
|
300
|
-
<div className="ml-auto flex items-center gap-1">
|
|
301
|
-
<span className="text-destructive mr-1 text-xs">Delete?</span>
|
|
302
|
-
<button
|
|
303
|
-
type="button"
|
|
304
|
-
onClick={() => handleDelete(section.id)}
|
|
305
|
-
className="text-destructive-foreground bg-destructive hover:bg-destructive/90 rounded-md px-2 py-1 text-xs font-medium transition-colors"
|
|
306
|
-
>
|
|
307
|
-
Yes
|
|
308
|
-
</button>
|
|
309
|
-
<button
|
|
310
|
-
type="button"
|
|
311
|
-
onClick={() => setDeleteConfirmId(null)}
|
|
312
|
-
className="text-foreground border-border hover:bg-accent rounded-md border px-2 py-1 text-xs font-medium transition-colors"
|
|
313
|
-
>
|
|
314
|
-
No
|
|
315
|
-
</button>
|
|
316
|
-
</div>
|
|
317
|
-
) : (
|
|
318
|
-
<button
|
|
319
|
-
type="button"
|
|
320
|
-
onClick={() => setDeleteConfirmId(section.id)}
|
|
321
|
-
className="text-destructive hover:bg-destructive/10 ml-auto flex items-center gap-1.5 rounded-md px-2.5 py-1.5 text-xs font-medium transition-colors"
|
|
322
|
-
aria-label={`Delete ${section.name}`}
|
|
323
|
-
>
|
|
324
|
-
<Trash2 size={13} />
|
|
325
|
-
Delete
|
|
326
|
-
</button>
|
|
327
|
-
)}
|
|
328
|
-
</div>
|
|
329
|
-
</div>
|
|
330
|
-
))}
|
|
331
|
-
</div>
|
|
332
|
-
)}
|
|
333
|
-
</div>
|
|
334
|
-
)
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
interface CategoryTabProps {
|
|
338
|
-
label: string
|
|
339
|
-
active: boolean
|
|
340
|
-
onClick: () => void
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
function CategoryTab({ label, active, onClick }: CategoryTabProps) {
|
|
344
|
-
return (
|
|
345
|
-
<button
|
|
346
|
-
type="button"
|
|
347
|
-
onClick={onClick}
|
|
348
|
-
className={`-mb-px border-b-2 px-3 py-2 text-sm transition-colors ${
|
|
349
|
-
active
|
|
350
|
-
? 'border-primary text-foreground font-medium'
|
|
351
|
-
: 'text-muted-foreground hover:text-foreground border-transparent'
|
|
352
|
-
}`}
|
|
353
|
-
>
|
|
354
|
-
{label}
|
|
355
|
-
</button>
|
|
356
|
-
)
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
interface SectionFormProps {
|
|
360
|
-
initial?: SavedSection
|
|
361
|
-
saving: boolean
|
|
362
|
-
onSave: (data: { name: string; description: string; category: string }) => void
|
|
363
|
-
onCancel: () => void
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
function SectionForm({ initial, saving, onSave, onCancel }: SectionFormProps) {
|
|
367
|
-
const [name, setName] = useState(initial?.name ?? '')
|
|
368
|
-
const [description, setDescription] = useState(initial?.description ?? '')
|
|
369
|
-
const [category, setCategory] = useState(initial?.category ?? 'content')
|
|
370
|
-
|
|
371
|
-
function handleSubmit(e: React.FormEvent) {
|
|
372
|
-
e.preventDefault()
|
|
373
|
-
if (!name.trim()) return
|
|
374
|
-
onSave({ name: name.trim(), description: description.trim(), category })
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
const treeSize = initial?.tree ? JSON.stringify(initial.tree).length : null
|
|
378
|
-
|
|
379
|
-
return (
|
|
380
|
-
<div className="p-4 pr-8">
|
|
381
|
-
<div className="mb-6">
|
|
382
|
-
<button
|
|
383
|
-
type="button"
|
|
384
|
-
onClick={onCancel}
|
|
385
|
-
className="text-muted-foreground hover:text-foreground mb-3 flex items-center gap-1.5 text-sm transition-colors"
|
|
386
|
-
aria-label="Back to saved sections"
|
|
387
|
-
>
|
|
388
|
-
<ArrowLeft size={16} />
|
|
389
|
-
Back
|
|
390
|
-
</button>
|
|
391
|
-
<h1 className="text-foreground">
|
|
392
|
-
{initial ? `Edit: ${initial.name}` : 'Create Saved Section'}
|
|
393
|
-
</h1>
|
|
394
|
-
</div>
|
|
395
|
-
|
|
396
|
-
<form onSubmit={handleSubmit} className="max-w-lg space-y-4">
|
|
397
|
-
<div>
|
|
398
|
-
<label htmlFor="section-name" className="text-foreground mb-1 block text-sm font-medium">
|
|
399
|
-
Name <span className="text-destructive">*</span>
|
|
400
|
-
</label>
|
|
401
|
-
<input
|
|
402
|
-
id="section-name"
|
|
403
|
-
type="text"
|
|
404
|
-
value={name}
|
|
405
|
-
onChange={(e) => setName(e.target.value)}
|
|
406
|
-
required
|
|
407
|
-
placeholder="e.g. Hero Banner"
|
|
408
|
-
className="bg-background border-input focus:ring-ring w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
|
|
409
|
-
/>
|
|
410
|
-
</div>
|
|
411
|
-
|
|
412
|
-
<div>
|
|
413
|
-
<label
|
|
414
|
-
htmlFor="section-description"
|
|
415
|
-
className="text-foreground mb-1 block text-sm font-medium"
|
|
416
|
-
>
|
|
417
|
-
Description
|
|
418
|
-
</label>
|
|
419
|
-
<textarea
|
|
420
|
-
id="section-description"
|
|
421
|
-
value={description}
|
|
422
|
-
onChange={(e) => setDescription(e.target.value)}
|
|
423
|
-
placeholder="Optional description of this section..."
|
|
424
|
-
rows={3}
|
|
425
|
-
className="bg-background border-input focus:ring-ring w-full resize-none rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
|
|
426
|
-
/>
|
|
427
|
-
</div>
|
|
428
|
-
|
|
429
|
-
<div>
|
|
430
|
-
<label
|
|
431
|
-
htmlFor="section-category"
|
|
432
|
-
className="text-foreground mb-1 block text-sm font-medium"
|
|
433
|
-
>
|
|
434
|
-
Category
|
|
435
|
-
</label>
|
|
436
|
-
<select
|
|
437
|
-
id="section-category"
|
|
438
|
-
value={category}
|
|
439
|
-
onChange={(e) => setCategory(e.target.value)}
|
|
440
|
-
className="bg-background border-input focus:ring-ring w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
|
|
441
|
-
>
|
|
442
|
-
{CATEGORIES.map((cat) => (
|
|
443
|
-
<option key={cat} value={cat}>
|
|
444
|
-
{cat.charAt(0).toUpperCase() + cat.slice(1)}
|
|
445
|
-
</option>
|
|
446
|
-
))}
|
|
447
|
-
</select>
|
|
448
|
-
</div>
|
|
449
|
-
|
|
450
|
-
{treeSize !== null && (
|
|
451
|
-
<div className="border-border bg-muted rounded-md border p-3">
|
|
452
|
-
<p className="text-muted-foreground text-xs">
|
|
453
|
-
Section tree editing is available in the page builder. Current tree size:{' '}
|
|
454
|
-
{(treeSize / 1024).toFixed(1)} KB
|
|
455
|
-
</p>
|
|
456
|
-
</div>
|
|
457
|
-
)}
|
|
458
|
-
|
|
459
|
-
<div className="flex items-center gap-3 pt-2">
|
|
460
|
-
<button
|
|
461
|
-
type="submit"
|
|
462
|
-
disabled={saving || !name.trim()}
|
|
463
|
-
className="bg-primary text-primary-foreground hover:bg-primary/90 flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50"
|
|
464
|
-
>
|
|
465
|
-
{saving && <Loader2 size={14} className="animate-spin" />}
|
|
466
|
-
{initial ? 'Save Changes' : 'Create Section'}
|
|
467
|
-
</button>
|
|
468
|
-
<button
|
|
469
|
-
type="button"
|
|
470
|
-
onClick={onCancel}
|
|
471
|
-
disabled={saving}
|
|
472
|
-
className="text-foreground border-border hover:bg-accent rounded-lg border px-4 py-2 text-sm font-medium transition-colors disabled:opacity-50"
|
|
473
|
-
>
|
|
474
|
-
Cancel
|
|
475
|
-
</button>
|
|
476
|
-
</div>
|
|
477
|
-
</form>
|
|
478
|
-
</div>
|
|
479
|
-
)
|
|
480
|
-
}
|