@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,67 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState } from 'react'
|
|
4
|
-
import type { ContainerNode } from '@prenta/core'
|
|
5
|
-
import { RowRenderer } from './RowRenderer.js'
|
|
6
|
-
|
|
7
|
-
export interface ContainerRendererProps {
|
|
8
|
-
node: ContainerNode
|
|
9
|
-
selectedNodeId: string | null
|
|
10
|
-
onSelectNode: (id: string | null) => void
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function ContainerRenderer({ node, selectedNodeId, onSelectNode }: ContainerRendererProps) {
|
|
14
|
-
const [hovered, setHovered] = useState(false)
|
|
15
|
-
const isSelected = selectedNodeId === node.id
|
|
16
|
-
const maxWidth = node.settings.maxWidth ?? '1200px'
|
|
17
|
-
const alignment = node.settings.alignment ?? 'center'
|
|
18
|
-
const padding = node.settings.padding
|
|
19
|
-
|
|
20
|
-
const marginMap: Record<string, string> = {
|
|
21
|
-
left: '0 auto 0 0',
|
|
22
|
-
center: '0 auto',
|
|
23
|
-
right: '0 0 0 auto',
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const handleClick = (e: React.MouseEvent) => {
|
|
27
|
-
e.stopPropagation()
|
|
28
|
-
onSelectNode(node.id)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return (
|
|
32
|
-
<div
|
|
33
|
-
data-node-id={node.id}
|
|
34
|
-
className={`relative transition-shadow ${
|
|
35
|
-
isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''
|
|
36
|
-
}`}
|
|
37
|
-
style={{
|
|
38
|
-
maxWidth,
|
|
39
|
-
margin: marginMap[alignment] ?? '0 auto',
|
|
40
|
-
padding,
|
|
41
|
-
}}
|
|
42
|
-
onClick={handleClick}
|
|
43
|
-
onMouseEnter={(e) => {
|
|
44
|
-
e.stopPropagation()
|
|
45
|
-
setHovered(true)
|
|
46
|
-
}}
|
|
47
|
-
onMouseLeave={() => setHovered(false)}
|
|
48
|
-
>
|
|
49
|
-
{(hovered || isSelected) && (
|
|
50
|
-
<span className="bg-primary text-primary-foreground absolute -top-2 -left-1 z-10 rounded px-1.5 py-0.5 text-xs font-medium">
|
|
51
|
-
Container
|
|
52
|
-
</span>
|
|
53
|
-
)}
|
|
54
|
-
|
|
55
|
-
<div className="flex flex-col gap-4">
|
|
56
|
-
{node.children.map((row) => (
|
|
57
|
-
<RowRenderer
|
|
58
|
-
key={row.id}
|
|
59
|
-
node={row}
|
|
60
|
-
selectedNodeId={selectedNodeId}
|
|
61
|
-
onSelectNode={onSelectNode}
|
|
62
|
-
/>
|
|
63
|
-
))}
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
)
|
|
67
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState } from 'react'
|
|
4
|
-
import type { RowNode } from '@prenta/core'
|
|
5
|
-
import { ColumnRenderer } from './ColumnRenderer.js'
|
|
6
|
-
|
|
7
|
-
export interface RowRendererProps {
|
|
8
|
-
node: RowNode
|
|
9
|
-
selectedNodeId: string | null
|
|
10
|
-
onSelectNode: (id: string | null) => void
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function RowRenderer({ node, selectedNodeId, onSelectNode }: RowRendererProps) {
|
|
14
|
-
const [hovered, setHovered] = useState(false)
|
|
15
|
-
const isSelected = selectedNodeId === node.id
|
|
16
|
-
const gap = node.settings.gap ?? '16px'
|
|
17
|
-
const verticalAlign = node.settings.verticalAlign ?? 'stretch'
|
|
18
|
-
|
|
19
|
-
const alignMap: Record<string, string> = {
|
|
20
|
-
top: 'start',
|
|
21
|
-
center: 'center',
|
|
22
|
-
bottom: 'end',
|
|
23
|
-
stretch: 'stretch',
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const handleClick = (e: React.MouseEvent) => {
|
|
27
|
-
e.stopPropagation()
|
|
28
|
-
onSelectNode(node.id)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return (
|
|
32
|
-
<div
|
|
33
|
-
data-node-id={node.id}
|
|
34
|
-
className={`relative transition-shadow ${
|
|
35
|
-
isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''
|
|
36
|
-
}`}
|
|
37
|
-
onClick={handleClick}
|
|
38
|
-
onMouseEnter={(e) => {
|
|
39
|
-
e.stopPropagation()
|
|
40
|
-
setHovered(true)
|
|
41
|
-
}}
|
|
42
|
-
onMouseLeave={() => setHovered(false)}
|
|
43
|
-
>
|
|
44
|
-
{(hovered || isSelected) && (
|
|
45
|
-
<span className="bg-primary text-primary-foreground absolute -top-2 -left-1 z-10 rounded px-1.5 py-0.5 text-xs font-medium">
|
|
46
|
-
Row
|
|
47
|
-
</span>
|
|
48
|
-
)}
|
|
49
|
-
|
|
50
|
-
<div
|
|
51
|
-
className="grid grid-cols-12"
|
|
52
|
-
style={{
|
|
53
|
-
gap,
|
|
54
|
-
alignItems: alignMap[verticalAlign] ?? 'stretch',
|
|
55
|
-
}}
|
|
56
|
-
>
|
|
57
|
-
{node.children.map((col) => (
|
|
58
|
-
<ColumnRenderer
|
|
59
|
-
key={col.id}
|
|
60
|
-
node={col}
|
|
61
|
-
selectedNodeId={selectedNodeId}
|
|
62
|
-
onSelectNode={onSelectNode}
|
|
63
|
-
/>
|
|
64
|
-
))}
|
|
65
|
-
</div>
|
|
66
|
-
</div>
|
|
67
|
-
)
|
|
68
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState } from 'react'
|
|
4
|
-
import type { SectionNode } from '@prenta/core'
|
|
5
|
-
import { ContainerRenderer } from './ContainerRenderer.js'
|
|
6
|
-
import { RowRenderer } from './RowRenderer.js'
|
|
7
|
-
|
|
8
|
-
export interface SectionRendererProps {
|
|
9
|
-
node: SectionNode
|
|
10
|
-
selectedNodeId: string | null
|
|
11
|
-
onSelectNode: (id: string | null) => void
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function SectionRenderer({ node, selectedNodeId, onSelectNode }: SectionRendererProps) {
|
|
15
|
-
const [hovered, setHovered] = useState(false)
|
|
16
|
-
const isSelected = selectedNodeId === node.id
|
|
17
|
-
|
|
18
|
-
const handleClick = (e: React.MouseEvent) => {
|
|
19
|
-
e.stopPropagation()
|
|
20
|
-
onSelectNode(node.id)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const backgroundStyle: React.CSSProperties = {}
|
|
24
|
-
if (node.settings.background) {
|
|
25
|
-
backgroundStyle.backgroundColor = node.settings.background
|
|
26
|
-
}
|
|
27
|
-
if (node.settings.backgroundImage) {
|
|
28
|
-
backgroundStyle.backgroundImage = `url(${node.settings.backgroundImage})`
|
|
29
|
-
backgroundStyle.backgroundSize = 'cover'
|
|
30
|
-
backgroundStyle.backgroundPosition = 'center'
|
|
31
|
-
}
|
|
32
|
-
if (node.settings.backgroundGradient) {
|
|
33
|
-
backgroundStyle.backgroundImage = node.settings.backgroundGradient
|
|
34
|
-
}
|
|
35
|
-
if (node.settings.paddingTop) {
|
|
36
|
-
backgroundStyle.paddingTop = node.settings.paddingTop
|
|
37
|
-
}
|
|
38
|
-
if (node.settings.paddingBottom) {
|
|
39
|
-
backgroundStyle.paddingBottom = node.settings.paddingBottom
|
|
40
|
-
}
|
|
41
|
-
if (node.settings.marginTop) {
|
|
42
|
-
backgroundStyle.marginTop = node.settings.marginTop
|
|
43
|
-
}
|
|
44
|
-
if (node.settings.marginBottom) {
|
|
45
|
-
backgroundStyle.marginBottom = node.settings.marginBottom
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<div
|
|
50
|
-
data-node-id={node.id}
|
|
51
|
-
className={`relative w-full transition-shadow ${
|
|
52
|
-
isSelected ? 'ring-primary ring-2 ring-offset-2' : hovered ? 'ring-primary/50 ring-1' : ''
|
|
53
|
-
}`}
|
|
54
|
-
style={backgroundStyle}
|
|
55
|
-
onClick={handleClick}
|
|
56
|
-
onMouseEnter={(e) => {
|
|
57
|
-
e.stopPropagation()
|
|
58
|
-
setHovered(true)
|
|
59
|
-
}}
|
|
60
|
-
onMouseLeave={() => setHovered(false)}
|
|
61
|
-
>
|
|
62
|
-
{(hovered || isSelected) && (
|
|
63
|
-
<span className="bg-primary text-primary-foreground absolute -top-2 -left-1 z-10 rounded px-1.5 py-0.5 text-xs font-medium">
|
|
64
|
-
Section
|
|
65
|
-
</span>
|
|
66
|
-
)}
|
|
67
|
-
|
|
68
|
-
{node.children.map((child) => {
|
|
69
|
-
if (child.type === 'container') {
|
|
70
|
-
return (
|
|
71
|
-
<ContainerRenderer
|
|
72
|
-
key={child.id}
|
|
73
|
-
node={child}
|
|
74
|
-
selectedNodeId={selectedNodeId}
|
|
75
|
-
onSelectNode={onSelectNode}
|
|
76
|
-
/>
|
|
77
|
-
)
|
|
78
|
-
}
|
|
79
|
-
if (child.type === 'row') {
|
|
80
|
-
return (
|
|
81
|
-
<RowRenderer
|
|
82
|
-
key={child.id}
|
|
83
|
-
node={child}
|
|
84
|
-
selectedNodeId={selectedNodeId}
|
|
85
|
-
onSelectNode={onSelectNode}
|
|
86
|
-
/>
|
|
87
|
-
)
|
|
88
|
-
}
|
|
89
|
-
return null
|
|
90
|
-
})}
|
|
91
|
-
</div>
|
|
92
|
-
)
|
|
93
|
-
}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useEffect, useState } from 'react'
|
|
4
|
-
import { AlertTriangle, Loader2, Pencil, X } from 'lucide-react'
|
|
5
|
-
import { fetchPageForEditor, type EditorPage } from '../../lib/page-editor-service.js'
|
|
6
|
-
import { SectionRenderer } from './sections/index.js'
|
|
7
|
-
|
|
8
|
-
interface PagePreviewProps {
|
|
9
|
-
documentId: string
|
|
10
|
-
onNavigate: (path: string) => void
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Clean, chrome-free render of a page using the SAME section renderers as
|
|
15
|
-
* the editor canvas — so the preview reflects what will actually ship.
|
|
16
|
-
* Only visible sections are rendered (hidden sections are omitted, exactly
|
|
17
|
-
* as the public page would behave).
|
|
18
|
-
*/
|
|
19
|
-
export function PagePreview({ documentId, onNavigate }: PagePreviewProps) {
|
|
20
|
-
const [page, setPage] = useState<EditorPage | null>(null)
|
|
21
|
-
const [loading, setLoading] = useState(true)
|
|
22
|
-
const [error, setError] = useState<string | null>(null)
|
|
23
|
-
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
let cancelled = false
|
|
26
|
-
setLoading(true)
|
|
27
|
-
fetchPageForEditor(documentId)
|
|
28
|
-
.then((p) => !cancelled && setPage(p))
|
|
29
|
-
.catch((err) => !cancelled && setError(err instanceof Error ? err.message : 'Failed to load'))
|
|
30
|
-
.finally(() => !cancelled && setLoading(false))
|
|
31
|
-
return () => {
|
|
32
|
-
cancelled = true
|
|
33
|
-
}
|
|
34
|
-
}, [documentId])
|
|
35
|
-
|
|
36
|
-
if (loading) {
|
|
37
|
-
return (
|
|
38
|
-
<div className="bg-background flex h-full items-center justify-center">
|
|
39
|
-
<Loader2 className="text-muted-foreground h-6 w-6 animate-spin" aria-hidden />
|
|
40
|
-
<span className="sr-only">Loading preview…</span>
|
|
41
|
-
</div>
|
|
42
|
-
)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (error || !page) {
|
|
46
|
-
return (
|
|
47
|
-
<div className="bg-background flex h-full items-center justify-center p-6">
|
|
48
|
-
<div className="border-destructive/30 bg-destructive/5 flex max-w-md items-center gap-3 rounded-lg border p-4">
|
|
49
|
-
<AlertTriangle className="text-destructive shrink-0" size={20} aria-hidden />
|
|
50
|
-
<p className="text-foreground text-sm font-medium">{error ?? 'Page not found.'}</p>
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
53
|
-
)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const visible = page.sections.filter((s) => s.visible)
|
|
57
|
-
|
|
58
|
-
return (
|
|
59
|
-
<div className="flex h-full flex-col">
|
|
60
|
-
{/* Slim preview bar — the only chrome; the page itself renders clean.
|
|
61
|
-
This view opens in its own browser tab, so actions are tab-scoped. */}
|
|
62
|
-
<div className="bg-card border-border flex h-12 shrink-0 items-center justify-between border-b px-4">
|
|
63
|
-
<button
|
|
64
|
-
type="button"
|
|
65
|
-
onClick={() => {
|
|
66
|
-
// Opened via the editor's "Preview" (script-opened tab) → close
|
|
67
|
-
// it. Opened by navigating to the URL directly (no opener, so
|
|
68
|
-
// `window.close()` is a no-op) → fall back to the editor so the
|
|
69
|
-
// button is never dead.
|
|
70
|
-
if (window.opener) window.close()
|
|
71
|
-
else onNavigate(`/pages/${documentId}/edit`)
|
|
72
|
-
}}
|
|
73
|
-
className="text-muted-foreground hover:text-foreground inline-flex items-center gap-1.5 text-sm"
|
|
74
|
-
aria-label="Close preview tab"
|
|
75
|
-
>
|
|
76
|
-
<X className="h-4 w-4" aria-hidden />
|
|
77
|
-
Close
|
|
78
|
-
</button>
|
|
79
|
-
<span className="text-muted-foreground text-xs">
|
|
80
|
-
Preview · {page.title || 'Untitled'} {page.path}
|
|
81
|
-
</span>
|
|
82
|
-
<button
|
|
83
|
-
type="button"
|
|
84
|
-
onClick={() => onNavigate(`/pages/${documentId}/edit`)}
|
|
85
|
-
className="bg-primary text-primary-foreground hover:bg-primary/90 inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium"
|
|
86
|
-
>
|
|
87
|
-
<Pencil className="h-3.5 w-3.5" aria-hidden />
|
|
88
|
-
Open editor
|
|
89
|
-
</button>
|
|
90
|
-
</div>
|
|
91
|
-
|
|
92
|
-
{/* The canvas is intentionally white regardless of the admin theme:
|
|
93
|
-
it emulates the public page surface, not admin chrome. */}
|
|
94
|
-
<div className="prenta-canvas bg-card flex-1 overflow-auto">
|
|
95
|
-
{visible.length === 0 ? (
|
|
96
|
-
<div className="text-muted-foreground flex h-full items-center justify-center text-sm">
|
|
97
|
-
This page has no visible sections yet.
|
|
98
|
-
</div>
|
|
99
|
-
) : (
|
|
100
|
-
visible.map((section) => <SectionRenderer key={section.id} section={section} />)
|
|
101
|
-
)}
|
|
102
|
-
</div>
|
|
103
|
-
</div>
|
|
104
|
-
)
|
|
105
|
-
}
|
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useEffect, useLayoutEffect, useRef, useState } from 'react'
|
|
4
|
-
import { Loader2 } from 'lucide-react'
|
|
5
|
-
import { injectPreviewEditChrome } from '../../lib/canvas-edit-chrome.js'
|
|
6
|
-
import {
|
|
7
|
-
canvasOriginFromSrc,
|
|
8
|
-
isPreviewBridgeMessage,
|
|
9
|
-
isPreviewEditMessage,
|
|
10
|
-
isPreviewRequestMediaMessage,
|
|
11
|
-
PREVIEW_BRIDGE_VERSION,
|
|
12
|
-
PREVIEW_SECTIONS_DEBOUNCE_MS,
|
|
13
|
-
toPreviewSectionPayload,
|
|
14
|
-
type PreviewHighlightMessage,
|
|
15
|
-
type PreviewModeMessage,
|
|
16
|
-
type PreviewSectionPayload,
|
|
17
|
-
type PreviewSectionsMessage,
|
|
18
|
-
} from '../../lib/preview-bridge.js'
|
|
19
|
-
import { getViewport, type ViewportId } from './viewports.js'
|
|
20
|
-
|
|
21
|
-
export interface CanvasEditPayload {
|
|
22
|
-
sectionId: string
|
|
23
|
-
fieldPath: string
|
|
24
|
-
value: string
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface CanvasMediaRequestPayload {
|
|
28
|
-
sectionId: string
|
|
29
|
-
fieldPath: string
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
interface SitePreviewFrameProps {
|
|
33
|
-
/** Canvas draft URL; null while the preview token is still minting. */
|
|
34
|
-
src: string | null
|
|
35
|
-
viewport: ViewportId
|
|
36
|
-
/** Changing this remounts the iframe so it reloads the persisted draft. */
|
|
37
|
-
reloadKey: number
|
|
38
|
-
title?: string
|
|
39
|
-
/** Currently selected section in the editor — pushed to the canvas as a highlight. */
|
|
40
|
-
selectedId?: string | null
|
|
41
|
-
/** Live editor sections — debounced push after canvas ready (Phase 3). */
|
|
42
|
-
sections?: PreviewSectionPayload[]
|
|
43
|
-
/**
|
|
44
|
-
* Increment after a canvas-originated text edit so the next sections push is
|
|
45
|
-
* skipped (avoids remounting a focused contenteditable).
|
|
46
|
-
*/
|
|
47
|
-
suppressSectionsEcho?: number
|
|
48
|
-
/** Canvas → admin: section (and optional field) clicked in the real design. */
|
|
49
|
-
onSelectSection?: (sectionId: string | null, fieldPath?: string) => void
|
|
50
|
-
/** Canvas → admin: inline text edit (Stage 3). */
|
|
51
|
-
onCanvasEdit?: (edit: CanvasEditPayload) => void
|
|
52
|
-
/** Canvas → admin: open media picker for a field (Stage 3 wave B). */
|
|
53
|
-
onCanvasRequestMedia?: (request: CanvasMediaRequestPayload) => void
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Inline branded preview surface — Next builder route in an iframe at the
|
|
58
|
-
* selected viewport's *true* CSS width, CSS-`transform: scale()`'d to fit
|
|
59
|
-
* (never crop). Stage 3: mode / edit / request-media + suppress-echo for
|
|
60
|
-
* canvas-originated text edits.
|
|
61
|
-
*/
|
|
62
|
-
export function SitePreviewFrame({
|
|
63
|
-
src,
|
|
64
|
-
viewport,
|
|
65
|
-
reloadKey,
|
|
66
|
-
title = 'Site preview',
|
|
67
|
-
selectedId = null,
|
|
68
|
-
sections,
|
|
69
|
-
suppressSectionsEcho = 0,
|
|
70
|
-
onSelectSection,
|
|
71
|
-
onCanvasEdit,
|
|
72
|
-
onCanvasRequestMedia,
|
|
73
|
-
}: SitePreviewFrameProps) {
|
|
74
|
-
const vp = getViewport(viewport)
|
|
75
|
-
const containerRef = useRef<HTMLDivElement>(null)
|
|
76
|
-
const sentinelRef = useRef<HTMLDivElement>(null)
|
|
77
|
-
const iframeRef = useRef<HTMLIFrameElement>(null)
|
|
78
|
-
const [scale, setScale] = useState(1)
|
|
79
|
-
const [frameHeight, setFrameHeight] = useState(600)
|
|
80
|
-
const [loaded, setLoaded] = useState(false)
|
|
81
|
-
const [canvasReady, setCanvasReady] = useState(false)
|
|
82
|
-
const canvasOrigin = canvasOriginFromSrc(src)
|
|
83
|
-
const lastSuppressRef = useRef(suppressSectionsEcho)
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Measure from a zero-height sentinel, never `clientWidth - 48`.
|
|
87
|
-
*
|
|
88
|
-
* The 48 was `p-6` written down a second time, in a second unit, four
|
|
89
|
-
* hundred lines from the class it mirrors. It disagrees with reality the
|
|
90
|
-
* moment a scrollbar appears, and it rots silently if the gutter ever
|
|
91
|
-
* changes — nothing fails, the preview just scales slightly wrong.
|
|
92
|
-
*
|
|
93
|
-
* The sentinel is subject to the same padding, the same scrollbar and the
|
|
94
|
-
* same host scaling as the frame, so its `offsetWidth` IS the usable width
|
|
95
|
-
* and there is no arithmetic to get wrong. Same rule as `CanvasSurface`,
|
|
96
|
-
* which is where this was first learned; this file is the third copy of the
|
|
97
|
-
* arithmetic and the last one to go.
|
|
98
|
-
*
|
|
99
|
-
* Height still comes from the container, because the sentinel is
|
|
100
|
-
* deliberately zero-height and can say nothing about it — but it is read as
|
|
101
|
-
* `clientHeight - (clientWidth - sentinelWidth)`, deriving the vertical
|
|
102
|
-
* gutter from the measured horizontal one rather than hardcoding it again.
|
|
103
|
-
* That holds for the symmetric `p-6` this uses and degrades to the old
|
|
104
|
-
* behaviour rather than breaking if it ever stops being symmetric.
|
|
105
|
-
*/
|
|
106
|
-
useLayoutEffect(() => {
|
|
107
|
-
const container = containerRef.current
|
|
108
|
-
const sentinel = sentinelRef.current
|
|
109
|
-
if (!container || !sentinel) return
|
|
110
|
-
const recompute = () => {
|
|
111
|
-
const availableW = sentinel.offsetWidth
|
|
112
|
-
if (availableW <= 0) return
|
|
113
|
-
const gutter = Math.max(0, container.clientWidth - availableW)
|
|
114
|
-
const availableH = container.clientHeight - gutter
|
|
115
|
-
const next = Math.min(1, availableW / vp.width)
|
|
116
|
-
setScale(next > 0 ? next : 1)
|
|
117
|
-
setFrameHeight(availableH > 0 ? availableH : 600)
|
|
118
|
-
}
|
|
119
|
-
recompute()
|
|
120
|
-
const ro = new ResizeObserver(recompute)
|
|
121
|
-
ro.observe(container)
|
|
122
|
-
ro.observe(sentinel)
|
|
123
|
-
return () => ro.disconnect()
|
|
124
|
-
}, [vp.width])
|
|
125
|
-
|
|
126
|
-
useEffect(() => {
|
|
127
|
-
setLoaded(false)
|
|
128
|
-
setCanvasReady(false)
|
|
129
|
-
}, [src, reloadKey])
|
|
130
|
-
|
|
131
|
-
// Canvas → admin: ready handshake + select + edit + request-media.
|
|
132
|
-
useEffect(() => {
|
|
133
|
-
if (!canvasOrigin) return
|
|
134
|
-
const onMessage = (event: MessageEvent) => {
|
|
135
|
-
if (event.origin !== canvasOrigin) return
|
|
136
|
-
if (!isPreviewBridgeMessage(event.data)) return
|
|
137
|
-
if (event.data.type === 'prenta-preview:ready') {
|
|
138
|
-
setCanvasReady(true)
|
|
139
|
-
return
|
|
140
|
-
}
|
|
141
|
-
if (event.data.type === 'prenta-preview:select' && onSelectSection) {
|
|
142
|
-
onSelectSection(event.data.sectionId, event.data.fieldPath)
|
|
143
|
-
return
|
|
144
|
-
}
|
|
145
|
-
if (isPreviewEditMessage(event.data) && onCanvasEdit) {
|
|
146
|
-
onCanvasEdit({
|
|
147
|
-
sectionId: event.data.sectionId,
|
|
148
|
-
fieldPath: event.data.fieldPath,
|
|
149
|
-
value: event.data.value,
|
|
150
|
-
})
|
|
151
|
-
return
|
|
152
|
-
}
|
|
153
|
-
if (isPreviewRequestMediaMessage(event.data) && onCanvasRequestMedia) {
|
|
154
|
-
onCanvasRequestMedia({
|
|
155
|
-
sectionId: event.data.sectionId,
|
|
156
|
-
fieldPath: event.data.fieldPath,
|
|
157
|
-
})
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
window.addEventListener('message', onMessage)
|
|
161
|
-
return () => window.removeEventListener('message', onMessage)
|
|
162
|
-
}, [canvasOrigin, onSelectSection, onCanvasEdit, onCanvasRequestMedia])
|
|
163
|
-
|
|
164
|
-
// Admin → canvas: enable inline editing once the canvas is ready.
|
|
165
|
-
useEffect(() => {
|
|
166
|
-
if (!canvasOrigin || !loaded || !canvasReady) return
|
|
167
|
-
const win = iframeRef.current?.contentWindow
|
|
168
|
-
if (!win) return
|
|
169
|
-
const msg: PreviewModeMessage = {
|
|
170
|
-
type: 'prenta-preview:mode',
|
|
171
|
-
v: PREVIEW_BRIDGE_VERSION,
|
|
172
|
-
editing: true,
|
|
173
|
-
}
|
|
174
|
-
win.postMessage(msg, canvasOrigin)
|
|
175
|
-
// Same-origin only — cross-origin previews skip silently.
|
|
176
|
-
injectPreviewEditChrome(iframeRef.current)
|
|
177
|
-
}, [canvasOrigin, loaded, canvasReady, reloadKey])
|
|
178
|
-
|
|
179
|
-
// Admin → canvas: highlight the selected section.
|
|
180
|
-
useEffect(() => {
|
|
181
|
-
if (!canvasOrigin || !loaded || !canvasReady) return
|
|
182
|
-
const win = iframeRef.current?.contentWindow
|
|
183
|
-
if (!win) return
|
|
184
|
-
const msg: PreviewHighlightMessage = {
|
|
185
|
-
type: 'prenta-preview:highlight',
|
|
186
|
-
v: PREVIEW_BRIDGE_VERSION,
|
|
187
|
-
sectionId: selectedId,
|
|
188
|
-
}
|
|
189
|
-
win.postMessage(msg, canvasOrigin)
|
|
190
|
-
}, [canvasOrigin, selectedId, loaded, canvasReady, reloadKey])
|
|
191
|
-
|
|
192
|
-
// Admin → canvas: live section content (debounced). Skip one cycle after
|
|
193
|
-
// canvas-originated text edits so contenteditable does not remount.
|
|
194
|
-
useEffect(() => {
|
|
195
|
-
if (!canvasOrigin || !loaded || !canvasReady || !sections) return
|
|
196
|
-
if (suppressSectionsEcho !== lastSuppressRef.current) {
|
|
197
|
-
lastSuppressRef.current = suppressSectionsEcho
|
|
198
|
-
return
|
|
199
|
-
}
|
|
200
|
-
const win = iframeRef.current?.contentWindow
|
|
201
|
-
if (!win) return
|
|
202
|
-
const timer = window.setTimeout(() => {
|
|
203
|
-
const msg: PreviewSectionsMessage = {
|
|
204
|
-
type: 'prenta-preview:sections',
|
|
205
|
-
v: PREVIEW_BRIDGE_VERSION,
|
|
206
|
-
sections: sections.map(toPreviewSectionPayload),
|
|
207
|
-
}
|
|
208
|
-
win.postMessage(msg, canvasOrigin)
|
|
209
|
-
}, PREVIEW_SECTIONS_DEBOUNCE_MS)
|
|
210
|
-
return () => window.clearTimeout(timer)
|
|
211
|
-
}, [canvasOrigin, loaded, canvasReady, sections, reloadKey, suppressSectionsEcho])
|
|
212
|
-
|
|
213
|
-
return (
|
|
214
|
-
<div ref={containerRef} className="bg-muted relative h-full overflow-hidden p-6">
|
|
215
|
-
{/*
|
|
216
|
-
* Zero-height sentinel — see the measurement effect above. Must stay the
|
|
217
|
-
* first child and must stay zero-height. `absolute` would defeat it: it
|
|
218
|
-
* has to sit in the padding box to inherit the gutter it is measuring.
|
|
219
|
-
*/}
|
|
220
|
-
<div ref={sentinelRef} aria-hidden className="h-0" />
|
|
221
|
-
{(!src || !loaded) && (
|
|
222
|
-
<div
|
|
223
|
-
className="absolute inset-0 z-10 flex flex-col items-center justify-center gap-2"
|
|
224
|
-
aria-live="polite"
|
|
225
|
-
>
|
|
226
|
-
<Loader2 className="text-muted-foreground h-6 w-6 animate-spin" aria-hidden />
|
|
227
|
-
<span className="text-muted-foreground text-sm">Loading site preview…</span>
|
|
228
|
-
</div>
|
|
229
|
-
)}
|
|
230
|
-
{src && (
|
|
231
|
-
<div className="mx-auto" style={{ width: vp.width * scale, height: frameHeight }}>
|
|
232
|
-
<iframe
|
|
233
|
-
key={reloadKey}
|
|
234
|
-
ref={iframeRef}
|
|
235
|
-
src={src}
|
|
236
|
-
title={title}
|
|
237
|
-
onLoad={() => setLoaded(true)}
|
|
238
|
-
className="border-border bg-card rounded-xl border shadow-sm"
|
|
239
|
-
style={{
|
|
240
|
-
width: vp.width,
|
|
241
|
-
height: frameHeight / scale,
|
|
242
|
-
transform: `scale(${scale})`,
|
|
243
|
-
transformOrigin: 'top left',
|
|
244
|
-
}}
|
|
245
|
-
/>
|
|
246
|
-
</div>
|
|
247
|
-
)}
|
|
248
|
-
</div>
|
|
249
|
-
)
|
|
250
|
-
}
|