@prenta/admin 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +104 -0
- package/design-system/tokens.css +179 -85
- package/design-system/tokens.json +276 -85
- package/design-system/tokens.scss +148 -44
- package/design-system/tokens.tailwind.cjs +50 -1
- package/dist/AdminRoot.d.ts.map +1 -1
- package/dist/AdminRoot.js +42 -20
- package/dist/AdminRoot.js.map +1 -1
- package/dist/LoginRoot.d.ts.map +1 -1
- package/dist/LoginRoot.js +2 -1
- package/dist/LoginRoot.js.map +1 -1
- package/dist/__tests__/components/author-avatar.test.js +3 -17
- package/dist/__tests__/components/author-avatar.test.js.map +1 -1
- package/dist/__tests__/components/notification-bell.test.js +86 -15
- package/dist/__tests__/components/notification-bell.test.js.map +1 -1
- package/dist/__tests__/components/responsive-tiers.render.test.d.ts +2 -0
- package/dist/__tests__/components/responsive-tiers.render.test.d.ts.map +1 -0
- package/dist/__tests__/components/responsive-tiers.render.test.js +313 -0
- package/dist/__tests__/components/responsive-tiers.render.test.js.map +1 -0
- package/dist/__tests__/components/serp-preview.render.test.js +6 -3
- package/dist/__tests__/components/serp-preview.render.test.js.map +1 -1
- package/dist/__tests__/components/shell-primitives.render.test.d.ts +2 -0
- package/dist/__tests__/components/shell-primitives.render.test.d.ts.map +1 -0
- package/dist/__tests__/components/shell-primitives.render.test.js +716 -0
- package/dist/__tests__/components/shell-primitives.render.test.js.map +1 -0
- package/dist/__tests__/components/theme-provider-accent.test.js +49 -7
- package/dist/__tests__/components/theme-provider-accent.test.js.map +1 -1
- package/dist/__tests__/components/toggle.test.js +10 -3
- package/dist/__tests__/components/toggle.test.js.map +1 -1
- package/dist/__tests__/components/ui-primitives.test.js +3 -7
- package/dist/__tests__/components/ui-primitives.test.js.map +1 -1
- package/dist/__tests__/layout/build-nav-items.test.js +1 -1
- package/dist/__tests__/layout/build-nav-items.test.js.map +1 -1
- package/dist/__tests__/layout/shell-nav.render.test.d.ts +2 -0
- package/dist/__tests__/layout/shell-nav.render.test.d.ts.map +1 -0
- package/dist/__tests__/layout/shell-nav.render.test.js +736 -0
- package/dist/__tests__/layout/shell-nav.render.test.js.map +1 -0
- package/dist/__tests__/layout/sidebar-forms-submenu.render.test.js +8 -4
- package/dist/__tests__/layout/sidebar-forms-submenu.render.test.js.map +1 -1
- package/dist/__tests__/layout/sidebar-groups.render.test.d.ts +2 -0
- package/dist/__tests__/layout/sidebar-groups.render.test.d.ts.map +1 -0
- package/dist/__tests__/layout/sidebar-groups.render.test.js +56 -0
- package/dist/__tests__/layout/sidebar-groups.render.test.js.map +1 -0
- package/dist/__tests__/layout/sidebar-menus.render.test.d.ts +2 -0
- package/dist/__tests__/layout/sidebar-menus.render.test.d.ts.map +1 -0
- package/dist/__tests__/layout/sidebar-menus.render.test.js +82 -0
- package/dist/__tests__/layout/sidebar-menus.render.test.js.map +1 -0
- package/dist/__tests__/layout/sidebar-plugin-nav.test.js +1 -1
- package/dist/__tests__/layout/sidebar-plugin-nav.test.js.map +1 -1
- package/dist/__tests__/layout/sidebar-posts.test.js +48 -38
- package/dist/__tests__/layout/sidebar-posts.test.js.map +1 -1
- package/dist/__tests__/layout/sidebar-submenu.render.test.js +26 -10
- package/dist/__tests__/layout/sidebar-submenu.render.test.js.map +1 -1
- package/dist/__tests__/layout/topbar.render.test.d.ts +2 -0
- package/dist/__tests__/layout/topbar.render.test.d.ts.map +1 -0
- package/dist/__tests__/layout/topbar.render.test.js +406 -0
- package/dist/__tests__/layout/topbar.render.test.js.map +1 -0
- package/dist/__tests__/lib/api.test.js +2 -0
- package/dist/__tests__/lib/api.test.js.map +1 -1
- package/dist/__tests__/lib/job-drawer.test.d.ts +2 -0
- package/dist/__tests__/lib/job-drawer.test.d.ts.map +1 -0
- package/dist/__tests__/lib/job-drawer.test.js +393 -0
- package/dist/__tests__/lib/job-drawer.test.js.map +1 -0
- package/dist/__tests__/lib/job-view.test.d.ts +2 -0
- package/dist/__tests__/lib/job-view.test.d.ts.map +1 -0
- package/dist/__tests__/lib/job-view.test.js +387 -0
- package/dist/__tests__/lib/job-view.test.js.map +1 -0
- package/dist/__tests__/lib/jobs-service.test.d.ts +2 -0
- package/dist/__tests__/lib/jobs-service.test.d.ts.map +1 -0
- package/dist/__tests__/lib/jobs-service.test.js +88 -0
- package/dist/__tests__/lib/jobs-service.test.js.map +1 -0
- package/dist/__tests__/router/admin-route-order.test.d.ts +2 -0
- package/dist/__tests__/router/admin-route-order.test.d.ts.map +1 -0
- package/dist/__tests__/router/admin-route-order.test.js +36 -0
- package/dist/__tests__/router/admin-route-order.test.js.map +1 -0
- package/dist/__tests__/styles/ai-gradient-contrast.test.d.ts +2 -0
- package/dist/__tests__/styles/ai-gradient-contrast.test.d.ts.map +1 -0
- package/dist/__tests__/styles/ai-gradient-contrast.test.js +110 -0
- package/dist/__tests__/styles/ai-gradient-contrast.test.js.map +1 -0
- package/dist/__tests__/styles/breakpoint-order.test.d.ts +2 -0
- package/dist/__tests__/styles/breakpoint-order.test.d.ts.map +1 -0
- package/dist/__tests__/styles/breakpoint-order.test.js +52 -0
- package/dist/__tests__/styles/breakpoint-order.test.js.map +1 -0
- package/dist/__tests__/styles/responsive-layer.test.js +303 -12
- package/dist/__tests__/styles/responsive-layer.test.js.map +1 -1
- package/dist/__tests__/styles/tailwind-preset.test.d.ts +2 -0
- package/dist/__tests__/styles/tailwind-preset.test.d.ts.map +1 -0
- package/dist/__tests__/styles/tailwind-preset.test.js +147 -0
- package/dist/__tests__/styles/tailwind-preset.test.js.map +1 -0
- package/dist/__tests__/styles/theme-token-scope.test.js +9 -3
- package/dist/__tests__/styles/theme-token-scope.test.js.map +1 -1
- package/dist/__tests__/styles/tiers.test.d.ts +2 -0
- package/dist/__tests__/styles/tiers.test.d.ts.map +1 -0
- package/dist/__tests__/styles/tiers.test.js +121 -0
- package/dist/__tests__/styles/tiers.test.js.map +1 -0
- package/dist/__tests__/styles/tokens-drift.test.js +57 -6
- package/dist/__tests__/styles/tokens-drift.test.js.map +1 -1
- package/dist/__tests__/views/admin-lazy-route.render.test.js +27 -1
- package/dist/__tests__/views/admin-lazy-route.render.test.js.map +1 -1
- package/dist/__tests__/views/ai-settings.render.test.js +4 -4
- package/dist/__tests__/views/appearance-menus-route.render.test.d.ts +2 -0
- package/dist/__tests__/views/appearance-menus-route.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/appearance-menus-route.render.test.js +50 -0
- package/dist/__tests__/views/appearance-menus-route.render.test.js.map +1 -0
- package/dist/__tests__/views/appearance-settings.render.test.js +8 -6
- package/dist/__tests__/views/appearance-settings.render.test.js.map +1 -1
- package/dist/__tests__/views/appearance-theme-provider.render.test.d.ts +2 -0
- package/dist/__tests__/views/appearance-theme-provider.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/appearance-theme-provider.render.test.js +286 -0
- package/dist/__tests__/views/appearance-theme-provider.render.test.js.map +1 -0
- package/dist/__tests__/views/dashboard.test.js +37 -0
- package/dist/__tests__/views/dashboard.test.js.map +1 -1
- package/dist/__tests__/views/document-edit-navigation.render.test.d.ts +2 -0
- package/dist/__tests__/views/document-edit-navigation.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/document-edit-navigation.render.test.js +101 -0
- package/dist/__tests__/views/document-edit-navigation.render.test.js.map +1 -0
- package/dist/__tests__/views/document-edit-routes.render.test.d.ts +2 -0
- package/dist/__tests__/views/document-edit-routes.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/document-edit-routes.render.test.js +113 -0
- package/dist/__tests__/views/document-edit-routes.render.test.js.map +1 -0
- package/dist/__tests__/views/email-settings.render.test.js +2 -2
- package/dist/__tests__/views/form-entries.render.test.js +15 -0
- package/dist/__tests__/views/form-entries.render.test.js.map +1 -1
- package/dist/__tests__/views/form-submissions.render.test.js +18 -0
- package/dist/__tests__/views/form-submissions.render.test.js.map +1 -1
- package/dist/__tests__/views/forms-list.render.test.js +12 -0
- package/dist/__tests__/views/forms-list.render.test.js.map +1 -1
- package/dist/__tests__/views/general-settings.render.test.js +26 -10
- package/dist/__tests__/views/general-settings.render.test.js.map +1 -1
- package/dist/__tests__/views/jobs-drawer.render.test.d.ts +2 -0
- package/dist/__tests__/views/jobs-drawer.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/jobs-drawer.render.test.js +908 -0
- package/dist/__tests__/views/jobs-drawer.render.test.js.map +1 -0
- package/dist/__tests__/views/jobs-list.render.test.d.ts +2 -0
- package/dist/__tests__/views/jobs-list.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/jobs-list.render.test.js +695 -0
- package/dist/__tests__/views/jobs-list.render.test.js.map +1 -0
- package/dist/__tests__/views/kpi-grid.test.d.ts +2 -0
- package/dist/__tests__/views/kpi-grid.test.d.ts.map +1 -0
- package/dist/__tests__/views/kpi-grid.test.js +26 -0
- package/dist/__tests__/views/kpi-grid.test.js.map +1 -0
- package/dist/__tests__/views/mcp-connect.render.test.js +1 -0
- package/dist/__tests__/views/mcp-connect.render.test.js.map +1 -1
- package/dist/__tests__/views/post-section-editor.test.js +3 -1
- package/dist/__tests__/views/post-section-editor.test.js.map +1 -1
- package/dist/__tests__/views/script-tags.render.test.js +25 -0
- package/dist/__tests__/views/script-tags.render.test.js.map +1 -1
- package/dist/__tests__/views/security-settings.render.test.js +9 -8
- package/dist/__tests__/views/security-settings.render.test.js.map +1 -1
- package/dist/__tests__/views/seo-settings.render.test.js +7 -7
- package/dist/__tests__/views/seo-settings.render.test.js.map +1 -1
- package/dist/__tests__/views/settings-save-bar.render.test.d.ts +2 -0
- package/dist/__tests__/views/settings-save-bar.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/settings-save-bar.render.test.js +68 -0
- package/dist/__tests__/views/settings-save-bar.render.test.js.map +1 -0
- package/dist/__tests__/views/settings-save-footer.render.test.js +23 -15
- package/dist/__tests__/views/settings-save-footer.render.test.js.map +1 -1
- package/dist/__tests__/views/settings-tabs.render.test.d.ts +2 -0
- package/dist/__tests__/views/settings-tabs.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/settings-tabs.render.test.js +319 -0
- package/dist/__tests__/views/settings-tabs.render.test.js.map +1 -0
- package/dist/__tests__/views/updates-tab.render.test.js +4 -3
- package/dist/__tests__/views/updates-tab.render.test.js.map +1 -1
- package/dist/components/Breadcrumbs.d.ts +8 -1
- package/dist/components/Breadcrumbs.d.ts.map +1 -1
- package/dist/components/Breadcrumbs.js +6 -0
- package/dist/components/Breadcrumbs.js.map +1 -1
- package/dist/components/CommandPalette.d.ts.map +1 -1
- package/dist/components/CommandPalette.js +40 -4
- package/dist/components/CommandPalette.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/NotificationBell.d.ts.map +1 -1
- package/dist/components/NotificationBell.js +44 -3
- package/dist/components/NotificationBell.js.map +1 -1
- package/dist/components/OfflineStatus.js +1 -1
- package/dist/components/OfflineStatus.js.map +1 -1
- package/dist/components/PresenceIndicator.d.ts.map +1 -1
- package/dist/components/PresenceIndicator.js +2 -1
- package/dist/components/PresenceIndicator.js.map +1 -1
- package/dist/components/ReflowMeter.js +2 -2
- package/dist/components/ReflowMeter.js.map +1 -1
- package/dist/components/SEOPanel.js +2 -2
- package/dist/components/SEOPanel.js.map +1 -1
- package/dist/components/ThemeProvider.d.ts +24 -4
- package/dist/components/ThemeProvider.d.ts.map +1 -1
- package/dist/components/ThemeProvider.js +80 -22
- package/dist/components/ThemeProvider.js.map +1 -1
- package/dist/components/TipTapEditor.d.ts.map +1 -1
- package/dist/components/TipTapEditor.js +3 -4
- package/dist/components/TipTapEditor.js.map +1 -1
- package/dist/components/forms/EmbedPanel.js +1 -1
- package/dist/components/forms/EmbedPanel.js.map +1 -1
- package/dist/components/forms/FormEntryDetailPane.js +6 -1
- package/dist/components/forms/FormEntryDetailPane.js.map +1 -1
- package/dist/components/forms/ShortcodeGlossary.d.ts.map +1 -1
- package/dist/components/forms/ShortcodeGlossary.js +6 -1
- package/dist/components/forms/ShortcodeGlossary.js.map +1 -1
- package/dist/components/forms/primitives.d.ts +15 -5
- package/dist/components/forms/primitives.d.ts.map +1 -1
- package/dist/components/forms/primitives.js +11 -11
- package/dist/components/forms/primitives.js.map +1 -1
- package/dist/components/pages/tag-badges.d.ts +2 -1
- package/dist/components/pages/tag-badges.d.ts.map +1 -1
- package/dist/components/pages/tag-badges.js +4 -3
- package/dist/components/pages/tag-badges.js.map +1 -1
- package/dist/components/seo/PageAuditPanel.js +2 -2
- package/dist/components/seo/PageAuditPanel.js.map +1 -1
- package/dist/components/seo/SerpPreview.d.ts +4 -4
- package/dist/components/seo/SerpPreview.js +1 -1
- package/dist/components/seo/SerpPreview.js.map +1 -1
- package/dist/components/seo/primitives.js +2 -2
- package/dist/components/seo/primitives.js.map +1 -1
- package/dist/components/ui/AuthorAvatar.d.ts +4 -4
- package/dist/components/ui/AuthorAvatar.d.ts.map +1 -1
- package/dist/components/ui/AuthorAvatar.js +11 -10
- package/dist/components/ui/AuthorAvatar.js.map +1 -1
- package/dist/components/ui/Badge.d.ts +1 -1
- package/dist/components/ui/Badge.js +1 -1
- package/dist/components/ui/Badge.js.map +1 -1
- package/dist/components/ui/Breadcrumb.d.ts +27 -0
- package/dist/components/ui/Breadcrumb.d.ts.map +1 -0
- package/dist/components/ui/Breadcrumb.js +41 -0
- package/dist/components/ui/Breadcrumb.js.map +1 -0
- package/dist/components/ui/Button.d.ts +2 -2
- package/dist/components/ui/Button.d.ts.map +1 -1
- package/dist/components/ui/Button.js +31 -16
- package/dist/components/ui/Button.js.map +1 -1
- package/dist/components/ui/Card.d.ts +8 -4
- package/dist/components/ui/Card.d.ts.map +1 -1
- package/dist/components/ui/Card.js +21 -13
- package/dist/components/ui/Card.js.map +1 -1
- package/dist/components/ui/CardListControls.d.ts +34 -0
- package/dist/components/ui/CardListControls.d.ts.map +1 -0
- package/dist/components/ui/CardListControls.js +25 -0
- package/dist/components/ui/CardListControls.js.map +1 -0
- package/dist/components/ui/CountChip.d.ts +20 -0
- package/dist/components/ui/CountChip.d.ts.map +1 -0
- package/dist/components/ui/CountChip.js +48 -0
- package/dist/components/ui/CountChip.js.map +1 -0
- package/dist/components/ui/FilterPill.d.ts +2 -1
- package/dist/components/ui/FilterPill.d.ts.map +1 -1
- package/dist/components/ui/FilterPill.js +3 -2
- package/dist/components/ui/FilterPill.js.map +1 -1
- package/dist/components/ui/Input.d.ts +1 -1
- package/dist/components/ui/InspectorPane.d.ts +1 -1
- package/dist/components/ui/InspectorPane.d.ts.map +1 -1
- package/dist/components/ui/InspectorPane.js +15 -4
- package/dist/components/ui/InspectorPane.js.map +1 -1
- package/dist/components/ui/Modal.d.ts.map +1 -1
- package/dist/components/ui/Modal.js +10 -2
- package/dist/components/ui/Modal.js.map +1 -1
- package/dist/components/ui/PageHeader.d.ts +28 -0
- package/dist/components/ui/PageHeader.d.ts.map +1 -0
- package/dist/components/ui/PageHeader.js +18 -0
- package/dist/components/ui/PageHeader.js.map +1 -0
- package/dist/components/ui/RowActions.d.ts +5 -0
- package/dist/components/ui/RowActions.d.ts.map +1 -1
- package/dist/components/ui/RowActions.js +7 -2
- package/dist/components/ui/RowActions.js.map +1 -1
- package/dist/components/ui/Segmented.d.ts +21 -0
- package/dist/components/ui/Segmented.d.ts.map +1 -0
- package/dist/components/ui/Segmented.js +41 -0
- package/dist/components/ui/Segmented.js.map +1 -0
- package/dist/components/ui/Toaster.d.ts +12 -0
- package/dist/components/ui/Toaster.d.ts.map +1 -0
- package/dist/components/ui/Toaster.js +103 -0
- package/dist/components/ui/Toaster.js.map +1 -0
- package/dist/components/ui/Toggle.d.ts +4 -3
- package/dist/components/ui/Toggle.d.ts.map +1 -1
- package/dist/components/ui/Toggle.js +16 -12
- package/dist/components/ui/Toggle.js.map +1 -1
- package/dist/components/ui/UnderlineTabs.d.ts +56 -0
- package/dist/components/ui/UnderlineTabs.d.ts.map +1 -0
- package/dist/components/ui/UnderlineTabs.js +205 -0
- package/dist/components/ui/UnderlineTabs.js.map +1 -0
- package/dist/components/ui/UnsavedBar.d.ts +25 -0
- package/dist/components/ui/UnsavedBar.d.ts.map +1 -0
- package/dist/components/ui/UnsavedBar.js +22 -0
- package/dist/components/ui/UnsavedBar.js.map +1 -0
- package/dist/components/ui/admin-links.d.ts +11 -0
- package/dist/components/ui/admin-links.d.ts.map +1 -0
- package/dist/components/ui/admin-links.js +10 -0
- package/dist/components/ui/admin-links.js.map +1 -0
- package/dist/components/ui/card-table.d.ts +43 -0
- package/dist/components/ui/card-table.d.ts.map +1 -0
- package/dist/components/ui/card-table.js +31 -0
- package/dist/components/ui/card-table.js.map +1 -0
- package/dist/components/virtual-window.d.ts +7 -0
- package/dist/components/virtual-window.d.ts.map +1 -1
- package/dist/components/virtual-window.js +5 -2
- package/dist/components/virtual-window.js.map +1 -1
- package/dist/fields/RelationshipField.js +1 -1
- package/dist/fields/RelationshipField.js.map +1 -1
- package/dist/files/dm-mono-latin-400-normal.woff +0 -0
- package/dist/files/dm-mono-latin-400-normal.woff2 +0 -0
- package/dist/files/dm-mono-latin-500-normal.woff +0 -0
- package/dist/files/dm-mono-latin-500-normal.woff2 +0 -0
- package/dist/files/dm-mono-latin-ext-400-normal.woff +0 -0
- package/dist/files/dm-mono-latin-ext-400-normal.woff2 +0 -0
- package/dist/files/dm-mono-latin-ext-500-normal.woff +0 -0
- package/dist/files/dm-mono-latin-ext-500-normal.woff2 +0 -0
- package/dist/files/dm-sans-latin-400-normal.woff +0 -0
- package/dist/files/dm-sans-latin-400-normal.woff2 +0 -0
- package/dist/files/dm-sans-latin-500-normal.woff +0 -0
- package/dist/files/dm-sans-latin-500-normal.woff2 +0 -0
- package/dist/files/dm-sans-latin-600-normal.woff +0 -0
- package/dist/files/dm-sans-latin-600-normal.woff2 +0 -0
- package/dist/files/dm-sans-latin-700-normal.woff +0 -0
- package/dist/files/dm-sans-latin-700-normal.woff2 +0 -0
- package/dist/files/dm-sans-latin-ext-400-normal.woff +0 -0
- package/dist/files/dm-sans-latin-ext-400-normal.woff2 +0 -0
- package/dist/files/dm-sans-latin-ext-500-normal.woff +0 -0
- package/dist/files/dm-sans-latin-ext-500-normal.woff2 +0 -0
- package/dist/files/dm-sans-latin-ext-600-normal.woff +0 -0
- package/dist/files/dm-sans-latin-ext-600-normal.woff2 +0 -0
- package/dist/files/dm-sans-latin-ext-700-normal.woff +0 -0
- package/dist/files/dm-sans-latin-ext-700-normal.woff2 +0 -0
- package/dist/hooks/useAppearanceBootstrap.d.ts.map +1 -1
- package/dist/hooks/useAppearanceBootstrap.js +9 -3
- package/dist/hooks/useAppearanceBootstrap.js.map +1 -1
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/layout/Header.d.ts +14 -5
- package/dist/layout/Header.d.ts.map +1 -1
- package/dist/layout/Header.js +78 -13
- package/dist/layout/Header.js.map +1 -1
- package/dist/layout/Layout.d.ts +5 -3
- package/dist/layout/Layout.d.ts.map +1 -1
- package/dist/layout/Layout.js +45 -54
- package/dist/layout/Layout.js.map +1 -1
- package/dist/layout/MobileTabBar.d.ts +20 -0
- package/dist/layout/MobileTabBar.d.ts.map +1 -0
- package/dist/layout/MobileTabBar.js +29 -0
- package/dist/layout/MobileTabBar.js.map +1 -0
- package/dist/layout/Sidebar.d.ts +8 -26
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/Sidebar.js +309 -345
- package/dist/layout/Sidebar.js.map +1 -1
- package/dist/layout/nav-config.d.ts +101 -0
- package/dist/layout/nav-config.d.ts.map +1 -0
- package/dist/layout/nav-config.js +297 -0
- package/dist/layout/nav-config.js.map +1 -0
- package/dist/layout/primitives/AdminShell.d.ts +10 -2
- package/dist/layout/primitives/AdminShell.d.ts.map +1 -1
- package/dist/layout/primitives/AdminShell.js +114 -6
- package/dist/layout/primitives/AdminShell.js.map +1 -1
- package/dist/layout/topbar-classes.d.ts +8 -0
- package/dist/layout/topbar-classes.d.ts.map +1 -0
- package/dist/layout/topbar-classes.js +8 -0
- package/dist/layout/topbar-classes.js.map +1 -0
- package/dist/layout/use-nav-items.d.ts +10 -0
- package/dist/layout/use-nav-items.d.ts.map +1 -0
- package/dist/layout/use-nav-items.js +39 -0
- package/dist/layout/use-nav-items.js.map +1 -0
- package/dist/lib/api.d.ts +6 -0
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +1 -1
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/appearance-api.d.ts +3 -1
- package/dist/lib/appearance-api.d.ts.map +1 -1
- package/dist/lib/appearance-api.js +1 -0
- package/dist/lib/appearance-api.js.map +1 -1
- package/dist/lib/job-drawer.d.ts +128 -0
- package/dist/lib/job-drawer.d.ts.map +1 -0
- package/dist/lib/job-drawer.js +351 -0
- package/dist/lib/job-drawer.js.map +1 -0
- package/dist/lib/job-view.d.ts +187 -0
- package/dist/lib/job-view.d.ts.map +1 -0
- package/dist/lib/job-view.js +363 -0
- package/dist/lib/job-view.js.map +1 -0
- package/dist/lib/jobs-service.d.ts +134 -0
- package/dist/lib/jobs-service.d.ts.map +1 -0
- package/dist/lib/jobs-service.js +179 -0
- package/dist/lib/jobs-service.js.map +1 -0
- package/dist/lib/sheet-focus.d.ts +24 -0
- package/dist/lib/sheet-focus.d.ts.map +1 -0
- package/dist/lib/sheet-focus.js +61 -0
- package/dist/lib/sheet-focus.js.map +1 -0
- package/dist/lib/tiers.d.ts +30 -0
- package/dist/lib/tiers.d.ts.map +1 -0
- package/dist/lib/tiers.js +43 -0
- package/dist/lib/tiers.js.map +1 -0
- package/dist/prenta-admin.css +1 -1
- package/dist/router/admin-routes.d.ts.map +1 -1
- package/dist/router/admin-routes.js +8 -0
- package/dist/router/admin-routes.js.map +1 -1
- package/dist/router/index.d.ts +5 -1
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +7 -0
- package/dist/router/index.js.map +1 -1
- package/dist/views/ApiKeys.js +2 -2
- package/dist/views/ApiKeys.js.map +1 -1
- package/dist/views/AppearanceChrome.d.ts +6 -0
- package/dist/views/AppearanceChrome.d.ts.map +1 -0
- package/dist/views/AppearanceChrome.js +25 -0
- package/dist/views/AppearanceChrome.js.map +1 -0
- package/dist/views/CollectionList.d.ts.map +1 -1
- package/dist/views/CollectionList.js +73 -53
- package/dist/views/CollectionList.js.map +1 -1
- package/dist/views/Dashboard.d.ts.map +1 -1
- package/dist/views/Dashboard.js +14 -8
- package/dist/views/Dashboard.js.map +1 -1
- package/dist/views/DocumentEdit.d.ts +6 -1
- package/dist/views/DocumentEdit.d.ts.map +1 -1
- package/dist/views/DocumentEdit.js +44 -8
- package/dist/views/DocumentEdit.js.map +1 -1
- package/dist/views/FormDeliveries.d.ts.map +1 -1
- package/dist/views/FormDeliveries.js +7 -1
- package/dist/views/FormDeliveries.js.map +1 -1
- package/dist/views/FormEntries.d.ts.map +1 -1
- package/dist/views/FormEntries.js +11 -2
- package/dist/views/FormEntries.js.map +1 -1
- package/dist/views/FormSubmissions.d.ts +1 -1
- package/dist/views/FormSubmissions.d.ts.map +1 -1
- package/dist/views/FormSubmissions.js +15 -4
- package/dist/views/FormSubmissions.js.map +1 -1
- package/dist/views/Forms.d.ts.map +1 -1
- package/dist/views/Forms.js +6 -4
- package/dist/views/Forms.js.map +1 -1
- package/dist/views/FormsSettings.d.ts +2 -0
- package/dist/views/FormsSettings.d.ts.map +1 -0
- package/dist/views/FormsSettings.js +37 -0
- package/dist/views/FormsSettings.js.map +1 -0
- package/dist/views/Jobs/BusyButton.d.ts +15 -0
- package/dist/views/Jobs/BusyButton.d.ts.map +1 -0
- package/dist/views/Jobs/BusyButton.js +26 -0
- package/dist/views/Jobs/BusyButton.js.map +1 -0
- package/dist/views/Jobs/CancelJobDialog.d.ts +21 -0
- package/dist/views/Jobs/CancelJobDialog.d.ts.map +1 -0
- package/dist/views/Jobs/CancelJobDialog.js +66 -0
- package/dist/views/Jobs/CancelJobDialog.js.map +1 -0
- package/dist/views/Jobs/DrawerActivity.d.ts +16 -0
- package/dist/views/Jobs/DrawerActivity.d.ts.map +1 -0
- package/dist/views/Jobs/DrawerActivity.js +59 -0
- package/dist/views/Jobs/DrawerActivity.js.map +1 -0
- package/dist/views/Jobs/DrawerOverview.d.ts +28 -0
- package/dist/views/Jobs/DrawerOverview.d.ts.map +1 -0
- package/dist/views/Jobs/DrawerOverview.js +32 -0
- package/dist/views/Jobs/DrawerOverview.js.map +1 -0
- package/dist/views/Jobs/DrawerResults.d.ts +25 -0
- package/dist/views/Jobs/DrawerResults.d.ts.map +1 -0
- package/dist/views/Jobs/DrawerResults.js +50 -0
- package/dist/views/Jobs/DrawerResults.js.map +1 -0
- package/dist/views/Jobs/DrawerReview.d.ts +44 -0
- package/dist/views/Jobs/DrawerReview.d.ts.map +1 -0
- package/dist/views/Jobs/DrawerReview.js +110 -0
- package/dist/views/Jobs/DrawerReview.js.map +1 -0
- package/dist/views/Jobs/JobDrawer.d.ts +31 -0
- package/dist/views/Jobs/JobDrawer.d.ts.map +1 -0
- package/dist/views/Jobs/JobDrawer.js +353 -0
- package/dist/views/Jobs/JobDrawer.js.map +1 -0
- package/dist/views/Jobs/JobsTable.d.ts +19 -0
- package/dist/views/Jobs/JobsTable.d.ts.map +1 -0
- package/dist/views/Jobs/JobsTable.js +80 -0
- package/dist/views/Jobs/JobsTable.js.map +1 -0
- package/dist/views/Jobs/WorkerStrip.d.ts +22 -0
- package/dist/views/Jobs/WorkerStrip.d.ts.map +1 -0
- package/dist/views/Jobs/WorkerStrip.js +63 -0
- package/dist/views/Jobs/WorkerStrip.js.map +1 -0
- package/dist/views/Jobs/atoms.d.ts +19 -0
- package/dist/views/Jobs/atoms.d.ts.map +1 -0
- package/dist/views/Jobs/atoms.js +52 -0
- package/dist/views/Jobs/atoms.js.map +1 -0
- package/dist/views/Jobs/focus.d.ts +23 -0
- package/dist/views/Jobs/focus.d.ts.map +1 -0
- package/dist/views/Jobs/focus.js +54 -0
- package/dist/views/Jobs/focus.js.map +1 -0
- package/dist/views/Jobs/icons.d.ts +22 -0
- package/dist/views/Jobs/icons.d.ts.map +1 -0
- package/dist/views/Jobs/icons.js +23 -0
- package/dist/views/Jobs/icons.js.map +1 -0
- package/dist/views/Jobs/placeholders.d.ts +6 -0
- package/dist/views/Jobs/placeholders.d.ts.map +1 -0
- package/dist/views/Jobs/placeholders.js +20 -0
- package/dist/views/Jobs/placeholders.js.map +1 -0
- package/dist/views/Jobs/useJobDetail.d.ts +21 -0
- package/dist/views/Jobs/useJobDetail.d.ts.map +1 -0
- package/dist/views/Jobs/useJobDetail.js +39 -0
- package/dist/views/Jobs/useJobDetail.js.map +1 -0
- package/dist/views/Jobs/useJobsFeed.d.ts +35 -0
- package/dist/views/Jobs/useJobsFeed.d.ts.map +1 -0
- package/dist/views/Jobs/useJobsFeed.js +231 -0
- package/dist/views/Jobs/useJobsFeed.js.map +1 -0
- package/dist/views/Jobs/useReviewItems.d.ts +39 -0
- package/dist/views/Jobs/useReviewItems.d.ts.map +1 -0
- package/dist/views/Jobs/useReviewItems.js +140 -0
- package/dist/views/Jobs/useReviewItems.js.map +1 -0
- package/dist/views/Jobs.d.ts +10 -1
- package/dist/views/Jobs.d.ts.map +1 -1
- package/dist/views/Jobs.js +126 -35
- package/dist/views/Jobs.js.map +1 -1
- package/dist/views/MediaBrowser.d.ts.map +1 -1
- package/dist/views/MediaBrowser.js +37 -9
- package/dist/views/MediaBrowser.js.map +1 -1
- package/dist/views/Pages/PagesListView.d.ts +1 -1
- package/dist/views/Pages/PagesListView.d.ts.map +1 -1
- package/dist/views/Pages/PagesListView.js +34 -5
- package/dist/views/Pages/PagesListView.js.map +1 -1
- package/dist/views/Posts/NewPostTypeInstructions.d.ts.map +1 -1
- package/dist/views/Posts/NewPostTypeInstructions.js +12 -2
- package/dist/views/Posts/NewPostTypeInstructions.js.map +1 -1
- package/dist/views/Posts/PostTypesView.d.ts.map +1 -1
- package/dist/views/Posts/PostTypesView.js +10 -1
- package/dist/views/Posts/PostTypesView.js.map +1 -1
- package/dist/views/Posts/PostsListView.d.ts +1 -2
- package/dist/views/Posts/PostsListView.d.ts.map +1 -1
- package/dist/views/Posts/PostsListView.js +31 -3
- package/dist/views/Posts/PostsListView.js.map +1 -1
- package/dist/views/SEO.d.ts.map +1 -1
- package/dist/views/SEO.js +3 -3
- package/dist/views/SEO.js.map +1 -1
- package/dist/views/ScriptTags.d.ts.map +1 -1
- package/dist/views/ScriptTags.js +20 -15
- package/dist/views/ScriptTags.js.map +1 -1
- package/dist/views/Settings.d.ts.map +1 -1
- package/dist/views/Settings.js +115 -51
- package/dist/views/Settings.js.map +1 -1
- package/dist/views/SpamFolder.d.ts +2 -0
- package/dist/views/SpamFolder.d.ts.map +1 -0
- package/dist/views/SpamFolder.js +14 -0
- package/dist/views/SpamFolder.js.map +1 -0
- package/dist/views/Trash.d.ts +6 -1
- package/dist/views/Trash.d.ts.map +1 -1
- package/dist/views/Trash.js +7 -2
- package/dist/views/Trash.js.map +1 -1
- package/dist/views/Users.js +2 -2
- package/dist/views/Users.js.map +1 -1
- package/dist/views/WidgetsPlaceholder.d.ts +2 -0
- package/dist/views/WidgetsPlaceholder.d.ts.map +1 -0
- package/dist/views/WidgetsPlaceholder.js +15 -0
- package/dist/views/WidgetsPlaceholder.js.map +1 -0
- package/dist/views/dashboard/kpi-grid.d.ts +18 -0
- package/dist/views/dashboard/kpi-grid.d.ts.map +1 -0
- package/dist/views/dashboard/kpi-grid.js +36 -0
- package/dist/views/dashboard/kpi-grid.js.map +1 -0
- package/dist/views/lazy-views.d.ts +4 -0
- package/dist/views/lazy-views.d.ts.map +1 -1
- package/dist/views/lazy-views.js +4 -0
- package/dist/views/lazy-views.js.map +1 -1
- package/dist/views/page-editor/PageTab.js +1 -1
- package/dist/views/page-editor/PageTab.js.map +1 -1
- package/dist/views/page-editor/ReviewBar.js +1 -1
- package/dist/views/page-editor/ReviewBar.js.map +1 -1
- package/dist/views/page-editor/VersionHistoryPanel.js +1 -1
- package/dist/views/page-editor/VersionHistoryPanel.js.map +1 -1
- package/dist/views/seo/AuditTab.js +1 -1
- package/dist/views/seo/AuditTab.js.map +1 -1
- package/dist/views/seo/OverviewTab.d.ts.map +1 -1
- package/dist/views/seo/OverviewTab.js +2 -2
- package/dist/views/seo/OverviewTab.js.map +1 -1
- package/dist/views/seo/ProposalsTab.js +1 -1
- package/dist/views/seo/ProposalsTab.js.map +1 -1
- package/dist/views/settings/AISettingsTab.d.ts.map +1 -1
- package/dist/views/settings/AISettingsTab.js +4 -2
- package/dist/views/settings/AISettingsTab.js.map +1 -1
- package/dist/views/settings/AccessProtectionCard.js +1 -1
- package/dist/views/settings/AccessProtectionCard.js.map +1 -1
- package/dist/views/settings/AdminThemeCard.d.ts.map +1 -1
- package/dist/views/settings/AdminThemeCard.js +63 -15
- package/dist/views/settings/AdminThemeCard.js.map +1 -1
- package/dist/views/settings/AppearanceTab.d.ts.map +1 -1
- package/dist/views/settings/AppearanceTab.js +4 -2
- package/dist/views/settings/AppearanceTab.js.map +1 -1
- package/dist/views/settings/BrandPreviewCard.js +1 -1
- package/dist/views/settings/BrandPreviewCard.js.map +1 -1
- package/dist/views/settings/BrandVoiceCard.js +1 -1
- package/dist/views/settings/BrandVoiceCard.js.map +1 -1
- package/dist/views/settings/EmailSettingsTab.d.ts.map +1 -1
- package/dist/views/settings/EmailSettingsTab.js +5 -3
- package/dist/views/settings/EmailSettingsTab.js.map +1 -1
- package/dist/views/settings/GeneralSettingsTab.d.ts.map +1 -1
- package/dist/views/settings/GeneralSettingsTab.js +4 -2
- package/dist/views/settings/GeneralSettingsTab.js.map +1 -1
- package/dist/views/settings/McpConnectTab.d.ts.map +1 -1
- package/dist/views/settings/McpConnectTab.js +1 -1
- package/dist/views/settings/McpConnectTab.js.map +1 -1
- package/dist/views/settings/ProviderConnectionCard.js +1 -1
- package/dist/views/settings/ProviderConnectionCard.js.map +1 -1
- package/dist/views/settings/SearchDataCard.js +1 -1
- package/dist/views/settings/SearchDataCard.js.map +1 -1
- package/dist/views/settings/SecurityStatusCard.js +2 -2
- package/dist/views/settings/SecurityStatusCard.js.map +1 -1
- package/dist/views/settings/SecurityTab.d.ts.map +1 -1
- package/dist/views/settings/SecurityTab.js +4 -2
- package/dist/views/settings/SecurityTab.js.map +1 -1
- package/dist/views/settings/SeoAutopilotCard.js +2 -2
- package/dist/views/settings/SeoAutopilotCard.js.map +1 -1
- package/dist/views/settings/SeoSettingsTab.d.ts.map +1 -1
- package/dist/views/settings/SeoSettingsTab.js +5 -3
- package/dist/views/settings/SeoSettingsTab.js.map +1 -1
- package/dist/views/settings/SiteIndexStatusCard.js +1 -1
- package/dist/views/settings/SiteIndexStatusCard.js.map +1 -1
- package/dist/views/settings/SiteThemeCard.js +1 -1
- package/dist/views/settings/UpdatesTab.d.ts.map +1 -1
- package/dist/views/settings/UpdatesTab.js +6 -5
- package/dist/views/settings/UpdatesTab.js.map +1 -1
- package/dist/views/settings/components.d.ts +7 -11
- package/dist/views/settings/components.d.ts.map +1 -1
- package/dist/views/settings/components.js +18 -12
- package/dist/views/settings/components.js.map +1 -1
- package/dist/views/settings/useAppearanceSettings.d.ts +7 -1
- package/dist/views/settings/useAppearanceSettings.d.ts.map +1 -1
- package/dist/views/settings/useAppearanceSettings.js +89 -22
- package/dist/views/settings/useAppearanceSettings.js.map +1 -1
- package/dist/views/users/UserDetailDrawer.js +1 -1
- package/dist/views/users/UserDetailDrawer.js.map +1 -1
- package/package.json +11 -9
- package/src/AdminRoot.tsx +88 -30
- package/src/LoginRoot.tsx +2 -1
- package/src/__tests__/components/author-avatar.test.tsx +3 -20
- package/src/__tests__/components/notification-bell.test.tsx +146 -14
- package/src/__tests__/components/responsive-tiers.render.test.tsx +461 -0
- package/src/__tests__/components/serp-preview.render.test.tsx +6 -3
- package/src/__tests__/components/shell-primitives.render.test.tsx +951 -0
- package/src/__tests__/components/theme-provider-accent.test.tsx +83 -8
- package/src/__tests__/components/toggle.test.tsx +11 -3
- package/src/__tests__/components/ui-primitives.test.tsx +5 -8
- package/src/__tests__/layout/build-nav-items.test.ts +1 -1
- package/src/__tests__/layout/shell-nav.render.test.tsx +983 -0
- package/src/__tests__/layout/sidebar-forms-submenu.render.test.tsx +8 -4
- package/src/__tests__/layout/sidebar-groups.render.test.tsx +116 -0
- package/src/__tests__/layout/sidebar-menus.render.test.tsx +116 -0
- package/src/__tests__/layout/sidebar-plugin-nav.test.ts +1 -1
- package/src/__tests__/layout/sidebar-posts.test.ts +48 -40
- package/src/__tests__/layout/sidebar-submenu.render.test.tsx +35 -10
- package/src/__tests__/layout/topbar.render.test.tsx +464 -0
- package/src/__tests__/lib/api.test.ts +2 -0
- package/src/__tests__/lib/job-drawer.test.ts +493 -0
- package/src/__tests__/lib/job-view.test.ts +437 -0
- package/src/__tests__/lib/jobs-service.test.ts +98 -0
- package/src/__tests__/router/admin-route-order.test.ts +39 -0
- package/src/__tests__/styles/ai-gradient-contrast.test.ts +135 -0
- package/src/__tests__/styles/breakpoint-order.test.ts +68 -0
- package/src/__tests__/styles/responsive-layer.test.ts +367 -12
- package/src/__tests__/styles/tailwind-preset.test.ts +154 -0
- package/src/__tests__/styles/theme-token-scope.test.ts +10 -3
- package/src/__tests__/styles/tiers.test.ts +136 -0
- package/src/__tests__/styles/tokens-drift.test.ts +67 -6
- package/src/__tests__/views/admin-lazy-route.render.test.tsx +41 -1
- package/src/__tests__/views/ai-settings.render.test.tsx +4 -4
- package/src/__tests__/views/appearance-menus-route.render.test.tsx +58 -0
- package/src/__tests__/views/appearance-settings.render.test.tsx +10 -8
- package/src/__tests__/views/appearance-theme-provider.render.test.tsx +347 -0
- package/src/__tests__/views/dashboard.test.tsx +48 -0
- package/src/__tests__/views/document-edit-navigation.render.test.tsx +130 -0
- package/src/__tests__/views/document-edit-routes.render.test.tsx +130 -0
- package/src/__tests__/views/email-settings.render.test.tsx +2 -2
- package/src/__tests__/views/form-entries.render.test.tsx +22 -0
- package/src/__tests__/views/form-submissions.render.test.tsx +22 -0
- package/src/__tests__/views/forms-list.render.test.tsx +13 -0
- package/src/__tests__/views/general-settings.render.test.tsx +38 -11
- package/src/__tests__/views/jobs-drawer.render.test.tsx +1047 -0
- package/src/__tests__/views/jobs-list.render.test.tsx +850 -0
- package/src/__tests__/views/kpi-grid.test.ts +29 -0
- package/src/__tests__/views/mcp-connect.render.test.tsx +1 -0
- package/src/__tests__/views/post-section-editor.test.tsx +5 -1
- package/src/__tests__/views/script-tags.render.test.tsx +29 -0
- package/src/__tests__/views/security-settings.render.test.tsx +9 -10
- package/src/__tests__/views/seo-settings.render.test.tsx +7 -9
- package/src/__tests__/views/settings-save-bar.render.test.tsx +91 -0
- package/src/__tests__/views/settings-save-footer.render.test.tsx +25 -15
- package/src/__tests__/views/settings-tabs.render.test.tsx +371 -0
- package/src/__tests__/views/updates-tab.render.test.tsx +4 -3
- package/src/components/Breadcrumbs.tsx +7 -1
- package/src/components/CommandPalette.tsx +51 -3
- package/src/components/LocaleSwitcher.tsx +5 -6
- package/src/components/NotificationBell.tsx +74 -18
- package/src/components/OfflineStatus.tsx +1 -1
- package/src/components/PresenceIndicator.tsx +2 -1
- package/src/components/ReflowMeter.tsx +3 -3
- package/src/components/SEOPanel.tsx +2 -2
- package/src/components/ThemeProvider.tsx +122 -42
- package/src/components/TipTapEditor.tsx +3 -4
- package/src/components/forms/EmbedPanel.tsx +1 -1
- package/src/components/forms/FormEntryDetailPane.tsx +7 -1
- package/src/components/forms/ShortcodeGlossary.tsx +7 -1
- package/src/components/forms/primitives.tsx +37 -21
- package/src/components/pages/tag-badges.tsx +4 -3
- package/src/components/seo/PageAuditPanel.tsx +2 -2
- package/src/components/seo/SerpPreview.tsx +5 -5
- package/src/components/seo/primitives.tsx +2 -2
- package/src/components/ui/AuthorAvatar.tsx +11 -10
- package/src/components/ui/Badge.tsx +1 -1
- package/src/components/ui/Breadcrumb.tsx +109 -0
- package/src/components/ui/Button.tsx +40 -15
- package/src/components/ui/Card.tsx +35 -32
- package/src/components/ui/CardListControls.tsx +90 -0
- package/src/components/ui/CountChip.tsx +90 -0
- package/src/components/ui/FilterPill.tsx +5 -3
- package/src/components/ui/InspectorPane.tsx +21 -7
- package/src/components/ui/Modal.tsx +20 -6
- package/src/components/ui/PageHeader.tsx +63 -0
- package/src/components/ui/RowActions.tsx +7 -2
- package/src/components/ui/Segmented.tsx +97 -0
- package/src/components/ui/Toaster.tsx +139 -0
- package/src/components/ui/Toggle.tsx +18 -14
- package/src/components/ui/UnderlineTabs.tsx +373 -0
- package/src/components/ui/UnsavedBar.tsx +119 -0
- package/src/components/ui/admin-links.tsx +20 -0
- package/src/components/ui/card-table.ts +34 -0
- package/src/components/virtual-window.tsx +13 -2
- package/src/fields/RelationshipField.tsx +1 -1
- package/src/hooks/useAppearanceBootstrap.ts +9 -3
- package/src/index.ts +19 -0
- package/src/layout/Header.tsx +210 -135
- package/src/layout/Layout.tsx +61 -108
- package/src/layout/MobileTabBar.tsx +92 -0
- package/src/layout/Sidebar.tsx +555 -593
- package/src/layout/nav-config.tsx +425 -0
- package/src/layout/primitives/AdminShell.tsx +154 -6
- package/src/layout/topbar-classes.ts +8 -0
- package/src/layout/use-nav-items.ts +40 -0
- package/src/lib/api.ts +7 -1
- package/src/lib/appearance-api.ts +4 -0
- package/src/lib/job-drawer.ts +424 -0
- package/src/lib/job-view.ts +456 -0
- package/src/lib/jobs-service.ts +290 -0
- package/src/lib/sheet-focus.ts +71 -0
- package/src/lib/tiers.ts +43 -0
- package/src/router/admin-routes.ts +8 -0
- package/src/router/index.ts +9 -1
- package/src/styles/prenta-tokens.css +263 -82
- package/src/styles/responsive.css +460 -22
- package/src/styles/theme.css +177 -28
- package/src/views/ApiKeys.tsx +2 -2
- package/src/views/AppearanceChrome.tsx +74 -0
- package/src/views/CollectionList.tsx +264 -205
- package/src/views/Dashboard.tsx +26 -13
- package/src/views/DocumentEdit.tsx +111 -56
- package/src/views/FormDeliveries.tsx +30 -17
- package/src/views/FormEntries.tsx +28 -20
- package/src/views/FormSubmissions.tsx +32 -34
- package/src/views/Forms.tsx +55 -34
- package/src/views/FormsSettings.tsx +94 -0
- package/src/views/Jobs/BusyButton.tsx +56 -0
- package/src/views/Jobs/CancelJobDialog.tsx +127 -0
- package/src/views/Jobs/DrawerActivity.tsx +142 -0
- package/src/views/Jobs/DrawerOverview.tsx +139 -0
- package/src/views/Jobs/DrawerResults.tsx +155 -0
- package/src/views/Jobs/DrawerReview.tsx +464 -0
- package/src/views/Jobs/JobDrawer.tsx +556 -0
- package/src/views/Jobs/JobsTable.tsx +260 -0
- package/src/views/Jobs/WorkerStrip.tsx +144 -0
- package/src/views/Jobs/atoms.tsx +93 -0
- package/src/views/Jobs/focus.ts +56 -0
- package/src/views/Jobs/icons.tsx +111 -0
- package/src/views/Jobs/placeholders.tsx +66 -0
- package/src/views/Jobs/useJobDetail.ts +64 -0
- package/src/views/Jobs/useJobsFeed.ts +249 -0
- package/src/views/Jobs/useReviewItems.ts +187 -0
- package/src/views/Jobs.tsx +282 -105
- package/src/views/MediaBrowser.tsx +71 -21
- package/src/views/Pages/PagesListView.tsx +115 -39
- package/src/views/Posts/NewPostTypeInstructions.tsx +15 -10
- package/src/views/Posts/PostTypesView.tsx +28 -6
- package/src/views/Posts/PostsListView.tsx +130 -40
- package/src/views/SEO.tsx +23 -8
- package/src/views/ScriptTags.tsx +233 -153
- package/src/views/Settings.tsx +215 -256
- package/src/views/SpamFolder.tsx +32 -0
- package/src/views/Trash.tsx +12 -1
- package/src/views/Users.tsx +2 -2
- package/src/views/WidgetsPlaceholder.tsx +33 -0
- package/src/views/dashboard/kpi-grid.ts +38 -0
- package/src/views/lazy-views.tsx +12 -0
- package/src/views/page-editor/PageTab.tsx +2 -2
- package/src/views/page-editor/ReviewBar.tsx +1 -1
- package/src/views/page-editor/VersionHistoryPanel.tsx +1 -1
- package/src/views/seo/AuditTab.tsx +1 -1
- package/src/views/seo/OverviewTab.tsx +6 -5
- package/src/views/seo/ProposalsTab.tsx +1 -1
- package/src/views/settings/AISettingsTab.tsx +10 -6
- package/src/views/settings/AccessProtectionCard.tsx +1 -1
- package/src/views/settings/AdminThemeCard.tsx +228 -35
- package/src/views/settings/AppearanceTab.tsx +10 -6
- package/src/views/settings/BrandPreviewCard.tsx +1 -1
- package/src/views/settings/BrandVoiceCard.tsx +1 -1
- package/src/views/settings/EmailSettingsTab.tsx +11 -7
- package/src/views/settings/GeneralSettingsTab.tsx +10 -6
- package/src/views/settings/McpConnectTab.tsx +2 -1
- package/src/views/settings/ProviderConnectionCard.tsx +1 -1
- package/src/views/settings/SearchDataCard.tsx +1 -1
- package/src/views/settings/SecurityStatusCard.tsx +2 -2
- package/src/views/settings/SecurityTab.tsx +10 -6
- package/src/views/settings/SeoAutopilotCard.tsx +2 -2
- package/src/views/settings/SeoSettingsTab.tsx +13 -9
- package/src/views/settings/SiteIndexStatusCard.tsx +1 -1
- package/src/views/settings/SiteThemeCard.tsx +1 -1
- package/src/views/settings/UpdatesTab.tsx +107 -101
- package/src/views/settings/components.tsx +26 -62
- package/src/views/settings/useAppearanceSettings.ts +116 -25
- package/src/views/users/UserDetailDrawer.tsx +1 -1
- package/dist/components/ui/StatPill.d.ts +0 -18
- package/dist/components/ui/StatPill.d.ts.map +0 -1
- package/dist/components/ui/StatPill.js +0 -5
- package/dist/components/ui/StatPill.js.map +0 -1
- package/src/components/ui/StatPill.tsx +0 -37
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BookOpen,
|
|
3
|
+
Briefcase,
|
|
4
|
+
Clipboard,
|
|
5
|
+
ClipboardList,
|
|
6
|
+
Code,
|
|
7
|
+
Cpu,
|
|
8
|
+
Download,
|
|
9
|
+
File,
|
|
10
|
+
FileText,
|
|
11
|
+
FolderOpen,
|
|
12
|
+
HelpCircle,
|
|
13
|
+
Image,
|
|
14
|
+
Inbox,
|
|
15
|
+
Key,
|
|
16
|
+
Layers,
|
|
17
|
+
LayoutGrid,
|
|
18
|
+
ListChecks,
|
|
19
|
+
ListTree,
|
|
20
|
+
Lock,
|
|
21
|
+
Mail,
|
|
22
|
+
Menu as MenuIcon,
|
|
23
|
+
Newspaper,
|
|
24
|
+
Palette,
|
|
25
|
+
PanelBottom,
|
|
26
|
+
PanelTop,
|
|
27
|
+
PanelsTopLeft,
|
|
28
|
+
Plug,
|
|
29
|
+
Search as SearchIcon,
|
|
30
|
+
Settings,
|
|
31
|
+
ShieldX,
|
|
32
|
+
TextAlignStart,
|
|
33
|
+
Trash2,
|
|
34
|
+
Users,
|
|
35
|
+
Webhook,
|
|
36
|
+
} from 'lucide-react'
|
|
37
|
+
import type { LucideIcon } from 'lucide-react'
|
|
38
|
+
import type { ReactElement } from 'react'
|
|
39
|
+
import type { FormsSidebarCount } from '../lib/forms-service.js'
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The admin's single nav config (SHELL.md §2 "Nav order (exact)", TRACKING
|
|
43
|
+
* P-02). It ports the kit's base NAV plus `nav-patches.js`: `forms()` (Forms
|
|
44
|
+
* children with per-form unread counts, nested as `cms-layouts.js` does),
|
|
45
|
+
* `appearance()` (a group above where Templates would be) and `jobs()` (above
|
|
46
|
+
* Settings, opening SETTINGS).
|
|
47
|
+
*
|
|
48
|
+
* Kit order:
|
|
49
|
+
* Dashboard · Pages › · Posts › · Appearance ›
|
|
50
|
+
* ── CONTENT ── Media · Forms › · SEO · Script Tags · <collections, plugins>
|
|
51
|
+
* <config collection groups, each under its own label>
|
|
52
|
+
* ── SETTINGS ── Jobs · Settings
|
|
53
|
+
*
|
|
54
|
+
* Templates is left out until its screen exists (CONFLICTS.md §2: never link
|
|
55
|
+
* to a redirect).
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
export interface NavItem {
|
|
59
|
+
path: string
|
|
60
|
+
label: string
|
|
61
|
+
icon: LucideIcon | NavIconComponent
|
|
62
|
+
/**
|
|
63
|
+
* Section label. Consecutive items sharing a `group` render under one
|
|
64
|
+
* header, shown when the group changes. Items without one render unlabelled.
|
|
65
|
+
*/
|
|
66
|
+
group?: string
|
|
67
|
+
/** Children, shown as a sub-group (expanded sidebar) or a flyout (rail). */
|
|
68
|
+
children?: NavItem[]
|
|
69
|
+
/** Unread count. Zero or undefined renders nothing. */
|
|
70
|
+
badge?: number
|
|
71
|
+
/**
|
|
72
|
+
* Contributed by the config or a plugin rather than the kit. The mobile tab
|
|
73
|
+
* bar leaves these to the "More" drawer.
|
|
74
|
+
*/
|
|
75
|
+
extra?: boolean
|
|
76
|
+
/** Icon size in px. Kit: 16 for top-level rows, 14 for patched children. */
|
|
77
|
+
iconSize?: number
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
type NavIconComponent = (props: {
|
|
81
|
+
className?: string
|
|
82
|
+
size?: number
|
|
83
|
+
strokeWidth?: number
|
|
84
|
+
}) => ReactElement
|
|
85
|
+
|
|
86
|
+
/** Per-form row marker: the kit's 12px dot (`circle r=2.5`). */
|
|
87
|
+
function FormDot({
|
|
88
|
+
className,
|
|
89
|
+
size = 12,
|
|
90
|
+
strokeWidth = 1.75,
|
|
91
|
+
}: {
|
|
92
|
+
className?: string
|
|
93
|
+
size?: number
|
|
94
|
+
strokeWidth?: number
|
|
95
|
+
}) {
|
|
96
|
+
return (
|
|
97
|
+
<svg
|
|
98
|
+
width={size}
|
|
99
|
+
height={size}
|
|
100
|
+
viewBox="0 0 24 24"
|
|
101
|
+
fill="none"
|
|
102
|
+
stroke="currentColor"
|
|
103
|
+
strokeWidth={strokeWidth}
|
|
104
|
+
className={className}
|
|
105
|
+
aria-hidden
|
|
106
|
+
>
|
|
107
|
+
<circle cx="12" cy="12" r="2.5" />
|
|
108
|
+
</svg>
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const ICON_MAP: Record<string, LucideIcon> = {
|
|
113
|
+
file: File,
|
|
114
|
+
'file-text': FileText,
|
|
115
|
+
briefcase: Briefcase,
|
|
116
|
+
folder: FolderOpen,
|
|
117
|
+
book: BookOpen,
|
|
118
|
+
help: HelpCircle,
|
|
119
|
+
newspaper: Newspaper,
|
|
120
|
+
navigation: ListTree,
|
|
121
|
+
menu: MenuIcon,
|
|
122
|
+
'list-tree': ListTree,
|
|
123
|
+
PanelTop: PanelTop,
|
|
124
|
+
PanelBottom: PanelBottom,
|
|
125
|
+
Layers: Layers,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const PAGES_CHILDREN: NavItem[] = [
|
|
129
|
+
{ path: '/pages', label: 'All Pages', icon: PanelsTopLeft },
|
|
130
|
+
{ path: '/pages/trash', label: 'Trash', icon: Trash2 },
|
|
131
|
+
]
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Post Types are reached through the `/posts/types` cards page, not listed
|
|
135
|
+
* one per type, so the shape is the same however many types exist.
|
|
136
|
+
*/
|
|
137
|
+
const POSTS_CHILDREN: NavItem[] = [
|
|
138
|
+
{ path: '/posts', label: 'All Posts', icon: File },
|
|
139
|
+
{ path: '/posts/types', label: 'Post Types', icon: Clipboard },
|
|
140
|
+
{ path: '/posts/trash', label: 'Trash', icon: Trash2 },
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Appearance → Menus opens plugin-navigation's `navigations` collection: its
|
|
145
|
+
* list and NavBuilder editor are the working menu editor.
|
|
146
|
+
*/
|
|
147
|
+
const MENUS_SLUG = 'navigations'
|
|
148
|
+
const MENUS_PATH = `/${MENUS_SLUG}`
|
|
149
|
+
|
|
150
|
+
/** Without the navigation plugin there are no menus, so Menus would 404. */
|
|
151
|
+
function appearanceItem(hasMenus: boolean): NavItem {
|
|
152
|
+
const children: NavItem[] = [
|
|
153
|
+
...(hasMenus ? [{ path: MENUS_PATH, label: 'Menus', icon: TextAlignStart, iconSize: 14 }] : []),
|
|
154
|
+
{ path: '/appearance/header', label: 'Header & Footer', icon: PanelsTopLeft, iconSize: 14 },
|
|
155
|
+
{ path: '/appearance/widgets', label: 'Widgets', icon: LayoutGrid, iconSize: 14 },
|
|
156
|
+
]
|
|
157
|
+
// No Appearance landing screen exists, so the parent opens its first child.
|
|
158
|
+
return { path: children[0]!.path, label: 'Appearance', icon: Palette, children }
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const DASHBOARD: NavItem = { path: '/', label: 'Dashboard', icon: LayoutGrid }
|
|
162
|
+
const PAGES: NavItem = {
|
|
163
|
+
path: '/pages',
|
|
164
|
+
label: 'Pages',
|
|
165
|
+
icon: PanelsTopLeft,
|
|
166
|
+
children: PAGES_CHILDREN,
|
|
167
|
+
}
|
|
168
|
+
const POSTS: NavItem = { path: '/posts', label: 'Posts', icon: File, children: POSTS_CHILDREN }
|
|
169
|
+
|
|
170
|
+
const CONTENT_STATIC: NavItem[] = [
|
|
171
|
+
{ path: '/media', label: 'Media', icon: Image, group: 'Content' },
|
|
172
|
+
{ path: '/forms', label: 'Forms', icon: Clipboard, group: 'Content' },
|
|
173
|
+
{ path: '/seo', label: 'SEO', icon: SearchIcon, group: 'Content' },
|
|
174
|
+
{ path: '/script-tags', label: 'Script Tags', icon: Code, group: 'Content' },
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
const SETTINGS_ITEMS: NavItem[] = [
|
|
178
|
+
{ path: '/jobs', label: 'Jobs', icon: ListChecks, group: 'Settings' },
|
|
179
|
+
{ path: '/settings', label: 'Settings', icon: Settings, group: 'Settings' },
|
|
180
|
+
]
|
|
181
|
+
|
|
182
|
+
function resolveIcon(collection: any): LucideIcon {
|
|
183
|
+
const mapped = collection.admin?.icon ? ICON_MAP[collection.admin.icon] : undefined
|
|
184
|
+
if (mapped) return mapped
|
|
185
|
+
return collection.type === 'page' ? File : FileText
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Build the nav tree from the CMS config. A config-less install gets the
|
|
190
|
+
* kit's default tree (no navigations collection, so no Menus).
|
|
191
|
+
*
|
|
192
|
+
* Repo-only destinations follow CONFLICTS.md §2: the `pages` collection is
|
|
193
|
+
* the kit's Pages item; other collections and plugin nav links continue the
|
|
194
|
+
* CONTENT block after Script Tags; collections with their own `admin.group`
|
|
195
|
+
* follow under their own labels; Users and API Keys live in Settings tabs.
|
|
196
|
+
*/
|
|
197
|
+
export function buildNavItems(config: any): NavItem[] {
|
|
198
|
+
if (!config?.collections) {
|
|
199
|
+
return [DASHBOARD, PAGES, POSTS, appearanceItem(false), ...CONTENT_STATIC, ...SETTINGS_ITEMS]
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const raw = config.collections
|
|
203
|
+
const collectionsList: any[] = Array.isArray(raw) ? raw : Object.values(raw)
|
|
204
|
+
// Appearance → Menus reaches the navigations collection, so neither it nor
|
|
205
|
+
// the plugin's own nav link to it is listed again.
|
|
206
|
+
const hasMenus = collectionsList.some((c) => c.slug === MENUS_SLUG)
|
|
207
|
+
const visible = collectionsList.filter((c) => !c.admin?.hidden && c.slug !== MENUS_SLUG)
|
|
208
|
+
|
|
209
|
+
// `admin.group: 'Posts'` (case-insensitive) is a synonym for `type: 'post'`.
|
|
210
|
+
const isPostsGroup = (c: any) =>
|
|
211
|
+
typeof c.admin?.group === 'string' && c.admin.group.toLowerCase() === 'posts'
|
|
212
|
+
const hasPages = visible.some((c) => c.slug === 'pages')
|
|
213
|
+
const hasPosts = visible.some((c) => c.type === 'post' || isPostsGroup(c))
|
|
214
|
+
// Every other ungrouped collection continues CONTENT after Script Tags.
|
|
215
|
+
const ungrouped = visible.filter(
|
|
216
|
+
(c) => c.slug !== 'pages' && c.type !== 'post' && !isPostsGroup(c) && !c.admin?.group,
|
|
217
|
+
)
|
|
218
|
+
const grouped = visible.filter((c) => c.admin?.group && !isPostsGroup(c) && c.type !== 'post')
|
|
219
|
+
|
|
220
|
+
const items: NavItem[] = [DASHBOARD]
|
|
221
|
+
if (hasPages) items.push(PAGES)
|
|
222
|
+
if (hasPosts) items.push(POSTS)
|
|
223
|
+
items.push(appearanceItem(hasMenus), ...CONTENT_STATIC)
|
|
224
|
+
|
|
225
|
+
const taken = (path: string) =>
|
|
226
|
+
items.some((n) => n.path === path || n.children?.some((c) => c.path === path))
|
|
227
|
+
|
|
228
|
+
for (const collection of ungrouped) {
|
|
229
|
+
const path = `/${collection.slug}`
|
|
230
|
+
if (taken(path)) continue
|
|
231
|
+
items.push({
|
|
232
|
+
label: collection.labels?.plural ?? collection.slug,
|
|
233
|
+
path,
|
|
234
|
+
icon: resolveIcon(collection),
|
|
235
|
+
group: 'Content',
|
|
236
|
+
extra: true,
|
|
237
|
+
})
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Plugin-contributed nav links (PluginDefinition.adminNavItems, collected
|
|
241
|
+
// onto `_pluginNavItems` by cms-core's applyPlugins), deduped by path so a
|
|
242
|
+
// plugin can't double a built-in destination or one of its own collections.
|
|
243
|
+
const pluginNav: Array<{ label?: string; icon?: string; path?: string }> = Array.isArray(
|
|
244
|
+
config?._pluginNavItems,
|
|
245
|
+
)
|
|
246
|
+
? config._pluginNavItems
|
|
247
|
+
: []
|
|
248
|
+
for (const item of pluginNav) {
|
|
249
|
+
if (!item?.path || (hasMenus && item.path === MENUS_PATH) || taken(item.path)) continue
|
|
250
|
+
items.push({
|
|
251
|
+
label: item.label ?? item.path,
|
|
252
|
+
path: item.path,
|
|
253
|
+
icon: (item.icon && ICON_MAP[item.icon]) || FileText,
|
|
254
|
+
group: 'Content',
|
|
255
|
+
extra: true,
|
|
256
|
+
})
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Config collection groups, each under its own label. A grouped collection
|
|
260
|
+
// whose path a built-in already provides is skipped: plugin-forms' `forms`
|
|
261
|
+
// (admin.group 'Forms', path `/forms`) would otherwise double Forms.
|
|
262
|
+
const groupBuckets = new Map<string, NavItem[]>()
|
|
263
|
+
for (const col of grouped) {
|
|
264
|
+
const path = `/${col.slug}`
|
|
265
|
+
if (taken(path)) continue
|
|
266
|
+
const group = col.admin.group as string
|
|
267
|
+
const bucket = groupBuckets.get(group) ?? []
|
|
268
|
+
bucket.push({
|
|
269
|
+
label: col.labels?.plural ?? col.slug,
|
|
270
|
+
path,
|
|
271
|
+
icon: resolveIcon(col),
|
|
272
|
+
group,
|
|
273
|
+
extra: true,
|
|
274
|
+
})
|
|
275
|
+
groupBuckets.set(group, bucket)
|
|
276
|
+
}
|
|
277
|
+
for (const bucket of groupBuckets.values()) items.push(...bucket)
|
|
278
|
+
|
|
279
|
+
items.push(...SETTINGS_ITEMS)
|
|
280
|
+
return items
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Forms children as in the kit: All Entries and All Forms each open a third
|
|
285
|
+
* level with one row per form (`cms-layouts.js` "3rd-level nav nesting"),
|
|
286
|
+
* followed by Spam, SMTP Log and Form Settings. The parent and All Entries
|
|
287
|
+
* carry the total unread count; each form's entries row carries its own.
|
|
288
|
+
*
|
|
289
|
+
* `forms` comes from `/forms/sidebar-counts`, which returns active forms only,
|
|
290
|
+
* so drafts aren't listed under All Forms yet and Spam has no count.
|
|
291
|
+
*/
|
|
292
|
+
export function applyFormsNav(items: NavItem[], forms: FormsSidebarCount[]): NavItem[] {
|
|
293
|
+
const totalUnread = forms.reduce((sum, f) => sum + (f.unread ?? 0), 0)
|
|
294
|
+
return items.map((item) => {
|
|
295
|
+
if (item.path !== '/forms') return item
|
|
296
|
+
const children: NavItem[] = [
|
|
297
|
+
{
|
|
298
|
+
path: '/forms/entries',
|
|
299
|
+
label: 'All Entries',
|
|
300
|
+
icon: Inbox,
|
|
301
|
+
badge: totalUnread,
|
|
302
|
+
iconSize: 14,
|
|
303
|
+
children: forms.map((f) => ({
|
|
304
|
+
path: `/forms/${f.formId}/submissions`,
|
|
305
|
+
label: f.name,
|
|
306
|
+
icon: FormDot,
|
|
307
|
+
iconSize: 12,
|
|
308
|
+
badge: f.unread,
|
|
309
|
+
})),
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
path: '/forms',
|
|
313
|
+
label: 'All Forms',
|
|
314
|
+
icon: ClipboardList,
|
|
315
|
+
iconSize: 14,
|
|
316
|
+
children: forms.map((f) => ({
|
|
317
|
+
path: `/forms/${f.formId}/edit`,
|
|
318
|
+
label: f.name,
|
|
319
|
+
icon: FormDot,
|
|
320
|
+
iconSize: 12,
|
|
321
|
+
})),
|
|
322
|
+
},
|
|
323
|
+
{ path: '/forms/spam', label: 'Spam', icon: ShieldX, iconSize: 14 },
|
|
324
|
+
{ path: '/forms/deliveries', label: 'SMTP Log', icon: Mail, iconSize: 14 },
|
|
325
|
+
{ path: '/forms/settings', label: 'Form Settings', icon: Settings, iconSize: 14 },
|
|
326
|
+
]
|
|
327
|
+
return { ...item, badge: totalUnread > 0 ? totalUnread : undefined, children }
|
|
328
|
+
})
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* The Settings tabs in strip order: Settings.html `TABS` with its 15px icons,
|
|
333
|
+
* plus the repo's Layout and Webhooks. One list for the Settings tab strip and
|
|
334
|
+
* the mobile drawer, so each tab reads the same in both. `layout` exists only
|
|
335
|
+
* when the site defines layout regions.
|
|
336
|
+
*/
|
|
337
|
+
export const SETTINGS_TABS: ReadonlyArray<{ id: string; label: string; icon: LucideIcon }> = [
|
|
338
|
+
{ id: 'general', label: 'General', icon: Settings },
|
|
339
|
+
{ id: 'appearance', label: 'Admin appearance', icon: Palette },
|
|
340
|
+
{ id: 'layout', label: 'Layout', icon: Layers },
|
|
341
|
+
{ id: 'security', label: 'Security', icon: Lock },
|
|
342
|
+
{ id: 'users', label: 'Users', icon: Users },
|
|
343
|
+
{ id: 'mcp', label: 'MCP', icon: Plug },
|
|
344
|
+
{ id: 'api-keys', label: 'API Keys', icon: Key },
|
|
345
|
+
{ id: 'seo', label: 'SEO', icon: SearchIcon },
|
|
346
|
+
{ id: 'email', label: 'Email (SMTP)', icon: Mail },
|
|
347
|
+
{ id: 'webhooks', label: 'Webhooks', icon: Webhook },
|
|
348
|
+
{ id: 'ai', label: 'AI', icon: Cpu },
|
|
349
|
+
{ id: 'updates', label: 'Updates', icon: Download },
|
|
350
|
+
]
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* The mobile drawer (behind the tab bar's More) also lists the Settings tabs
|
|
354
|
+
* (CONFLICTS.md §2, DECIDED mobile nav), which don't fit in the bar. Layout
|
|
355
|
+
* only applies this below 769px; the desktop sidebar keeps Settings a leaf.
|
|
356
|
+
*/
|
|
357
|
+
export function withSettingsTabs(
|
|
358
|
+
items: NavItem[],
|
|
359
|
+
config: { layout?: { regions?: Record<string, unknown> } } | null | undefined,
|
|
360
|
+
): NavItem[] {
|
|
361
|
+
const hasLayout = Object.keys(config?.layout?.regions ?? {}).length > 0
|
|
362
|
+
const tab = (id: string, label: string, icon: LucideIcon): NavItem => ({
|
|
363
|
+
path: `/settings?tab=${id}`,
|
|
364
|
+
label,
|
|
365
|
+
icon,
|
|
366
|
+
iconSize: 14,
|
|
367
|
+
})
|
|
368
|
+
const children: NavItem[] = SETTINGS_TABS.filter(
|
|
369
|
+
(settingsTab) => settingsTab.id !== 'layout' || hasLayout,
|
|
370
|
+
).map((settingsTab) => tab(settingsTab.id, settingsTab.label, settingsTab.icon))
|
|
371
|
+
return items.map((item) => (item.path === '/settings' ? { ...item, children } : item))
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Whether `itemPath` is the current page. Query and hash are ignored so
|
|
376
|
+
* state-bearing routes (`/seo?tab=audit`) still match.
|
|
377
|
+
*/
|
|
378
|
+
export function isPathActive(currentPath: string, itemPath: string): boolean {
|
|
379
|
+
const path = currentPath.split('?')[0]!.split('#')[0]!
|
|
380
|
+
// A query in the item path (Settings tabs, `/settings?tab=security`) must
|
|
381
|
+
// match too; Settings without `?tab=` shows General.
|
|
382
|
+
if (itemPath.includes('?')) {
|
|
383
|
+
const [itemPathname, itemQuery] = itemPath.split('?') as [string, string]
|
|
384
|
+
if (path !== itemPathname) return false
|
|
385
|
+
const current = new URLSearchParams(currentPath.split('#')[0]!.split('?')[1] ?? '')
|
|
386
|
+
const wanted = new URLSearchParams(itemQuery)
|
|
387
|
+
for (const [key, value] of wanted) {
|
|
388
|
+
const have = current.get(key) ?? (key === 'tab' ? 'general' : null)
|
|
389
|
+
if (have !== value) return false
|
|
390
|
+
}
|
|
391
|
+
return true
|
|
392
|
+
}
|
|
393
|
+
if (itemPath === '/') return path === '/'
|
|
394
|
+
// `/posts` is a prefix of `/posts/types`; All Posts is exact-only.
|
|
395
|
+
if (itemPath === '/posts') return path === '/posts' || path === '/posts/new'
|
|
396
|
+
return path === itemPath || path.startsWith(itemPath + '/')
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* The row that owns the current page, searching every level below: the
|
|
401
|
+
* longest matching path wins, so All Pages (`/pages`) yields to Trash on
|
|
402
|
+
* `/pages/trash` and All Forms (`/forms`) to All Entries on `/forms/entries`.
|
|
403
|
+
*/
|
|
404
|
+
export function activeChildPath(children: NavItem[], currentPath: string): string | undefined {
|
|
405
|
+
let best: string | undefined
|
|
406
|
+
const visit = (items: NavItem[]) => {
|
|
407
|
+
for (const child of items) {
|
|
408
|
+
if (isPathActive(currentPath, child.path) && (!best || child.path.length > best.length)) {
|
|
409
|
+
best = child.path
|
|
410
|
+
}
|
|
411
|
+
if (child.children) visit(child.children)
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
visit(children)
|
|
415
|
+
return best
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/** True when the current page is one of `items` or anything nested below them. */
|
|
419
|
+
export function hasActiveDescendant(items: NavItem[], currentPath: string): boolean {
|
|
420
|
+
return items.some(
|
|
421
|
+
(item) =>
|
|
422
|
+
isPathActive(currentPath, item.path) ||
|
|
423
|
+
(!!item.children && hasActiveDescendant(item.children, currentPath)),
|
|
424
|
+
)
|
|
425
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react'
|
|
1
|
+
import { useEffect, useRef, useState, type KeyboardEvent as ReactKeyboardEvent } from 'react'
|
|
2
2
|
import type { ReactNode } from 'react'
|
|
3
|
+
import { X } from 'lucide-react'
|
|
3
4
|
|
|
4
5
|
export interface AdminShellProps {
|
|
5
6
|
/** Sidebar/navigation slot. Rendered in the left column on desktop. */
|
|
@@ -10,10 +11,16 @@ export interface AdminShellProps {
|
|
|
10
11
|
breadcrumbs?: ReactNode
|
|
11
12
|
/** Main content. Scrolls independently of the sidebar. */
|
|
12
13
|
children: ReactNode
|
|
14
|
+
/**
|
|
15
|
+
* Mobile bottom tab bar, rendered below `desktopBreakpoint` only. The main
|
|
16
|
+
* area reserves `--tabbar-h` at the bottom so content isn't hidden behind it.
|
|
17
|
+
*/
|
|
18
|
+
tabBar?: ReactNode
|
|
13
19
|
/**
|
|
14
20
|
* Whether the mobile sidebar overlay is currently open. Controlled.
|
|
15
21
|
* AdminShell renders the backdrop + slide transform; the consumer owns
|
|
16
|
-
* the open state and the
|
|
22
|
+
* the open state and the control that toggles it (the admin's tab bar
|
|
23
|
+
* More).
|
|
17
24
|
*/
|
|
18
25
|
mobileSidebarOpen?: boolean
|
|
19
26
|
onMobileSidebarClose?: () => void
|
|
@@ -24,6 +31,27 @@ export interface AdminShellProps {
|
|
|
24
31
|
desktopBreakpoint?: number
|
|
25
32
|
}
|
|
26
33
|
|
|
34
|
+
/** The mobile drawer's id, for an opener's `aria-controls`. */
|
|
35
|
+
export const DRAWER_ID = 'prenta-nav-drawer'
|
|
36
|
+
|
|
37
|
+
const FOCUSABLE =
|
|
38
|
+
'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
|
39
|
+
|
|
40
|
+
function setInert(el: HTMLElement | null, inert: boolean) {
|
|
41
|
+
if (el) (el as HTMLElement & { inert?: boolean }).inert = inert
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The drawer's Tab stops: rendered (a `display: none` ancestor leaves no
|
|
46
|
+
* client rects, like the sidebar's collapse footer below 1025px) and not
|
|
47
|
+
* inert.
|
|
48
|
+
*/
|
|
49
|
+
function tabStops(root: HTMLElement): HTMLElement[] {
|
|
50
|
+
return Array.from(root.querySelectorAll<HTMLElement>(FOCUSABLE)).filter(
|
|
51
|
+
(el) => el.getClientRects().length > 0 && !el.closest('[inert]'),
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
27
55
|
/**
|
|
28
56
|
* The canonical admin chrome. Owns the entire viewport, splits into
|
|
29
57
|
* `sidebar | (header + breadcrumbs + content)`, and handles the mobile
|
|
@@ -47,11 +75,17 @@ export function AdminShell({
|
|
|
47
75
|
header,
|
|
48
76
|
breadcrumbs,
|
|
49
77
|
children,
|
|
78
|
+
tabBar,
|
|
50
79
|
mobileSidebarOpen = false,
|
|
51
80
|
onMobileSidebarClose,
|
|
52
81
|
desktopBreakpoint = 768,
|
|
53
82
|
}: AdminShellProps) {
|
|
54
83
|
const [isDesktop, setIsDesktop] = useState(false)
|
|
84
|
+
const sidebarRef = useRef<HTMLDivElement>(null)
|
|
85
|
+
const contentRef = useRef<HTMLDivElement>(null)
|
|
86
|
+
const tabBarRef = useRef<HTMLDivElement>(null)
|
|
87
|
+
const skipRef = useRef<HTMLAnchorElement>(null)
|
|
88
|
+
const drawerOpen = !isDesktop && mobileSidebarOpen
|
|
55
89
|
|
|
56
90
|
useEffect(() => {
|
|
57
91
|
if (typeof window === 'undefined') return
|
|
@@ -62,6 +96,74 @@ export function AdminShell({
|
|
|
62
96
|
return () => mq.removeEventListener('change', handler)
|
|
63
97
|
}, [desktopBreakpoint])
|
|
64
98
|
|
|
99
|
+
// The closed mobile drawer is off-screen: keep it out of the tab order and
|
|
100
|
+
// the accessibility tree. Set on the element because React 18 has no
|
|
101
|
+
// `inert` prop.
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
setInert(sidebarRef.current, !isDesktop && !mobileSidebarOpen)
|
|
104
|
+
}, [isDesktop, mobileSidebarOpen])
|
|
105
|
+
|
|
106
|
+
// The drawer only exists below the breakpoint: close it on the way out, or
|
|
107
|
+
// it would reopen by itself when the window narrows again.
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
if (isDesktop && mobileSidebarOpen) onMobileSidebarClose?.()
|
|
110
|
+
}, [isDesktop, mobileSidebarOpen, onMobileSidebarClose])
|
|
111
|
+
|
|
112
|
+
// The open drawer is modal: the skip link, the content and the tab bar go
|
|
113
|
+
// inert, focus moves in (to its close button), and on close it returns to
|
|
114
|
+
// the opener (the tab bar's More, or a custom header's menu button). One effect so the
|
|
115
|
+
// opener is read before it goes inert and un-inerted before it takes focus
|
|
116
|
+
// back.
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
if (!drawerOpen) return
|
|
119
|
+
const opener = document.activeElement as HTMLElement | null
|
|
120
|
+
const behind = [skipRef.current, contentRef.current, tabBarRef.current]
|
|
121
|
+
for (const el of behind) setInert(el, true)
|
|
122
|
+
const drawer = sidebarRef.current
|
|
123
|
+
if (drawer) (tabStops(drawer)[0] ?? drawer).focus()
|
|
124
|
+
// App shortcuts listening on `document` would open UI in the inert column
|
|
125
|
+
// (the command palette's Ctrl/Cmd+K); a modal ignores them.
|
|
126
|
+
const blockShortcuts = (e: KeyboardEvent) => {
|
|
127
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {
|
|
128
|
+
e.stopPropagation()
|
|
129
|
+
// Also keep the browser's own Ctrl+K (focus the address bar) from
|
|
130
|
+
// firing; Shift combos (e.g. Edge's Duplicate tab) are left alone.
|
|
131
|
+
if (!e.shiftKey) e.preventDefault()
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
document.addEventListener('keydown', blockShortcuts, true)
|
|
135
|
+
return () => {
|
|
136
|
+
document.removeEventListener('keydown', blockShortcuts, true)
|
|
137
|
+
for (const el of behind) setInert(el, false)
|
|
138
|
+
if (opener && opener !== document.body && document.contains(opener)) opener.focus()
|
|
139
|
+
}
|
|
140
|
+
}, [drawerOpen])
|
|
141
|
+
|
|
142
|
+
// Esc closes the drawer; Tab and Shift+Tab stay inside it. Keys from
|
|
143
|
+
// portals rendered in the drawer's React tree (a Radix menu's Esc) bubble
|
|
144
|
+
// here too; they belong to that layer.
|
|
145
|
+
const onDrawerKeyDown = (e: ReactKeyboardEvent<HTMLDivElement>) => {
|
|
146
|
+
if (!drawerOpen || e.defaultPrevented) return
|
|
147
|
+
if (!e.currentTarget.contains(e.target as Node)) return
|
|
148
|
+
if (e.key === 'Escape') {
|
|
149
|
+
e.stopPropagation()
|
|
150
|
+
onMobileSidebarClose?.()
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
if (e.key !== 'Tab') return
|
|
154
|
+
const items = tabStops(e.currentTarget)
|
|
155
|
+
if (items.length === 0) return
|
|
156
|
+
const first = items[0]!
|
|
157
|
+
const last = items[items.length - 1]!
|
|
158
|
+
if (e.shiftKey && document.activeElement === first) {
|
|
159
|
+
e.preventDefault()
|
|
160
|
+
last.focus()
|
|
161
|
+
} else if (!e.shiftKey && document.activeElement === last) {
|
|
162
|
+
e.preventDefault()
|
|
163
|
+
first.focus()
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
65
167
|
return (
|
|
66
168
|
<div
|
|
67
169
|
className="bg-background text-foreground h-screen overflow-hidden"
|
|
@@ -77,7 +179,7 @@ export function AdminShell({
|
|
|
77
179
|
* focused; styling lives in `responsive.css` because it has to survive
|
|
78
180
|
* a consumer whose Tailwind build does not scan this file.
|
|
79
181
|
*/}
|
|
80
|
-
<a className="prenta-skip-link" href="#prenta-main">
|
|
182
|
+
<a ref={skipRef} className="prenta-skip-link" href="#prenta-main">
|
|
81
183
|
Skip to content
|
|
82
184
|
</a>
|
|
83
185
|
|
|
@@ -90,7 +192,17 @@ export function AdminShell({
|
|
|
90
192
|
)}
|
|
91
193
|
|
|
92
194
|
<div
|
|
93
|
-
|
|
195
|
+
ref={sidebarRef}
|
|
196
|
+
id={DRAWER_ID}
|
|
197
|
+
// Below the desktop breakpoint the open sidebar is a modal drawer.
|
|
198
|
+
role={drawerOpen ? 'dialog' : undefined}
|
|
199
|
+
aria-modal={drawerOpen ? true : undefined}
|
|
200
|
+
aria-label={drawerOpen ? 'Navigation' : undefined}
|
|
201
|
+
tabIndex={drawerOpen ? -1 : undefined}
|
|
202
|
+
onKeyDown={onDrawerKeyDown}
|
|
203
|
+
// A class, not an inline transition, so the in-app Reduce motion
|
|
204
|
+
// setting (and prefers-reduced-motion) can stop the slide.
|
|
205
|
+
className={`z-50 outline-none ${isDesktop ? '' : 'motion-safe:transition-transform motion-safe:duration-300 motion-safe:ease-out'}`}
|
|
94
206
|
style={
|
|
95
207
|
isDesktop
|
|
96
208
|
? {
|
|
@@ -104,14 +216,27 @@ export function AdminShell({
|
|
|
104
216
|
bottom: 0,
|
|
105
217
|
left: 0,
|
|
106
218
|
transform: mobileSidebarOpen ? 'translateX(0)' : 'translateX(-100%)',
|
|
107
|
-
transition: 'transform 300ms ease',
|
|
108
219
|
}
|
|
109
220
|
}
|
|
110
221
|
>
|
|
222
|
+
{/* The drawer's own dismiss: the scrim is pointer-only, and its
|
|
223
|
+
opener is inert behind the modal. First in the drawer, so it takes
|
|
224
|
+
focus on open. */}
|
|
225
|
+
{!isDesktop && onMobileSidebarClose ? (
|
|
226
|
+
<button
|
|
227
|
+
type="button"
|
|
228
|
+
onClick={onMobileSidebarClose}
|
|
229
|
+
aria-label="Close navigation"
|
|
230
|
+
className="rounded-7 text-sub hover:bg-acc-l hover:text-acc prenta-touch-target absolute top-2.5 right-2.5 z-[1] flex h-9 w-9 cursor-pointer items-center justify-center border-0 bg-transparent p-0"
|
|
231
|
+
>
|
|
232
|
+
<X className="h-4 w-4" strokeWidth={1.75} aria-hidden />
|
|
233
|
+
</button>
|
|
234
|
+
) : null}
|
|
111
235
|
{sidebar}
|
|
112
236
|
</div>
|
|
113
237
|
|
|
114
238
|
<div
|
|
239
|
+
ref={contentRef}
|
|
115
240
|
className="flex flex-col overflow-hidden"
|
|
116
241
|
style={
|
|
117
242
|
isDesktop
|
|
@@ -121,10 +246,33 @@ export function AdminShell({
|
|
|
121
246
|
>
|
|
122
247
|
{header}
|
|
123
248
|
{breadcrumbs}
|
|
124
|
-
|
|
249
|
+
{/* scroll-padding-bottom keeps a focused field clear of the floating
|
|
250
|
+
unsaved bar (52px, 16px up) when focus scrolls it into view
|
|
251
|
+
(WCAG 2.4.11); on mobile the fixed tab bar covers another
|
|
252
|
+
--tabbar-h, which the content also reserves at its end.
|
|
253
|
+
`relative`: visually hidden text (`sr-only`, absolutely positioned)
|
|
254
|
+
with no positioned ancestor otherwise sized the fixed admin root,
|
|
255
|
+
and on long pages the whole shell scrolled. */}
|
|
256
|
+
<main
|
|
257
|
+
id="prenta-main"
|
|
258
|
+
className="relative min-h-0 flex-1 scroll-pb-[84px] overflow-x-hidden overflow-y-auto"
|
|
259
|
+
style={
|
|
260
|
+
!isDesktop && tabBar
|
|
261
|
+
? {
|
|
262
|
+
// --fab-clear: room for a floating action button
|
|
263
|
+
// (responsive.css sets it while the page has one).
|
|
264
|
+
paddingBottom:
|
|
265
|
+
'calc(var(--tabbar-h) + env(safe-area-inset-bottom) + var(--fab-clear, 0px))',
|
|
266
|
+
scrollPaddingBottom: 'calc(84px + var(--tabbar-h) + env(safe-area-inset-bottom))',
|
|
267
|
+
}
|
|
268
|
+
: undefined
|
|
269
|
+
}
|
|
270
|
+
>
|
|
125
271
|
{children}
|
|
126
272
|
</main>
|
|
127
273
|
</div>
|
|
274
|
+
|
|
275
|
+
{!isDesktop && tabBar ? <div ref={tabBarRef}>{tabBar}</div> : null}
|
|
128
276
|
</div>
|
|
129
277
|
)
|
|
130
278
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kit's topbar icon button (`.icbtn`, SHELL.md §3): 34×34, radius 8,
|
|
3
|
+
* `--sub`, hover `--acc-l` / `--acc`; 44×44 below 769px (cms-layouts.css) and
|
|
4
|
+
* at least 44px on touch screens (`.prenta-touch-target`). `relative` so the
|
|
5
|
+
* bell's unread dot can sit in its corner.
|
|
6
|
+
*/
|
|
7
|
+
export const TOPBAR_ICON_BUTTON =
|
|
8
|
+
'rounded-8 text-sub hover:bg-acc-l hover:text-acc prenta-touch-target relative flex h-[34px] w-[34px] shrink-0 cursor-pointer items-center justify-center border-0 bg-transparent p-0 mobile:h-11 mobile:w-11'
|