@jhits/plugin-blog 0.0.8 → 0.0.9
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/api/categories.d.ts +8 -0
- package/dist/api/categories.d.ts.map +1 -0
- package/dist/api/categories.js +30 -0
- package/dist/api/check-title.d.ts +8 -0
- package/dist/api/check-title.d.ts.map +1 -0
- package/dist/api/check-title.js +47 -0
- package/dist/api/config-handler.d.ts +21 -0
- package/dist/api/config-handler.d.ts.map +1 -0
- package/dist/api/config-handler.js +46 -0
- package/dist/api/handler.d.ts +42 -0
- package/dist/api/handler.d.ts.map +1 -0
- package/dist/api/handler.js +331 -0
- package/dist/api/index.d.ts +12 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +12 -0
- package/dist/api/route.d.ts +50 -0
- package/dist/api/route.d.ts.map +1 -0
- package/dist/api/route.js +69 -0
- package/dist/api/router.d.ts +27 -0
- package/dist/api/router.d.ts.map +1 -0
- package/dist/api/router.js +98 -0
- package/dist/api-server.d.ts +9 -0
- package/dist/api-server.d.ts.map +1 -0
- package/dist/api-server.js +9 -0
- package/dist/config.d.ts +14 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +156 -0
- package/dist/hooks/index.d.ts +8 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +7 -0
- package/dist/hooks/useBlog.d.ts +31 -0
- package/dist/hooks/useBlog.d.ts.map +1 -0
- package/dist/hooks/useBlog.js +57 -0
- package/dist/hooks/useBlogs.d.ts +39 -0
- package/dist/hooks/useBlogs.d.ts.map +1 -0
- package/dist/hooks/useBlogs.js +82 -0
- package/dist/hooks/useCategories.d.ts +9 -0
- package/dist/hooks/useCategories.d.ts.map +1 -0
- package/dist/hooks/useCategories.js +70 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +228 -0
- package/dist/index.server.d.ts +12 -0
- package/dist/index.server.d.ts.map +1 -0
- package/dist/index.server.js +10 -0
- package/dist/init.d.ts +40 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +41 -0
- package/dist/lib/blocks/BlockRenderer.d.ts +54 -0
- package/dist/lib/blocks/BlockRenderer.d.ts.map +1 -0
- package/dist/lib/blocks/BlockRenderer.js +54 -0
- package/dist/lib/blocks/index.d.ts +5 -0
- package/dist/lib/blocks/index.d.ts.map +1 -0
- package/dist/lib/blocks/index.js +4 -0
- package/dist/lib/config-storage.d.ts +30 -0
- package/dist/lib/config-storage.d.ts.map +1 -0
- package/dist/lib/config-storage.js +31 -0
- package/dist/lib/index.d.ts +8 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +7 -0
- package/dist/lib/layouts/blocks/ColumnsBlock.d.ts +25 -0
- package/dist/lib/layouts/blocks/ColumnsBlock.d.ts.map +1 -0
- package/dist/lib/layouts/blocks/ColumnsBlock.js +186 -0
- package/dist/lib/layouts/blocks/SectionBlock.d.ts +25 -0
- package/dist/lib/layouts/blocks/SectionBlock.d.ts.map +1 -0
- package/dist/lib/layouts/blocks/SectionBlock.js +44 -0
- package/dist/lib/layouts/blocks/index.d.ts +7 -0
- package/dist/lib/layouts/blocks/index.d.ts.map +1 -0
- package/dist/lib/layouts/blocks/index.js +6 -0
- package/dist/lib/layouts/index.d.ts +23 -0
- package/dist/lib/layouts/index.d.ts.map +1 -0
- package/dist/lib/layouts/index.js +45 -0
- package/dist/lib/layouts/registerLayoutBlocks.d.ts +9 -0
- package/dist/lib/layouts/registerLayoutBlocks.d.ts.map +1 -0
- package/dist/lib/layouts/registerLayoutBlocks.js +60 -0
- package/dist/lib/mappers/apiMapper.d.ts +66 -0
- package/dist/lib/mappers/apiMapper.d.ts.map +1 -0
- package/dist/lib/mappers/apiMapper.js +188 -0
- package/dist/lib/migration/index.d.ts +5 -0
- package/dist/lib/migration/index.d.ts.map +1 -0
- package/dist/lib/migration/index.js +4 -0
- package/dist/lib/migration/mapper.d.ts +37 -0
- package/dist/lib/migration/mapper.d.ts.map +1 -0
- package/dist/lib/migration/mapper.js +98 -0
- package/dist/lib/rich-text/RichTextEditor.d.ts +45 -0
- package/dist/lib/rich-text/RichTextEditor.d.ts.map +1 -0
- package/dist/lib/rich-text/RichTextEditor.js +556 -0
- package/dist/lib/rich-text/RichTextPreview.d.ts +16 -0
- package/dist/lib/rich-text/RichTextPreview.d.ts.map +1 -0
- package/dist/lib/rich-text/RichTextPreview.js +144 -0
- package/dist/lib/rich-text/index.d.ts +9 -0
- package/dist/lib/rich-text/index.d.ts.map +1 -0
- package/dist/lib/rich-text/index.js +6 -0
- package/dist/lib/utils/blockHelpers.d.ts +23 -0
- package/dist/lib/utils/blockHelpers.d.ts.map +1 -0
- package/dist/lib/utils/blockHelpers.js +65 -0
- package/dist/lib/utils/configValidation.d.ts +23 -0
- package/dist/lib/utils/configValidation.d.ts.map +1 -0
- package/dist/lib/utils/configValidation.js +111 -0
- package/dist/lib/utils/index.d.ts +7 -0
- package/dist/lib/utils/index.d.ts.map +1 -0
- package/dist/lib/utils/index.js +6 -0
- package/dist/lib/utils/slugify.d.ts +25 -0
- package/dist/lib/utils/slugify.d.ts.map +1 -0
- package/dist/lib/utils/slugify.js +65 -0
- package/dist/registry/BlockRegistry.d.ts +62 -0
- package/dist/registry/BlockRegistry.d.ts.map +1 -0
- package/dist/registry/BlockRegistry.js +112 -0
- package/dist/registry/index.d.ts +6 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +4 -0
- package/dist/state/EditorContext.d.ts +45 -0
- package/dist/state/EditorContext.d.ts.map +1 -0
- package/dist/state/EditorContext.js +215 -0
- package/dist/state/index.d.ts +7 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +6 -0
- package/dist/state/reducer.d.ts +11 -0
- package/dist/state/reducer.d.ts.map +1 -0
- package/dist/state/reducer.js +599 -0
- package/dist/state/types.d.ts +162 -0
- package/dist/state/types.d.ts.map +1 -0
- package/dist/state/types.js +27 -0
- package/dist/types/block.d.ts +221 -0
- package/dist/types/block.d.ts.map +1 -0
- package/dist/types/block.js +6 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/post.d.ts +136 -0
- package/dist/types/post.d.ts.map +1 -0
- package/dist/types/post.js +5 -0
- package/dist/utils/client.d.ts +48 -0
- package/dist/utils/client.d.ts.map +1 -0
- package/dist/utils/client.js +77 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/views/CanvasEditor/BlockWrapper.d.ts +16 -0
- package/dist/views/CanvasEditor/BlockWrapper.d.ts.map +1 -0
- package/dist/views/CanvasEditor/BlockWrapper.js +285 -0
- package/dist/views/CanvasEditor/CanvasEditorView.d.ts +14 -0
- package/dist/views/CanvasEditor/CanvasEditorView.d.ts.map +1 -0
- package/dist/views/CanvasEditor/CanvasEditorView.js +215 -0
- package/dist/views/CanvasEditor/EditorBody.d.ts +22 -0
- package/dist/views/CanvasEditor/EditorBody.d.ts.map +1 -0
- package/dist/views/CanvasEditor/EditorBody.js +505 -0
- package/dist/views/CanvasEditor/EditorHeader.d.ts +18 -0
- package/dist/views/CanvasEditor/EditorHeader.d.ts.map +1 -0
- package/dist/views/CanvasEditor/EditorHeader.js +101 -0
- package/dist/views/CanvasEditor/LayoutContainer.d.ts +17 -0
- package/dist/views/CanvasEditor/LayoutContainer.d.ts.map +1 -0
- package/dist/views/CanvasEditor/LayoutContainer.js +222 -0
- package/dist/views/CanvasEditor/SaveConfirmationModal.d.ts +13 -0
- package/dist/views/CanvasEditor/SaveConfirmationModal.d.ts.map +1 -0
- package/dist/views/CanvasEditor/SaveConfirmationModal.js +78 -0
- package/dist/views/CanvasEditor/components/CustomBlockItem.d.ts +14 -0
- package/dist/views/CanvasEditor/components/CustomBlockItem.d.ts.map +1 -0
- package/dist/views/CanvasEditor/components/CustomBlockItem.js +44 -0
- package/dist/views/CanvasEditor/components/EditorCanvas.d.ts +29 -0
- package/dist/views/CanvasEditor/components/EditorCanvas.d.ts.map +1 -0
- package/dist/views/CanvasEditor/components/EditorCanvas.js +32 -0
- package/dist/views/CanvasEditor/components/EditorLibrary.d.ts +7 -0
- package/dist/views/CanvasEditor/components/EditorLibrary.d.ts.map +1 -0
- package/dist/views/CanvasEditor/components/EditorLibrary.js +25 -0
- package/dist/views/CanvasEditor/components/EditorSidebar.d.ts +13 -0
- package/dist/views/CanvasEditor/components/EditorSidebar.d.ts.map +1 -0
- package/dist/views/CanvasEditor/components/EditorSidebar.js +19 -0
- package/dist/views/CanvasEditor/components/ErrorBanner.d.ts +6 -0
- package/dist/views/CanvasEditor/components/ErrorBanner.d.ts.map +1 -0
- package/dist/views/CanvasEditor/components/ErrorBanner.js +8 -0
- package/dist/views/CanvasEditor/components/FeaturedMediaSection.d.ts +25 -0
- package/dist/views/CanvasEditor/components/FeaturedMediaSection.d.ts.map +1 -0
- package/dist/views/CanvasEditor/components/FeaturedMediaSection.js +199 -0
- package/dist/views/CanvasEditor/components/LibraryItem.d.ts +14 -0
- package/dist/views/CanvasEditor/components/LibraryItem.d.ts.map +1 -0
- package/dist/views/CanvasEditor/components/LibraryItem.js +43 -0
- package/dist/views/CanvasEditor/components/PrivacySettingsSection.d.ts +15 -0
- package/dist/views/CanvasEditor/components/PrivacySettingsSection.d.ts.map +1 -0
- package/dist/views/CanvasEditor/components/PrivacySettingsSection.js +70 -0
- package/dist/views/CanvasEditor/components/index.d.ts +21 -0
- package/dist/views/CanvasEditor/components/index.d.ts.map +1 -0
- package/dist/views/CanvasEditor/components/index.js +12 -0
- package/dist/views/CanvasEditor/hooks/index.d.ts +10 -0
- package/dist/views/CanvasEditor/hooks/index.d.ts.map +1 -0
- package/dist/views/CanvasEditor/hooks/index.js +9 -0
- package/dist/views/CanvasEditor/hooks/useHeroBlock.d.ts +8 -0
- package/dist/views/CanvasEditor/hooks/useHeroBlock.d.ts.map +1 -0
- package/dist/views/CanvasEditor/hooks/useHeroBlock.js +90 -0
- package/dist/views/CanvasEditor/hooks/useKeyboardShortcuts.d.ts +3 -0
- package/dist/views/CanvasEditor/hooks/useKeyboardShortcuts.d.ts.map +1 -0
- package/dist/views/CanvasEditor/hooks/useKeyboardShortcuts.js +119 -0
- package/dist/views/CanvasEditor/hooks/usePostLoader.d.ts +5 -0
- package/dist/views/CanvasEditor/hooks/usePostLoader.d.ts.map +1 -0
- package/dist/views/CanvasEditor/hooks/usePostLoader.js +32 -0
- package/dist/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts +2 -0
- package/dist/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts.map +1 -0
- package/dist/views/CanvasEditor/hooks/useRegisteredBlocks.js +47 -0
- package/dist/views/CanvasEditor/hooks/useUnsavedChanges.d.ts +25 -0
- package/dist/views/CanvasEditor/hooks/useUnsavedChanges.d.ts.map +1 -0
- package/dist/views/CanvasEditor/hooks/useUnsavedChanges.js +285 -0
- package/dist/views/CanvasEditor/index.d.ts +16 -0
- package/dist/views/CanvasEditor/index.d.ts.map +1 -0
- package/dist/views/CanvasEditor/index.js +9 -0
- package/dist/views/PostManager/EmptyState.d.ts +10 -0
- package/dist/views/PostManager/EmptyState.d.ts.map +1 -0
- package/dist/views/PostManager/EmptyState.js +12 -0
- package/dist/views/PostManager/PostActionsMenu.d.ts +12 -0
- package/dist/views/PostManager/PostActionsMenu.d.ts.map +1 -0
- package/dist/views/PostManager/PostActionsMenu.js +58 -0
- package/dist/views/PostManager/PostCards.d.ts +15 -0
- package/dist/views/PostManager/PostCards.d.ts.map +1 -0
- package/dist/views/PostManager/PostCards.js +77 -0
- package/dist/views/PostManager/PostFilters.d.ts +16 -0
- package/dist/views/PostManager/PostFilters.d.ts.map +1 -0
- package/dist/views/PostManager/PostFilters.js +10 -0
- package/dist/views/PostManager/PostManagerView.d.ts +11 -0
- package/dist/views/PostManager/PostManagerView.d.ts.map +1 -0
- package/dist/views/PostManager/PostManagerView.js +179 -0
- package/dist/views/PostManager/PostStats.d.ts +11 -0
- package/dist/views/PostManager/PostStats.d.ts.map +1 -0
- package/dist/views/PostManager/PostStats.js +46 -0
- package/dist/views/PostManager/PostTable.d.ts +15 -0
- package/dist/views/PostManager/PostTable.d.ts.map +1 -0
- package/dist/views/PostManager/PostTable.js +77 -0
- package/dist/views/PostManager/index.d.ts +12 -0
- package/dist/views/PostManager/index.d.ts.map +1 -0
- package/dist/views/PostManager/index.js +11 -0
- package/dist/views/Preview/PreviewBridgeView.d.ts +12 -0
- package/dist/views/Preview/PreviewBridgeView.d.ts.map +1 -0
- package/dist/views/Preview/PreviewBridgeView.js +11 -0
- package/dist/views/Preview/index.d.ts +6 -0
- package/dist/views/Preview/index.d.ts.map +1 -0
- package/dist/views/Preview/index.js +4 -0
- package/dist/views/Settings/SettingsView.d.ts +10 -0
- package/dist/views/Settings/SettingsView.d.ts.map +1 -0
- package/dist/views/Settings/SettingsView.js +113 -0
- package/dist/views/Settings/index.d.ts +6 -0
- package/dist/views/Settings/index.d.ts.map +1 -0
- package/dist/views/Settings/index.js +4 -0
- package/dist/views/SlugSEO/SlugSEOManagerView.d.ts +12 -0
- package/dist/views/SlugSEO/SlugSEOManagerView.d.ts.map +1 -0
- package/dist/views/SlugSEO/SlugSEOManagerView.js +11 -0
- package/dist/views/SlugSEO/index.d.ts +6 -0
- package/dist/views/SlugSEO/index.d.ts.map +1 -0
- package/dist/views/SlugSEO/index.js +4 -0
- package/package.json +59 -59
- package/src/hooks/index.d.ts +8 -0
- package/src/hooks/index.d.ts.map +1 -0
- package/src/hooks/index.js +7 -0
- package/src/hooks/useBlog.d.ts +31 -0
- package/src/hooks/useBlog.d.ts.map +1 -0
- package/src/hooks/useBlog.js +57 -0
- package/src/hooks/useBlogs.d.ts +39 -0
- package/src/hooks/useBlogs.d.ts.map +1 -0
- package/src/hooks/useBlogs.js +82 -0
- package/src/hooks/useCategories.d.ts +9 -0
- package/src/hooks/useCategories.d.ts.map +1 -0
- package/src/hooks/useCategories.js +70 -0
- package/src/index.d.ts +55 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +228 -0
- package/src/init.d.ts +40 -0
- package/src/init.d.ts.map +1 -0
- package/src/init.js +41 -0
- package/src/lib/blocks/BlockRenderer.d.ts +54 -0
- package/src/lib/blocks/BlockRenderer.d.ts.map +1 -0
- package/src/lib/blocks/BlockRenderer.js +54 -0
- package/src/lib/config-storage.d.ts +30 -0
- package/src/lib/config-storage.d.ts.map +1 -0
- package/src/lib/config-storage.js +31 -0
- package/src/lib/layouts/blocks/ColumnsBlock.d.ts +25 -0
- package/src/lib/layouts/blocks/ColumnsBlock.d.ts.map +1 -0
- package/src/lib/layouts/blocks/ColumnsBlock.js +182 -0
- package/src/lib/layouts/blocks/SectionBlock.d.ts +25 -0
- package/src/lib/layouts/blocks/SectionBlock.d.ts.map +1 -0
- package/src/lib/layouts/blocks/SectionBlock.js +44 -0
- package/src/lib/layouts/index.d.ts +23 -0
- package/src/lib/layouts/index.d.ts.map +1 -0
- package/src/lib/layouts/index.js +45 -0
- package/src/lib/layouts/registerLayoutBlocks.d.ts +9 -0
- package/src/lib/layouts/registerLayoutBlocks.d.ts.map +1 -0
- package/src/lib/layouts/registerLayoutBlocks.js +60 -0
- package/src/lib/mappers/apiMapper.d.ts +66 -0
- package/src/lib/mappers/apiMapper.d.ts.map +1 -0
- package/src/lib/mappers/apiMapper.js +191 -0
- package/src/lib/rich-text/RichTextEditor.d.ts +45 -0
- package/src/lib/rich-text/RichTextEditor.d.ts.map +1 -0
- package/src/lib/rich-text/RichTextEditor.js +564 -0
- package/src/lib/rich-text/RichTextPreview.d.ts +16 -0
- package/src/lib/rich-text/RichTextPreview.d.ts.map +1 -0
- package/src/lib/rich-text/RichTextPreview.js +144 -0
- package/src/lib/rich-text/index.d.ts +9 -0
- package/src/lib/rich-text/index.d.ts.map +1 -0
- package/src/lib/rich-text/index.js +6 -0
- package/src/lib/utils/blockHelpers.d.ts +23 -0
- package/src/lib/utils/blockHelpers.d.ts.map +1 -0
- package/src/lib/utils/blockHelpers.js +65 -0
- package/src/lib/utils/configValidation.d.ts +23 -0
- package/src/lib/utils/configValidation.d.ts.map +1 -0
- package/src/lib/utils/configValidation.js +113 -0
- package/src/registry/BlockRegistry.d.ts +62 -0
- package/src/registry/BlockRegistry.d.ts.map +1 -0
- package/src/registry/BlockRegistry.js +112 -0
- package/src/registry/index.d.ts +6 -0
- package/src/registry/index.d.ts.map +1 -0
- package/src/registry/index.js +4 -0
- package/src/state/EditorContext.d.ts +45 -0
- package/src/state/EditorContext.d.ts.map +1 -0
- package/src/state/EditorContext.js +215 -0
- package/src/state/index.d.ts +7 -0
- package/src/state/index.d.ts.map +1 -0
- package/src/state/index.js +6 -0
- package/src/state/reducer.d.ts +11 -0
- package/src/state/reducer.d.ts.map +1 -0
- package/src/state/reducer.js +443 -0
- package/src/state/types.d.ts +162 -0
- package/src/state/types.d.ts.map +1 -0
- package/src/state/types.js +27 -0
- package/src/types/block.d.ts +221 -0
- package/src/types/block.d.ts.map +1 -0
- package/src/types/block.js +6 -0
- package/src/types/index.d.ts +8 -0
- package/src/types/index.d.ts.map +1 -0
- package/src/types/index.js +5 -0
- package/src/types/post.d.ts +136 -0
- package/src/types/post.d.ts.map +1 -0
- package/src/types/post.js +5 -0
- package/src/utils/client.d.ts +48 -0
- package/src/utils/client.d.ts.map +1 -0
- package/src/utils/client.js +77 -0
- package/src/views/CanvasEditor/BlockWrapper.d.ts +16 -0
- package/src/views/CanvasEditor/BlockWrapper.d.ts.map +1 -0
- package/src/views/CanvasEditor/BlockWrapper.js +276 -0
- package/src/views/CanvasEditor/CanvasEditorView.d.ts +14 -0
- package/src/views/CanvasEditor/CanvasEditorView.d.ts.map +1 -0
- package/src/views/CanvasEditor/CanvasEditorView.js +209 -0
- package/src/views/CanvasEditor/EditorBody.d.ts +22 -0
- package/src/views/CanvasEditor/EditorBody.d.ts.map +1 -0
- package/src/views/CanvasEditor/EditorBody.js +505 -0
- package/src/views/CanvasEditor/EditorHeader.d.ts +18 -0
- package/src/views/CanvasEditor/EditorHeader.d.ts.map +1 -0
- package/src/views/CanvasEditor/EditorHeader.js +101 -0
- package/src/views/CanvasEditor/LayoutContainer.d.ts +17 -0
- package/src/views/CanvasEditor/LayoutContainer.d.ts.map +1 -0
- package/src/views/CanvasEditor/LayoutContainer.js +222 -0
- package/src/views/CanvasEditor/SaveConfirmationModal.d.ts +13 -0
- package/src/views/CanvasEditor/SaveConfirmationModal.d.ts.map +1 -0
- package/src/views/CanvasEditor/SaveConfirmationModal.js +78 -0
- package/src/views/CanvasEditor/components/CustomBlockItem.d.ts +14 -0
- package/src/views/CanvasEditor/components/CustomBlockItem.d.ts.map +1 -0
- package/src/views/CanvasEditor/components/CustomBlockItem.js +44 -0
- package/src/views/CanvasEditor/components/EditorCanvas.d.ts +29 -0
- package/src/views/CanvasEditor/components/EditorCanvas.d.ts.map +1 -0
- package/src/views/CanvasEditor/components/EditorCanvas.js +32 -0
- package/src/views/CanvasEditor/components/EditorLibrary.d.ts +7 -0
- package/src/views/CanvasEditor/components/EditorLibrary.d.ts.map +1 -0
- package/src/views/CanvasEditor/components/EditorLibrary.js +25 -0
- package/src/views/CanvasEditor/components/EditorSidebar.d.ts +13 -0
- package/src/views/CanvasEditor/components/EditorSidebar.d.ts.map +1 -0
- package/src/views/CanvasEditor/components/EditorSidebar.js +20 -0
- package/src/views/CanvasEditor/components/ErrorBanner.d.ts +6 -0
- package/src/views/CanvasEditor/components/ErrorBanner.d.ts.map +1 -0
- package/src/views/CanvasEditor/components/ErrorBanner.js +8 -0
- package/src/views/CanvasEditor/components/FeaturedMediaSection.d.ts +25 -0
- package/src/views/CanvasEditor/components/FeaturedMediaSection.d.ts.map +1 -0
- package/src/views/CanvasEditor/components/FeaturedMediaSection.js +182 -0
- package/src/views/CanvasEditor/components/LibraryItem.d.ts +14 -0
- package/src/views/CanvasEditor/components/LibraryItem.d.ts.map +1 -0
- package/src/views/CanvasEditor/components/LibraryItem.js +43 -0
- package/src/views/CanvasEditor/components/PrivacySettingsSection.d.ts +15 -0
- package/src/views/CanvasEditor/components/PrivacySettingsSection.d.ts.map +1 -0
- package/src/views/CanvasEditor/components/PrivacySettingsSection.js +63 -0
- package/src/views/CanvasEditor/components/index.d.ts +21 -0
- package/src/views/CanvasEditor/components/index.d.ts.map +1 -0
- package/src/views/CanvasEditor/components/index.js +12 -0
- package/src/views/CanvasEditor/hooks/index.d.ts +10 -0
- package/src/views/CanvasEditor/hooks/index.d.ts.map +1 -0
- package/src/views/CanvasEditor/hooks/index.js +9 -0
- package/src/views/CanvasEditor/hooks/useHeroBlock.d.ts +8 -0
- package/src/views/CanvasEditor/hooks/useHeroBlock.d.ts.map +1 -0
- package/src/views/CanvasEditor/hooks/useHeroBlock.js +79 -0
- package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.d.ts +3 -0
- package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.d.ts.map +1 -0
- package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.js +114 -0
- package/src/views/CanvasEditor/hooks/usePostLoader.d.ts +5 -0
- package/src/views/CanvasEditor/hooks/usePostLoader.d.ts.map +1 -0
- package/src/views/CanvasEditor/hooks/usePostLoader.js +32 -0
- package/src/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts +2 -0
- package/src/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts.map +1 -0
- package/src/views/CanvasEditor/hooks/useRegisteredBlocks.js +47 -0
- package/src/views/CanvasEditor/hooks/useUnsavedChanges.d.ts +25 -0
- package/src/views/CanvasEditor/hooks/useUnsavedChanges.d.ts.map +1 -0
- package/src/views/CanvasEditor/hooks/useUnsavedChanges.js +285 -0
- package/src/views/CanvasEditor/index.d.ts +16 -0
- package/src/views/CanvasEditor/index.d.ts.map +1 -0
- package/src/views/CanvasEditor/index.js +9 -0
- package/src/views/PostManager/EmptyState.d.ts +10 -0
- package/src/views/PostManager/EmptyState.d.ts.map +1 -0
- package/src/views/PostManager/EmptyState.js +12 -0
- package/src/views/PostManager/PostActionsMenu.d.ts +12 -0
- package/src/views/PostManager/PostActionsMenu.d.ts.map +1 -0
- package/src/views/PostManager/PostActionsMenu.js +58 -0
- package/src/views/PostManager/PostCards.d.ts +15 -0
- package/src/views/PostManager/PostCards.d.ts.map +1 -0
- package/src/views/PostManager/PostCards.js +79 -0
- package/src/views/PostManager/PostFilters.d.ts +16 -0
- package/src/views/PostManager/PostFilters.d.ts.map +1 -0
- package/src/views/PostManager/PostFilters.js +10 -0
- package/src/views/PostManager/PostManagerView.d.ts +11 -0
- package/src/views/PostManager/PostManagerView.d.ts.map +1 -0
- package/src/views/PostManager/PostManagerView.js +174 -0
- package/src/views/PostManager/PostStats.d.ts +11 -0
- package/src/views/PostManager/PostStats.d.ts.map +1 -0
- package/src/views/PostManager/PostStats.js +46 -0
- package/src/views/PostManager/PostTable.d.ts +15 -0
- package/src/views/PostManager/PostTable.d.ts.map +1 -0
- package/src/views/PostManager/PostTable.js +79 -0
- package/src/views/PostManager/index.d.ts +12 -0
- package/src/views/PostManager/index.d.ts.map +1 -0
- package/src/views/PostManager/index.js +11 -0
- package/src/views/Preview/PreviewBridgeView.d.ts +12 -0
- package/src/views/Preview/PreviewBridgeView.d.ts.map +1 -0
- package/src/views/Preview/PreviewBridgeView.js +11 -0
- package/src/views/Preview/index.d.ts +6 -0
- package/src/views/Preview/index.d.ts.map +1 -0
- package/src/views/Preview/index.js +4 -0
- package/src/views/Settings/SettingsView.d.ts +10 -0
- package/src/views/Settings/SettingsView.d.ts.map +1 -0
- package/src/views/Settings/SettingsView.js +111 -0
- package/src/views/Settings/index.d.ts +6 -0
- package/src/views/Settings/index.d.ts.map +1 -0
- package/src/views/Settings/index.js +4 -0
- package/src/views/SlugSEO/SlugSEOManagerView.d.ts +12 -0
- package/src/views/SlugSEO/SlugSEOManagerView.d.ts.map +1 -0
- package/src/views/SlugSEO/SlugSEOManagerView.js +11 -0
- package/src/views/SlugSEO/index.d.ts +6 -0
- package/src/views/SlugSEO/index.d.ts.map +1 -0
- package/src/views/SlugSEO/index.js +4 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePostLoader.d.ts","sourceRoot":"","sources":["usePostLoader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,wBAAgB,aAAa,CACzB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,QAAQ,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,EAClC,cAAc,EAAE,MAAM,IAAI;;EA8B7B"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { apiToBlogPost } from '../../../lib/mappers/apiMapper';
|
|
3
|
+
export function usePostLoader(postId, currentPostId, loadPost, resetHeroBlock) {
|
|
4
|
+
const [isLoadingPost, setIsLoadingPost] = useState(false);
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
if (postId && !currentPostId) {
|
|
7
|
+
const loadPostData = async () => {
|
|
8
|
+
try {
|
|
9
|
+
setIsLoadingPost(true);
|
|
10
|
+
// Reset hero block before loading new post so it gets re-initialized from the new post's blocks
|
|
11
|
+
resetHeroBlock();
|
|
12
|
+
const response = await fetch(`/api/plugin-blog/${postId}`);
|
|
13
|
+
if (!response.ok) {
|
|
14
|
+
throw new Error('Failed to load post');
|
|
15
|
+
}
|
|
16
|
+
const apiDoc = await response.json();
|
|
17
|
+
const blogPost = apiToBlogPost(apiDoc);
|
|
18
|
+
loadPost(blogPost);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
console.error('Failed to load post:', error);
|
|
22
|
+
alert('Failed to load post. Please try again.');
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
setIsLoadingPost(false);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
loadPostData();
|
|
29
|
+
}
|
|
30
|
+
}, [postId, currentPostId, loadPost, resetHeroBlock]);
|
|
31
|
+
return { isLoadingPost };
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRegisteredBlocks.d.ts","sourceRoot":"","sources":["useRegisteredBlocks.ts"],"names":[],"mappings":"AAGA,wBAAgB,mBAAmB,6CAmDlC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { blockRegistry } from '../../../registry/BlockRegistry';
|
|
3
|
+
export function useRegisteredBlocks() {
|
|
4
|
+
const [registeredBlocks, setRegisteredBlocks] = useState(() => {
|
|
5
|
+
const initial = blockRegistry.getAll();
|
|
6
|
+
return initial;
|
|
7
|
+
});
|
|
8
|
+
// Watch for registry changes and update state
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
// Check immediately
|
|
11
|
+
const checkBlocks = () => {
|
|
12
|
+
const currentBlocks = blockRegistry.getAll();
|
|
13
|
+
const hasChanged = currentBlocks.length !== registeredBlocks.length ||
|
|
14
|
+
currentBlocks.some((b, i) => { var _a; return b.type !== ((_a = registeredBlocks[i]) === null || _a === void 0 ? void 0 : _a.type); }) ||
|
|
15
|
+
registeredBlocks.some((b, i) => { var _a; return b.type !== ((_a = currentBlocks[i]) === null || _a === void 0 ? void 0 : _a.type); });
|
|
16
|
+
if (hasChanged) {
|
|
17
|
+
setRegisteredBlocks([...currentBlocks]);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
// Initial check
|
|
21
|
+
checkBlocks();
|
|
22
|
+
// Poll for registry changes (blocks are registered asynchronously in useEffect)
|
|
23
|
+
// Use a shorter interval initially, then longer
|
|
24
|
+
let pollCount = 0;
|
|
25
|
+
const interval = setInterval(() => {
|
|
26
|
+
pollCount++;
|
|
27
|
+
checkBlocks();
|
|
28
|
+
// Stop polling after 5 seconds (25 checks at 200ms)
|
|
29
|
+
if (pollCount > 25) {
|
|
30
|
+
clearInterval(interval);
|
|
31
|
+
}
|
|
32
|
+
}, 200);
|
|
33
|
+
// Also check after delays to catch initial registrations
|
|
34
|
+
const timeouts = [
|
|
35
|
+
setTimeout(checkBlocks, 50),
|
|
36
|
+
setTimeout(checkBlocks, 100),
|
|
37
|
+
setTimeout(checkBlocks, 300),
|
|
38
|
+
setTimeout(checkBlocks, 500),
|
|
39
|
+
setTimeout(checkBlocks, 1000),
|
|
40
|
+
];
|
|
41
|
+
return () => {
|
|
42
|
+
clearInterval(interval);
|
|
43
|
+
timeouts.forEach(clearTimeout);
|
|
44
|
+
};
|
|
45
|
+
}, [registeredBlocks.length]);
|
|
46
|
+
return registeredBlocks;
|
|
47
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for managing unsaved changes warnings and auto-save
|
|
3
|
+
*/
|
|
4
|
+
import type { EditorState } from '../../../state/types';
|
|
5
|
+
import type { Block } from '../../../types/block';
|
|
6
|
+
interface UseUnsavedChangesOptions {
|
|
7
|
+
state: EditorState;
|
|
8
|
+
isDirty: boolean;
|
|
9
|
+
onSave: (heroBlock?: Block | null) => Promise<void>;
|
|
10
|
+
heroBlock?: Block | null;
|
|
11
|
+
autoSaveEnabled?: boolean;
|
|
12
|
+
autoSaveDelay?: number;
|
|
13
|
+
postId?: string | null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Hook to manage unsaved changes warnings and auto-save
|
|
17
|
+
*/
|
|
18
|
+
export declare function useUnsavedChanges({ state, isDirty, onSave, heroBlock, autoSaveEnabled: propAutoSaveEnabled, autoSaveDelay, postId, }: UseUnsavedChangesOptions): {
|
|
19
|
+
autoSaveEnabled: boolean;
|
|
20
|
+
setAutoSaveEnabled: (enabled: boolean) => void;
|
|
21
|
+
countdown: number | null;
|
|
22
|
+
saveStatus: "error" | "idle" | "saving" | "saved";
|
|
23
|
+
};
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=useUnsavedChanges.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useUnsavedChanges.d.ts","sourceRoot":"","sources":["useUnsavedChanges.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAElD,UAAU,wBAAwB;IAC9B,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,SAAS,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IACzB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAKD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAC9B,KAAK,EACL,OAAO,EACP,MAAM,EACN,SAAS,EACT,eAAe,EAAE,mBAAmB,EACpC,aAAuC,EACvC,MAAM,GACT,EAAE,wBAAwB;;kCAoD6B,OAAO;;;EA4P9D"}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for managing unsaved changes warnings and auto-save
|
|
3
|
+
*/
|
|
4
|
+
'use client';
|
|
5
|
+
import { useEffect, useRef, useCallback, useState } from 'react';
|
|
6
|
+
const AUTO_SAVE_STORAGE_KEY = 'blog-editor-autosave-enabled';
|
|
7
|
+
const DEFAULT_AUTO_SAVE_DELAY = 10000; // 10 seconds
|
|
8
|
+
/**
|
|
9
|
+
* Hook to manage unsaved changes warnings and auto-save
|
|
10
|
+
*/
|
|
11
|
+
export function useUnsavedChanges({ state, isDirty, onSave, heroBlock, autoSaveEnabled: propAutoSaveEnabled, autoSaveDelay = DEFAULT_AUTO_SAVE_DELAY, postId, }) {
|
|
12
|
+
const autoSaveTimeoutRef = useRef(null);
|
|
13
|
+
const isSavingRef = useRef(false);
|
|
14
|
+
const lastSavedStateRef = useRef('');
|
|
15
|
+
const countdownIntervalRef = useRef(null);
|
|
16
|
+
const [countdown, setCountdown] = useState(null);
|
|
17
|
+
const [saveStatus, setSaveStatus] = useState('idle');
|
|
18
|
+
const saveStatusTimeoutRef = useRef(null);
|
|
19
|
+
const previousIsDirtyRef = useRef(false);
|
|
20
|
+
const countdownStartTimeRef = useRef(null);
|
|
21
|
+
const performAutoSaveRef = useRef(null);
|
|
22
|
+
// Get auto-save preference from localStorage
|
|
23
|
+
const getAutoSavePreference = useCallback(() => {
|
|
24
|
+
if (typeof window === 'undefined')
|
|
25
|
+
return false;
|
|
26
|
+
try {
|
|
27
|
+
const stored = localStorage.getItem(AUTO_SAVE_STORAGE_KEY);
|
|
28
|
+
if (stored !== null) {
|
|
29
|
+
return stored === 'true';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
console.error('[useUnsavedChanges] Failed to read auto-save preference:', error);
|
|
34
|
+
}
|
|
35
|
+
// Default to false if not set
|
|
36
|
+
return false;
|
|
37
|
+
}, []);
|
|
38
|
+
// State to track auto-save enabled status (reactive)
|
|
39
|
+
const [autoSaveEnabledState, setAutoSaveEnabledState] = useState(() => {
|
|
40
|
+
// Initialize from prop or localStorage
|
|
41
|
+
if (propAutoSaveEnabled !== undefined) {
|
|
42
|
+
return propAutoSaveEnabled;
|
|
43
|
+
}
|
|
44
|
+
return getAutoSavePreference();
|
|
45
|
+
});
|
|
46
|
+
// Sync with prop changes
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (propAutoSaveEnabled !== undefined) {
|
|
49
|
+
setAutoSaveEnabledState(propAutoSaveEnabled);
|
|
50
|
+
}
|
|
51
|
+
}, [propAutoSaveEnabled]);
|
|
52
|
+
// Initialize from localStorage on mount (if no prop provided)
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (propAutoSaveEnabled === undefined && typeof window !== 'undefined') {
|
|
55
|
+
const stored = getAutoSavePreference();
|
|
56
|
+
setAutoSaveEnabledState(stored);
|
|
57
|
+
}
|
|
58
|
+
}, []); // Only run on mount
|
|
59
|
+
// Set auto-save preference in localStorage and state
|
|
60
|
+
const setAutoSavePreference = useCallback((enabled) => {
|
|
61
|
+
if (typeof window === 'undefined')
|
|
62
|
+
return;
|
|
63
|
+
try {
|
|
64
|
+
localStorage.setItem(AUTO_SAVE_STORAGE_KEY, enabled.toString());
|
|
65
|
+
setAutoSaveEnabledState(enabled);
|
|
66
|
+
console.log('[useUnsavedChanges] Auto-save preference updated:', enabled);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.error('[useUnsavedChanges] Failed to save auto-save preference:', error);
|
|
70
|
+
}
|
|
71
|
+
}, []);
|
|
72
|
+
// Determine if auto-save is enabled (prop takes precedence over state)
|
|
73
|
+
const autoSaveEnabled = propAutoSaveEnabled !== undefined
|
|
74
|
+
? propAutoSaveEnabled
|
|
75
|
+
: autoSaveEnabledState;
|
|
76
|
+
// Create a stable reference of the current state for comparison
|
|
77
|
+
const getStateSnapshot = useCallback(() => {
|
|
78
|
+
return JSON.stringify({
|
|
79
|
+
title: state.title,
|
|
80
|
+
slug: state.slug,
|
|
81
|
+
blocks: state.blocks,
|
|
82
|
+
seo: state.seo,
|
|
83
|
+
metadata: state.metadata,
|
|
84
|
+
status: state.status,
|
|
85
|
+
});
|
|
86
|
+
}, [state]);
|
|
87
|
+
// Initialize lastSavedStateRef when a post is loaded and marked as clean
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
// When a post is loaded (postId exists) and isDirty is false, update the saved state reference
|
|
90
|
+
if (postId && !isDirty && lastSavedStateRef.current === '') {
|
|
91
|
+
lastSavedStateRef.current = getStateSnapshot();
|
|
92
|
+
console.log('[useUnsavedChanges] Initialized saved state reference after post load');
|
|
93
|
+
}
|
|
94
|
+
// Also update if isDirty becomes false after being true (e.g., after save or MARK_CLEAN)
|
|
95
|
+
if (!isDirty && lastSavedStateRef.current !== getStateSnapshot()) {
|
|
96
|
+
lastSavedStateRef.current = getStateSnapshot();
|
|
97
|
+
}
|
|
98
|
+
}, [postId, isDirty, getStateSnapshot]);
|
|
99
|
+
// Auto-save function
|
|
100
|
+
const performAutoSave = useCallback(async () => {
|
|
101
|
+
if (isSavingRef.current || !isDirty) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
isSavingRef.current = true;
|
|
106
|
+
setSaveStatus('saving');
|
|
107
|
+
setCountdown(null);
|
|
108
|
+
countdownStartTimeRef.current = null;
|
|
109
|
+
console.log('[useUnsavedChanges] Auto-saving...');
|
|
110
|
+
await onSave(heroBlock);
|
|
111
|
+
lastSavedStateRef.current = getStateSnapshot();
|
|
112
|
+
setSaveStatus('saved');
|
|
113
|
+
console.log('[useUnsavedChanges] Auto-save completed');
|
|
114
|
+
// Clear save status after 2 seconds
|
|
115
|
+
if (saveStatusTimeoutRef.current) {
|
|
116
|
+
clearTimeout(saveStatusTimeoutRef.current);
|
|
117
|
+
}
|
|
118
|
+
saveStatusTimeoutRef.current = setTimeout(() => {
|
|
119
|
+
setSaveStatus('idle');
|
|
120
|
+
}, 2000);
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
console.error('[useUnsavedChanges] Auto-save failed:', error);
|
|
124
|
+
setSaveStatus('error');
|
|
125
|
+
// Clear error status after 3 seconds
|
|
126
|
+
if (saveStatusTimeoutRef.current) {
|
|
127
|
+
clearTimeout(saveStatusTimeoutRef.current);
|
|
128
|
+
}
|
|
129
|
+
saveStatusTimeoutRef.current = setTimeout(() => {
|
|
130
|
+
setSaveStatus('idle');
|
|
131
|
+
}, 3000);
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
isSavingRef.current = false;
|
|
135
|
+
}
|
|
136
|
+
}, [isDirty, onSave, heroBlock, getStateSnapshot]);
|
|
137
|
+
// Keep ref updated with latest function
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
performAutoSaveRef.current = performAutoSave;
|
|
140
|
+
}, [performAutoSave]);
|
|
141
|
+
// Set up auto-save timer and countdown when state changes
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
// Only reset countdown if isDirty changed from false to true, or if auto-save was just disabled
|
|
144
|
+
const isDirtyChanged = previousIsDirtyRef.current !== isDirty;
|
|
145
|
+
const becameDirty = !previousIsDirtyRef.current && isDirty;
|
|
146
|
+
// Update previous isDirty ref
|
|
147
|
+
previousIsDirtyRef.current = isDirty;
|
|
148
|
+
// Clear existing countdown interval
|
|
149
|
+
if (countdownIntervalRef.current) {
|
|
150
|
+
clearInterval(countdownIntervalRef.current);
|
|
151
|
+
countdownIntervalRef.current = null;
|
|
152
|
+
}
|
|
153
|
+
if (!autoSaveEnabled || !isDirty || isSavingRef.current) {
|
|
154
|
+
setCountdown(null);
|
|
155
|
+
countdownStartTimeRef.current = null;
|
|
156
|
+
// Clear timeout if auto-save is disabled or not dirty
|
|
157
|
+
if (autoSaveTimeoutRef.current) {
|
|
158
|
+
clearTimeout(autoSaveTimeoutRef.current);
|
|
159
|
+
autoSaveTimeoutRef.current = null;
|
|
160
|
+
}
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
// Only reset countdown if:
|
|
164
|
+
// 1. isDirty just became true (new changes)
|
|
165
|
+
// 2. Or if there's no active countdown
|
|
166
|
+
const shouldResetCountdown = becameDirty || countdownStartTimeRef.current === null;
|
|
167
|
+
if (shouldResetCountdown) {
|
|
168
|
+
// Clear existing timeout
|
|
169
|
+
if (autoSaveTimeoutRef.current) {
|
|
170
|
+
clearTimeout(autoSaveTimeoutRef.current);
|
|
171
|
+
}
|
|
172
|
+
// Initialize countdown
|
|
173
|
+
const secondsRemaining = Math.ceil(autoSaveDelay / 1000);
|
|
174
|
+
setCountdown(secondsRemaining);
|
|
175
|
+
countdownStartTimeRef.current = Date.now();
|
|
176
|
+
// Set new timeout for auto-save
|
|
177
|
+
autoSaveTimeoutRef.current = setTimeout(() => {
|
|
178
|
+
if (performAutoSaveRef.current) {
|
|
179
|
+
performAutoSaveRef.current();
|
|
180
|
+
}
|
|
181
|
+
}, autoSaveDelay);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
// Countdown is already running, just update it based on elapsed time
|
|
185
|
+
if (countdownStartTimeRef.current && autoSaveTimeoutRef.current) {
|
|
186
|
+
const elapsed = Date.now() - countdownStartTimeRef.current;
|
|
187
|
+
const remaining = Math.max(0, autoSaveDelay - elapsed);
|
|
188
|
+
const secondsRemaining = Math.ceil(remaining / 1000);
|
|
189
|
+
setCountdown(secondsRemaining);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Update countdown every second (only if we have an active countdown)
|
|
193
|
+
if (shouldResetCountdown || countdownIntervalRef.current === null) {
|
|
194
|
+
countdownIntervalRef.current = setInterval(() => {
|
|
195
|
+
if (countdownStartTimeRef.current && autoSaveTimeoutRef.current) {
|
|
196
|
+
const elapsed = Date.now() - countdownStartTimeRef.current;
|
|
197
|
+
const remaining = Math.max(0, autoSaveDelay - elapsed);
|
|
198
|
+
const secondsRemaining = Math.ceil(remaining / 1000);
|
|
199
|
+
if (secondsRemaining <= 0) {
|
|
200
|
+
setCountdown(null);
|
|
201
|
+
if (countdownIntervalRef.current) {
|
|
202
|
+
clearInterval(countdownIntervalRef.current);
|
|
203
|
+
countdownIntervalRef.current = null;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
setCountdown(secondsRemaining);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}, 1000);
|
|
211
|
+
}
|
|
212
|
+
return () => {
|
|
213
|
+
if (autoSaveTimeoutRef.current) {
|
|
214
|
+
clearTimeout(autoSaveTimeoutRef.current);
|
|
215
|
+
}
|
|
216
|
+
if (countdownIntervalRef.current) {
|
|
217
|
+
clearInterval(countdownIntervalRef.current);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
}, [autoSaveEnabled, isDirty, autoSaveDelay]);
|
|
221
|
+
// Handle browser beforeunload event (page refresh/close)
|
|
222
|
+
useEffect(() => {
|
|
223
|
+
if (!isDirty) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const handleBeforeUnload = (e) => {
|
|
227
|
+
e.preventDefault();
|
|
228
|
+
// Modern browsers ignore custom messages, but we still need to set returnValue
|
|
229
|
+
e.returnValue = '';
|
|
230
|
+
return '';
|
|
231
|
+
};
|
|
232
|
+
window.addEventListener('beforeunload', handleBeforeUnload);
|
|
233
|
+
return () => {
|
|
234
|
+
window.removeEventListener('beforeunload', handleBeforeUnload);
|
|
235
|
+
};
|
|
236
|
+
}, [isDirty]);
|
|
237
|
+
// Handle link clicks (for Next.js App Router)
|
|
238
|
+
useEffect(() => {
|
|
239
|
+
if (!isDirty) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const handleLinkClick = (e) => {
|
|
243
|
+
const target = e.target;
|
|
244
|
+
const link = target.closest('a');
|
|
245
|
+
if (link && link.href) {
|
|
246
|
+
const url = new URL(link.href);
|
|
247
|
+
const currentPath = window.location.pathname;
|
|
248
|
+
// Check if navigating away from editor
|
|
249
|
+
if (!url.pathname.includes('/blog/editor') && !url.pathname.includes('/blog/new')) {
|
|
250
|
+
const confirmed = window.confirm('You have unsaved changes. Are you sure you want to leave? Your changes will be lost.');
|
|
251
|
+
if (!confirmed) {
|
|
252
|
+
e.preventDefault();
|
|
253
|
+
e.stopPropagation();
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
// Listen for clicks on links
|
|
260
|
+
document.addEventListener('click', handleLinkClick, true);
|
|
261
|
+
return () => {
|
|
262
|
+
document.removeEventListener('click', handleLinkClick, true);
|
|
263
|
+
};
|
|
264
|
+
}, [isDirty]);
|
|
265
|
+
// Cleanup on unmount
|
|
266
|
+
useEffect(() => {
|
|
267
|
+
return () => {
|
|
268
|
+
if (autoSaveTimeoutRef.current) {
|
|
269
|
+
clearTimeout(autoSaveTimeoutRef.current);
|
|
270
|
+
}
|
|
271
|
+
if (countdownIntervalRef.current) {
|
|
272
|
+
clearInterval(countdownIntervalRef.current);
|
|
273
|
+
}
|
|
274
|
+
if (saveStatusTimeoutRef.current) {
|
|
275
|
+
clearTimeout(saveStatusTimeoutRef.current);
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
}, []);
|
|
279
|
+
return {
|
|
280
|
+
autoSaveEnabled,
|
|
281
|
+
setAutoSaveEnabled: setAutoSavePreference,
|
|
282
|
+
countdown,
|
|
283
|
+
saveStatus,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas Editor View Exports
|
|
3
|
+
*/
|
|
4
|
+
export { CanvasEditorView } from './CanvasEditorView';
|
|
5
|
+
export type { CanvasEditorViewProps } from './CanvasEditorView';
|
|
6
|
+
export { EditorBody } from './EditorBody';
|
|
7
|
+
export { LayoutContainer } from './LayoutContainer';
|
|
8
|
+
export type { LayoutContainerProps } from './LayoutContainer';
|
|
9
|
+
export type { EditorBodyProps } from './EditorBody';
|
|
10
|
+
export { BlockWrapper } from './BlockWrapper';
|
|
11
|
+
export type { BlockWrapperProps } from './BlockWrapper';
|
|
12
|
+
export { EditorHeader } from './EditorHeader';
|
|
13
|
+
export type { EditorHeaderProps } from './EditorHeader';
|
|
14
|
+
export { SaveConfirmationModal } from './SaveConfirmationModal';
|
|
15
|
+
export type { SaveConfirmationModalProps } from './SaveConfirmationModal';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,YAAY,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas Editor View Exports
|
|
3
|
+
*/
|
|
4
|
+
export { CanvasEditorView } from './CanvasEditorView';
|
|
5
|
+
export { EditorBody } from './EditorBody';
|
|
6
|
+
export { LayoutContainer } from './LayoutContainer';
|
|
7
|
+
export { BlockWrapper } from './BlockWrapper';
|
|
8
|
+
export { EditorHeader } from './EditorHeader';
|
|
9
|
+
export { SaveConfirmationModal } from './SaveConfirmationModal';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Empty State Component
|
|
3
|
+
* Botanical-themed empty state for when no posts are found
|
|
4
|
+
*/
|
|
5
|
+
export interface EmptyStateProps {
|
|
6
|
+
hasFilters: boolean;
|
|
7
|
+
onCreatePost: () => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function EmptyState({ hasFilters, onCreatePost }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
//# sourceMappingURL=EmptyState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmptyState.d.ts","sourceRoot":"","sources":["EmptyState.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,MAAM,WAAW,eAAe;IAC5B,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,wBAAgB,UAAU,CAAC,EAAE,UAAU,EAAE,YAAY,EAAE,EAAE,eAAe,2CAyBvE"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Empty State Component
|
|
3
|
+
* Botanical-themed empty state for when no posts are found
|
|
4
|
+
*/
|
|
5
|
+
'use client';
|
|
6
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { Sprout, Plus } from 'lucide-react';
|
|
8
|
+
export function EmptyState({ hasFilters, onCreatePost }) {
|
|
9
|
+
return (_jsxs("div", { className: "flex flex-col items-center justify-center py-20 px-8 bg-neutral-100 dark:bg-neutral-800/50 rounded-[2.5rem] border-2 border-dashed border-neutral-300 dark:border-neutral-700", children: [_jsx("div", { className: "w-24 h-24 rounded-full bg-green-500/10 dark:bg-green-500/20 flex items-center justify-center mb-6", children: _jsx(Sprout, { className: "text-green-600 dark:text-green-400 size-12" }) }), _jsx("h3", { className: "text-xl font-black text-neutral-950 dark:text-white uppercase tracking-tight mb-2", children: hasFilters ? 'No Posts Found' : 'No Posts Yet' }), _jsx("p", { className: "text-sm text-neutral-500 dark:text-neutral-400 text-center mb-6 max-w-md", children: hasFilters
|
|
10
|
+
? 'Try adjusting your search or filter criteria to find what you\'re looking for.'
|
|
11
|
+
: 'Start growing your content garden. Create your first blog post to share your botanical knowledge with the world.' }), !hasFilters && (_jsxs("button", { onClick: onCreatePost, className: "inline-flex items-center gap-2 px-6 py-3 bg-primary text-white rounded-full text-[10px] font-black uppercase tracking-widest hover:bg-primary/90 transition-all shadow-lg shadow-primary/20", children: [_jsx(Plus, { size: 16 }), "Create Your First Post"] }))] }));
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post Actions Menu Component
|
|
3
|
+
* Three-dot menu with actions for each post
|
|
4
|
+
*/
|
|
5
|
+
export interface PostActionsMenuProps {
|
|
6
|
+
onEdit: () => void;
|
|
7
|
+
onPreview: () => void;
|
|
8
|
+
onDuplicate: () => void;
|
|
9
|
+
onDelete: () => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function PostActionsMenu({ onEdit, onPreview, onDuplicate, onDelete, }: PostActionsMenuProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=PostActionsMenu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PostActionsMenu.d.ts","sourceRoot":"","sources":["PostActionsMenu.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,MAAM,WAAW,oBAAoB;IACjC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,wBAAgB,eAAe,CAAC,EAC5B,MAAM,EACN,SAAS,EACT,WAAW,EACX,QAAQ,GACX,EAAE,oBAAoB,2CAuFtB"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post Actions Menu Component
|
|
3
|
+
* Three-dot menu with actions for each post
|
|
4
|
+
*/
|
|
5
|
+
'use client';
|
|
6
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
7
|
+
import { useState, useRef, useEffect } from 'react';
|
|
8
|
+
import { createPortal } from 'react-dom';
|
|
9
|
+
import { MoreVertical, Edit, Copy, Trash2 } from 'lucide-react';
|
|
10
|
+
export function PostActionsMenu({ onEdit, onPreview, onDuplicate, onDelete, }) {
|
|
11
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
12
|
+
const [menuPosition, setMenuPosition] = useState({ top: 0, right: 0 });
|
|
13
|
+
const buttonRef = useRef(null);
|
|
14
|
+
const menuRef = useRef(null);
|
|
15
|
+
// Calculate menu position when opening
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (isOpen && buttonRef.current) {
|
|
18
|
+
const buttonRect = buttonRef.current.getBoundingClientRect();
|
|
19
|
+
setMenuPosition({
|
|
20
|
+
top: buttonRect.bottom + 8, // 8px = mt-2 equivalent
|
|
21
|
+
right: window.innerWidth - buttonRect.right,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}, [isOpen]);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
function handleClickOutside(event) {
|
|
27
|
+
if (menuRef.current &&
|
|
28
|
+
!menuRef.current.contains(event.target) &&
|
|
29
|
+
buttonRef.current &&
|
|
30
|
+
!buttonRef.current.contains(event.target)) {
|
|
31
|
+
setIsOpen(false);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (isOpen) {
|
|
35
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
36
|
+
}
|
|
37
|
+
return () => {
|
|
38
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
39
|
+
};
|
|
40
|
+
}, [isOpen]);
|
|
41
|
+
const actions = [
|
|
42
|
+
{ label: 'Edit', icon: Edit, onClick: onEdit, color: 'text-neutral-600 dark:text-neutral-400' },
|
|
43
|
+
// { label: 'Preview', icon: Eye, onClick: onPreview, color: 'text-blue-600 dark:text-blue-400' },
|
|
44
|
+
{ label: 'Duplicate', icon: Copy, onClick: onDuplicate, color: 'text-neutral-600 dark:text-neutral-400' },
|
|
45
|
+
{ label: 'Delete', icon: Trash2, onClick: onDelete, color: 'text-red-600 dark:text-red-400' },
|
|
46
|
+
];
|
|
47
|
+
const menuContent = isOpen && (_jsx("div", { ref: menuRef, className: "fixed w-48 bg-dashboard-card border border-dashboard-border rounded-2xl shadow-xl z-9999 overflow-hidden", style: {
|
|
48
|
+
top: `${menuPosition.top}px`,
|
|
49
|
+
right: `${menuPosition.right}px`,
|
|
50
|
+
}, children: actions.map((action) => {
|
|
51
|
+
const Icon = action.icon;
|
|
52
|
+
return (_jsxs("button", { onClick: () => {
|
|
53
|
+
action.onClick();
|
|
54
|
+
setIsOpen(false);
|
|
55
|
+
}, className: `w-full flex items-center font-sans gap-3 px-4 py-3 text-sm hover:bg-dashboard-bg transition-colors ${action.color}`, children: [_jsx(Icon, { size: 16 }), _jsx("span", { children: action.label })] }, action.label));
|
|
56
|
+
}) }));
|
|
57
|
+
return (_jsxs(_Fragment, { children: [_jsx("button", { ref: buttonRef, onClick: () => setIsOpen(!isOpen), className: "p-2 text-neutral-400 hover:text-dashboard-text hover:bg-dashboard-bg rounded-full transition-colors", title: "Actions", children: _jsx(MoreVertical, { size: 18 }) }), typeof window !== 'undefined' && isOpen && createPortal(menuContent, document.body)] }));
|
|
58
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post Cards Component
|
|
3
|
+
* Card-based layout for displaying posts
|
|
4
|
+
*/
|
|
5
|
+
import { PostListItem } from '../../types/post';
|
|
6
|
+
export interface PostCardsProps {
|
|
7
|
+
posts: PostListItem[];
|
|
8
|
+
locale: string;
|
|
9
|
+
onEdit: (postId: string) => void;
|
|
10
|
+
onPreview: (postId: string) => void;
|
|
11
|
+
onDuplicate: (postId: string) => void;
|
|
12
|
+
onDelete: (postId: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare function PostCards({ posts, locale, onEdit, onPreview, onDuplicate, onDelete, }: PostCardsProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
//# sourceMappingURL=PostCards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PostCards.d.ts","sourceRoot":"","sources":["PostCards.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,EAAE,YAAY,EAAc,MAAM,kBAAkB,CAAC;AAI5D,MAAM,WAAW,cAAc;IAC3B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AA0BD,wBAAgB,SAAS,CAAC,EACtB,KAAK,EACL,MAAM,EACN,MAAM,EACN,SAAS,EACT,WAAW,EACX,QAAQ,GACX,EAAE,cAAc,2CA6IhB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post Cards Component
|
|
3
|
+
* Card-based layout for displaying posts
|
|
4
|
+
*/
|
|
5
|
+
'use client';
|
|
6
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { useState, useEffect } from 'react';
|
|
8
|
+
import { Calendar, User, UserCheck } from 'lucide-react';
|
|
9
|
+
import { Image } from '@jhits/plugin-images';
|
|
10
|
+
import { PostActionsMenu } from './PostActionsMenu';
|
|
11
|
+
import { useSession } from 'next-auth/react';
|
|
12
|
+
function getStatusBadgeColor(status) {
|
|
13
|
+
switch (status) {
|
|
14
|
+
case 'published':
|
|
15
|
+
return 'bg-green-500/10 text-green-700 dark:text-green-400 border-green-500/20';
|
|
16
|
+
case 'draft':
|
|
17
|
+
return 'bg-amber-500/10 text-amber-700 dark:text-amber-400 border-amber-500/20';
|
|
18
|
+
case 'scheduled':
|
|
19
|
+
return 'bg-blue-500/10 text-blue-700 dark:text-blue-400 border-blue-500/20';
|
|
20
|
+
case 'archived':
|
|
21
|
+
return 'bg-neutral-500/10 text-neutral-700 dark:text-neutral-400 border-neutral-500/20';
|
|
22
|
+
default:
|
|
23
|
+
return 'bg-neutral-500/10 text-neutral-700 dark:text-neutral-400 border-neutral-500/20';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function formatDate(dateString, locale) {
|
|
27
|
+
if (!dateString)
|
|
28
|
+
return 'No date';
|
|
29
|
+
return new Date(dateString).toLocaleDateString(locale, {
|
|
30
|
+
day: 'numeric',
|
|
31
|
+
month: 'short',
|
|
32
|
+
year: 'numeric',
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export function PostCards({ posts, locale, onEdit, onPreview, onDuplicate, onDelete, }) {
|
|
36
|
+
var _a;
|
|
37
|
+
const { data: session, status: sessionStatus } = useSession();
|
|
38
|
+
const currentUserId = (_a = session === null || session === void 0 ? void 0 : session.user) === null || _a === void 0 ? void 0 : _a.id;
|
|
39
|
+
const [userMap, setUserMap] = useState({});
|
|
40
|
+
// Helper function to check if user is the owner
|
|
41
|
+
const isPostOwner = (post) => {
|
|
42
|
+
if (sessionStatus === 'loading')
|
|
43
|
+
return false; // Don't show actions while loading
|
|
44
|
+
if (!currentUserId || !post.authorId)
|
|
45
|
+
return false;
|
|
46
|
+
// Convert both to strings for comparison to handle ObjectId vs string
|
|
47
|
+
return String(currentUserId) === String(post.authorId);
|
|
48
|
+
};
|
|
49
|
+
// Fetch users to map IDs to names
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
const fetchUsers = async () => {
|
|
52
|
+
try {
|
|
53
|
+
const response = await fetch('/api/users');
|
|
54
|
+
const users = await response.json();
|
|
55
|
+
if (Array.isArray(users)) {
|
|
56
|
+
const map = {};
|
|
57
|
+
users.forEach((user) => {
|
|
58
|
+
var _a;
|
|
59
|
+
const id = (_a = user._id) === null || _a === void 0 ? void 0 : _a.toString();
|
|
60
|
+
if (id) {
|
|
61
|
+
map[id] = user.name || user.email || 'Unknown';
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
setUserMap(map);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
console.error('Failed to fetch users:', error);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
fetchUsers();
|
|
72
|
+
}, []);
|
|
73
|
+
const getAuthorName = (authorId) => {
|
|
74
|
+
if (!authorId)
|
|
75
|
+
return 'Unknown';
|
|
76
|
+
return userMap[authorId] || authorId;
|
|
77
|
+
};
|
|
78
|
+
return (_jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6", children: posts.map((post) => (_jsxs("div", { className: "bg-dashboard-card rounded-2xl border border-dashboard-border overflow-hidden hover:shadow-xl transition-all duration-300 group", children: [_jsxs("div", { className: "relative w-full h-48 bg-neutral-200 dark:bg-neutral-800 overflow-hidden", children: [post.featuredImage ? (_jsx(Image, { id: post.featuredImage, alt: post.title, fill: true, editable: false, className: "w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" })) : (_jsx("div", { className: "w-full h-full flex items-center justify-center", children: _jsx("span", { className: "text-sm text-neutral-400", children: "No Image" }) })), isPostOwner(post) && (_jsx("div", { className: "absolute top-4 left-4 z-10", children: _jsx("div", { className: "bg-white/90 dark:bg-neutral-900/90 backdrop-blur-sm rounded-full p-1 shadow-lg border border-neutral-200 dark:border-neutral-700", children: _jsx(PostActionsMenu, { onEdit: () => onEdit(post.id), onPreview: () => onPreview(post.id), onDuplicate: () => onDuplicate(post.id), onDelete: () => onDelete(post.id) }) }) })), _jsx("div", { className: "absolute top-4 right-4", children: _jsx("span", { className: `inline-flex items-center px-3 py-1 rounded-full text-[10px] font-black uppercase tracking-wider border backdrop-blur-sm ${getStatusBadgeColor(post.status)}`, children: post.status }) })] }), _jsxs("div", { className: "p-6", children: [_jsxs("div", { className: "mb-4", children: [_jsx("button", { onClick: () => onEdit(post.id), className: "text-left w-full hover:cursor-pointer", children: _jsx("h3", { className: "font-bold text-lg text-neutral-950 dark:text-white mb-2 line-clamp-2 group-hover:text-primary transition-colors hover:underline", children: post.title }) }), _jsxs("p", { className: "text-xs text-neutral-500 dark:text-neutral-400 font-mono", children: ["/", post.slug] })] }), post.excerpt && (_jsx("p", { className: "text-sm text-neutral-600 dark:text-neutral-400 mb-4 line-clamp-2", children: post.excerpt })), _jsxs("div", { className: "space-y-3 pt-4 border-t border-neutral-200 dark:border-neutral-700", children: [_jsxs("div", { className: "flex items-center gap-2", children: [isPostOwner(post) ? (_jsx(UserCheck, { size: 14, className: "text-primary" })) : (_jsx(User, { size: 14, className: "text-neutral-400" })), _jsxs("span", { className: `text-xs ${isPostOwner(post) ? 'text-primary font-semibold' : 'text-neutral-600 dark:text-neutral-400'}`, children: [getAuthorName(post.authorId), isPostOwner(post) && (_jsx("span", { className: "ml-1", children: "(You)" }))] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Calendar, { size: 14, className: "text-neutral-400" }), _jsx("span", { className: "text-xs text-neutral-600 dark:text-neutral-400", children: formatDate(post.updatedAt, locale) })] })] })] })] }, post.id))) }));
|
|
79
|
+
}
|