@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
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
'use client'
|
|
1
|
+
'use client'
|
|
2
2
|
|
|
3
|
-
import { useState, type FormEvent } from 'react'
|
|
4
|
-
import { Shield, ArrowLeft, Loader2, CheckCircle2, AlertTriangle } from 'lucide-react'
|
|
5
|
-
import { cmsApi } from '../lib/api.js'
|
|
3
|
+
import { useState, type FormEvent } from 'react'
|
|
4
|
+
import { Shield, ArrowLeft, Loader2, CheckCircle2, AlertTriangle } from 'lucide-react'
|
|
5
|
+
import { cmsApi } from '../lib/api.js'
|
|
6
6
|
|
|
7
7
|
export interface ForgotPasswordProps {
|
|
8
|
-
onNavigate: (path: string) => void
|
|
8
|
+
onNavigate: (path: string) => void
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export function ForgotPassword({ onNavigate }: ForgotPasswordProps) {
|
|
12
|
-
const [email, setEmail] = useState('')
|
|
13
|
-
const [submitting, setSubmitting] = useState(false)
|
|
14
|
-
const [sent, setSent] = useState(false)
|
|
15
|
-
const [error, setError] = useState('')
|
|
12
|
+
const [email, setEmail] = useState('')
|
|
13
|
+
const [submitting, setSubmitting] = useState(false)
|
|
14
|
+
const [sent, setSent] = useState(false)
|
|
15
|
+
const [error, setError] = useState('')
|
|
16
16
|
|
|
17
|
-
const canSubmit = email.trim() && !submitting
|
|
17
|
+
const canSubmit = email.trim() && !submitting
|
|
18
18
|
|
|
19
19
|
const handleSubmit = async (e: FormEvent) => {
|
|
20
|
-
e.preventDefault()
|
|
21
|
-
if (!canSubmit) return
|
|
20
|
+
e.preventDefault()
|
|
21
|
+
if (!canSubmit) return
|
|
22
22
|
|
|
23
|
-
setError('')
|
|
24
|
-
setSubmitting(true)
|
|
23
|
+
setError('')
|
|
24
|
+
setSubmitting(true)
|
|
25
25
|
|
|
26
26
|
try {
|
|
27
27
|
const result = await cmsApi('/auth/forgot-password', {
|
|
28
28
|
method: 'POST',
|
|
29
29
|
body: JSON.stringify({ email: email.trim() }),
|
|
30
|
-
})
|
|
30
|
+
})
|
|
31
31
|
|
|
32
32
|
if (result.error && result.status === 429) {
|
|
33
|
-
setError('Too many requests. Please try again later.')
|
|
33
|
+
setError('Too many requests. Please try again later.')
|
|
34
34
|
} else {
|
|
35
|
-
setSent(true)
|
|
35
|
+
setSent(true)
|
|
36
36
|
}
|
|
37
37
|
} catch {
|
|
38
|
-
setError('An unexpected error occurred. Please try again.')
|
|
38
|
+
setError('An unexpected error occurred. Please try again.')
|
|
39
39
|
} finally {
|
|
40
|
-
setSubmitting(false)
|
|
40
|
+
setSubmitting(false)
|
|
41
41
|
}
|
|
42
|
-
}
|
|
42
|
+
}
|
|
43
43
|
|
|
44
44
|
return (
|
|
45
45
|
<div className="min-h-screen flex items-center justify-center bg-gray-50 px-4">
|
|
@@ -63,7 +63,8 @@ export function ForgotPassword({ onNavigate }: ForgotPasswordProps) {
|
|
|
63
63
|
<CheckCircle2 className="w-6 h-6 text-green-600" />
|
|
64
64
|
</div>
|
|
65
65
|
<p className="text-sm text-gray-600">
|
|
66
|
-
If an account exists for <strong>{email}</strong>, you will receive a password reset
|
|
66
|
+
If an account exists for <strong>{email}</strong>, you will receive a password reset
|
|
67
|
+
email shortly.
|
|
67
68
|
</p>
|
|
68
69
|
<p className="text-xs text-gray-500">
|
|
69
70
|
The link expires in 1 hour. Check your spam folder if you don't see it.
|
|
@@ -86,7 +87,10 @@ export function ForgotPassword({ onNavigate }: ForgotPasswordProps) {
|
|
|
86
87
|
)}
|
|
87
88
|
|
|
88
89
|
<div>
|
|
89
|
-
<label
|
|
90
|
+
<label
|
|
91
|
+
htmlFor="forgot-email"
|
|
92
|
+
className="block text-sm font-medium text-gray-700 mb-1.5"
|
|
93
|
+
>
|
|
90
94
|
Email Address
|
|
91
95
|
</label>
|
|
92
96
|
<input
|
|
@@ -132,5 +136,5 @@ export function ForgotPassword({ onNavigate }: ForgotPasswordProps) {
|
|
|
132
136
|
</div>
|
|
133
137
|
</div>
|
|
134
138
|
</div>
|
|
135
|
-
)
|
|
139
|
+
)
|
|
136
140
|
}
|
package/src/views/FormEditor.tsx
CHANGED
|
@@ -1,39 +1,47 @@
|
|
|
1
|
-
'use client'
|
|
1
|
+
'use client'
|
|
2
2
|
|
|
3
|
-
import { useState, useCallback, useEffect } from 'react'
|
|
3
|
+
import { useState, useCallback, useEffect } from 'react'
|
|
4
4
|
import {
|
|
5
|
-
Save,
|
|
6
|
-
|
|
5
|
+
Save,
|
|
6
|
+
ArrowLeft,
|
|
7
|
+
Plus,
|
|
8
|
+
Trash2,
|
|
9
|
+
GripVertical,
|
|
10
|
+
MessageSquare,
|
|
11
|
+
ExternalLink,
|
|
12
|
+
BarChart3,
|
|
13
|
+
ChevronDown,
|
|
14
|
+
ChevronRight,
|
|
7
15
|
Loader2,
|
|
8
|
-
} from 'lucide-react'
|
|
9
|
-
import { useApiData } from '../lib/useApiData.js'
|
|
10
|
-
import { cmsApi } from '../lib/api.js'
|
|
16
|
+
} from 'lucide-react'
|
|
17
|
+
import { useApiData } from '../lib/useApiData.js'
|
|
18
|
+
import { cmsApi } from '../lib/api.js'
|
|
11
19
|
|
|
12
20
|
interface FormField {
|
|
13
|
-
id: string
|
|
14
|
-
type: string
|
|
15
|
-
label: string
|
|
16
|
-
placeholder?: string
|
|
17
|
-
required: boolean
|
|
18
|
-
options?: string[]
|
|
21
|
+
id: string
|
|
22
|
+
type: string
|
|
23
|
+
label: string
|
|
24
|
+
placeholder?: string
|
|
25
|
+
required: boolean
|
|
26
|
+
options?: string[]
|
|
19
27
|
}
|
|
20
28
|
|
|
21
29
|
interface ConfirmationConfig {
|
|
22
|
-
type: 'message' | 'redirect'
|
|
23
|
-
message: string
|
|
24
|
-
redirectUrl: string
|
|
25
|
-
redirectDelay: number
|
|
30
|
+
type: 'message' | 'redirect'
|
|
31
|
+
message: string
|
|
32
|
+
redirectUrl: string
|
|
33
|
+
redirectDelay: number
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
interface AnalyticsConfig {
|
|
29
|
-
enabled: boolean
|
|
30
|
-
measurementId: string
|
|
31
|
-
submitEventName: string
|
|
32
|
-
startEventName: string
|
|
33
|
-
trackAsConversion: boolean
|
|
34
|
-
conversionValue: number
|
|
35
|
-
conversionCurrency: string
|
|
36
|
-
customParameters: Record<string, string
|
|
37
|
+
enabled: boolean
|
|
38
|
+
measurementId: string
|
|
39
|
+
submitEventName: string
|
|
40
|
+
startEventName: string
|
|
41
|
+
trackAsConversion: boolean
|
|
42
|
+
conversionValue: number
|
|
43
|
+
conversionCurrency: string
|
|
44
|
+
customParameters: Record<string, string>
|
|
37
45
|
}
|
|
38
46
|
|
|
39
47
|
const FIELD_TYPES = [
|
|
@@ -48,32 +56,32 @@ const FIELD_TYPES = [
|
|
|
48
56
|
{ value: 'url', label: 'URL' },
|
|
49
57
|
{ value: 'file', label: 'File Upload' },
|
|
50
58
|
{ value: 'hidden', label: 'Hidden' },
|
|
51
|
-
] as const
|
|
59
|
+
] as const
|
|
52
60
|
|
|
53
61
|
export interface FormEditorProps {
|
|
54
|
-
formId?: string
|
|
55
|
-
onNavigate?: (path: string) => void
|
|
62
|
+
formId?: string
|
|
63
|
+
onNavigate?: (path: string) => void
|
|
56
64
|
}
|
|
57
65
|
|
|
58
66
|
export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
59
|
-
const isNew = !formId
|
|
67
|
+
const isNew = !formId
|
|
60
68
|
const { data: existingForm, loading } = useApiData<any>(
|
|
61
69
|
formId ? `/collections/forms/${formId}` : null,
|
|
62
|
-
)
|
|
70
|
+
)
|
|
63
71
|
|
|
64
|
-
const [name, setName] = useState('')
|
|
65
|
-
const [description, setDescription] = useState('')
|
|
66
|
-
const [status, setStatus] = useState('active')
|
|
67
|
-
const [fields, setFields] = useState<FormField[]>([])
|
|
68
|
-
const [saving, setSaving] = useState(false)
|
|
69
|
-
const [expandedSection, setExpandedSection] = useState<string | null>('fields')
|
|
72
|
+
const [name, setName] = useState('')
|
|
73
|
+
const [description, setDescription] = useState('')
|
|
74
|
+
const [status, setStatus] = useState('active')
|
|
75
|
+
const [fields, setFields] = useState<FormField[]>([])
|
|
76
|
+
const [saving, setSaving] = useState(false)
|
|
77
|
+
const [expandedSection, setExpandedSection] = useState<string | null>('fields')
|
|
70
78
|
|
|
71
79
|
const [confirmation, setConfirmation] = useState<ConfirmationConfig>({
|
|
72
80
|
type: 'message',
|
|
73
81
|
message: 'Thank you! Your submission has been received.',
|
|
74
82
|
redirectUrl: '',
|
|
75
83
|
redirectDelay: 0,
|
|
76
|
-
})
|
|
84
|
+
})
|
|
77
85
|
|
|
78
86
|
const [analytics, setAnalytics] = useState<AnalyticsConfig>({
|
|
79
87
|
enabled: false,
|
|
@@ -84,23 +92,23 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
84
92
|
conversionValue: 0,
|
|
85
93
|
conversionCurrency: 'USD',
|
|
86
94
|
customParameters: {},
|
|
87
|
-
})
|
|
95
|
+
})
|
|
88
96
|
|
|
89
97
|
useEffect(() => {
|
|
90
98
|
if (existingForm) {
|
|
91
|
-
const d = existingForm.data ?? existingForm
|
|
92
|
-
setName(d.name ?? '')
|
|
93
|
-
setDescription(d.description ?? '')
|
|
94
|
-
setStatus(d.status ?? 'active')
|
|
95
|
-
if (Array.isArray(d.fields)) setFields(d.fields)
|
|
99
|
+
const d = existingForm.data ?? existingForm
|
|
100
|
+
setName(d.name ?? '')
|
|
101
|
+
setDescription(d.description ?? '')
|
|
102
|
+
setStatus(d.status ?? 'active')
|
|
103
|
+
if (Array.isArray(d.fields)) setFields(d.fields)
|
|
96
104
|
if (d.confirmation) {
|
|
97
|
-
setConfirmation((prev) => ({ ...prev, ...d.confirmation }))
|
|
105
|
+
setConfirmation((prev) => ({ ...prev, ...d.confirmation }))
|
|
98
106
|
}
|
|
99
107
|
if (d.analytics) {
|
|
100
|
-
setAnalytics((prev) => ({ ...prev, ...d.analytics }))
|
|
108
|
+
setAnalytics((prev) => ({ ...prev, ...d.analytics }))
|
|
101
109
|
}
|
|
102
110
|
}
|
|
103
|
-
}, [existingForm])
|
|
111
|
+
}, [existingForm])
|
|
104
112
|
|
|
105
113
|
const addField = useCallback((type: string) => {
|
|
106
114
|
setFields((prev) => [
|
|
@@ -111,28 +119,28 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
111
119
|
label: `New ${type} field`,
|
|
112
120
|
required: false,
|
|
113
121
|
},
|
|
114
|
-
])
|
|
115
|
-
}, [])
|
|
122
|
+
])
|
|
123
|
+
}, [])
|
|
116
124
|
|
|
117
125
|
const removeField = useCallback((id: string) => {
|
|
118
|
-
setFields((prev) => prev.filter((f) => f.id !== id))
|
|
119
|
-
}, [])
|
|
126
|
+
setFields((prev) => prev.filter((f) => f.id !== id))
|
|
127
|
+
}, [])
|
|
120
128
|
|
|
121
129
|
const updateField = useCallback((id: string, updates: Partial<FormField>) => {
|
|
122
|
-
setFields((prev) => prev.map((f) => (f.id === id ? { ...f, ...updates } : f)))
|
|
123
|
-
}, [])
|
|
130
|
+
setFields((prev) => prev.map((f) => (f.id === id ? { ...f, ...updates } : f)))
|
|
131
|
+
}, [])
|
|
124
132
|
|
|
125
133
|
const moveField = useCallback((from: number, to: number) => {
|
|
126
134
|
setFields((prev) => {
|
|
127
|
-
const next = [...prev]
|
|
128
|
-
const [moved] = next.splice(from, 1)
|
|
129
|
-
next.splice(to, 0, moved!)
|
|
130
|
-
return next
|
|
131
|
-
})
|
|
132
|
-
}, [])
|
|
135
|
+
const next = [...prev]
|
|
136
|
+
const [moved] = next.splice(from, 1)
|
|
137
|
+
next.splice(to, 0, moved!)
|
|
138
|
+
return next
|
|
139
|
+
})
|
|
140
|
+
}, [])
|
|
133
141
|
|
|
134
142
|
const handleSave = async () => {
|
|
135
|
-
setSaving(true)
|
|
143
|
+
setSaving(true)
|
|
136
144
|
try {
|
|
137
145
|
const payload = {
|
|
138
146
|
name,
|
|
@@ -141,35 +149,35 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
141
149
|
fields,
|
|
142
150
|
confirmation,
|
|
143
151
|
analytics: analytics.enabled ? analytics : { enabled: false },
|
|
144
|
-
}
|
|
152
|
+
}
|
|
145
153
|
|
|
146
154
|
if (isNew) {
|
|
147
155
|
await cmsApi('/collections/forms', {
|
|
148
156
|
method: 'POST',
|
|
149
157
|
body: JSON.stringify(payload),
|
|
150
|
-
})
|
|
158
|
+
})
|
|
151
159
|
} else {
|
|
152
160
|
await cmsApi(`/collections/forms/${formId}`, {
|
|
153
161
|
method: 'PUT',
|
|
154
162
|
body: JSON.stringify(payload),
|
|
155
|
-
})
|
|
163
|
+
})
|
|
156
164
|
}
|
|
157
|
-
onNavigate?.('/forms')
|
|
165
|
+
onNavigate?.('/forms')
|
|
158
166
|
} finally {
|
|
159
|
-
setSaving(false)
|
|
167
|
+
setSaving(false)
|
|
160
168
|
}
|
|
161
|
-
}
|
|
169
|
+
}
|
|
162
170
|
|
|
163
171
|
const toggleSection = (section: string) => {
|
|
164
|
-
setExpandedSection(expandedSection === section ? null : section)
|
|
165
|
-
}
|
|
172
|
+
setExpandedSection(expandedSection === section ? null : section)
|
|
173
|
+
}
|
|
166
174
|
|
|
167
175
|
if (loading) {
|
|
168
176
|
return (
|
|
169
177
|
<div className="p-4 flex items-center justify-center h-64">
|
|
170
178
|
<Loader2 className="w-6 h-6 animate-spin text-blue-600" />
|
|
171
179
|
</div>
|
|
172
|
-
)
|
|
180
|
+
)
|
|
173
181
|
}
|
|
174
182
|
|
|
175
183
|
return (
|
|
@@ -241,7 +249,11 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
241
249
|
className="w-full flex items-center justify-between p-4 hover:bg-gray-50 transition-colors"
|
|
242
250
|
>
|
|
243
251
|
<div className="flex items-center gap-2">
|
|
244
|
-
{expandedSection === 'fields' ?
|
|
252
|
+
{expandedSection === 'fields' ? (
|
|
253
|
+
<ChevronDown className="w-4 h-4" />
|
|
254
|
+
) : (
|
|
255
|
+
<ChevronRight className="w-4 h-4" />
|
|
256
|
+
)}
|
|
245
257
|
<span className="font-medium text-gray-900">Form Fields</span>
|
|
246
258
|
<span className="text-sm text-gray-500">({fields.length})</span>
|
|
247
259
|
</div>
|
|
@@ -273,8 +285,8 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
273
285
|
onDragStart={(e) => e.dataTransfer.setData('text/plain', String(index))}
|
|
274
286
|
onDragOver={(e) => e.preventDefault()}
|
|
275
287
|
onDrop={(e) => {
|
|
276
|
-
const from = Number(e.dataTransfer.getData('text/plain'))
|
|
277
|
-
moveField(from, index)
|
|
288
|
+
const from = Number(e.dataTransfer.getData('text/plain'))
|
|
289
|
+
moveField(from, index)
|
|
278
290
|
}}
|
|
279
291
|
className="flex items-center gap-3 p-3 border border-gray-200 rounded-lg bg-gray-50 hover:bg-white transition-colors"
|
|
280
292
|
>
|
|
@@ -318,7 +330,11 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
318
330
|
className="w-full flex items-center justify-between p-4 hover:bg-gray-50 transition-colors"
|
|
319
331
|
>
|
|
320
332
|
<div className="flex items-center gap-2">
|
|
321
|
-
{expandedSection === 'confirmation' ?
|
|
333
|
+
{expandedSection === 'confirmation' ? (
|
|
334
|
+
<ChevronDown className="w-4 h-4" />
|
|
335
|
+
) : (
|
|
336
|
+
<ChevronRight className="w-4 h-4" />
|
|
337
|
+
)}
|
|
322
338
|
<MessageSquare className="w-4 h-4 text-green-600" />
|
|
323
339
|
<span className="font-medium text-gray-900">Confirmation</span>
|
|
324
340
|
<span className="text-xs text-gray-500 bg-gray-100 px-2 py-0.5 rounded">
|
|
@@ -329,10 +345,16 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
329
345
|
{expandedSection === 'confirmation' && (
|
|
330
346
|
<div className="border-t border-gray-200 p-4">
|
|
331
347
|
<div className="mb-4">
|
|
332
|
-
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
348
|
+
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
349
|
+
After submission
|
|
350
|
+
</label>
|
|
333
351
|
<div className="flex gap-3">
|
|
334
|
-
<label
|
|
335
|
-
|
|
352
|
+
<label
|
|
353
|
+
className="flex items-center gap-2 px-4 py-2 border rounded-lg cursor-pointer transition-colors hover:bg-gray-50"
|
|
354
|
+
style={{
|
|
355
|
+
borderColor: confirmation.type === 'message' ? '#2563eb' : '#d1d5db',
|
|
356
|
+
backgroundColor: confirmation.type === 'message' ? '#eff6ff' : 'transparent',
|
|
357
|
+
}}
|
|
336
358
|
>
|
|
337
359
|
<input
|
|
338
360
|
type="radio"
|
|
@@ -345,8 +367,12 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
345
367
|
<MessageSquare className="w-4 h-4" />
|
|
346
368
|
<span className="text-sm">Show Message</span>
|
|
347
369
|
</label>
|
|
348
|
-
<label
|
|
349
|
-
|
|
370
|
+
<label
|
|
371
|
+
className="flex items-center gap-2 px-4 py-2 border rounded-lg cursor-pointer transition-colors hover:bg-gray-50"
|
|
372
|
+
style={{
|
|
373
|
+
borderColor: confirmation.type === 'redirect' ? '#2563eb' : '#d1d5db',
|
|
374
|
+
backgroundColor: confirmation.type === 'redirect' ? '#eff6ff' : 'transparent',
|
|
375
|
+
}}
|
|
350
376
|
>
|
|
351
377
|
<input
|
|
352
378
|
type="radio"
|
|
@@ -364,7 +390,9 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
364
390
|
|
|
365
391
|
{confirmation.type === 'message' ? (
|
|
366
392
|
<div>
|
|
367
|
-
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
393
|
+
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
394
|
+
Success Message
|
|
395
|
+
</label>
|
|
368
396
|
<textarea
|
|
369
397
|
value={confirmation.message}
|
|
370
398
|
onChange={(e) => setConfirmation((c) => ({ ...c, message: e.target.value }))}
|
|
@@ -376,21 +404,29 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
376
404
|
) : (
|
|
377
405
|
<div className="grid gap-3">
|
|
378
406
|
<div>
|
|
379
|
-
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
407
|
+
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
408
|
+
Redirect URL
|
|
409
|
+
</label>
|
|
380
410
|
<input
|
|
381
411
|
type="url"
|
|
382
412
|
value={confirmation.redirectUrl}
|
|
383
|
-
onChange={(e) =>
|
|
413
|
+
onChange={(e) =>
|
|
414
|
+
setConfirmation((c) => ({ ...c, redirectUrl: e.target.value }))
|
|
415
|
+
}
|
|
384
416
|
placeholder="https://example.com/thank-you"
|
|
385
417
|
className="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
386
418
|
/>
|
|
387
419
|
</div>
|
|
388
420
|
<div>
|
|
389
|
-
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
421
|
+
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
422
|
+
Redirect Delay (ms)
|
|
423
|
+
</label>
|
|
390
424
|
<input
|
|
391
425
|
type="number"
|
|
392
426
|
value={confirmation.redirectDelay}
|
|
393
|
-
onChange={(e) =>
|
|
427
|
+
onChange={(e) =>
|
|
428
|
+
setConfirmation((c) => ({ ...c, redirectDelay: Number(e.target.value) }))
|
|
429
|
+
}
|
|
394
430
|
min={0}
|
|
395
431
|
step={500}
|
|
396
432
|
className="w-32 px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
@@ -410,10 +446,16 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
410
446
|
className="w-full flex items-center justify-between p-4 hover:bg-gray-50 transition-colors"
|
|
411
447
|
>
|
|
412
448
|
<div className="flex items-center gap-2">
|
|
413
|
-
{expandedSection === 'analytics' ?
|
|
449
|
+
{expandedSection === 'analytics' ? (
|
|
450
|
+
<ChevronDown className="w-4 h-4" />
|
|
451
|
+
) : (
|
|
452
|
+
<ChevronRight className="w-4 h-4" />
|
|
453
|
+
)}
|
|
414
454
|
<BarChart3 className="w-4 h-4 text-purple-600" />
|
|
415
455
|
<span className="font-medium text-gray-900">GA4 Analytics</span>
|
|
416
|
-
<span
|
|
456
|
+
<span
|
|
457
|
+
className={`text-xs px-2 py-0.5 rounded ${analytics.enabled ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-500'}`}
|
|
458
|
+
>
|
|
417
459
|
{analytics.enabled ? 'Enabled' : 'Disabled'}
|
|
418
460
|
</span>
|
|
419
461
|
</div>
|
|
@@ -430,7 +472,9 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
430
472
|
/>
|
|
431
473
|
<div className="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-blue-600" />
|
|
432
474
|
</label>
|
|
433
|
-
<span className="text-sm font-medium text-gray-700">
|
|
475
|
+
<span className="text-sm font-medium text-gray-700">
|
|
476
|
+
Push events to Google Analytics 4
|
|
477
|
+
</span>
|
|
434
478
|
</div>
|
|
435
479
|
|
|
436
480
|
{analytics.enabled && (
|
|
@@ -447,25 +491,35 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
447
491
|
placeholder="G-XXXXXXXXXX"
|
|
448
492
|
className="w-64 px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
449
493
|
/>
|
|
450
|
-
<p className="text-xs text-gray-500 mt-1">
|
|
494
|
+
<p className="text-xs text-gray-500 mt-1">
|
|
495
|
+
Leave blank to use your site's default GA4 tag
|
|
496
|
+
</p>
|
|
451
497
|
</div>
|
|
452
498
|
|
|
453
499
|
<div className="grid grid-cols-2 gap-4">
|
|
454
500
|
<div>
|
|
455
|
-
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
501
|
+
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
502
|
+
Submit Event Name
|
|
503
|
+
</label>
|
|
456
504
|
<input
|
|
457
505
|
type="text"
|
|
458
506
|
value={analytics.submitEventName}
|
|
459
|
-
onChange={(e) =>
|
|
507
|
+
onChange={(e) =>
|
|
508
|
+
setAnalytics((a) => ({ ...a, submitEventName: e.target.value }))
|
|
509
|
+
}
|
|
460
510
|
className="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
461
511
|
/>
|
|
462
512
|
</div>
|
|
463
513
|
<div>
|
|
464
|
-
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
514
|
+
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
515
|
+
Start Event Name
|
|
516
|
+
</label>
|
|
465
517
|
<input
|
|
466
518
|
type="text"
|
|
467
519
|
value={analytics.startEventName}
|
|
468
|
-
onChange={(e) =>
|
|
520
|
+
onChange={(e) =>
|
|
521
|
+
setAnalytics((a) => ({ ...a, startEventName: e.target.value }))
|
|
522
|
+
}
|
|
469
523
|
className="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
470
524
|
/>
|
|
471
525
|
</div>
|
|
@@ -477,7 +531,9 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
477
531
|
type="checkbox"
|
|
478
532
|
id="trackConversion"
|
|
479
533
|
checked={analytics.trackAsConversion}
|
|
480
|
-
onChange={(e) =>
|
|
534
|
+
onChange={(e) =>
|
|
535
|
+
setAnalytics((a) => ({ ...a, trackAsConversion: e.target.checked }))
|
|
536
|
+
}
|
|
481
537
|
className="rounded"
|
|
482
538
|
/>
|
|
483
539
|
<label htmlFor="trackConversion" className="text-sm font-medium text-gray-700">
|
|
@@ -488,21 +544,29 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
488
544
|
{analytics.trackAsConversion && (
|
|
489
545
|
<div className="grid grid-cols-2 gap-4 ml-6">
|
|
490
546
|
<div>
|
|
491
|
-
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
547
|
+
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
548
|
+
Conversion Value
|
|
549
|
+
</label>
|
|
492
550
|
<input
|
|
493
551
|
type="number"
|
|
494
552
|
value={analytics.conversionValue}
|
|
495
|
-
onChange={(e) =>
|
|
553
|
+
onChange={(e) =>
|
|
554
|
+
setAnalytics((a) => ({ ...a, conversionValue: Number(e.target.value) }))
|
|
555
|
+
}
|
|
496
556
|
min={0}
|
|
497
557
|
step={0.01}
|
|
498
558
|
className="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
499
559
|
/>
|
|
500
560
|
</div>
|
|
501
561
|
<div>
|
|
502
|
-
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
562
|
+
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
563
|
+
Currency
|
|
564
|
+
</label>
|
|
503
565
|
<select
|
|
504
566
|
value={analytics.conversionCurrency}
|
|
505
|
-
onChange={(e) =>
|
|
567
|
+
onChange={(e) =>
|
|
568
|
+
setAnalytics((a) => ({ ...a, conversionCurrency: e.target.value }))
|
|
569
|
+
}
|
|
506
570
|
className="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
507
571
|
>
|
|
508
572
|
<option value="USD">USD</option>
|
|
@@ -518,9 +582,11 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
518
582
|
|
|
519
583
|
<div className="bg-blue-50 border border-blue-200 rounded-lg p-3">
|
|
520
584
|
<p className="text-xs text-blue-800">
|
|
521
|
-
<strong>Note:</strong> Your site must have the GA4 snippet or GTM container
|
|
522
|
-
Actuate pushes events via
|
|
523
|
-
<code className="bg-blue-100 px-1 rounded">
|
|
585
|
+
<strong>Note:</strong> Your site must have the GA4 snippet or GTM container
|
|
586
|
+
installed. Actuate pushes events via{' '}
|
|
587
|
+
<code className="bg-blue-100 px-1 rounded">gtag()</code> /
|
|
588
|
+
<code className="bg-blue-100 px-1 rounded">dataLayer</code> — it does not load
|
|
589
|
+
the GA4 script.
|
|
524
590
|
</p>
|
|
525
591
|
</div>
|
|
526
592
|
</div>
|
|
@@ -529,5 +595,5 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
529
595
|
)}
|
|
530
596
|
</div>
|
|
531
597
|
</div>
|
|
532
|
-
)
|
|
598
|
+
)
|
|
533
599
|
}
|