@jhits/plugin-blog 0.0.18 → 0.0.20
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.map +1 -1
- package/dist/api/categories.js +42 -38
- package/dist/api/handler.d.ts +1 -26
- package/dist/api/handler.d.ts.map +1 -1
- package/dist/api/handler.js +81 -500
- package/dist/api/router.d.ts +0 -5
- package/dist/api/router.d.ts.map +1 -1
- package/dist/api/router.js +8 -35
- package/dist/api/service.d.ts +80 -0
- package/dist/api/service.d.ts.map +1 -0
- package/dist/api/service.js +219 -0
- package/dist/hooks/useAutoSave.d.ts +10 -0
- package/dist/hooks/useAutoSave.d.ts.map +1 -0
- package/dist/hooks/useAutoSave.js +57 -0
- package/dist/hooks/useCategories.d.ts +1 -1
- package/dist/hooks/useCategories.d.ts.map +1 -1
- package/dist/hooks/useCategories.js +15 -46
- package/dist/index.d.ts +24 -31
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -201
- package/dist/init.d.ts +20 -7
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +8 -7
- package/dist/lib/blocks/BlockRenderer.d.ts.map +1 -1
- package/dist/lib/layouts/blocks/ColumnsBlock.d.ts.map +1 -1
- package/dist/lib/layouts/blocks/ColumnsBlock.js +30 -113
- package/dist/lib/layouts/blocks/SectionBlock.d.ts.map +1 -1
- package/dist/lib/layouts/blocks/SectionBlock.js +9 -21
- package/dist/lib/layouts/index.d.ts +3 -3
- package/dist/lib/layouts/index.js +4 -4
- package/dist/lib/mappers/apiMapper.d.ts +10 -0
- package/dist/lib/mappers/apiMapper.d.ts.map +1 -1
- package/dist/lib/mappers/apiMapper.js +47 -32
- package/dist/lib/rich-text/RichTextEditor.d.ts +4 -2
- package/dist/lib/rich-text/RichTextEditor.d.ts.map +1 -1
- package/dist/lib/rich-text/RichTextEditor.js +12 -9
- package/dist/lib/utils/config-resolver.d.ts +28 -0
- package/dist/lib/utils/config-resolver.d.ts.map +1 -0
- package/dist/lib/utils/config-resolver.js +46 -0
- package/dist/lib/utils/tree.d.ts +29 -0
- package/dist/lib/utils/tree.d.ts.map +1 -0
- package/dist/lib/utils/tree.js +129 -0
- package/dist/state/EditorContext.d.ts +3 -25
- package/dist/state/EditorContext.d.ts.map +1 -1
- package/dist/state/EditorContext.js +124 -174
- package/dist/state/reducer.d.ts +1 -5
- package/dist/state/reducer.d.ts.map +1 -1
- package/dist/state/reducer.js +128 -521
- package/dist/state/types.d.ts +12 -1
- package/dist/state/types.d.ts.map +1 -1
- package/dist/types/block.d.ts +9 -0
- package/dist/types/block.d.ts.map +1 -1
- package/dist/types/post.d.ts +17 -1
- package/dist/types/post.d.ts.map +1 -1
- package/dist/views/CanvasEditor/BlockWrapper.d.ts +5 -6
- package/dist/views/CanvasEditor/BlockWrapper.d.ts.map +1 -1
- package/dist/views/CanvasEditor/BlockWrapper.js +56 -264
- package/dist/views/CanvasEditor/CanvasEditorView.d.ts +5 -3
- package/dist/views/CanvasEditor/CanvasEditorView.d.ts.map +1 -1
- package/dist/views/CanvasEditor/CanvasEditorView.js +55 -315
- package/dist/views/CanvasEditor/EditorBody.d.ts +6 -8
- package/dist/views/CanvasEditor/EditorBody.d.ts.map +1 -1
- package/dist/views/CanvasEditor/EditorBody.js +34 -482
- package/dist/views/CanvasEditor/EditorHeader.d.ts.map +1 -1
- package/dist/views/CanvasEditor/EditorHeader.js +27 -63
- package/dist/views/CanvasEditor/LayoutContainer.d.ts.map +1 -1
- package/dist/views/CanvasEditor/LayoutContainer.js +49 -70
- package/dist/views/CanvasEditor/components/CustomBlockItem.js +1 -1
- package/dist/views/CanvasEditor/components/EditorCanvas.d.ts +15 -3
- package/dist/views/CanvasEditor/components/EditorCanvas.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/EditorCanvas.js +40 -18
- package/dist/views/CanvasEditor/components/EditorLibrary.d.ts +5 -1
- package/dist/views/CanvasEditor/components/EditorLibrary.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/EditorLibrary.js +11 -7
- package/dist/views/CanvasEditor/components/EditorSidebar.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/EditorSidebar.js +32 -14
- package/dist/views/CanvasEditor/components/FeaturedMediaSection.d.ts +0 -6
- package/dist/views/CanvasEditor/components/FeaturedMediaSection.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/FeaturedMediaSection.js +17 -128
- package/dist/views/CanvasEditor/components/JSONInspector.d.ts +9 -0
- package/dist/views/CanvasEditor/components/JSONInspector.d.ts.map +1 -0
- package/dist/views/CanvasEditor/components/JSONInspector.js +56 -0
- package/dist/views/CanvasEditor/components/LibraryItem.js +2 -2
- package/dist/views/CanvasEditor/components/PrivacySettingsSection.d.ts +0 -4
- package/dist/views/CanvasEditor/components/PrivacySettingsSection.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/PrivacySettingsSection.js +6 -28
- package/dist/views/CanvasEditor/components/index.d.ts +2 -0
- package/dist/views/CanvasEditor/components/index.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/index.js +1 -0
- package/dist/views/CanvasEditor/hooks/useHeroBlock.d.ts.map +1 -1
- package/dist/views/CanvasEditor/hooks/useHeroBlock.js +15 -18
- package/dist/views/CanvasEditor/hooks/usePostLoader.d.ts +3 -0
- package/dist/views/CanvasEditor/hooks/usePostLoader.d.ts.map +1 -1
- package/dist/views/CanvasEditor/hooks/usePostLoader.js +12 -13
- package/dist/views/CanvasEditor/hooks/useUnsavedChanges.js +0 -4
- package/dist/views/PostManager/EmptyState.d.ts +1 -1
- package/dist/views/PostManager/EmptyState.js +4 -4
- package/dist/views/PostManager/FilterDropdown.d.ts +21 -0
- package/dist/views/PostManager/FilterDropdown.d.ts.map +1 -0
- package/dist/views/PostManager/FilterDropdown.js +28 -0
- package/dist/views/PostManager/LanguageFlags.d.ts.map +1 -1
- package/dist/views/PostManager/LanguageFlags.js +4 -1
- package/dist/views/PostManager/PostCards.d.ts.map +1 -1
- package/dist/views/PostManager/PostCards.js +23 -40
- package/dist/views/PostManager/PostFilters.d.ts.map +1 -1
- package/dist/views/PostManager/PostFilters.js +34 -3
- package/dist/views/PostManager/PostManagerView.d.ts +1 -2
- package/dist/views/PostManager/PostManagerView.d.ts.map +1 -1
- package/dist/views/PostManager/PostManagerView.js +30 -96
- package/dist/views/PostManager/PostStats.d.ts.map +1 -1
- package/dist/views/PostManager/PostStats.js +10 -10
- package/dist/views/PostManager/PostTable.d.ts.map +1 -1
- package/dist/views/PostManager/PostTable.js +23 -40
- package/dist/views/Settings/SettingsView.d.ts +1 -1
- package/dist/views/Settings/SettingsView.d.ts.map +1 -1
- package/dist/views/Settings/SettingsView.js +12 -39
- package/dist/views/SlugSEO/SlugSEOManagerView.d.ts.map +1 -1
- package/dist/views/SlugSEO/SlugSEOManagerView.js +2 -2
- package/package.json +42 -6
- package/src/api/categories.ts +48 -52
- package/src/api/handler.ts +87 -604
- package/src/api/router.ts +15 -65
- package/src/api/service.ts +241 -0
- package/src/hooks/useAutoSave.ts +64 -0
- package/src/hooks/useCategories.ts +19 -47
- package/src/index.tsx +79 -293
- package/src/init.tsx +24 -11
- package/src/lib/blocks/BlockRenderer.tsx +1 -0
- package/src/lib/layouts/blocks/ColumnsBlock.tsx +60 -173
- package/src/lib/layouts/blocks/SectionBlock.tsx +22 -26
- package/src/lib/layouts/index.ts +4 -4
- package/src/lib/mappers/apiMapper.ts +63 -32
- package/src/lib/rich-text/RichTextEditor.tsx +16 -9
- package/src/lib/utils/config-resolver.ts +64 -0
- package/src/lib/utils/tree.ts +150 -0
- package/src/state/EditorContext.tsx +153 -232
- package/src/state/reducer.ts +141 -606
- package/src/state/types.ts +14 -1
- package/src/types/block.ts +10 -0
- package/src/types/post.ts +19 -1
- package/src/views/CanvasEditor/BlockWrapper.tsx +130 -460
- package/src/views/CanvasEditor/CanvasEditorView.tsx +145 -420
- package/src/views/CanvasEditor/EditorBody.tsx +98 -610
- package/src/views/CanvasEditor/EditorHeader.tsx +176 -196
- package/src/views/CanvasEditor/LayoutContainer.tsx +74 -89
- package/src/views/CanvasEditor/components/CustomBlockItem.tsx +7 -8
- package/src/views/CanvasEditor/components/EditorCanvas.tsx +139 -84
- package/src/views/CanvasEditor/components/EditorLibrary.tsx +25 -10
- package/src/views/CanvasEditor/components/EditorSidebar.tsx +196 -127
- package/src/views/CanvasEditor/components/FeaturedMediaSection.tsx +78 -210
- package/src/views/CanvasEditor/components/JSONInspector.tsx +125 -0
- package/src/views/CanvasEditor/components/LibraryItem.tsx +5 -6
- package/src/views/CanvasEditor/components/PrivacySettingsSection.tsx +73 -124
- package/src/views/CanvasEditor/components/index.ts +2 -1
- package/src/views/CanvasEditor/hooks/useHeroBlock.ts +15 -18
- package/src/views/CanvasEditor/hooks/usePostLoader.ts +21 -13
- package/src/views/CanvasEditor/hooks/useUnsavedChanges.ts +4 -4
- package/src/views/PostManager/EmptyState.tsx +9 -10
- package/src/views/PostManager/FilterDropdown.tsx +95 -0
- package/src/views/PostManager/LanguageFlags.tsx +6 -2
- package/src/views/PostManager/PostCards.tsx +127 -133
- package/src/views/PostManager/PostFilters.tsx +73 -68
- package/src/views/PostManager/PostManagerView.tsx +132 -179
- package/src/views/PostManager/PostStats.tsx +21 -20
- package/src/views/PostManager/PostTable.tsx +137 -165
- package/src/views/Settings/SettingsView.tsx +64 -180
- package/src/views/SlugSEO/SlugSEOManagerView.tsx +59 -44
- package/src/hooks/index.d.ts +0 -8
- package/src/hooks/index.d.ts.map +0 -1
- package/src/hooks/useBlog.d.ts +0 -31
- package/src/hooks/useBlog.d.ts.map +0 -1
- package/src/hooks/useBlogs.d.ts +0 -39
- package/src/hooks/useBlogs.d.ts.map +0 -1
- package/src/hooks/useCategories.d.ts +0 -9
- package/src/hooks/useCategories.d.ts.map +0 -1
- package/src/lib/blocks/BlockRenderer.d.ts +0 -54
- package/src/lib/blocks/BlockRenderer.d.ts.map +0 -1
- package/src/lib/config-storage.d.ts +0 -30
- package/src/lib/config-storage.d.ts.map +0 -1
- package/src/lib/layouts/blocks/ColumnsBlock.d.ts +0 -25
- package/src/lib/layouts/blocks/ColumnsBlock.d.ts.map +0 -1
- package/src/lib/layouts/blocks/SectionBlock.d.ts +0 -25
- package/src/lib/layouts/blocks/SectionBlock.d.ts.map +0 -1
- package/src/lib/layouts/index.d.ts +0 -23
- package/src/lib/layouts/index.d.ts.map +0 -1
- package/src/lib/layouts/registerLayoutBlocks.d.ts +0 -9
- package/src/lib/layouts/registerLayoutBlocks.d.ts.map +0 -1
- package/src/lib/mappers/apiMapper.d.ts +0 -66
- package/src/lib/mappers/apiMapper.d.ts.map +0 -1
- package/src/lib/rich-text/RichTextEditor.d.ts +0 -45
- package/src/lib/rich-text/RichTextEditor.d.ts.map +0 -1
- package/src/lib/rich-text/RichTextPreview.d.ts +0 -16
- package/src/lib/rich-text/RichTextPreview.d.ts.map +0 -1
- package/src/lib/rich-text/index.d.ts +0 -9
- package/src/lib/rich-text/index.d.ts.map +0 -1
- package/src/lib/utils/blockHelpers.d.ts +0 -23
- package/src/lib/utils/blockHelpers.d.ts.map +0 -1
- package/src/lib/utils/configValidation.d.ts +0 -23
- package/src/lib/utils/configValidation.d.ts.map +0 -1
- package/src/registry/BlockRegistry.d.ts +0 -62
- package/src/registry/BlockRegistry.d.ts.map +0 -1
- package/src/registry/index.d.ts +0 -6
- package/src/registry/index.d.ts.map +0 -1
- package/src/state/EditorContext.d.ts +0 -45
- package/src/state/EditorContext.d.ts.map +0 -1
- package/src/state/index.d.ts +0 -7
- package/src/state/index.d.ts.map +0 -1
- package/src/state/reducer.d.ts +0 -11
- package/src/state/reducer.d.ts.map +0 -1
- package/src/state/types.d.ts +0 -162
- package/src/state/types.d.ts.map +0 -1
- package/src/types/block.d.ts +0 -221
- package/src/types/block.d.ts.map +0 -1
- package/src/types/index.d.ts +0 -8
- package/src/types/index.d.ts.map +0 -1
- package/src/types/post.d.ts +0 -136
- package/src/types/post.d.ts.map +0 -1
- package/src/utils/client.d.ts +0 -48
- package/src/utils/client.d.ts.map +0 -1
- package/src/views/CanvasEditor/BlockWrapper.d.ts +0 -16
- package/src/views/CanvasEditor/BlockWrapper.d.ts.map +0 -1
- package/src/views/CanvasEditor/CanvasEditorView.d.ts +0 -14
- package/src/views/CanvasEditor/CanvasEditorView.d.ts.map +0 -1
- package/src/views/CanvasEditor/EditorBody.d.ts +0 -22
- package/src/views/CanvasEditor/EditorBody.d.ts.map +0 -1
- package/src/views/CanvasEditor/EditorHeader.d.ts +0 -18
- package/src/views/CanvasEditor/EditorHeader.d.ts.map +0 -1
- package/src/views/CanvasEditor/LayoutContainer.d.ts +0 -17
- package/src/views/CanvasEditor/LayoutContainer.d.ts.map +0 -1
- package/src/views/CanvasEditor/SaveConfirmationModal.d.ts +0 -13
- package/src/views/CanvasEditor/SaveConfirmationModal.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/CustomBlockItem.d.ts +0 -14
- package/src/views/CanvasEditor/components/CustomBlockItem.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/EditorCanvas.d.ts +0 -29
- package/src/views/CanvasEditor/components/EditorCanvas.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/EditorLibrary.d.ts +0 -7
- package/src/views/CanvasEditor/components/EditorLibrary.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/EditorSidebar.d.ts +0 -13
- package/src/views/CanvasEditor/components/EditorSidebar.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/ErrorBanner.d.ts +0 -6
- package/src/views/CanvasEditor/components/ErrorBanner.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/FeaturedMediaSection.d.ts +0 -25
- package/src/views/CanvasEditor/components/FeaturedMediaSection.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/LibraryItem.d.ts +0 -14
- package/src/views/CanvasEditor/components/LibraryItem.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/PrivacySettingsSection.d.ts +0 -15
- package/src/views/CanvasEditor/components/PrivacySettingsSection.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/index.d.ts +0 -21
- package/src/views/CanvasEditor/components/index.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/index.d.ts +0 -10
- package/src/views/CanvasEditor/hooks/index.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/useHeroBlock.d.ts +0 -8
- package/src/views/CanvasEditor/hooks/useHeroBlock.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.d.ts +0 -3
- package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/usePostLoader.d.ts +0 -5
- package/src/views/CanvasEditor/hooks/usePostLoader.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts +0 -2
- package/src/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/useUnsavedChanges.d.ts +0 -25
- package/src/views/CanvasEditor/hooks/useUnsavedChanges.d.ts.map +0 -1
- package/src/views/CanvasEditor/index.d.ts +0 -16
- package/src/views/CanvasEditor/index.d.ts.map +0 -1
- package/src/views/PostManager/EmptyState.d.ts +0 -10
- package/src/views/PostManager/EmptyState.d.ts.map +0 -1
- package/src/views/PostManager/PostActionsMenu.d.ts +0 -12
- package/src/views/PostManager/PostActionsMenu.d.ts.map +0 -1
- package/src/views/PostManager/PostCards.d.ts +0 -15
- package/src/views/PostManager/PostCards.d.ts.map +0 -1
- package/src/views/PostManager/PostFilters.d.ts +0 -16
- package/src/views/PostManager/PostFilters.d.ts.map +0 -1
- package/src/views/PostManager/PostManagerView.d.ts +0 -11
- package/src/views/PostManager/PostManagerView.d.ts.map +0 -1
- package/src/views/PostManager/PostStats.d.ts +0 -11
- package/src/views/PostManager/PostStats.d.ts.map +0 -1
- package/src/views/PostManager/PostTable.d.ts +0 -15
- package/src/views/PostManager/PostTable.d.ts.map +0 -1
- package/src/views/PostManager/index.d.ts +0 -12
- package/src/views/PostManager/index.d.ts.map +0 -1
- package/src/views/Preview/PreviewBridgeView.d.ts +0 -12
- package/src/views/Preview/PreviewBridgeView.d.ts.map +0 -1
- package/src/views/Preview/index.d.ts +0 -6
- package/src/views/Preview/index.d.ts.map +0 -1
- package/src/views/Settings/SettingsView.d.ts +0 -10
- package/src/views/Settings/SettingsView.d.ts.map +0 -1
- package/src/views/Settings/index.d.ts +0 -6
- package/src/views/Settings/index.d.ts.map +0 -1
- package/src/views/SlugSEO/SlugSEOManagerView.d.ts +0 -12
- package/src/views/SlugSEO/SlugSEOManagerView.d.ts.map +0 -1
- package/src/views/SlugSEO/index.d.ts +0 -6
- package/src/views/SlugSEO/index.d.ts.map +0 -1
|
@@ -1,481 +1,206 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import React, { useState, useEffect
|
|
3
|
+
import React, { useState, useEffect } from 'react';
|
|
4
4
|
import { useEditor } from '../../state/EditorContext';
|
|
5
5
|
import { EditorHeader } from './EditorHeader';
|
|
6
6
|
import { ErrorBanner } from './components/ErrorBanner';
|
|
7
7
|
import { EditorLibrary } from './components/EditorLibrary';
|
|
8
|
-
import { EditorCanvas } from './components/EditorCanvas';
|
|
9
8
|
import { EditorSidebar } from './components/EditorSidebar';
|
|
10
|
-
import {
|
|
9
|
+
import { EditorCanvas } from './components/EditorCanvas';
|
|
10
|
+
import { JSONInspector } from './components/JSONInspector';
|
|
11
|
+
import { useRegisteredBlocks } from './hooks/useRegisteredBlocks';
|
|
12
|
+
import { useAutoSave } from '../../hooks/useAutoSave';
|
|
13
|
+
import { usePostLoader } from './hooks/usePostLoader';
|
|
14
|
+
import { RefreshCw } from 'lucide-react';
|
|
11
15
|
import type { Block } from '../../types/block';
|
|
12
|
-
import type { SEOMetadata, PostMetadata } from '../../types/post';
|
|
13
16
|
|
|
14
17
|
export interface CanvasEditorViewProps {
|
|
15
18
|
postId?: string;
|
|
16
19
|
siteId: string;
|
|
17
20
|
locale: string;
|
|
18
|
-
|
|
21
|
+
initialData?: any;
|
|
22
|
+
availableLanguages?: string[];
|
|
19
23
|
darkMode?: boolean;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
light: string;
|
|
23
|
-
dark?: string;
|
|
24
|
-
};
|
|
24
|
+
backgroundColors?: { light: string; dark?: string };
|
|
25
|
+
LayoutWrapper?: React.ComponentType<any>;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
export function CanvasEditorView({
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
export function CanvasEditorView({
|
|
29
|
+
postId,
|
|
30
|
+
siteId,
|
|
31
|
+
locale,
|
|
32
|
+
initialData,
|
|
33
|
+
availableLanguages = [],
|
|
34
|
+
darkMode = false,
|
|
35
|
+
backgroundColors,
|
|
36
|
+
LayoutWrapper
|
|
37
|
+
}: CanvasEditorViewProps) {
|
|
38
|
+
const { state, dispatch, helpers, availableLanguages: contextLanguages } = useEditor();
|
|
39
|
+
const registeredBlocks = useRegisteredBlocks();
|
|
40
|
+
|
|
32
41
|
const [isLibraryOpen, setLibraryOpen] = useState(true);
|
|
42
|
+
const [isSidebarOpen, setSidebarOpen] = useState(true);
|
|
33
43
|
const [isPreviewMode, setIsPreviewMode] = useState(false);
|
|
34
44
|
const [isSaving, setIsSaving] = useState(false);
|
|
35
45
|
const [saveError, setSaveError] = useState<string | null>(null);
|
|
36
46
|
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// Get registered blocks
|
|
44
|
-
const registeredBlocks = useRegisteredBlocks();
|
|
45
|
-
|
|
46
|
-
// Hero block management
|
|
47
|
-
const { heroBlock, setHeroBlock, heroBlockDefinition } = useHeroBlock(state, registeredBlocks);
|
|
47
|
+
// Ensure currentLanguage is always set from the locale prop
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (locale && !state.currentLanguage) {
|
|
50
|
+
dispatch({ type: 'SET_CURRENT_LANGUAGE', payload: locale });
|
|
51
|
+
}
|
|
52
|
+
}, [locale, state.currentLanguage, dispatch]);
|
|
48
53
|
|
|
49
|
-
//
|
|
54
|
+
// Initial post loading logic
|
|
50
55
|
const { isLoadingPost } = usePostLoader(
|
|
51
56
|
postId,
|
|
52
57
|
state.postId,
|
|
53
|
-
|
|
54
|
-
helpers.loadPost(post);
|
|
55
|
-
// Don't reset current language when loading - preserve user's selection
|
|
56
|
-
// This allows switching to a new language even if no content exists yet
|
|
57
|
-
// Update available languages from post's languages object
|
|
58
|
-
if (post.languages && Object.keys(post.languages).length > 0) {
|
|
59
|
-
const langs = Object.keys(post.languages);
|
|
60
|
-
// Add current language to available if not already there
|
|
61
|
-
if (!langs.includes(currentLanguage)) {
|
|
62
|
-
langs.push(currentLanguage);
|
|
63
|
-
}
|
|
64
|
-
setAvailableLanguages(langs);
|
|
65
|
-
}
|
|
66
|
-
// After loading, ensure we're marked as clean
|
|
67
|
-
// Use setTimeout to ensure this runs after the reducer has processed LOAD_POST
|
|
68
|
-
setTimeout(() => {
|
|
69
|
-
dispatch({ type: 'MARK_CLEAN' });
|
|
70
|
-
}, 0);
|
|
71
|
-
},
|
|
58
|
+
helpers.loadPost,
|
|
72
59
|
() => setHeroBlock(null),
|
|
73
|
-
|
|
60
|
+
locale
|
|
74
61
|
);
|
|
75
62
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const fetchLanguageSettings = async () => {
|
|
84
|
-
try {
|
|
85
|
-
// Use the locale prop as the initial language
|
|
86
|
-
// Only set this once on initial load, don't override if user already selected a language
|
|
87
|
-
if (!currentLanguage || currentLanguage === 'en') {
|
|
88
|
-
setPrimaryLanguage(locale || 'nl');
|
|
89
|
-
if (!availableLanguages.includes(locale || 'nl')) {
|
|
90
|
-
setAvailableLanguages([locale || 'nl']);
|
|
91
|
-
}
|
|
92
|
-
setCurrentLanguage(locale || 'nl');
|
|
93
|
-
dispatch({ type: 'SET_CURRENT_LANGUAGE', payload: locale || 'nl' });
|
|
94
|
-
}
|
|
95
|
-
} catch (error) {
|
|
96
|
-
console.error('Failed to fetch language settings:', error);
|
|
97
|
-
} finally {
|
|
98
|
-
setIsLoadingLanguage(false);
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
fetchLanguageSettings();
|
|
102
|
-
}, []); // Empty dependency - only run once on mount
|
|
103
|
-
|
|
104
|
-
// Handle language change
|
|
105
|
-
const handleLanguageChange = async (newLanguage: string) => {
|
|
106
|
-
// Save current content first if dirty
|
|
107
|
-
if (state.isDirty) {
|
|
108
|
-
const confirmed = window.confirm('You have unsaved changes. Do you want to save them first?');
|
|
109
|
-
if (confirmed) {
|
|
110
|
-
await handleSave();
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
setCurrentLanguage(newLanguage);
|
|
115
|
-
dispatch({ type: 'SET_CURRENT_LANGUAGE', payload: newLanguage });
|
|
116
|
-
|
|
117
|
-
// Reload with new language
|
|
118
|
-
if (postId) {
|
|
119
|
-
try {
|
|
120
|
-
const response = await fetch(`/api/plugin-blog/${postId}?language=${newLanguage}`);
|
|
121
|
-
if (response && response.ok) {
|
|
122
|
-
const apiDoc = await response.json();
|
|
123
|
-
|
|
124
|
-
// Manually update state instead of going through loadPost
|
|
125
|
-
// This avoids re-triggering the usePostLoader hook
|
|
126
|
-
const blocks = apiDoc.contentBlocks || apiDoc.blocks || [];
|
|
127
|
-
dispatch({ type: 'SET_TITLE', payload: apiDoc.title || '' });
|
|
128
|
-
|
|
129
|
-
// Replace all blocks
|
|
130
|
-
// First clear, then set new blocks via LOAD_POST-like behavior
|
|
131
|
-
// We use a custom dispatch to update blocks without resetting postId
|
|
132
|
-
dispatch({
|
|
133
|
-
type: 'LOAD_POST',
|
|
134
|
-
payload: {
|
|
135
|
-
id: state.postId || apiDoc._id || apiDoc.id,
|
|
136
|
-
title: apiDoc.title || '',
|
|
137
|
-
slug: apiDoc.slug || state.slug,
|
|
138
|
-
blocks: blocks,
|
|
139
|
-
seo: apiDoc.seo || {},
|
|
140
|
-
publication: {
|
|
141
|
-
status: apiDoc.publicationData?.status === 'concept' ? 'draft' : (apiDoc.publicationData?.status || state.status),
|
|
142
|
-
date: apiDoc.publicationData?.date,
|
|
143
|
-
authorId: apiDoc.authorId,
|
|
144
|
-
},
|
|
145
|
-
metadata: {
|
|
146
|
-
featuredImage: apiDoc.image ? {
|
|
147
|
-
id: apiDoc.image.id || apiDoc.image.src,
|
|
148
|
-
alt: apiDoc.image.alt,
|
|
149
|
-
isCustom: apiDoc.image.isCustom,
|
|
150
|
-
} : state.metadata?.featuredImage,
|
|
151
|
-
categories: apiDoc.categoryTags?.category ? [apiDoc.categoryTags.category] : [],
|
|
152
|
-
tags: apiDoc.categoryTags?.tags || [],
|
|
153
|
-
excerpt: apiDoc.summary || '',
|
|
154
|
-
lang: newLanguage,
|
|
155
|
-
},
|
|
156
|
-
languages: apiDoc.languages,
|
|
157
|
-
createdAt: apiDoc.createdAt || new Date().toISOString(),
|
|
158
|
-
updatedAt: apiDoc.updatedAt || new Date().toISOString(),
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
// Update available languages
|
|
163
|
-
if (apiDoc.availableLanguages) {
|
|
164
|
-
const langs = [...apiDoc.availableLanguages];
|
|
165
|
-
if (!langs.includes(newLanguage)) {
|
|
166
|
-
langs.push(newLanguage);
|
|
167
|
-
}
|
|
168
|
-
setAvailableLanguages(langs);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Reset hero block so it re-initializes from new blocks
|
|
172
|
-
setHeroBlock(null);
|
|
173
|
-
|
|
174
|
-
setTimeout(() => {
|
|
175
|
-
dispatch({ type: 'MARK_CLEAN' });
|
|
176
|
-
}, 100);
|
|
177
|
-
}
|
|
178
|
-
} catch (error) {
|
|
179
|
-
console.error('Failed to switch language:', error);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
// Handle adding a new language
|
|
185
|
-
const handleAddLanguage = async (newLanguage: string) => {
|
|
186
|
-
if (availableLanguages.includes(newLanguage)) return;
|
|
187
|
-
|
|
188
|
-
// Add the new language to the list
|
|
189
|
-
setAvailableLanguages([...availableLanguages, newLanguage]);
|
|
190
|
-
|
|
191
|
-
// Switch to the new language (it will copy from primary language)
|
|
192
|
-
await handleLanguageChange(newLanguage);
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
// Track if we just loaded a post to prevent marking as dirty during cleanup
|
|
196
|
-
const justLoadedRef = useRef(false);
|
|
197
|
-
const previousIsLoadingRef = useRef<boolean>(false);
|
|
198
|
-
const loadingCleanupTimerRef = useRef<NodeJS.Timeout | null>(null);
|
|
199
|
-
|
|
200
|
-
// Mark when post loading completes and ensure it stays clean after all effects
|
|
201
|
-
useEffect(() => {
|
|
202
|
-
// Detect when loading just finished (was loading, now not loading, and we have a postId)
|
|
203
|
-
const loadingJustFinished = previousIsLoadingRef.current && !isLoadingPost && state.postId;
|
|
204
|
-
|
|
205
|
-
if (loadingJustFinished) {
|
|
206
|
-
justLoadedRef.current = true;
|
|
207
|
-
|
|
208
|
-
// Clear any existing cleanup timer
|
|
209
|
-
if (loadingCleanupTimerRef.current) {
|
|
210
|
-
clearTimeout(loadingCleanupTimerRef.current);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Wait for all effects to complete, then ensure we're marked as clean
|
|
214
|
-
// Use multiple animation frames + setTimeout to ensure all effects have run
|
|
215
|
-
requestAnimationFrame(() => {
|
|
216
|
-
requestAnimationFrame(() => {
|
|
217
|
-
loadingCleanupTimerRef.current = setTimeout(() => {
|
|
218
|
-
// Force mark as clean after loading - this ensures cleanup effects don't leave us dirty
|
|
219
|
-
console.log('[CanvasEditorView] Post loading complete - ensuring clean state');
|
|
220
|
-
dispatch({ type: 'MARK_CLEAN' });
|
|
221
|
-
justLoadedRef.current = false;
|
|
222
|
-
loadingCleanupTimerRef.current = null;
|
|
223
|
-
}, 500); // Delay to ensure all effects complete
|
|
224
|
-
});
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// Update ref
|
|
229
|
-
previousIsLoadingRef.current = isLoadingPost;
|
|
230
|
-
|
|
231
|
-
return () => {
|
|
232
|
-
if (loadingCleanupTimerRef.current) {
|
|
233
|
-
clearTimeout(loadingCleanupTimerRef.current);
|
|
234
|
-
loadingCleanupTimerRef.current = null;
|
|
235
|
-
}
|
|
236
|
-
};
|
|
237
|
-
}, [isLoadingPost, state.postId, dispatch]);
|
|
238
|
-
|
|
239
|
-
// Keyboard shortcuts
|
|
240
|
-
useKeyboardShortcuts(state, dispatch, canUndo, canRedo, helpers.undo, helpers.redo);
|
|
241
|
-
|
|
242
|
-
// Unsaved changes warning and auto-save
|
|
243
|
-
const { autoSaveEnabled, setAutoSaveEnabled, countdown, saveStatus } = useUnsavedChanges({
|
|
244
|
-
state,
|
|
245
|
-
isDirty: state.isDirty,
|
|
246
|
-
onSave: async () => {
|
|
247
|
-
// Preserve current status: if already published, keep it published
|
|
248
|
-
// Otherwise save as draft
|
|
249
|
-
const shouldPublish = state.status === 'published';
|
|
250
|
-
await handleSave(shouldPublish);
|
|
251
|
-
},
|
|
252
|
-
heroBlock,
|
|
253
|
-
postId: state.postId,
|
|
63
|
+
const {
|
|
64
|
+
autoSaveEnabled,
|
|
65
|
+
setAutoSaveEnabled,
|
|
66
|
+
saveStatus,
|
|
67
|
+
countdown
|
|
68
|
+
} = useAutoSave(postId, state, async (data) => {
|
|
69
|
+
await helpers.save(heroBlock);
|
|
254
70
|
});
|
|
255
71
|
|
|
256
|
-
//
|
|
72
|
+
// Initialize editor with post data (fallback if not using usePostLoader)
|
|
257
73
|
useEffect(() => {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
useEffect(() => {
|
|
268
|
-
const heroBlocksInContent = state.blocks.filter(b => b.type === 'hero');
|
|
269
|
-
if (heroBlocksInContent.length > 0) {
|
|
270
|
-
heroBlocksInContent.forEach(block => {
|
|
271
|
-
dispatch({ type: 'DELETE_BLOCK', payload: { id: block.id } });
|
|
272
|
-
});
|
|
273
|
-
// Don't mark as clean here - let the loading cleanup effect handle it
|
|
274
|
-
// This ensures we wait for all effects to complete before marking clean
|
|
74
|
+
if (initialData) {
|
|
75
|
+
const data = initialData.data || initialData;
|
|
76
|
+
if (data.blocks) dispatch({ type: 'SET_BLOCKS', payload: data.blocks });
|
|
77
|
+
if (data.title) dispatch({ type: 'SET_TITLE', payload: data.title });
|
|
78
|
+
if (data.slug) dispatch({ type: 'SET_SLUG', payload: data.slug });
|
|
79
|
+
if (data.seo) dispatch({ type: 'SET_SEO', payload: data.seo });
|
|
80
|
+
if (data.metadata) dispatch({ type: 'SET_METADATA', payload: data.metadata });
|
|
81
|
+
if (data.status) dispatch({ type: 'SET_STATUS', payload: data.status });
|
|
82
|
+
dispatch({ type: 'SET_CURRENT_LANGUAGE', payload: locale });
|
|
275
83
|
}
|
|
276
|
-
}, [
|
|
277
|
-
|
|
278
|
-
// Filter out hero blocks from content blocks
|
|
279
|
-
const contentBlocks = state.blocks.filter(b => b.type !== 'hero');
|
|
280
|
-
|
|
281
|
-
// Handler to add block at the bottom when clicking (not dragging)
|
|
282
|
-
const handleAddBlockAtBottom = (blockType: string) => {
|
|
283
|
-
// Add at the end of content blocks (excluding hero)
|
|
284
|
-
helpers.addBlock(blockType, contentBlocks.length, undefined);
|
|
285
|
-
};
|
|
84
|
+
}, [initialData, locale, dispatch]);
|
|
286
85
|
|
|
287
|
-
|
|
288
|
-
const handleSave = async (publish?: boolean) => {
|
|
86
|
+
const handleSave = async (publish: boolean = false) => {
|
|
289
87
|
setIsSaving(true);
|
|
290
88
|
setSaveError(null);
|
|
291
89
|
try {
|
|
292
|
-
|
|
293
|
-
console.log('[CanvasEditorView] onSave called with publish:', publish, 'current status:', state.status);
|
|
294
|
-
|
|
295
|
-
// Only change status if explicitly requested (publish is true or false)
|
|
296
|
-
// If publish is undefined, preserve the current status (used for autosave)
|
|
297
|
-
if (publish === true && state.status !== 'published') {
|
|
298
|
-
console.warn('[CanvasEditorView] Status mismatch! Setting to published...');
|
|
299
|
-
dispatch({ type: 'SET_STATUS', payload: 'published' });
|
|
300
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
301
|
-
} else if (publish === false && state.status !== 'draft' && state.status !== 'published') {
|
|
302
|
-
// Only set to draft if not already published (preserve published status)
|
|
303
|
-
// This prevents autosave from changing published posts back to draft
|
|
304
|
-
console.warn('[CanvasEditorView] Status mismatch! Setting to draft...');
|
|
305
|
-
dispatch({ type: 'SET_STATUS', payload: 'draft' });
|
|
306
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
console.log('[CanvasEditorView] Final status before save:', state.status);
|
|
310
|
-
|
|
311
|
-
// Pass hero block to save function so it can be included in the saved data
|
|
312
|
-
await helpers.save(heroBlock);
|
|
313
|
-
setIsSaving(false);
|
|
90
|
+
await helpers.save(heroBlock, publish ? 'published' : 'draft');
|
|
314
91
|
} catch (error: any) {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
// Make error messages more user-friendly
|
|
320
|
-
if (errorMessage.includes('Missing required fields')) {
|
|
321
|
-
errorMessage = errorMessage.replace('Missing required fields for publishing:', 'To publish, please fill in:');
|
|
322
|
-
} else if (errorMessage.includes('All required fields')) {
|
|
323
|
-
errorMessage = 'To publish, please fill in all required fields: summary, featured image, category, and content.';
|
|
324
|
-
} else if (errorMessage.includes('Unauthorized')) {
|
|
325
|
-
errorMessage = 'You are not authorized to save this post. Please log in again.';
|
|
326
|
-
} else if (errorMessage.includes('Failed to save')) {
|
|
327
|
-
errorMessage = 'Unable to save the post. Please check your connection and try again.';
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
setSaveError(errorMessage);
|
|
331
|
-
setIsSaving(false); // Always reset saving state on error
|
|
332
|
-
throw error; // Re-throw so EditorHeader can handle it
|
|
92
|
+
setSaveError(error.message || 'Failed to save publication');
|
|
93
|
+
} finally {
|
|
94
|
+
setIsSaving(false);
|
|
333
95
|
}
|
|
334
96
|
};
|
|
335
97
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
if (!heroBlock) return;
|
|
339
|
-
|
|
340
|
-
setHeroBlock({
|
|
341
|
-
...heroBlock,
|
|
342
|
-
data: { ...heroBlock.data, ...data },
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
// Sync title to editor state
|
|
346
|
-
if (data.title !== undefined && typeof data.title === 'string') {
|
|
347
|
-
dispatch({ type: 'SET_TITLE', payload: data.title });
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// Sync summary to editor state metadata
|
|
351
|
-
if (data.summary !== undefined && typeof data.summary === 'string') {
|
|
352
|
-
dispatch({
|
|
353
|
-
type: 'SET_METADATA',
|
|
354
|
-
payload: { excerpt: data.summary }
|
|
355
|
-
});
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
// Hero image and featured image are completely independent
|
|
359
|
-
// Do NOT sync hero image to featured image
|
|
360
|
-
// The featured image is a separate thumbnail that the client adjusts independently
|
|
361
|
-
|
|
362
|
-
// Sync category to editor state metadata
|
|
363
|
-
if (data.category !== undefined && typeof data.category === 'string') {
|
|
364
|
-
dispatch({
|
|
365
|
-
type: 'SET_METADATA',
|
|
366
|
-
payload: {
|
|
367
|
-
categories: data.category.trim() ? [data.category.trim()] : []
|
|
368
|
-
}
|
|
369
|
-
});
|
|
370
|
-
}
|
|
98
|
+
const handleHeroUpdate = (block: any) => {
|
|
99
|
+
setHeroBlock(block);
|
|
371
100
|
};
|
|
372
101
|
|
|
373
|
-
//
|
|
374
|
-
const
|
|
375
|
-
|
|
376
|
-
const
|
|
377
|
-
setHeroBlock(
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
102
|
+
// Find hero block if it exists
|
|
103
|
+
const [heroBlock, setHeroBlock] = useState<any>(null);
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
const hero = state.blocks.find((b: any) => b.type === 'hero' || b.category === 'hero');
|
|
106
|
+
if (hero) setHeroBlock(hero);
|
|
107
|
+
}, [state.blocks]);
|
|
108
|
+
|
|
109
|
+
const heroBlockDefinition = registeredBlocks.find(b => b.type === heroBlock?.type);
|
|
110
|
+
|
|
111
|
+
if (isLoadingPost) {
|
|
112
|
+
return (
|
|
113
|
+
<div className="absolute inset-0 w-full flex items-center justify-center bg-dashboard-bg/10 backdrop-blur-sm z-[100]">
|
|
114
|
+
<div className="flex flex-col items-center gap-4">
|
|
115
|
+
<RefreshCw className="size-10 text-primary animate-spin" />
|
|
116
|
+
<p className="text-[10px] font-black uppercase tracking-[0.3em] text-primary">Synchronizing_Node_Data...</p>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
382
121
|
|
|
383
122
|
return (
|
|
384
|
-
<div className="
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
setSaveError(null);
|
|
406
|
-
}
|
|
407
|
-
}}
|
|
408
|
-
autoSaveEnabled={autoSaveEnabled}
|
|
409
|
-
onAutoSaveToggle={setAutoSaveEnabled}
|
|
410
|
-
isDirty={state.isDirty}
|
|
411
|
-
autoSaveCountdown={countdown}
|
|
412
|
-
autoSaveStatus={saveStatus}
|
|
413
|
-
languages={availableLanguages}
|
|
414
|
-
currentLanguage={currentLanguage}
|
|
415
|
-
onLanguageChange={handleLanguageChange}
|
|
416
|
-
onAddLanguage={handleAddLanguage}
|
|
417
|
-
/>
|
|
418
|
-
</header>
|
|
123
|
+
<div className="absolute inset-0 w-full flex flex-col overflow-hidden bg-dashboard-bg/10 backdrop-blur-sm">
|
|
124
|
+
<EditorHeader
|
|
125
|
+
isLibraryOpen={isLibraryOpen}
|
|
126
|
+
onLibraryToggle={() => setLibraryOpen(!isLibraryOpen)}
|
|
127
|
+
isPreviewMode={isPreviewMode}
|
|
128
|
+
onPreviewToggle={() => setIsPreviewMode(!isPreviewMode)}
|
|
129
|
+
isSidebarOpen={isSidebarOpen}
|
|
130
|
+
onSidebarToggle={() => setSidebarOpen(!isSidebarOpen)}
|
|
131
|
+
isSaving={isSaving}
|
|
132
|
+
onSave={handleSave}
|
|
133
|
+
onSaveError={setSaveError}
|
|
134
|
+
autoSaveEnabled={autoSaveEnabled}
|
|
135
|
+
onAutoSaveToggle={setAutoSaveEnabled}
|
|
136
|
+
isDirty={state.isDirty}
|
|
137
|
+
autoSaveCountdown={countdown}
|
|
138
|
+
autoSaveStatus={saveStatus}
|
|
139
|
+
languages={contextLanguages}
|
|
140
|
+
currentLanguage={state.currentLanguage || locale}
|
|
141
|
+
onLanguageChange={(lang) => helpers.switchLanguage(lang, postId)}
|
|
142
|
+
onAddLanguage={(lang) => helpers.switchLanguage(lang, postId)}
|
|
143
|
+
/>
|
|
419
144
|
|
|
420
|
-
{/* Error Banner */}
|
|
421
145
|
<ErrorBanner error={saveError} onDismiss={() => setSaveError(null)} />
|
|
422
146
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
<
|
|
426
|
-
{
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
)}
|
|
438
|
-
|
|
439
|
-
{/* CENTER: THE WRITING CANVAS */}
|
|
147
|
+
<main className="flex flex-1 relative overflow-hidden">
|
|
148
|
+
{/* 1. BLOCKS LIBRARY */}
|
|
149
|
+
<aside
|
|
150
|
+
className={`transition-all duration-500 bg-dashboard-sidebar/40 backdrop-blur-xl border-r border-dashboard-border/50 relative z-20 overflow-hidden ${
|
|
151
|
+
isLibraryOpen ? 'w-72' : 'w-0'
|
|
152
|
+
}`}
|
|
153
|
+
>
|
|
154
|
+
<div className="w-72 h-full opacity-100 transition-opacity duration-300">
|
|
155
|
+
<EditorLibrary registeredBlocks={registeredBlocks} onAddBlock={(type) => helpers.addBlock(type)} />
|
|
156
|
+
</div>
|
|
157
|
+
</aside>
|
|
158
|
+
|
|
159
|
+
{/* 2. MAIN CANVAS */}
|
|
160
|
+
<div className="flex-1 relative overflow-hidden bg-white/[0.01] flex flex-col">
|
|
440
161
|
<EditorCanvas
|
|
441
162
|
isPreviewMode={isPreviewMode}
|
|
442
163
|
heroBlock={heroBlock}
|
|
443
164
|
heroBlockDefinition={heroBlockDefinition}
|
|
444
|
-
contentBlocks={
|
|
165
|
+
contentBlocks={state.blocks}
|
|
445
166
|
title={state.title}
|
|
446
167
|
siteId={siteId}
|
|
447
168
|
locale={locale}
|
|
448
|
-
darkMode={
|
|
449
|
-
backgroundColors={
|
|
169
|
+
darkMode={darkMode}
|
|
170
|
+
backgroundColors={backgroundColors}
|
|
450
171
|
featuredImage={state.metadata.featuredImage}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
172
|
+
LayoutWrapper={LayoutWrapper}
|
|
173
|
+
onTitleChange={(title) => dispatch({ type: 'SET_TITLE', payload: title })}
|
|
174
|
+
onHeroBlockUpdate={handleHeroUpdate}
|
|
175
|
+
onHeroBlockDelete={() => setHeroBlock(null)}
|
|
176
|
+
onBlockAdd={helpers.addBlock}
|
|
177
|
+
onBlockUpdate={helpers.updateBlock}
|
|
178
|
+
onBlockDelete={helpers.deleteBlock}
|
|
179
|
+
onBlockMove={helpers.moveBlock}
|
|
458
180
|
/>
|
|
459
|
-
|
|
460
|
-
{/* RIGHT SIDEBAR: THE "DESK" (SETTINGS) */}
|
|
461
|
-
{!isPreviewMode && (
|
|
462
|
-
<aside
|
|
463
|
-
className={`transition-all duration-500 ease-[cubic-bezier(0.4,0,0.2,1)] border-l border-dashboard-border bg-dashboard-sidebar overflow-y-auto overflow-x-hidden h-full ${isSidebarOpen ? 'w-80' : 'w-0 opacity-0 pointer-events-none'
|
|
464
|
-
}`}
|
|
465
|
-
>
|
|
466
|
-
<EditorSidebar
|
|
467
|
-
slug={state.slug}
|
|
468
|
-
seo={state.seo}
|
|
469
|
-
metadata={state.metadata}
|
|
470
|
-
heroBlock={heroBlock}
|
|
471
|
-
status={state.status}
|
|
472
|
-
onSEOUpdate={(seo: Partial<SEOMetadata>) => dispatch({ type: 'SET_SEO', payload: seo })}
|
|
473
|
-
onMetadataUpdate={(metadata: Partial<PostMetadata>) => dispatch({ type: 'SET_METADATA', payload: metadata })}
|
|
474
|
-
/>
|
|
475
|
-
</aside>
|
|
476
|
-
)}
|
|
477
181
|
</div>
|
|
182
|
+
|
|
183
|
+
{/* 3. SETTINGS SIDEBAR */}
|
|
184
|
+
<aside
|
|
185
|
+
className={`transition-all duration-500 bg-dashboard-sidebar/40 backdrop-blur-xl border-l border-dashboard-border/50 relative z-20 overflow-hidden ${
|
|
186
|
+
isSidebarOpen ? 'w-80' : 'w-0'
|
|
187
|
+
}`}
|
|
188
|
+
>
|
|
189
|
+
<div className="w-80 h-full opacity-100 transition-opacity duration-300">
|
|
190
|
+
<EditorSidebar
|
|
191
|
+
slug={state.slug}
|
|
192
|
+
seo={state.seo}
|
|
193
|
+
metadata={state.metadata}
|
|
194
|
+
heroBlock={heroBlock}
|
|
195
|
+
status={state.status}
|
|
196
|
+
onSEOUpdate={(seo) => dispatch({ type: 'SET_SEO', payload: seo })}
|
|
197
|
+
onMetadataUpdate={(meta) => dispatch({ type: 'SET_METADATA', payload: meta })}
|
|
198
|
+
/>
|
|
199
|
+
</div>
|
|
200
|
+
</aside>
|
|
478
201
|
</main>
|
|
202
|
+
|
|
203
|
+
<JSONInspector data={state} />
|
|
479
204
|
</div>
|
|
480
205
|
);
|
|
481
206
|
}
|