@actuate-media/cms-admin 0.8.0 → 0.8.2
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 +44 -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.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 +40 -17
- 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 +1 -1
- 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 +4 -2
- 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 +263 -191
- 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 +34 -34
- 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 +26 -2
- 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 +607 -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 +94 -96
- 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 +156 -155
- 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,50 +1,67 @@
|
|
|
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'
|
|
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'
|
|
30
30
|
|
|
31
31
|
export interface AdminRootProps {
|
|
32
|
-
config: any
|
|
33
|
-
session: any
|
|
34
|
-
basePath?: string
|
|
35
|
-
initialPath?: string
|
|
36
|
-
setupRequired?: boolean
|
|
37
|
-
onSetupComplete?: (data: {
|
|
38
|
-
|
|
39
|
-
|
|
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 }
|
|
40
48
|
}
|
|
41
49
|
|
|
42
|
-
function AdminShell({
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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)
|
|
48
65
|
|
|
49
66
|
// When the session was minted via a custom Server Action (the Next.js App
|
|
50
67
|
// Router pattern) the admin won't have hit /auth/login directly and thus
|
|
@@ -53,47 +70,79 @@ function AdminShell({ config, session, basePath = '/admin', initialPath = '/', s
|
|
|
53
70
|
// also bootstraps lazily inside non-GET requests as a belt-and-braces.
|
|
54
71
|
useEffect(() => {
|
|
55
72
|
if (session) {
|
|
56
|
-
void ensureCsrfToken()
|
|
57
|
-
}
|
|
58
|
-
}, [session])
|
|
59
|
-
|
|
60
|
-
const shortcuts = useMemo(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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])
|
|
79
121
|
|
|
80
122
|
if (setupRequired && onSetupComplete) {
|
|
81
|
-
return
|
|
123
|
+
return (
|
|
124
|
+
<SetupWizard
|
|
125
|
+
onComplete={onSetupComplete}
|
|
126
|
+
siteName={config?.admin?.branding?.name ?? 'Actuate CMS'}
|
|
127
|
+
/>
|
|
128
|
+
)
|
|
82
129
|
}
|
|
83
130
|
|
|
84
131
|
if (!session && !setupRequired) {
|
|
85
132
|
if (matchRoute('/forgot-password')) {
|
|
86
|
-
return <ForgotPassword onNavigate={navigate}
|
|
133
|
+
return <ForgotPassword onNavigate={navigate} />
|
|
87
134
|
}
|
|
88
135
|
|
|
89
|
-
const resetMatch = matchRoute('/reset-password')
|
|
136
|
+
const resetMatch = matchRoute('/reset-password')
|
|
90
137
|
if (resetMatch) {
|
|
91
|
-
const params = new URLSearchParams(
|
|
92
|
-
|
|
138
|
+
const params = new URLSearchParams(
|
|
139
|
+
typeof window !== 'undefined' ? window.location.search : '',
|
|
140
|
+
)
|
|
141
|
+
return <ResetPassword onNavigate={navigate} token={params.get('token')} />
|
|
93
142
|
}
|
|
94
143
|
|
|
95
144
|
if (onLogin) {
|
|
96
|
-
return <Login onLogin={onLogin} onNavigate={navigate} captchaConfig={captchaConfig}
|
|
145
|
+
return <Login onLogin={onLogin} onNavigate={navigate} captchaConfig={captchaConfig} />
|
|
97
146
|
}
|
|
98
147
|
return (
|
|
99
148
|
<div className="min-h-screen flex items-center justify-center bg-background">
|
|
@@ -102,32 +151,12 @@ function AdminShell({ config, session, basePath = '/admin', initialPath = '/', s
|
|
|
102
151
|
<p className="text-sm text-muted-foreground">Please log in to access the admin panel.</p>
|
|
103
152
|
</div>
|
|
104
153
|
</div>
|
|
105
|
-
)
|
|
154
|
+
)
|
|
106
155
|
}
|
|
107
156
|
|
|
108
|
-
// Map of collection slug → definition. Used to:
|
|
109
|
-
// 1. Decide which editor (PageBuilder vs DocumentEdit) to render based
|
|
110
|
-
// on `collection.type === 'page'`.
|
|
111
|
-
// 2. Skip collections that collide with reserved admin paths so a
|
|
112
|
-
// consumer-defined collection named `users` can't hijack the Users
|
|
113
|
-
// view (or vice versa).
|
|
114
|
-
const collectionMap = useMemo(() => {
|
|
115
|
-
const map = new Map<string, { slug: string; type?: string }>();
|
|
116
|
-
if (config?.collections) {
|
|
117
|
-
for (const c of Object.values(config.collections as Record<string, { slug: string; type?: string }>)) {
|
|
118
|
-
if (c?.slug) map.set(c.slug, c);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
if (map.size === 0) {
|
|
122
|
-
map.set('pages', { slug: 'pages', type: 'page' });
|
|
123
|
-
map.set('posts', { slug: 'posts' });
|
|
124
|
-
}
|
|
125
|
-
return map;
|
|
126
|
-
}, [config]);
|
|
127
|
-
|
|
128
157
|
function renderView() {
|
|
129
158
|
if (matchRoute('/')) {
|
|
130
|
-
return <Dashboard config={config} session={session} onNavigate={navigate}
|
|
159
|
+
return <Dashboard config={config} session={session} onNavigate={navigate} />
|
|
131
160
|
}
|
|
132
161
|
|
|
133
162
|
// Reserved admin routes — must match BEFORE iterating collection slugs
|
|
@@ -135,122 +164,165 @@ function AdminShell({ config, session, basePath = '/admin', initialPath = '/', s
|
|
|
135
164
|
// a collection slugged `media`, `users`, or `settings`).
|
|
136
165
|
|
|
137
166
|
if (matchRoute('/media')) {
|
|
138
|
-
return <MediaBrowser onNavigate={navigate}
|
|
167
|
+
return <MediaBrowser onNavigate={navigate} />
|
|
139
168
|
}
|
|
140
169
|
|
|
141
170
|
if (matchRoute('/forms/new')) {
|
|
142
|
-
return <FormEditor onNavigate={navigate}
|
|
171
|
+
return <FormEditor onNavigate={navigate} />
|
|
143
172
|
}
|
|
144
|
-
const formEdit = matchRoute('/forms/:id/edit')
|
|
173
|
+
const formEdit = matchRoute('/forms/:id/edit')
|
|
145
174
|
if (formEdit?.id) {
|
|
146
|
-
return <FormEditor formId={formEdit.id} onNavigate={navigate}
|
|
175
|
+
return <FormEditor formId={formEdit.id} onNavigate={navigate} />
|
|
147
176
|
}
|
|
148
|
-
const formSubmissions = matchRoute('/forms/:id/submissions')
|
|
177
|
+
const formSubmissions = matchRoute('/forms/:id/submissions')
|
|
149
178
|
if (formSubmissions?.id) {
|
|
150
|
-
return <FormSubmissions formId={formSubmissions.id} onNavigate={navigate}
|
|
179
|
+
return <FormSubmissions formId={formSubmissions.id} onNavigate={navigate} />
|
|
151
180
|
}
|
|
152
181
|
if (matchRoute('/forms')) {
|
|
153
|
-
return <Forms onNavigate={navigate}
|
|
182
|
+
return <Forms onNavigate={navigate} />
|
|
154
183
|
}
|
|
155
184
|
|
|
156
185
|
if (matchRoute('/seo/redirects')) {
|
|
157
|
-
return <SEO onNavigate={navigate} initialTab="redirects"
|
|
186
|
+
return <SEO onNavigate={navigate} initialTab="redirects" />
|
|
158
187
|
}
|
|
159
188
|
if (matchRoute('/seo/canonicals')) {
|
|
160
|
-
return <SEO onNavigate={navigate} initialTab="canonicals"
|
|
189
|
+
return <SEO onNavigate={navigate} initialTab="canonicals" />
|
|
161
190
|
}
|
|
162
191
|
if (matchRoute('/seo/links')) {
|
|
163
|
-
return <SEO onNavigate={navigate} initialTab="links"
|
|
192
|
+
return <SEO onNavigate={navigate} initialTab="links" />
|
|
164
193
|
}
|
|
165
194
|
if (matchRoute('/seo')) {
|
|
166
|
-
return <SEO onNavigate={navigate} initialTab="pages"
|
|
195
|
+
return <SEO onNavigate={navigate} initialTab="pages" />
|
|
167
196
|
}
|
|
168
197
|
|
|
169
198
|
if (matchRoute('/script-tags/new')) {
|
|
170
|
-
return <ScriptTagEditor onNavigate={navigate}
|
|
199
|
+
return <ScriptTagEditor onNavigate={navigate} />
|
|
171
200
|
}
|
|
172
|
-
const scriptTagEdit = matchRoute('/script-tags/:id')
|
|
201
|
+
const scriptTagEdit = matchRoute('/script-tags/:id')
|
|
173
202
|
if (scriptTagEdit?.id) {
|
|
174
|
-
return <ScriptTagEditor tagId={scriptTagEdit.id} onNavigate={navigate}
|
|
203
|
+
return <ScriptTagEditor tagId={scriptTagEdit.id} onNavigate={navigate} />
|
|
175
204
|
}
|
|
176
205
|
if (matchRoute('/script-tags')) {
|
|
177
|
-
return <ScriptTags onNavigate={navigate}
|
|
206
|
+
return <ScriptTags onNavigate={navigate} />
|
|
178
207
|
}
|
|
179
208
|
|
|
180
209
|
if (matchRoute('/saved-sections')) {
|
|
181
|
-
return <SavedSections onNavigate={navigate} config={config}
|
|
210
|
+
return <SavedSections onNavigate={navigate} config={config} />
|
|
182
211
|
}
|
|
183
212
|
|
|
184
213
|
if (matchRoute('/page-templates')) {
|
|
185
|
-
return <PageTemplates onNavigate={navigate}
|
|
214
|
+
return <PageTemplates onNavigate={navigate} />
|
|
186
215
|
}
|
|
187
216
|
|
|
188
217
|
if (matchRoute('/users')) {
|
|
189
|
-
return <Users onNavigate={navigate}
|
|
218
|
+
return <Users onNavigate={navigate} />
|
|
190
219
|
}
|
|
191
220
|
|
|
192
221
|
if (matchRoute('/settings')) {
|
|
193
|
-
return <Settings onNavigate={navigate} config={config}
|
|
222
|
+
return <Settings onNavigate={navigate} config={config} />
|
|
194
223
|
}
|
|
195
224
|
|
|
196
225
|
// Page Builder routes — explicit /page-builder/* takes precedence over
|
|
197
226
|
// the collection-derived routing below, but we ALSO route a collection
|
|
198
227
|
// declared as `type: 'page'` through the Page Builder by default.
|
|
199
|
-
const pageBuilderNew = matchRoute('/page-builder/new')
|
|
228
|
+
const pageBuilderNew = matchRoute('/page-builder/new')
|
|
200
229
|
if (pageBuilderNew) {
|
|
201
|
-
return <PageBuilder collectionSlug="pages" config={config} onNavigate={navigate}
|
|
230
|
+
return <PageBuilder collectionSlug="pages" config={config} onNavigate={navigate} />
|
|
202
231
|
}
|
|
203
232
|
|
|
204
|
-
const pageBuilderEdit = matchRoute('/page-builder/:id')
|
|
233
|
+
const pageBuilderEdit = matchRoute('/page-builder/:id')
|
|
205
234
|
if (pageBuilderEdit?.id) {
|
|
206
|
-
return
|
|
235
|
+
return (
|
|
236
|
+
<PageBuilder
|
|
237
|
+
documentId={pageBuilderEdit.id}
|
|
238
|
+
collectionSlug="pages"
|
|
239
|
+
config={config}
|
|
240
|
+
onNavigate={navigate}
|
|
241
|
+
/>
|
|
242
|
+
)
|
|
207
243
|
}
|
|
208
244
|
|
|
209
245
|
const RESERVED_SLUGS = new Set([
|
|
210
|
-
'media',
|
|
211
|
-
'
|
|
212
|
-
|
|
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
|
+
])
|
|
213
257
|
|
|
214
258
|
for (const [slug, def] of collectionMap) {
|
|
215
|
-
if (RESERVED_SLUGS.has(slug)) continue
|
|
259
|
+
if (RESERVED_SLUGS.has(slug)) continue
|
|
216
260
|
|
|
217
|
-
const isPageType = def.type === 'page'
|
|
218
|
-
const newMatch = matchRoute(`/${slug}/new`)
|
|
261
|
+
const isPageType = def.type === 'page'
|
|
262
|
+
const newMatch = matchRoute(`/${slug}/new`)
|
|
219
263
|
if (newMatch) {
|
|
220
|
-
return isPageType
|
|
221
|
-
|
|
222
|
-
|
|
264
|
+
return isPageType ? (
|
|
265
|
+
<PageBuilder collectionSlug={slug} config={config} onNavigate={navigate} />
|
|
266
|
+
) : (
|
|
267
|
+
<DocumentEdit collectionSlug={slug} config={config} />
|
|
268
|
+
)
|
|
223
269
|
}
|
|
224
|
-
const editMatch = matchRoute(`/${slug}/:id`)
|
|
270
|
+
const editMatch = matchRoute(`/${slug}/:id`)
|
|
225
271
|
if (editMatch?.id) {
|
|
226
|
-
return isPageType
|
|
227
|
-
|
|
228
|
-
|
|
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
|
+
)
|
|
229
282
|
}
|
|
230
283
|
if (matchRoute(`/${slug}`)) {
|
|
231
|
-
return <CollectionList collectionSlug={slug} config={config} onNavigate={navigate}
|
|
284
|
+
return <CollectionList collectionSlug={slug} config={config} onNavigate={navigate} />
|
|
232
285
|
}
|
|
233
286
|
}
|
|
234
287
|
|
|
235
|
-
const newCollMatch = matchRoute('/collections/:slug/new')
|
|
288
|
+
const newCollMatch = matchRoute('/collections/:slug/new')
|
|
236
289
|
if (newCollMatch?.slug) {
|
|
237
|
-
const def = collectionMap.get(newCollMatch.slug)
|
|
238
|
-
return def?.type === 'page'
|
|
239
|
-
|
|
240
|
-
|
|
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
|
+
)
|
|
241
296
|
}
|
|
242
297
|
|
|
243
|
-
const editCollMatch = matchRoute('/collections/:slug/:id')
|
|
298
|
+
const editCollMatch = matchRoute('/collections/:slug/:id')
|
|
244
299
|
if (editCollMatch?.slug && editCollMatch.id) {
|
|
245
|
-
const def = collectionMap.get(editCollMatch.slug)
|
|
246
|
-
return def?.type === 'page'
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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')
|
|
252
318
|
if (collectionMatch?.slug) {
|
|
253
|
-
return
|
|
319
|
+
return (
|
|
320
|
+
<CollectionList
|
|
321
|
+
collectionSlug={collectionMatch.slug}
|
|
322
|
+
config={config}
|
|
323
|
+
onNavigate={navigate}
|
|
324
|
+
/>
|
|
325
|
+
)
|
|
254
326
|
}
|
|
255
327
|
|
|
256
328
|
return (
|
|
@@ -264,24 +336,24 @@ function AdminShell({ config, session, basePath = '/admin', initialPath = '/', s
|
|
|
264
336
|
Back to Dashboard
|
|
265
337
|
</button>
|
|
266
338
|
</div>
|
|
267
|
-
)
|
|
339
|
+
)
|
|
268
340
|
}
|
|
269
341
|
|
|
270
342
|
return (
|
|
271
343
|
<Layout config={config} session={session} currentPath={currentPath} onNavigate={navigate}>
|
|
272
|
-
<ErrorBoundary>
|
|
273
|
-
{renderView()}
|
|
274
|
-
</ErrorBoundary>
|
|
344
|
+
<ErrorBoundary>{renderView()}</ErrorBoundary>
|
|
275
345
|
{shortcutHelpOpen && <ShortcutHelp onClose={() => setShortcutHelpOpen(false)} />}
|
|
276
346
|
</Layout>
|
|
277
|
-
)
|
|
347
|
+
)
|
|
278
348
|
}
|
|
279
349
|
|
|
280
350
|
function ShortcutHelp({ onClose }: { onClose: () => void }) {
|
|
281
351
|
return (
|
|
282
352
|
<div
|
|
283
353
|
className="fixed inset-0 z-100 flex items-center justify-center bg-black/50"
|
|
284
|
-
onClick={(e) => {
|
|
354
|
+
onClick={(e) => {
|
|
355
|
+
if (e.target === e.currentTarget) onClose()
|
|
356
|
+
}}
|
|
285
357
|
>
|
|
286
358
|
<div className="bg-card text-card-foreground rounded-xl shadow-2xl border border-border p-6 max-w-sm w-full mx-4">
|
|
287
359
|
<h3 className="text-lg font-semibold mb-4">Keyboard Shortcuts</h3>
|
|
@@ -306,86 +378,86 @@ function ShortcutHelp({ onClose }: { onClose: () => void }) {
|
|
|
306
378
|
</button>
|
|
307
379
|
</div>
|
|
308
380
|
</div>
|
|
309
|
-
)
|
|
381
|
+
)
|
|
310
382
|
}
|
|
311
383
|
|
|
312
384
|
function useBranding(config: any) {
|
|
313
|
-
const originalFaviconRef = useRef<string | null>(null)
|
|
314
|
-
const originalTitleRef = useRef<string | null>(null)
|
|
315
|
-
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)
|
|
316
388
|
|
|
317
389
|
useEffect(() => {
|
|
318
|
-
const branding = config?.admin?.branding
|
|
319
|
-
if (!branding) return
|
|
390
|
+
const branding = config?.admin?.branding
|
|
391
|
+
if (!branding) return
|
|
320
392
|
|
|
321
393
|
// --- Favicon ---
|
|
322
394
|
if (branding.favicon) {
|
|
323
|
-
const existing = document.querySelector<HTMLLinkElement>('link[rel="icon"]')
|
|
324
|
-
originalFaviconRef.current = existing?.href ?? null
|
|
395
|
+
const existing = document.querySelector<HTMLLinkElement>('link[rel="icon"]')
|
|
396
|
+
originalFaviconRef.current = existing?.href ?? null
|
|
325
397
|
|
|
326
398
|
if (existing) {
|
|
327
|
-
existing.href = branding.favicon
|
|
399
|
+
existing.href = branding.favicon
|
|
328
400
|
} else {
|
|
329
|
-
const link = document.createElement('link')
|
|
330
|
-
link.rel = 'icon'
|
|
331
|
-
link.href = branding.favicon
|
|
332
|
-
document.head.appendChild(link)
|
|
333
|
-
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
|
|
334
406
|
}
|
|
335
407
|
}
|
|
336
408
|
|
|
337
409
|
// --- Document title ---
|
|
338
|
-
originalTitleRef.current = document.title
|
|
410
|
+
originalTitleRef.current = document.title
|
|
339
411
|
if (branding.title) {
|
|
340
|
-
document.title = branding.title
|
|
412
|
+
document.title = branding.title
|
|
341
413
|
} else if (branding.name) {
|
|
342
|
-
document.title = `${branding.name} Admin
|
|
414
|
+
document.title = `${branding.name} Admin`
|
|
343
415
|
}
|
|
344
416
|
|
|
345
417
|
// --- Primary color ---
|
|
346
|
-
const adminEl = document.querySelector<HTMLElement>('.actuate-admin')
|
|
418
|
+
const adminEl = document.querySelector<HTMLElement>('.actuate-admin')
|
|
347
419
|
if (branding.primaryColor && adminEl) {
|
|
348
|
-
adminEl.style.setProperty('--primary', branding.primaryColor)
|
|
349
|
-
adminEl.style.setProperty('--sidebar-primary', branding.primaryColor)
|
|
420
|
+
adminEl.style.setProperty('--primary', branding.primaryColor)
|
|
421
|
+
adminEl.style.setProperty('--sidebar-primary', branding.primaryColor)
|
|
350
422
|
}
|
|
351
423
|
|
|
352
424
|
return () => {
|
|
353
425
|
// Restore favicon
|
|
354
426
|
if (branding.favicon) {
|
|
355
|
-
const link = document.querySelector<HTMLLinkElement>('link[rel="icon"]')
|
|
427
|
+
const link = document.querySelector<HTMLLinkElement>('link[rel="icon"]')
|
|
356
428
|
if (link && originalFaviconRef.current) {
|
|
357
|
-
link.href = originalFaviconRef.current
|
|
429
|
+
link.href = originalFaviconRef.current
|
|
358
430
|
}
|
|
359
431
|
if (injectedLinkRef.current) {
|
|
360
|
-
injectedLinkRef.current.remove()
|
|
361
|
-
injectedLinkRef.current = null
|
|
432
|
+
injectedLinkRef.current.remove()
|
|
433
|
+
injectedLinkRef.current = null
|
|
362
434
|
}
|
|
363
435
|
}
|
|
364
436
|
|
|
365
437
|
// Restore title
|
|
366
438
|
if (originalTitleRef.current !== null) {
|
|
367
|
-
document.title = originalTitleRef.current
|
|
439
|
+
document.title = originalTitleRef.current
|
|
368
440
|
}
|
|
369
441
|
|
|
370
442
|
// Remove primary color override
|
|
371
443
|
if (branding.primaryColor && adminEl) {
|
|
372
|
-
adminEl.style.removeProperty('--primary')
|
|
373
|
-
adminEl.style.removeProperty('--sidebar-primary')
|
|
444
|
+
adminEl.style.removeProperty('--primary')
|
|
445
|
+
adminEl.style.removeProperty('--sidebar-primary')
|
|
374
446
|
}
|
|
375
|
-
}
|
|
376
|
-
}, [config])
|
|
447
|
+
}
|
|
448
|
+
}, [config])
|
|
377
449
|
}
|
|
378
450
|
|
|
379
451
|
function useAdminPageTitle(config: any, currentPath: string) {
|
|
380
452
|
useEffect(() => {
|
|
381
|
-
const branding = config?.admin?.branding
|
|
382
|
-
const baseName = branding?.title ?? (branding?.name ? `${branding.name} Admin` : null)
|
|
383
|
-
if (!baseName) return
|
|
384
|
-
|
|
385
|
-
const segment = currentPath === '/' ? 'Dashboard' : currentPath.split('/').filter(Boolean)[0]
|
|
386
|
-
const pageName = segment ? segment.charAt(0).toUpperCase() + segment.slice(1) : 'Dashboard'
|
|
387
|
-
document.title = `${pageName} — ${baseName}
|
|
388
|
-
}, [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])
|
|
389
461
|
}
|
|
390
462
|
|
|
391
463
|
const ISOLATION_STYLE: React.CSSProperties = {
|
|
@@ -394,10 +466,10 @@ const ISOLATION_STYLE: React.CSSProperties = {
|
|
|
394
466
|
zIndex: 50,
|
|
395
467
|
overflow: 'auto',
|
|
396
468
|
isolation: 'isolate',
|
|
397
|
-
}
|
|
469
|
+
}
|
|
398
470
|
|
|
399
471
|
export function AdminRoot(props: AdminRootProps) {
|
|
400
|
-
const defaultDarkMode = props.config?.admin?.branding?.darkMode
|
|
472
|
+
const defaultDarkMode = props.config?.admin?.branding?.darkMode
|
|
401
473
|
|
|
402
474
|
return (
|
|
403
475
|
<div style={ISOLATION_STYLE} className="actuate-admin">
|
|
@@ -407,5 +479,5 @@ export function AdminRoot(props: AdminRootProps) {
|
|
|
407
479
|
</LocaleProvider>
|
|
408
480
|
</ThemeProvider>
|
|
409
481
|
</div>
|
|
410
|
-
)
|
|
482
|
+
)
|
|
411
483
|
}
|