@actuate-media/cms-admin 0.7.3 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AdminRoot.d.ts.map +1 -1
- package/dist/AdminRoot.js +95 -42
- package/dist/AdminRoot.js.map +1 -1
- package/dist/__tests__/lib/search.test.js +10 -10
- package/dist/__tests__/lib/search.test.js.map +1 -1
- package/dist/__tests__/lib/utils.test.js.map +1 -1
- package/dist/__tests__/router/match-route.test.js.map +1 -1
- package/dist/__tests__/router/strip-base.test.js.map +1 -1
- package/dist/actuate-admin.css +1 -1
- package/dist/components/Breadcrumbs.d.ts.map +1 -1
- package/dist/components/Breadcrumbs.js +2 -4
- package/dist/components/Breadcrumbs.js.map +1 -1
- package/dist/components/CommandPalette.d.ts.map +1 -1
- package/dist/components/CommandPalette.js +7 -3
- package/dist/components/CommandPalette.js.map +1 -1
- package/dist/components/ContentOverviewChart.d.ts.map +1 -1
- package/dist/components/ContentOverviewChart.js.map +1 -1
- package/dist/components/ErrorBoundary.d.ts.map +1 -1
- package/dist/components/ErrorBoundary.js.map +1 -1
- package/dist/components/FocalPointPicker.d.ts.map +1 -1
- package/dist/components/FocalPointPicker.js +4 -2
- package/dist/components/FocalPointPicker.js.map +1 -1
- package/dist/components/FolderTree.d.ts.map +1 -1
- package/dist/components/FolderTree.js +18 -10
- package/dist/components/FolderTree.js.map +1 -1
- package/dist/components/LivePreview.d.ts +1 -1
- package/dist/components/LivePreview.d.ts.map +1 -1
- package/dist/components/LivePreview.js +6 -2
- package/dist/components/LivePreview.js.map +1 -1
- package/dist/components/LocaleProvider.d.ts.map +1 -1
- package/dist/components/LocaleProvider.js.map +1 -1
- package/dist/components/LocaleSwitcher.d.ts.map +1 -1
- package/dist/components/LocaleSwitcher.js +1 -1
- package/dist/components/LocaleSwitcher.js.map +1 -1
- package/dist/components/MediaPickerModal.d.ts.map +1 -1
- package/dist/components/MediaPickerModal.js.map +1 -1
- package/dist/components/PresenceIndicator.d.ts.map +1 -1
- package/dist/components/PresenceIndicator.js +5 -2
- package/dist/components/PresenceIndicator.js.map +1 -1
- package/dist/components/SEOPanel.d.ts +1 -1
- package/dist/components/SEOPanel.d.ts.map +1 -1
- package/dist/components/SEOPanel.js +110 -24
- package/dist/components/SEOPanel.js.map +1 -1
- package/dist/components/SEOPerformance.d.ts.map +1 -1
- package/dist/components/SEOPerformance.js +2 -2
- package/dist/components/SEOPerformance.js.map +1 -1
- package/dist/components/ThemeProvider.d.ts.map +1 -1
- package/dist/components/ThemeProvider.js.map +1 -1
- package/dist/components/TipTapEditor.d.ts.map +1 -1
- package/dist/components/TipTapEditor.js +5 -1
- package/dist/components/TipTapEditor.js.map +1 -1
- package/dist/components/VersionHistory.d.ts +1 -1
- package/dist/components/VersionHistory.d.ts.map +1 -1
- package/dist/components/VersionHistory.js +1 -1
- package/dist/components/VersionHistory.js.map +1 -1
- package/dist/components/ui/Avatar.d.ts.map +1 -1
- package/dist/components/ui/Avatar.js.map +1 -1
- package/dist/components/ui/Badge.d.ts.map +1 -1
- package/dist/components/ui/Badge.js.map +1 -1
- package/dist/components/ui/Button.d.ts.map +1 -1
- package/dist/components/ui/Button.js.map +1 -1
- package/dist/components/ui/CommandPalette.d.ts.map +1 -1
- package/dist/components/ui/CommandPalette.js +8 -2
- package/dist/components/ui/CommandPalette.js.map +1 -1
- package/dist/components/ui/ConfirmDialog.d.ts.map +1 -1
- package/dist/components/ui/ConfirmDialog.js.map +1 -1
- package/dist/components/ui/DataTable.d.ts.map +1 -1
- package/dist/components/ui/DataTable.js +1 -3
- package/dist/components/ui/DataTable.js.map +1 -1
- package/dist/components/ui/EmptyState.d.ts.map +1 -1
- package/dist/components/ui/EmptyState.js +1 -1
- package/dist/components/ui/EmptyState.js.map +1 -1
- package/dist/components/ui/Modal.d.ts.map +1 -1
- package/dist/components/ui/Modal.js.map +1 -1
- package/dist/components/ui/Pagination.d.ts +1 -1
- package/dist/components/ui/Pagination.d.ts.map +1 -1
- package/dist/components/ui/Pagination.js +7 -2
- package/dist/components/ui/Pagination.js.map +1 -1
- package/dist/components/ui/SearchInput.d.ts.map +1 -1
- package/dist/components/ui/SearchInput.js.map +1 -1
- package/dist/components/ui/Skeleton.d.ts.map +1 -1
- package/dist/components/ui/Skeleton.js.map +1 -1
- package/dist/components/ui/Toast.d.ts.map +1 -1
- package/dist/components/ui/Toast.js.map +1 -1
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js.map +1 -1
- package/dist/fields/ArrayField.d.ts.map +1 -1
- package/dist/fields/ArrayField.js +1 -1
- package/dist/fields/ArrayField.js.map +1 -1
- package/dist/fields/BlockBuilderField.d.ts.map +1 -1
- package/dist/fields/BlockBuilderField.js +7 -7
- package/dist/fields/BlockBuilderField.js.map +1 -1
- package/dist/fields/DateField.d.ts.map +1 -1
- package/dist/fields/DateField.js +1 -1
- package/dist/fields/DateField.js.map +1 -1
- package/dist/fields/FieldRenderer.d.ts.map +1 -1
- package/dist/fields/FieldRenderer.js.map +1 -1
- package/dist/fields/GroupField.d.ts.map +1 -1
- package/dist/fields/GroupField.js +1 -1
- package/dist/fields/GroupField.js.map +1 -1
- package/dist/fields/MediaField.d.ts.map +1 -1
- package/dist/fields/MediaField.js +1 -1
- package/dist/fields/MediaField.js.map +1 -1
- package/dist/fields/NavBuilderField.d.ts.map +1 -1
- package/dist/fields/NavBuilderField.js +2 -5
- package/dist/fields/NavBuilderField.js.map +1 -1
- package/dist/fields/NumberField.d.ts +1 -1
- package/dist/fields/NumberField.d.ts.map +1 -1
- package/dist/fields/NumberField.js +2 -2
- package/dist/fields/NumberField.js.map +1 -1
- package/dist/fields/RelationshipField.d.ts.map +1 -1
- package/dist/fields/RelationshipField.js +7 -3
- package/dist/fields/RelationshipField.js.map +1 -1
- package/dist/fields/RichTextField.d.ts +1 -1
- package/dist/fields/RichTextField.d.ts.map +1 -1
- package/dist/fields/RichTextField.js +2 -2
- package/dist/fields/RichTextField.js.map +1 -1
- package/dist/fields/SelectField.d.ts.map +1 -1
- package/dist/fields/SelectField.js +9 -7
- package/dist/fields/SelectField.js.map +1 -1
- package/dist/fields/SlugField.d.ts.map +1 -1
- package/dist/fields/SlugField.js +1 -1
- package/dist/fields/SlugField.js.map +1 -1
- package/dist/fields/TextField.d.ts +1 -1
- package/dist/fields/TextField.d.ts.map +1 -1
- package/dist/fields/TextField.js +2 -2
- package/dist/fields/TextField.js.map +1 -1
- package/dist/fields/ToggleField.d.ts.map +1 -1
- package/dist/fields/ToggleField.js +1 -1
- package/dist/fields/ToggleField.js.map +1 -1
- package/dist/fields/block-types.d.ts.map +1 -1
- package/dist/fields/block-types.js +28 -8
- package/dist/fields/block-types.js.map +1 -1
- package/dist/fields/index.d.ts.map +1 -1
- package/dist/fields/index.js.map +1 -1
- package/dist/hooks/useBuilderState.d.ts.map +1 -1
- package/dist/hooks/useBuilderState.js.map +1 -1
- package/dist/hooks/useContentLock.d.ts.map +1 -1
- package/dist/hooks/useContentLock.js.map +1 -1
- package/dist/hooks/useDebounce.js.map +1 -1
- package/dist/hooks/useKeyboardShortcuts.d.ts.map +1 -1
- package/dist/hooks/useKeyboardShortcuts.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/layout/Header.d.ts.map +1 -1
- package/dist/layout/Header.js.map +1 -1
- package/dist/layout/Layout.d.ts.map +1 -1
- package/dist/layout/Layout.js.map +1 -1
- package/dist/layout/Sidebar.d.ts +1 -1
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/Sidebar.js +5 -8
- package/dist/layout/Sidebar.js.map +1 -1
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +33 -4
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/search.d.ts.map +1 -1
- package/dist/lib/search.js +3 -5
- package/dist/lib/search.js.map +1 -1
- package/dist/lib/useApiData.d.ts.map +1 -1
- package/dist/lib/useApiData.js.map +1 -1
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +1 -3
- package/dist/router/index.js.map +1 -1
- package/dist/views/CollectionList.d.ts.map +1 -1
- package/dist/views/CollectionList.js +56 -17
- package/dist/views/CollectionList.js.map +1 -1
- package/dist/views/Dashboard.d.ts.map +1 -1
- package/dist/views/Dashboard.js +26 -13
- package/dist/views/Dashboard.js.map +1 -1
- package/dist/views/DocumentEdit.d.ts +1 -1
- package/dist/views/DocumentEdit.d.ts.map +1 -1
- package/dist/views/DocumentEdit.js +33 -15
- package/dist/views/DocumentEdit.js.map +1 -1
- package/dist/views/ForgotPassword.d.ts.map +1 -1
- package/dist/views/ForgotPassword.js.map +1 -1
- package/dist/views/FormEditor.d.ts.map +1 -1
- package/dist/views/FormEditor.js +8 -2
- package/dist/views/FormEditor.js.map +1 -1
- package/dist/views/FormSubmissions.d.ts.map +1 -1
- package/dist/views/FormSubmissions.js +6 -6
- package/dist/views/FormSubmissions.js.map +1 -1
- package/dist/views/Forms.d.ts.map +1 -1
- package/dist/views/Forms.js.map +1 -1
- package/dist/views/Login.d.ts.map +1 -1
- package/dist/views/Login.js +5 -2
- package/dist/views/Login.js.map +1 -1
- package/dist/views/MediaBrowser.d.ts.map +1 -1
- package/dist/views/MediaBrowser.js +39 -19
- package/dist/views/MediaBrowser.js.map +1 -1
- package/dist/views/PageEditor.d.ts.map +1 -1
- package/dist/views/PageEditor.js.map +1 -1
- package/dist/views/Pages.d.ts.map +1 -1
- package/dist/views/Pages.js +20 -10
- package/dist/views/Pages.js.map +1 -1
- package/dist/views/PostEditor.d.ts.map +1 -1
- package/dist/views/PostEditor.js.map +1 -1
- package/dist/views/Posts.d.ts.map +1 -1
- package/dist/views/Posts.js +13 -7
- package/dist/views/Posts.js.map +1 -1
- package/dist/views/Redirects.d.ts.map +1 -1
- package/dist/views/Redirects.js +17 -5
- package/dist/views/Redirects.js.map +1 -1
- package/dist/views/ResetPassword.d.ts.map +1 -1
- package/dist/views/ResetPassword.js.map +1 -1
- package/dist/views/SEO.d.ts.map +1 -1
- package/dist/views/SEO.js +39 -16
- package/dist/views/SEO.js.map +1 -1
- package/dist/views/ScriptTagEditor.d.ts.map +1 -1
- package/dist/views/ScriptTagEditor.js +2 -1
- package/dist/views/ScriptTagEditor.js.map +1 -1
- package/dist/views/ScriptTags.d.ts.map +1 -1
- package/dist/views/ScriptTags.js.map +1 -1
- package/dist/views/Settings.d.ts.map +1 -1
- package/dist/views/Settings.js +38 -11
- package/dist/views/Settings.js.map +1 -1
- package/dist/views/SetupWizard.d.ts.map +1 -1
- package/dist/views/SetupWizard.js.map +1 -1
- package/dist/views/Users.d.ts.map +1 -1
- package/dist/views/Users.js +5 -3
- package/dist/views/Users.js.map +1 -1
- package/dist/views/page-builder/AIBlockAssist.d.ts.map +1 -1
- package/dist/views/page-builder/AIBlockAssist.js +1 -1
- package/dist/views/page-builder/AIBlockAssist.js.map +1 -1
- package/dist/views/page-builder/AIGenerateDialog.d.ts.map +1 -1
- package/dist/views/page-builder/AIGenerateDialog.js +4 -1
- package/dist/views/page-builder/AIGenerateDialog.js.map +1 -1
- package/dist/views/page-builder/BlockEditor.d.ts.map +1 -1
- package/dist/views/page-builder/BlockEditor.js +94 -3
- package/dist/views/page-builder/BlockEditor.js.map +1 -1
- package/dist/views/page-builder/BlockPicker.d.ts.map +1 -1
- package/dist/views/page-builder/BlockPicker.js.map +1 -1
- package/dist/views/page-builder/BottomBar.d.ts.map +1 -1
- package/dist/views/page-builder/BottomBar.js.map +1 -1
- package/dist/views/page-builder/BuilderToolbar.d.ts.map +1 -1
- package/dist/views/page-builder/BuilderToolbar.js.map +1 -1
- package/dist/views/page-builder/ContextPanel.d.ts.map +1 -1
- package/dist/views/page-builder/ContextPanel.js +4 -1
- package/dist/views/page-builder/ContextPanel.js.map +1 -1
- package/dist/views/page-builder/DesignScore.d.ts.map +1 -1
- package/dist/views/page-builder/DesignScore.js.map +1 -1
- package/dist/views/page-builder/NodeSettings.d.ts.map +1 -1
- package/dist/views/page-builder/NodeSettings.js +1 -1
- package/dist/views/page-builder/NodeSettings.js.map +1 -1
- package/dist/views/page-builder/PageBuilder.d.ts +1 -1
- package/dist/views/page-builder/PageBuilder.d.ts.map +1 -1
- package/dist/views/page-builder/PageBuilder.js +25 -3
- package/dist/views/page-builder/PageBuilder.js.map +1 -1
- package/dist/views/page-builder/PageSettings.d.ts.map +1 -1
- package/dist/views/page-builder/PageSettings.js.map +1 -1
- package/dist/views/page-builder/PageTemplates.d.ts.map +1 -1
- package/dist/views/page-builder/PageTemplates.js.map +1 -1
- package/dist/views/page-builder/SEOPanel.d.ts.map +1 -1
- package/dist/views/page-builder/SEOPanel.js +1 -3
- package/dist/views/page-builder/SEOPanel.js.map +1 -1
- package/dist/views/page-builder/SavedSections.d.ts.map +1 -1
- package/dist/views/page-builder/SavedSections.js +3 -7
- package/dist/views/page-builder/SavedSections.js.map +1 -1
- package/dist/views/page-builder/TemplatePicker.d.ts.map +1 -1
- package/dist/views/page-builder/TemplatePicker.js.map +1 -1
- package/dist/views/page-builder/block-renderers/CTAPreview.d.ts.map +1 -1
- package/dist/views/page-builder/block-renderers/CTAPreview.js +1 -1
- package/dist/views/page-builder/block-renderers/CTAPreview.js.map +1 -1
- package/dist/views/page-builder/block-renderers/CardsPreview.d.ts.map +1 -1
- package/dist/views/page-builder/block-renderers/CardsPreview.js +1 -1
- package/dist/views/page-builder/block-renderers/CardsPreview.js.map +1 -1
- package/dist/views/page-builder/block-renderers/CodePreview.d.ts.map +1 -1
- package/dist/views/page-builder/block-renderers/CodePreview.js +1 -5
- package/dist/views/page-builder/block-renderers/CodePreview.js.map +1 -1
- package/dist/views/page-builder/block-renderers/FAQPreview.d.ts.map +1 -1
- package/dist/views/page-builder/block-renderers/FAQPreview.js +4 -1
- package/dist/views/page-builder/block-renderers/FAQPreview.js.map +1 -1
- package/dist/views/page-builder/block-renderers/FallbackPreview.d.ts.map +1 -1
- package/dist/views/page-builder/block-renderers/FallbackPreview.js.map +1 -1
- package/dist/views/page-builder/block-renderers/FormPreview.d.ts.map +1 -1
- package/dist/views/page-builder/block-renderers/FormPreview.js +2 -2
- package/dist/views/page-builder/block-renderers/FormPreview.js.map +1 -1
- package/dist/views/page-builder/block-renderers/GalleryPreview.d.ts.map +1 -1
- package/dist/views/page-builder/block-renderers/GalleryPreview.js +1 -3
- package/dist/views/page-builder/block-renderers/GalleryPreview.js.map +1 -1
- package/dist/views/page-builder/block-renderers/HeroPreview.d.ts.map +1 -1
- package/dist/views/page-builder/block-renderers/HeroPreview.js.map +1 -1
- package/dist/views/page-builder/block-renderers/ImagePreview.d.ts.map +1 -1
- package/dist/views/page-builder/block-renderers/ImagePreview.js.map +1 -1
- package/dist/views/page-builder/block-renderers/TextPreview.d.ts.map +1 -1
- package/dist/views/page-builder/block-renderers/TextPreview.js +2 -6
- package/dist/views/page-builder/block-renderers/TextPreview.js.map +1 -1
- package/dist/views/page-builder/block-renderers/VideoPreview.d.ts.map +1 -1
- package/dist/views/page-builder/block-renderers/VideoPreview.js +2 -5
- package/dist/views/page-builder/block-renderers/VideoPreview.js.map +1 -1
- package/dist/views/page-builder/block-renderers/index.d.ts.map +1 -1
- package/dist/views/page-builder/block-renderers/index.js.map +1 -1
- package/dist/views/page-builder/canvas/BlockRenderer.d.ts.map +1 -1
- package/dist/views/page-builder/canvas/BlockRenderer.js +1 -5
- package/dist/views/page-builder/canvas/BlockRenderer.js.map +1 -1
- package/dist/views/page-builder/canvas/BuilderCanvas.d.ts.map +1 -1
- package/dist/views/page-builder/canvas/BuilderCanvas.js.map +1 -1
- package/dist/views/page-builder/canvas/ColumnRenderer.d.ts.map +1 -1
- package/dist/views/page-builder/canvas/ColumnRenderer.js +1 -5
- package/dist/views/page-builder/canvas/ColumnRenderer.js.map +1 -1
- package/dist/views/page-builder/canvas/ContainerRenderer.d.ts.map +1 -1
- package/dist/views/page-builder/canvas/ContainerRenderer.js +1 -5
- package/dist/views/page-builder/canvas/ContainerRenderer.js.map +1 -1
- package/dist/views/page-builder/canvas/RowRenderer.d.ts.map +1 -1
- package/dist/views/page-builder/canvas/RowRenderer.js +1 -5
- package/dist/views/page-builder/canvas/RowRenderer.js.map +1 -1
- package/dist/views/page-builder/canvas/SectionRenderer.d.ts.map +1 -1
- package/dist/views/page-builder/canvas/SectionRenderer.js +1 -5
- package/dist/views/page-builder/canvas/SectionRenderer.js.map +1 -1
- package/dist/views/page-builder/canvas/index.d.ts.map +1 -1
- package/dist/views/page-builder/canvas/index.js.map +1 -1
- package/package.json +2 -2
- package/src/AdminRoot.tsx +302 -177
- package/src/__tests__/lib/search.test.ts +60 -69
- package/src/__tests__/lib/utils.test.ts +12 -12
- package/src/__tests__/router/match-route.test.ts +24 -26
- package/src/__tests__/router/strip-base.test.ts +15 -15
- package/src/components/Breadcrumbs.tsx +27 -24
- package/src/components/CommandPalette.tsx +115 -99
- package/src/components/ContentOverviewChart.tsx +19 -14
- package/src/components/ErrorBoundary.tsx +13 -13
- package/src/components/FocalPointPicker.tsx +31 -20
- package/src/components/FolderTree.tsx +172 -139
- package/src/components/LivePreview.tsx +68 -41
- package/src/components/LocaleProvider.tsx +26 -20
- package/src/components/LocaleSwitcher.tsx +9 -11
- package/src/components/MediaPickerModal.tsx +46 -45
- package/src/components/PresenceIndicator.tsx +30 -27
- package/src/components/SEOPanel.tsx +378 -228
- package/src/components/SEOPerformance.tsx +52 -30
- package/src/components/ThemeProvider.tsx +46 -46
- package/src/components/TipTapEditor.tsx +60 -64
- package/src/components/VersionHistory.tsx +63 -52
- package/src/components/ui/Avatar.tsx +8 -8
- package/src/components/ui/Badge.tsx +7 -5
- package/src/components/ui/Button.tsx +24 -13
- package/src/components/ui/CommandPalette.tsx +56 -42
- package/src/components/ui/ConfirmDialog.tsx +14 -14
- package/src/components/ui/DataTable.tsx +37 -39
- package/src/components/ui/EmptyState.tsx +9 -11
- package/src/components/ui/Modal.tsx +21 -15
- package/src/components/ui/Pagination.tsx +34 -19
- package/src/components/ui/SearchInput.tsx +17 -7
- package/src/components/ui/Skeleton.tsx +7 -7
- package/src/components/ui/Toast.tsx +29 -22
- package/src/components/ui/index.ts +24 -24
- package/src/fields/ArrayField.tsx +43 -25
- package/src/fields/BlockBuilderField.tsx +80 -99
- package/src/fields/DateField.tsx +20 -12
- package/src/fields/FieldRenderer.tsx +34 -34
- package/src/fields/GroupField.tsx +8 -10
- package/src/fields/MediaField.tsx +8 -10
- package/src/fields/NavBuilderField.tsx +24 -25
- package/src/fields/NumberField.tsx +21 -14
- package/src/fields/RelationshipField.tsx +105 -91
- package/src/fields/RichTextField.tsx +16 -12
- package/src/fields/SelectField.tsx +42 -34
- package/src/fields/SlugField.tsx +29 -17
- package/src/fields/TextField.tsx +24 -16
- package/src/fields/ToggleField.tsx +7 -9
- package/src/fields/block-types.ts +50 -24
- package/src/fields/index.ts +17 -17
- package/src/hooks/useBuilderState.ts +260 -221
- package/src/hooks/useContentLock.ts +23 -20
- package/src/hooks/useDebounce.ts +7 -7
- package/src/hooks/useKeyboardShortcuts.ts +16 -16
- package/src/index.ts +69 -58
- package/src/layout/Header.tsx +21 -20
- package/src/layout/Layout.tsx +22 -24
- package/src/layout/Sidebar.tsx +107 -72
- package/src/lib/api.ts +58 -30
- package/src/lib/search.ts +30 -34
- package/src/lib/useApiData.ts +65 -62
- package/src/lib/utils.ts +3 -3
- package/src/router/index.ts +33 -35
- package/src/styles/build-input.css +2 -2
- package/src/styles/tailwind.css +1 -1
- package/src/styles/theme.css +7 -1
- package/src/views/CollectionList.tsx +275 -121
- package/src/views/Dashboard.tsx +164 -117
- package/src/views/DocumentEdit.tsx +298 -253
- package/src/views/ForgotPassword.tsx +27 -23
- package/src/views/FormEditor.tsx +165 -99
- package/src/views/FormSubmissions.tsx +261 -117
- package/src/views/Forms.tsx +56 -26
- package/src/views/Login.tsx +107 -84
- package/src/views/MediaBrowser.tsx +717 -523
- package/src/views/PageEditor.tsx +44 -46
- package/src/views/Pages.tsx +312 -149
- package/src/views/PostEditor.tsx +57 -51
- package/src/views/Posts.tsx +206 -74
- package/src/views/Redirects.tsx +173 -117
- package/src/views/ResetPassword.tsx +43 -32
- package/src/views/SEO.tsx +589 -160
- package/src/views/ScriptTagEditor.tsx +69 -69
- package/src/views/ScriptTags.tsx +54 -42
- package/src/views/Settings.tsx +430 -220
- package/src/views/SetupWizard.tsx +69 -46
- package/src/views/Users.tsx +154 -120
- package/src/views/page-builder/AIBlockAssist.tsx +21 -25
- package/src/views/page-builder/AIGenerateDialog.tsx +134 -127
- package/src/views/page-builder/BlockEditor.tsx +258 -81
- package/src/views/page-builder/BlockPicker.tsx +73 -88
- package/src/views/page-builder/BottomBar.tsx +15 -11
- package/src/views/page-builder/BuilderToolbar.tsx +32 -29
- package/src/views/page-builder/ContextPanel.tsx +57 -57
- package/src/views/page-builder/DesignScore.tsx +52 -59
- package/src/views/page-builder/NodeSettings.tsx +59 -59
- package/src/views/page-builder/PageBuilder.tsx +164 -146
- package/src/views/page-builder/PageSettings.tsx +16 -15
- package/src/views/page-builder/PageTemplates.tsx +23 -17
- package/src/views/page-builder/SEOPanel.tsx +90 -111
- package/src/views/page-builder/SavedSections.tsx +99 -105
- package/src/views/page-builder/TemplatePicker.tsx +44 -48
- package/src/views/page-builder/block-renderers/CTAPreview.tsx +11 -13
- package/src/views/page-builder/block-renderers/CardsPreview.tsx +13 -15
- package/src/views/page-builder/block-renderers/CodePreview.tsx +16 -16
- package/src/views/page-builder/block-renderers/FAQPreview.tsx +20 -23
- package/src/views/page-builder/block-renderers/FallbackPreview.tsx +5 -5
- package/src/views/page-builder/block-renderers/FormPreview.tsx +9 -13
- package/src/views/page-builder/block-renderers/GalleryPreview.tsx +22 -28
- package/src/views/page-builder/block-renderers/HeroPreview.tsx +17 -30
- package/src/views/page-builder/block-renderers/ImagePreview.tsx +12 -12
- package/src/views/page-builder/block-renderers/TextPreview.tsx +22 -22
- package/src/views/page-builder/block-renderers/VideoPreview.tsx +13 -18
- package/src/views/page-builder/block-renderers/index.ts +17 -17
- package/src/views/page-builder/canvas/BlockRenderer.tsx +19 -23
- package/src/views/page-builder/canvas/BuilderCanvas.tsx +17 -20
- package/src/views/page-builder/canvas/ColumnRenderer.tsx +22 -26
- package/src/views/page-builder/canvas/ContainerRenderer.tsx +20 -24
- package/src/views/page-builder/canvas/RowRenderer.tsx +19 -23
- package/src/views/page-builder/canvas/SectionRenderer.tsx +30 -34
- package/src/views/page-builder/canvas/index.ts +2 -2
package/src/AdminRoot.tsx
CHANGED
|
@@ -1,87 +1,148 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState, useMemo, useEffect, useRef } from 'react'
|
|
4
|
-
import { Layout } from './layout/Layout.js'
|
|
5
|
-
import { useAdminRouter } from './router/index.js'
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState, useMemo, useEffect, useRef } from 'react'
|
|
4
|
+
import { Layout } from './layout/Layout.js'
|
|
5
|
+
import { useAdminRouter } from './router/index.js'
|
|
6
|
+
import { ensureCsrfToken } from './lib/api.js'
|
|
7
|
+
import { Dashboard } from './views/Dashboard.js'
|
|
8
|
+
import { CollectionList } from './views/CollectionList.js'
|
|
9
|
+
import { DocumentEdit } from './views/DocumentEdit.js'
|
|
10
|
+
import { MediaBrowser } from './views/MediaBrowser.js'
|
|
11
|
+
import { Settings } from './views/Settings.js'
|
|
12
|
+
import { Forms } from './views/Forms.js'
|
|
13
|
+
import { FormEditor } from './views/FormEditor.js'
|
|
14
|
+
import { FormSubmissions } from './views/FormSubmissions.js'
|
|
15
|
+
import { Users } from './views/Users.js'
|
|
16
|
+
import { SEO } from './views/SEO.js'
|
|
17
|
+
import { ScriptTags } from './views/ScriptTags.js'
|
|
18
|
+
import { ScriptTagEditor } from './views/ScriptTagEditor.js'
|
|
19
|
+
import { SetupWizard } from './views/SetupWizard.js'
|
|
20
|
+
import { Login } from './views/Login.js'
|
|
21
|
+
import { ForgotPassword } from './views/ForgotPassword.js'
|
|
22
|
+
import { ResetPassword } from './views/ResetPassword.js'
|
|
23
|
+
import { ErrorBoundary } from './components/ErrorBoundary.js'
|
|
24
|
+
import { ThemeProvider } from './components/ThemeProvider.js'
|
|
25
|
+
import { LocaleProvider } from './components/LocaleProvider.js'
|
|
26
|
+
import { useKeyboardShortcuts } from './hooks/useKeyboardShortcuts.js'
|
|
27
|
+
import { PageBuilder } from './views/page-builder/PageBuilder.js'
|
|
28
|
+
import { SavedSections } from './views/page-builder/SavedSections.js'
|
|
29
|
+
import { PageTemplates } from './views/page-builder/PageTemplates.js'
|
|
29
30
|
|
|
30
31
|
export interface AdminRootProps {
|
|
31
|
-
config: any
|
|
32
|
-
session: any
|
|
33
|
-
basePath?: string
|
|
34
|
-
initialPath?: string
|
|
35
|
-
setupRequired?: boolean
|
|
36
|
-
onSetupComplete?: (data: {
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
config: any
|
|
33
|
+
session: any
|
|
34
|
+
basePath?: string
|
|
35
|
+
initialPath?: string
|
|
36
|
+
setupRequired?: boolean
|
|
37
|
+
onSetupComplete?: (data: {
|
|
38
|
+
name: string
|
|
39
|
+
email: string
|
|
40
|
+
password: string
|
|
41
|
+
}) => Promise<{ success: boolean; error?: string }>
|
|
42
|
+
onLogin?: (
|
|
43
|
+
email: string,
|
|
44
|
+
password: string,
|
|
45
|
+
captchaToken?: string,
|
|
46
|
+
) => Promise<{ success: boolean; error?: string }>
|
|
47
|
+
captchaConfig?: { provider: 'recaptcha' | 'turnstile' | 'none'; siteKey: string | null }
|
|
39
48
|
}
|
|
40
49
|
|
|
41
|
-
function AdminShell({
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
50
|
+
function AdminShell({
|
|
51
|
+
config,
|
|
52
|
+
session,
|
|
53
|
+
basePath = '/admin',
|
|
54
|
+
initialPath = '/',
|
|
55
|
+
setupRequired,
|
|
56
|
+
onSetupComplete,
|
|
57
|
+
onLogin,
|
|
58
|
+
captchaConfig,
|
|
59
|
+
}: AdminRootProps) {
|
|
60
|
+
const { currentPath, navigate, matchRoute } = useAdminRouter(basePath, initialPath)
|
|
61
|
+
const [shortcutHelpOpen, setShortcutHelpOpen] = useState(false)
|
|
62
|
+
|
|
63
|
+
useBranding(config)
|
|
64
|
+
useAdminPageTitle(config, currentPath)
|
|
65
|
+
|
|
66
|
+
// When the session was minted via a custom Server Action (the Next.js App
|
|
67
|
+
// Router pattern) the admin won't have hit /auth/login directly and thus
|
|
68
|
+
// won't have an actuate_csrf cookie yet — every subsequent mutation 403s.
|
|
69
|
+
// Proactively bootstrap one as soon as we mount with a session. cmsApi
|
|
70
|
+
// also bootstraps lazily inside non-GET requests as a belt-and-braces.
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
if (session) {
|
|
73
|
+
void ensureCsrfToken()
|
|
74
|
+
}
|
|
75
|
+
}, [session])
|
|
76
|
+
|
|
77
|
+
const shortcuts = useMemo(
|
|
78
|
+
() => ({
|
|
79
|
+
'mod+k': () => {
|
|
80
|
+
const searchInput = document.querySelector<HTMLInputElement>('input[placeholder*="Search"]')
|
|
81
|
+
searchInput?.focus()
|
|
82
|
+
},
|
|
83
|
+
'mod+s': () => {
|
|
84
|
+
const saveBtn = document.querySelector<HTMLButtonElement>('[data-shortcut="save"]')
|
|
85
|
+
saveBtn?.click()
|
|
86
|
+
},
|
|
87
|
+
escape: () => {
|
|
88
|
+
const closeBtn = document.querySelector<HTMLButtonElement>('[data-shortcut="close"]')
|
|
89
|
+
closeBtn?.click()
|
|
90
|
+
},
|
|
91
|
+
'mod+/': () => {
|
|
92
|
+
setShortcutHelpOpen((prev) => !prev)
|
|
93
|
+
},
|
|
94
|
+
}),
|
|
95
|
+
[],
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
useKeyboardShortcuts(shortcuts)
|
|
99
|
+
|
|
100
|
+
// IMPORTANT: this useMemo MUST stay above the `setupRequired` / `!session`
|
|
101
|
+
// early returns. React's Rules of Hooks require the same number of hooks
|
|
102
|
+
// on every render — putting it below the early returns means we call N
|
|
103
|
+
// hooks pre-login and N+1 post-login, which crashes AdminShell with
|
|
104
|
+
// "Rendered more hooks than during the previous render." (caught by the
|
|
105
|
+
// e2e auth.spec.ts → login redirects to dashboard test).
|
|
106
|
+
const collectionMap = useMemo(() => {
|
|
107
|
+
const map = new Map<string, { slug: string; type?: string }>()
|
|
108
|
+
if (config?.collections) {
|
|
109
|
+
for (const c of Object.values(
|
|
110
|
+
config.collections as Record<string, { slug: string; type?: string }>,
|
|
111
|
+
)) {
|
|
112
|
+
if (c?.slug) map.set(c.slug, c)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (map.size === 0) {
|
|
116
|
+
map.set('pages', { slug: 'pages', type: 'page' })
|
|
117
|
+
map.set('posts', { slug: 'posts' })
|
|
118
|
+
}
|
|
119
|
+
return map
|
|
120
|
+
}, [config])
|
|
67
121
|
|
|
68
122
|
if (setupRequired && onSetupComplete) {
|
|
69
|
-
return
|
|
123
|
+
return (
|
|
124
|
+
<SetupWizard
|
|
125
|
+
onComplete={onSetupComplete}
|
|
126
|
+
siteName={config?.admin?.branding?.name ?? 'Actuate CMS'}
|
|
127
|
+
/>
|
|
128
|
+
)
|
|
70
129
|
}
|
|
71
130
|
|
|
72
131
|
if (!session && !setupRequired) {
|
|
73
132
|
if (matchRoute('/forgot-password')) {
|
|
74
|
-
return <ForgotPassword onNavigate={navigate}
|
|
133
|
+
return <ForgotPassword onNavigate={navigate} />
|
|
75
134
|
}
|
|
76
135
|
|
|
77
|
-
const resetMatch = matchRoute('/reset-password')
|
|
136
|
+
const resetMatch = matchRoute('/reset-password')
|
|
78
137
|
if (resetMatch) {
|
|
79
|
-
const params = new URLSearchParams(
|
|
80
|
-
|
|
138
|
+
const params = new URLSearchParams(
|
|
139
|
+
typeof window !== 'undefined' ? window.location.search : '',
|
|
140
|
+
)
|
|
141
|
+
return <ResetPassword onNavigate={navigate} token={params.get('token')} />
|
|
81
142
|
}
|
|
82
143
|
|
|
83
144
|
if (onLogin) {
|
|
84
|
-
return <Login onLogin={onLogin} onNavigate={navigate} captchaConfig={captchaConfig}
|
|
145
|
+
return <Login onLogin={onLogin} onNavigate={navigate} captchaConfig={captchaConfig} />
|
|
85
146
|
}
|
|
86
147
|
return (
|
|
87
148
|
<div className="min-h-screen flex items-center justify-center bg-background">
|
|
@@ -90,114 +151,178 @@ function AdminShell({ config, session, basePath = '/admin', initialPath = '/', s
|
|
|
90
151
|
<p className="text-sm text-muted-foreground">Please log in to access the admin panel.</p>
|
|
91
152
|
</div>
|
|
92
153
|
</div>
|
|
93
|
-
)
|
|
154
|
+
)
|
|
94
155
|
}
|
|
95
156
|
|
|
96
|
-
const collectionSlugs = config?.collections
|
|
97
|
-
? Object.values(config.collections as Record<string, { slug: string }>).map((c) => c.slug)
|
|
98
|
-
: ['pages', 'posts'];
|
|
99
|
-
|
|
100
157
|
function renderView() {
|
|
101
158
|
if (matchRoute('/')) {
|
|
102
|
-
return <Dashboard config={config} session={session} onNavigate={navigate}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const pageBuilderNew = matchRoute('/page-builder/new');
|
|
106
|
-
if (pageBuilderNew) {
|
|
107
|
-
return <PageBuilder collectionSlug="pages" config={config} onNavigate={navigate} />;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const pageBuilderEdit = matchRoute('/page-builder/:id');
|
|
111
|
-
if (pageBuilderEdit?.id) {
|
|
112
|
-
return <PageBuilder documentId={pageBuilderEdit.id} collectionSlug="pages" config={config} onNavigate={navigate} />;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
for (const slug of collectionSlugs) {
|
|
116
|
-
const newMatch = matchRoute(`/${slug}/new`);
|
|
117
|
-
if (newMatch) {
|
|
118
|
-
return <DocumentEdit collectionSlug={slug} config={config} />;
|
|
119
|
-
}
|
|
120
|
-
const editMatch = matchRoute(`/${slug}/:id`);
|
|
121
|
-
if (editMatch?.id) {
|
|
122
|
-
return <DocumentEdit collectionSlug={slug} documentId={editMatch.id} config={config} />;
|
|
123
|
-
}
|
|
124
|
-
if (matchRoute(`/${slug}`)) {
|
|
125
|
-
return <CollectionList collectionSlug={slug} config={config} onNavigate={navigate} />;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const newCollMatch = matchRoute('/collections/:slug/new');
|
|
130
|
-
if (newCollMatch?.slug) {
|
|
131
|
-
return <DocumentEdit collectionSlug={newCollMatch.slug} config={config} />;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const editCollMatch = matchRoute('/collections/:slug/:id');
|
|
135
|
-
if (editCollMatch?.slug && editCollMatch.id) {
|
|
136
|
-
return <DocumentEdit collectionSlug={editCollMatch.slug} documentId={editCollMatch.id} config={config} />;
|
|
159
|
+
return <Dashboard config={config} session={session} onNavigate={navigate} />
|
|
137
160
|
}
|
|
138
161
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
162
|
+
// Reserved admin routes — must match BEFORE iterating collection slugs
|
|
163
|
+
// so they cannot be shadowed by a consumer-defined collection (e.g.
|
|
164
|
+
// a collection slugged `media`, `users`, or `settings`).
|
|
143
165
|
|
|
144
166
|
if (matchRoute('/media')) {
|
|
145
|
-
return <MediaBrowser onNavigate={navigate}
|
|
167
|
+
return <MediaBrowser onNavigate={navigate} />
|
|
146
168
|
}
|
|
147
169
|
|
|
148
170
|
if (matchRoute('/forms/new')) {
|
|
149
|
-
return <FormEditor onNavigate={navigate}
|
|
171
|
+
return <FormEditor onNavigate={navigate} />
|
|
150
172
|
}
|
|
151
|
-
const formEdit = matchRoute('/forms/:id/edit')
|
|
173
|
+
const formEdit = matchRoute('/forms/:id/edit')
|
|
152
174
|
if (formEdit?.id) {
|
|
153
|
-
return <FormEditor formId={formEdit.id} onNavigate={navigate}
|
|
175
|
+
return <FormEditor formId={formEdit.id} onNavigate={navigate} />
|
|
154
176
|
}
|
|
155
|
-
const formSubmissions = matchRoute('/forms/:id/submissions')
|
|
177
|
+
const formSubmissions = matchRoute('/forms/:id/submissions')
|
|
156
178
|
if (formSubmissions?.id) {
|
|
157
|
-
return <FormSubmissions formId={formSubmissions.id} onNavigate={navigate}
|
|
179
|
+
return <FormSubmissions formId={formSubmissions.id} onNavigate={navigate} />
|
|
158
180
|
}
|
|
159
181
|
if (matchRoute('/forms')) {
|
|
160
|
-
return <Forms onNavigate={navigate}
|
|
182
|
+
return <Forms onNavigate={navigate} />
|
|
161
183
|
}
|
|
162
184
|
|
|
163
185
|
if (matchRoute('/seo/redirects')) {
|
|
164
|
-
return <SEO onNavigate={navigate} initialTab="redirects"
|
|
186
|
+
return <SEO onNavigate={navigate} initialTab="redirects" />
|
|
165
187
|
}
|
|
166
188
|
if (matchRoute('/seo/canonicals')) {
|
|
167
|
-
return <SEO onNavigate={navigate} initialTab="canonicals"
|
|
189
|
+
return <SEO onNavigate={navigate} initialTab="canonicals" />
|
|
168
190
|
}
|
|
169
191
|
if (matchRoute('/seo/links')) {
|
|
170
|
-
return <SEO onNavigate={navigate} initialTab="links"
|
|
192
|
+
return <SEO onNavigate={navigate} initialTab="links" />
|
|
171
193
|
}
|
|
172
194
|
if (matchRoute('/seo')) {
|
|
173
|
-
return <SEO onNavigate={navigate} initialTab="pages"
|
|
195
|
+
return <SEO onNavigate={navigate} initialTab="pages" />
|
|
174
196
|
}
|
|
175
197
|
|
|
176
198
|
if (matchRoute('/script-tags/new')) {
|
|
177
|
-
return <ScriptTagEditor onNavigate={navigate}
|
|
199
|
+
return <ScriptTagEditor onNavigate={navigate} />
|
|
178
200
|
}
|
|
179
|
-
const scriptTagEdit = matchRoute('/script-tags/:id')
|
|
201
|
+
const scriptTagEdit = matchRoute('/script-tags/:id')
|
|
180
202
|
if (scriptTagEdit?.id) {
|
|
181
|
-
return <ScriptTagEditor tagId={scriptTagEdit.id} onNavigate={navigate}
|
|
203
|
+
return <ScriptTagEditor tagId={scriptTagEdit.id} onNavigate={navigate} />
|
|
182
204
|
}
|
|
183
205
|
if (matchRoute('/script-tags')) {
|
|
184
|
-
return <ScriptTags onNavigate={navigate}
|
|
206
|
+
return <ScriptTags onNavigate={navigate} />
|
|
185
207
|
}
|
|
186
208
|
|
|
187
209
|
if (matchRoute('/saved-sections')) {
|
|
188
|
-
return <SavedSections onNavigate={navigate} config={config}
|
|
210
|
+
return <SavedSections onNavigate={navigate} config={config} />
|
|
189
211
|
}
|
|
190
212
|
|
|
191
213
|
if (matchRoute('/page-templates')) {
|
|
192
|
-
return <PageTemplates onNavigate={navigate}
|
|
214
|
+
return <PageTemplates onNavigate={navigate} />
|
|
193
215
|
}
|
|
194
216
|
|
|
195
217
|
if (matchRoute('/users')) {
|
|
196
|
-
return <Users onNavigate={navigate}
|
|
218
|
+
return <Users onNavigate={navigate} />
|
|
197
219
|
}
|
|
198
220
|
|
|
199
221
|
if (matchRoute('/settings')) {
|
|
200
|
-
return <Settings onNavigate={navigate} config={config}
|
|
222
|
+
return <Settings onNavigate={navigate} config={config} />
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Page Builder routes — explicit /page-builder/* takes precedence over
|
|
226
|
+
// the collection-derived routing below, but we ALSO route a collection
|
|
227
|
+
// declared as `type: 'page'` through the Page Builder by default.
|
|
228
|
+
const pageBuilderNew = matchRoute('/page-builder/new')
|
|
229
|
+
if (pageBuilderNew) {
|
|
230
|
+
return <PageBuilder collectionSlug="pages" config={config} onNavigate={navigate} />
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const pageBuilderEdit = matchRoute('/page-builder/:id')
|
|
234
|
+
if (pageBuilderEdit?.id) {
|
|
235
|
+
return (
|
|
236
|
+
<PageBuilder
|
|
237
|
+
documentId={pageBuilderEdit.id}
|
|
238
|
+
collectionSlug="pages"
|
|
239
|
+
config={config}
|
|
240
|
+
onNavigate={navigate}
|
|
241
|
+
/>
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const RESERVED_SLUGS = new Set([
|
|
246
|
+
'media',
|
|
247
|
+
'forms',
|
|
248
|
+
'seo',
|
|
249
|
+
'script-tags',
|
|
250
|
+
'saved-sections',
|
|
251
|
+
'page-templates',
|
|
252
|
+
'users',
|
|
253
|
+
'settings',
|
|
254
|
+
'page-builder',
|
|
255
|
+
'collections',
|
|
256
|
+
])
|
|
257
|
+
|
|
258
|
+
for (const [slug, def] of collectionMap) {
|
|
259
|
+
if (RESERVED_SLUGS.has(slug)) continue
|
|
260
|
+
|
|
261
|
+
const isPageType = def.type === 'page'
|
|
262
|
+
const newMatch = matchRoute(`/${slug}/new`)
|
|
263
|
+
if (newMatch) {
|
|
264
|
+
return isPageType ? (
|
|
265
|
+
<PageBuilder collectionSlug={slug} config={config} onNavigate={navigate} />
|
|
266
|
+
) : (
|
|
267
|
+
<DocumentEdit collectionSlug={slug} config={config} />
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
const editMatch = matchRoute(`/${slug}/:id`)
|
|
271
|
+
if (editMatch?.id) {
|
|
272
|
+
return isPageType ? (
|
|
273
|
+
<PageBuilder
|
|
274
|
+
documentId={editMatch.id}
|
|
275
|
+
collectionSlug={slug}
|
|
276
|
+
config={config}
|
|
277
|
+
onNavigate={navigate}
|
|
278
|
+
/>
|
|
279
|
+
) : (
|
|
280
|
+
<DocumentEdit collectionSlug={slug} documentId={editMatch.id} config={config} />
|
|
281
|
+
)
|
|
282
|
+
}
|
|
283
|
+
if (matchRoute(`/${slug}`)) {
|
|
284
|
+
return <CollectionList collectionSlug={slug} config={config} onNavigate={navigate} />
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const newCollMatch = matchRoute('/collections/:slug/new')
|
|
289
|
+
if (newCollMatch?.slug) {
|
|
290
|
+
const def = collectionMap.get(newCollMatch.slug)
|
|
291
|
+
return def?.type === 'page' ? (
|
|
292
|
+
<PageBuilder collectionSlug={newCollMatch.slug} config={config} onNavigate={navigate} />
|
|
293
|
+
) : (
|
|
294
|
+
<DocumentEdit collectionSlug={newCollMatch.slug} config={config} />
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const editCollMatch = matchRoute('/collections/:slug/:id')
|
|
299
|
+
if (editCollMatch?.slug && editCollMatch.id) {
|
|
300
|
+
const def = collectionMap.get(editCollMatch.slug)
|
|
301
|
+
return def?.type === 'page' ? (
|
|
302
|
+
<PageBuilder
|
|
303
|
+
documentId={editCollMatch.id}
|
|
304
|
+
collectionSlug={editCollMatch.slug}
|
|
305
|
+
config={config}
|
|
306
|
+
onNavigate={navigate}
|
|
307
|
+
/>
|
|
308
|
+
) : (
|
|
309
|
+
<DocumentEdit
|
|
310
|
+
collectionSlug={editCollMatch.slug}
|
|
311
|
+
documentId={editCollMatch.id}
|
|
312
|
+
config={config}
|
|
313
|
+
/>
|
|
314
|
+
)
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const collectionMatch = matchRoute('/collections/:slug')
|
|
318
|
+
if (collectionMatch?.slug) {
|
|
319
|
+
return (
|
|
320
|
+
<CollectionList
|
|
321
|
+
collectionSlug={collectionMatch.slug}
|
|
322
|
+
config={config}
|
|
323
|
+
onNavigate={navigate}
|
|
324
|
+
/>
|
|
325
|
+
)
|
|
201
326
|
}
|
|
202
327
|
|
|
203
328
|
return (
|
|
@@ -211,24 +336,24 @@ function AdminShell({ config, session, basePath = '/admin', initialPath = '/', s
|
|
|
211
336
|
Back to Dashboard
|
|
212
337
|
</button>
|
|
213
338
|
</div>
|
|
214
|
-
)
|
|
339
|
+
)
|
|
215
340
|
}
|
|
216
341
|
|
|
217
342
|
return (
|
|
218
343
|
<Layout config={config} session={session} currentPath={currentPath} onNavigate={navigate}>
|
|
219
|
-
<ErrorBoundary>
|
|
220
|
-
{renderView()}
|
|
221
|
-
</ErrorBoundary>
|
|
344
|
+
<ErrorBoundary>{renderView()}</ErrorBoundary>
|
|
222
345
|
{shortcutHelpOpen && <ShortcutHelp onClose={() => setShortcutHelpOpen(false)} />}
|
|
223
346
|
</Layout>
|
|
224
|
-
)
|
|
347
|
+
)
|
|
225
348
|
}
|
|
226
349
|
|
|
227
350
|
function ShortcutHelp({ onClose }: { onClose: () => void }) {
|
|
228
351
|
return (
|
|
229
352
|
<div
|
|
230
353
|
className="fixed inset-0 z-100 flex items-center justify-center bg-black/50"
|
|
231
|
-
onClick={(e) => {
|
|
354
|
+
onClick={(e) => {
|
|
355
|
+
if (e.target === e.currentTarget) onClose()
|
|
356
|
+
}}
|
|
232
357
|
>
|
|
233
358
|
<div className="bg-card text-card-foreground rounded-xl shadow-2xl border border-border p-6 max-w-sm w-full mx-4">
|
|
234
359
|
<h3 className="text-lg font-semibold mb-4">Keyboard Shortcuts</h3>
|
|
@@ -253,86 +378,86 @@ function ShortcutHelp({ onClose }: { onClose: () => void }) {
|
|
|
253
378
|
</button>
|
|
254
379
|
</div>
|
|
255
380
|
</div>
|
|
256
|
-
)
|
|
381
|
+
)
|
|
257
382
|
}
|
|
258
383
|
|
|
259
384
|
function useBranding(config: any) {
|
|
260
|
-
const originalFaviconRef = useRef<string | null>(null)
|
|
261
|
-
const originalTitleRef = useRef<string | null>(null)
|
|
262
|
-
const injectedLinkRef = useRef<HTMLLinkElement | null>(null)
|
|
385
|
+
const originalFaviconRef = useRef<string | null>(null)
|
|
386
|
+
const originalTitleRef = useRef<string | null>(null)
|
|
387
|
+
const injectedLinkRef = useRef<HTMLLinkElement | null>(null)
|
|
263
388
|
|
|
264
389
|
useEffect(() => {
|
|
265
|
-
const branding = config?.admin?.branding
|
|
266
|
-
if (!branding) return
|
|
390
|
+
const branding = config?.admin?.branding
|
|
391
|
+
if (!branding) return
|
|
267
392
|
|
|
268
393
|
// --- Favicon ---
|
|
269
394
|
if (branding.favicon) {
|
|
270
|
-
const existing = document.querySelector<HTMLLinkElement>('link[rel="icon"]')
|
|
271
|
-
originalFaviconRef.current = existing?.href ?? null
|
|
395
|
+
const existing = document.querySelector<HTMLLinkElement>('link[rel="icon"]')
|
|
396
|
+
originalFaviconRef.current = existing?.href ?? null
|
|
272
397
|
|
|
273
398
|
if (existing) {
|
|
274
|
-
existing.href = branding.favicon
|
|
399
|
+
existing.href = branding.favicon
|
|
275
400
|
} else {
|
|
276
|
-
const link = document.createElement('link')
|
|
277
|
-
link.rel = 'icon'
|
|
278
|
-
link.href = branding.favicon
|
|
279
|
-
document.head.appendChild(link)
|
|
280
|
-
injectedLinkRef.current = link
|
|
401
|
+
const link = document.createElement('link')
|
|
402
|
+
link.rel = 'icon'
|
|
403
|
+
link.href = branding.favicon
|
|
404
|
+
document.head.appendChild(link)
|
|
405
|
+
injectedLinkRef.current = link
|
|
281
406
|
}
|
|
282
407
|
}
|
|
283
408
|
|
|
284
409
|
// --- Document title ---
|
|
285
|
-
originalTitleRef.current = document.title
|
|
410
|
+
originalTitleRef.current = document.title
|
|
286
411
|
if (branding.title) {
|
|
287
|
-
document.title = branding.title
|
|
412
|
+
document.title = branding.title
|
|
288
413
|
} else if (branding.name) {
|
|
289
|
-
document.title = `${branding.name} Admin
|
|
414
|
+
document.title = `${branding.name} Admin`
|
|
290
415
|
}
|
|
291
416
|
|
|
292
417
|
// --- Primary color ---
|
|
293
|
-
const adminEl = document.querySelector<HTMLElement>('.actuate-admin')
|
|
418
|
+
const adminEl = document.querySelector<HTMLElement>('.actuate-admin')
|
|
294
419
|
if (branding.primaryColor && adminEl) {
|
|
295
|
-
adminEl.style.setProperty('--primary', branding.primaryColor)
|
|
296
|
-
adminEl.style.setProperty('--sidebar-primary', branding.primaryColor)
|
|
420
|
+
adminEl.style.setProperty('--primary', branding.primaryColor)
|
|
421
|
+
adminEl.style.setProperty('--sidebar-primary', branding.primaryColor)
|
|
297
422
|
}
|
|
298
423
|
|
|
299
424
|
return () => {
|
|
300
425
|
// Restore favicon
|
|
301
426
|
if (branding.favicon) {
|
|
302
|
-
const link = document.querySelector<HTMLLinkElement>('link[rel="icon"]')
|
|
427
|
+
const link = document.querySelector<HTMLLinkElement>('link[rel="icon"]')
|
|
303
428
|
if (link && originalFaviconRef.current) {
|
|
304
|
-
link.href = originalFaviconRef.current
|
|
429
|
+
link.href = originalFaviconRef.current
|
|
305
430
|
}
|
|
306
431
|
if (injectedLinkRef.current) {
|
|
307
|
-
injectedLinkRef.current.remove()
|
|
308
|
-
injectedLinkRef.current = null
|
|
432
|
+
injectedLinkRef.current.remove()
|
|
433
|
+
injectedLinkRef.current = null
|
|
309
434
|
}
|
|
310
435
|
}
|
|
311
436
|
|
|
312
437
|
// Restore title
|
|
313
438
|
if (originalTitleRef.current !== null) {
|
|
314
|
-
document.title = originalTitleRef.current
|
|
439
|
+
document.title = originalTitleRef.current
|
|
315
440
|
}
|
|
316
441
|
|
|
317
442
|
// Remove primary color override
|
|
318
443
|
if (branding.primaryColor && adminEl) {
|
|
319
|
-
adminEl.style.removeProperty('--primary')
|
|
320
|
-
adminEl.style.removeProperty('--sidebar-primary')
|
|
444
|
+
adminEl.style.removeProperty('--primary')
|
|
445
|
+
adminEl.style.removeProperty('--sidebar-primary')
|
|
321
446
|
}
|
|
322
|
-
}
|
|
323
|
-
}, [config])
|
|
447
|
+
}
|
|
448
|
+
}, [config])
|
|
324
449
|
}
|
|
325
450
|
|
|
326
451
|
function useAdminPageTitle(config: any, currentPath: string) {
|
|
327
452
|
useEffect(() => {
|
|
328
|
-
const branding = config?.admin?.branding
|
|
329
|
-
const baseName = branding?.title ?? (branding?.name ? `${branding.name} Admin` : null)
|
|
330
|
-
if (!baseName) return
|
|
331
|
-
|
|
332
|
-
const segment = currentPath === '/' ? 'Dashboard' : currentPath.split('/').filter(Boolean)[0]
|
|
333
|
-
const pageName = segment ? segment.charAt(0).toUpperCase() + segment.slice(1) : 'Dashboard'
|
|
334
|
-
document.title = `${pageName} — ${baseName}
|
|
335
|
-
}, [config, currentPath])
|
|
453
|
+
const branding = config?.admin?.branding
|
|
454
|
+
const baseName = branding?.title ?? (branding?.name ? `${branding.name} Admin` : null)
|
|
455
|
+
if (!baseName) return
|
|
456
|
+
|
|
457
|
+
const segment = currentPath === '/' ? 'Dashboard' : currentPath.split('/').filter(Boolean)[0]
|
|
458
|
+
const pageName = segment ? segment.charAt(0).toUpperCase() + segment.slice(1) : 'Dashboard'
|
|
459
|
+
document.title = `${pageName} — ${baseName}`
|
|
460
|
+
}, [config, currentPath])
|
|
336
461
|
}
|
|
337
462
|
|
|
338
463
|
const ISOLATION_STYLE: React.CSSProperties = {
|
|
@@ -341,10 +466,10 @@ const ISOLATION_STYLE: React.CSSProperties = {
|
|
|
341
466
|
zIndex: 50,
|
|
342
467
|
overflow: 'auto',
|
|
343
468
|
isolation: 'isolate',
|
|
344
|
-
}
|
|
469
|
+
}
|
|
345
470
|
|
|
346
471
|
export function AdminRoot(props: AdminRootProps) {
|
|
347
|
-
const defaultDarkMode = props.config?.admin?.branding?.darkMode
|
|
472
|
+
const defaultDarkMode = props.config?.admin?.branding?.darkMode
|
|
348
473
|
|
|
349
474
|
return (
|
|
350
475
|
<div style={ISOLATION_STYLE} className="actuate-admin">
|
|
@@ -354,5 +479,5 @@ export function AdminRoot(props: AdminRootProps) {
|
|
|
354
479
|
</LocaleProvider>
|
|
355
480
|
</ThemeProvider>
|
|
356
481
|
</div>
|
|
357
|
-
)
|
|
482
|
+
)
|
|
358
483
|
}
|