@jhits/plugin-blog 0.0.19 → 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 -490
- 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 -594
- 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
|
@@ -32,7 +32,7 @@ export function LayoutContainer({
|
|
|
32
32
|
className = '',
|
|
33
33
|
emptyLabel = 'Drop blocks here',
|
|
34
34
|
}: LayoutContainerProps) {
|
|
35
|
-
const { darkMode } = useEditor();
|
|
35
|
+
const { darkMode, helpers } = useEditor();
|
|
36
36
|
|
|
37
37
|
// --- State ---
|
|
38
38
|
const [dragOverIndex, setDragOverIndex] = useState<number | null>(null);
|
|
@@ -47,28 +47,37 @@ export function LayoutContainer({
|
|
|
47
47
|
|
|
48
48
|
// --- Cleanup & Event Listeners ---
|
|
49
49
|
useEffect(() => {
|
|
50
|
-
const resetState = () => {
|
|
50
|
+
const resetState = (e: Event) => {
|
|
51
|
+
// Only reset if this is the container that was actually being dragged over
|
|
52
|
+
// or if it's a global dragend event
|
|
51
53
|
setDropIndicatorPosition(null);
|
|
52
54
|
setDragOverIndex(null);
|
|
53
55
|
setDropAtEnd(false);
|
|
54
|
-
dropAtEndRef.current = false;
|
|
56
|
+
dropAtEndRef.current = false;
|
|
55
57
|
setIsDragging(false);
|
|
56
|
-
// Clear global dragged block ID on dragend (in case drag was cancelled)
|
|
57
|
-
if (typeof window !== 'undefined') {
|
|
58
|
-
(window as any).__DRAGGED_BLOCK_ID__ = null;
|
|
59
|
-
}
|
|
60
58
|
};
|
|
61
59
|
|
|
62
60
|
const container = containerRef.current;
|
|
63
61
|
if (container) {
|
|
64
62
|
container.addEventListener('clear-drop-indicator', resetState);
|
|
65
|
-
|
|
63
|
+
|
|
64
|
+
// Listen for dragend on the document but ONLY if we are currently dragging
|
|
65
|
+
const handleGlobalDragEnd = () => {
|
|
66
|
+
if (isDragging) {
|
|
67
|
+
resetState(new Event('dragend'));
|
|
68
|
+
if (typeof window !== 'undefined') {
|
|
69
|
+
(window as any).__DRAGGED_BLOCK_ID__ = null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
document.addEventListener('dragend', handleGlobalDragEnd);
|
|
66
75
|
return () => {
|
|
67
76
|
container.removeEventListener('clear-drop-indicator', resetState);
|
|
68
|
-
document.removeEventListener('dragend',
|
|
77
|
+
document.removeEventListener('dragend', handleGlobalDragEnd);
|
|
69
78
|
};
|
|
70
79
|
}
|
|
71
|
-
}, []);
|
|
80
|
+
}, [isDragging]);
|
|
72
81
|
|
|
73
82
|
// --- Drag & Drop Logic ---
|
|
74
83
|
|
|
@@ -152,67 +161,35 @@ export function LayoutContainer({
|
|
|
152
161
|
e.preventDefault();
|
|
153
162
|
e.stopPropagation();
|
|
154
163
|
|
|
155
|
-
|
|
156
|
-
const
|
|
164
|
+
// MATCHING KEYS: use blockId and blockType (not hyphenated)
|
|
165
|
+
const blockId = e.dataTransfer.getData('blockId') || (window as any).__DRAGGED_BLOCK_ID__ || e.dataTransfer.getData('text/plain');
|
|
166
|
+
const blockType = e.dataTransfer.getData('blockType');
|
|
157
167
|
|
|
158
|
-
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
// Clear the global dragged block ID immediately
|
|
159
171
|
if (typeof window !== 'undefined') {
|
|
160
172
|
(window as any).__DRAGGED_BLOCK_ID__ = null;
|
|
161
173
|
}
|
|
162
174
|
|
|
163
|
-
// Logic: index is null when dropping on the container background (appends to end)
|
|
164
|
-
// When dropAtEnd is true, we want to place it AFTER the block at index, so targetIndex = index + 1
|
|
165
|
-
// When dropAtEnd is false, we want to place it BEFORE the block at index, so targetIndex = index
|
|
166
|
-
// Use ref to get the latest value (React state updates are async)
|
|
167
175
|
const isDropAtEnd = dropAtEndRef.current;
|
|
168
176
|
let targetIndex = index === null ? blocks.length : (isDropAtEnd ? index + 1 : index);
|
|
169
177
|
|
|
170
178
|
if (blockId) {
|
|
171
179
|
const currentIndex = blocks.findIndex(b => b.id === blockId);
|
|
172
180
|
if (currentIndex !== -1) {
|
|
173
|
-
// Moving within
|
|
181
|
+
// Moving within same container
|
|
174
182
|
let finalMoveIndex = targetIndex;
|
|
175
|
-
|
|
176
183
|
if (currentIndex < targetIndex) {
|
|
177
|
-
|
|
178
|
-
if (isDropAtEnd) {
|
|
179
|
-
// Dropping below: we want it at index + 1 in the original array
|
|
180
|
-
// If currentIndex <= index: after removal, block at index stays at index, so we want index + 1 = targetIndex
|
|
181
|
-
// If index < currentIndex < targetIndex: after removal, we still want index + 1, but since we removed
|
|
182
|
-
// an item before targetIndex, the position targetIndex in original = targetIndex - 1 in new array
|
|
183
|
-
if (index !== null && currentIndex <= index) {
|
|
184
|
-
// Item is at or before target block - no adjustment needed
|
|
185
|
-
finalMoveIndex = targetIndex;
|
|
186
|
-
} else {
|
|
187
|
-
// Item is after target block but before targetIndex - need to adjust
|
|
188
|
-
finalMoveIndex = targetIndex - 1;
|
|
189
|
-
}
|
|
190
|
-
} else {
|
|
191
|
-
// Dropping above: targetIndex = index means "before the block at index"
|
|
192
|
-
// After removal, if currentIndex < index, the block at index shifts to index - 1,
|
|
193
|
-
// so we want it at index - 1 in the new array.
|
|
194
|
-
finalMoveIndex = targetIndex - 1;
|
|
195
|
-
}
|
|
184
|
+
finalMoveIndex = targetIndex - 1;
|
|
196
185
|
}
|
|
197
|
-
// If currentIndex >= targetIndex, no adjustment needed (moving backward or same position)
|
|
198
|
-
|
|
199
|
-
console.log('[LayoutContainer] Drop calculation:', {
|
|
200
|
-
blockId,
|
|
201
|
-
index,
|
|
202
|
-
dropAtEnd: isDropAtEnd,
|
|
203
|
-
currentIndex,
|
|
204
|
-
targetIndex,
|
|
205
|
-
finalMoveIndex,
|
|
206
|
-
blocksCount: blocks.length
|
|
207
|
-
});
|
|
208
|
-
|
|
209
186
|
onBlockMove(blockId, Math.max(0, finalMoveIndex), containerId);
|
|
210
187
|
} else {
|
|
211
|
-
// Moving from
|
|
188
|
+
// Moving from different container
|
|
212
189
|
onBlockMove(blockId, targetIndex, containerId);
|
|
213
190
|
}
|
|
214
191
|
} else if (blockType) {
|
|
215
|
-
// Adding new block
|
|
192
|
+
// Adding new block
|
|
216
193
|
onBlockAdd(blockType, targetIndex, containerId);
|
|
217
194
|
}
|
|
218
195
|
|
|
@@ -230,11 +207,21 @@ export function LayoutContainer({
|
|
|
230
207
|
<div
|
|
231
208
|
ref={containerRef}
|
|
232
209
|
data-layout-container={containerId}
|
|
233
|
-
className={`relative flex flex-col min-h-[40px] transition-colors ${className}`}
|
|
234
|
-
|
|
210
|
+
className={`relative flex flex-col min-h-[40px] transition-colors pb-2 ${className}`}
|
|
211
|
+
onDragEnter={(e) => {
|
|
212
|
+
e.preventDefault();
|
|
213
|
+
e.stopPropagation();
|
|
214
|
+
setIsDragging(true);
|
|
215
|
+
}}
|
|
216
|
+
onDragOver={(e) => {
|
|
217
|
+
e.preventDefault();
|
|
218
|
+
e.stopPropagation();
|
|
219
|
+
setIsDragging(true);
|
|
220
|
+
}}
|
|
235
221
|
onDrop={(e) => handleDrop(e, null)}
|
|
236
222
|
onDragLeave={(e) => {
|
|
237
223
|
if (!e.currentTarget.contains(e.relatedTarget as Node)) {
|
|
224
|
+
setIsDragging(false);
|
|
238
225
|
setDropIndicatorPosition(null);
|
|
239
226
|
}
|
|
240
227
|
}}
|
|
@@ -260,8 +247,16 @@ export function LayoutContainer({
|
|
|
260
247
|
block={block}
|
|
261
248
|
onUpdate={(data) => onBlockUpdate(block.id, data, containerId)}
|
|
262
249
|
onDelete={() => onBlockDelete(block.id, containerId)}
|
|
250
|
+
onDuplicate={() => helpers.duplicateBlock(block.id)}
|
|
263
251
|
onMoveUp={index > 0 ? () => onBlockMove(block.id, index - 1, containerId) : undefined}
|
|
264
252
|
onMoveDown={index < blocks.length - 1 ? () => onBlockMove(block.id, index + 1, containerId) : undefined}
|
|
253
|
+
|
|
254
|
+
// Essential for nested rendering: pass children and handlers to the Edit component
|
|
255
|
+
childBlocks={Array.isArray(block.children) && typeof block.children[0] === 'object' ? (block.children as Block[]) : []}
|
|
256
|
+
onChildBlockAdd={(type, idx, cid) => onBlockAdd(type, idx ?? 0, cid || containerId)}
|
|
257
|
+
onChildBlockUpdate={(bid, data, cid) => onBlockUpdate(bid, data, cid || containerId)}
|
|
258
|
+
onChildBlockDelete={(bid, cid) => onBlockDelete(bid, cid || containerId)}
|
|
259
|
+
onChildBlockMove={(bid, idx, cid) => onBlockMove(bid, idx, cid || containerId)}
|
|
265
260
|
/>
|
|
266
261
|
</div>
|
|
267
262
|
))
|
|
@@ -271,52 +266,42 @@ export function LayoutContainer({
|
|
|
271
266
|
}
|
|
272
267
|
|
|
273
268
|
/**
|
|
274
|
-
* Visual
|
|
269
|
+
* Visual Components
|
|
275
270
|
*/
|
|
276
|
-
function DropIndicator({ position, darkMode }: { position:
|
|
271
|
+
function DropIndicator({ position, darkMode }: { position: { top: number, left: number, width: number }, darkMode: boolean }) {
|
|
277
272
|
return (
|
|
278
273
|
<div
|
|
279
|
-
className="absolute z-50 pointer-events-none"
|
|
274
|
+
className="absolute z-50 pointer-events-none transition-all duration-150 ease-out"
|
|
280
275
|
style={{
|
|
281
|
-
top:
|
|
282
|
-
left:
|
|
283
|
-
width:
|
|
284
|
-
height: '
|
|
276
|
+
top: position.top,
|
|
277
|
+
left: position.left,
|
|
278
|
+
width: position.width,
|
|
279
|
+
height: '4px',
|
|
280
|
+
marginTop: '-2px', // Center on the line
|
|
285
281
|
}}
|
|
286
282
|
>
|
|
287
|
-
<div className=
|
|
288
|
-
|
|
289
|
-
/>
|
|
290
|
-
<div className={`absolute top-1/2 left-0 right-0 h-0.5 transform -translate-y-1/2
|
|
291
|
-
${darkMode ? 'bg-primary' : 'bg-primary'}`}
|
|
292
|
-
/>
|
|
293
|
-
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
|
|
294
|
-
<div className="w-6 h-6 rounded-full flex items-center justify-center bg-primary shadow-lg">
|
|
295
|
-
<div className="w-2 h-2 rounded-full bg-white" />
|
|
296
|
-
</div>
|
|
297
|
-
</div>
|
|
283
|
+
<div className="w-full h-full bg-primary rounded-full shadow-[0_0_8px_rgba(var(--primary-rgb),0.5)] animate-pulse" />
|
|
284
|
+
<div className="absolute left-0 top-1/2 -translate-y-1/2 -translate-x-1 w-2 h-2 rounded-full bg-primary" />
|
|
285
|
+
<div className="absolute right-0 top-1/2 -translate-y-1/2 translate-x-1 w-2 h-2 rounded-full bg-primary" />
|
|
298
286
|
</div>
|
|
299
287
|
);
|
|
300
288
|
}
|
|
301
289
|
|
|
302
|
-
|
|
303
|
-
* Placeholder when the container is empty
|
|
304
|
-
*/
|
|
305
|
-
function EmptyState({ isDragging, darkMode, label }: { isDragging: boolean; darkMode: boolean; label: string }) {
|
|
290
|
+
function EmptyState({ isDragging, darkMode, label }: { isDragging: boolean, darkMode: boolean, label: string }) {
|
|
306
291
|
return (
|
|
307
|
-
<div
|
|
308
|
-
${
|
|
309
|
-
?
|
|
310
|
-
:
|
|
311
|
-
|
|
292
|
+
<div
|
|
293
|
+
className={`flex flex-col items-center justify-center py-10 rounded-2xl border-2 border-dashed transition-all duration-300 ${isDragging
|
|
294
|
+
? 'border-primary bg-primary/5 scale-[0.98]'
|
|
295
|
+
: 'border-neutral-200 dark:border-neutral-800 bg-neutral-50/50 dark:bg-neutral-900/20'
|
|
296
|
+
}`}
|
|
312
297
|
>
|
|
313
|
-
<
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
{
|
|
319
|
-
</
|
|
298
|
+
<Plus
|
|
299
|
+
size={24}
|
|
300
|
+
className={`mb-2 transition-colors ${isDragging ? 'text-primary' : 'text-neutral-300 dark:text-neutral-700'}`}
|
|
301
|
+
/>
|
|
302
|
+
<span className={`text-[10px] font-bold uppercase tracking-widest ${isDragging ? 'text-primary' : 'text-neutral-400 dark:text-neutral-600'}`}>
|
|
303
|
+
{label}
|
|
304
|
+
</span>
|
|
320
305
|
</div>
|
|
321
306
|
);
|
|
322
|
-
}
|
|
307
|
+
}
|
|
@@ -67,26 +67,25 @@ export function CustomBlockItem({
|
|
|
67
67
|
onMouseDown={handleMouseDown}
|
|
68
68
|
onMouseMove={handleMouseMove}
|
|
69
69
|
onClick={handleClick}
|
|
70
|
-
className="p-
|
|
70
|
+
className="p-5 rounded-[1.5rem] border border-dashboard-border/50 bg-dashboard-card/30 backdrop-blur-sm hover:border-primary/40 hover:bg-primary/[0.02] hover:shadow-2xl hover:shadow-primary/10 transition-all duration-500 cursor-grab active:cursor-grabbing group"
|
|
71
71
|
title={description}
|
|
72
72
|
>
|
|
73
|
-
<div className="flex items-center justify-between mb-
|
|
74
|
-
<div className="flex items-center gap-
|
|
75
|
-
<div className="text-
|
|
73
|
+
<div className="flex items-center justify-between mb-3">
|
|
74
|
+
<div className="flex items-center gap-3">
|
|
75
|
+
<div className="text-dashboard-text-secondary group-hover:text-primary transition-all duration-500 group-hover:scale-110">
|
|
76
76
|
{icon}
|
|
77
77
|
</div>
|
|
78
|
-
<span className="text-[10px] font-
|
|
78
|
+
<span className="text-[10px] font-black uppercase tracking-[0.2em] text-dashboard-text-secondary group-hover:text-dashboard-text transition-colors">
|
|
79
79
|
{name}
|
|
80
80
|
</span>
|
|
81
81
|
</div>
|
|
82
|
-
<GripVertical size={
|
|
82
|
+
<GripVertical size={14} className="text-dashboard-text-secondary/30 group-hover:text-primary transition-colors" />
|
|
83
83
|
</div>
|
|
84
84
|
{description && (
|
|
85
|
-
<p className="text-[9px] text-
|
|
85
|
+
<p className="text-[9px] text-dashboard-text-secondary/60 leading-relaxed line-clamp-2 italic font-medium">
|
|
86
86
|
{description}
|
|
87
87
|
</p>
|
|
88
88
|
)}
|
|
89
89
|
</div>
|
|
90
90
|
);
|
|
91
91
|
}
|
|
92
|
-
|
|
@@ -16,20 +16,31 @@ export interface EditorCanvasProps {
|
|
|
16
16
|
siteId: string;
|
|
17
17
|
locale: string;
|
|
18
18
|
darkMode: boolean;
|
|
19
|
+
tags?: string[];
|
|
19
20
|
backgroundColors?: {
|
|
20
21
|
light: string;
|
|
21
22
|
dark?: string;
|
|
22
23
|
};
|
|
23
24
|
featuredImage?: {
|
|
24
25
|
id?: string; // Semantic ID - plugin-images handles transforms
|
|
26
|
+
src?: string; // Preview URL
|
|
25
27
|
alt?: string;
|
|
26
28
|
};
|
|
29
|
+
LayoutWrapper?: React.ComponentType<{
|
|
30
|
+
children: React.ReactNode;
|
|
31
|
+
header?: React.ReactNode;
|
|
32
|
+
footer?: React.ReactNode;
|
|
33
|
+
heroImage?: React.ReactNode;
|
|
34
|
+
isPreview?: boolean;
|
|
35
|
+
isWrapper?: boolean;
|
|
36
|
+
tags?: string[];
|
|
37
|
+
}>;
|
|
27
38
|
onTitleChange: (title: string) => void;
|
|
28
39
|
onHeroBlockUpdate: (data: Partial<Block['data']>) => void;
|
|
29
40
|
onHeroBlockDelete: () => void;
|
|
30
41
|
onBlockAdd: (type: string, index: number, containerId?: string) => void;
|
|
31
|
-
onBlockUpdate: (id: string, data: Partial<Block['data']
|
|
32
|
-
onBlockDelete: (id: string) => void;
|
|
42
|
+
onBlockUpdate: (id: string, data: Partial<Block['data']>, containerId?: string) => void;
|
|
43
|
+
onBlockDelete: (id: string, containerId?: string) => void;
|
|
33
44
|
onBlockMove: (id: string, newIndex: number, containerId?: string) => void;
|
|
34
45
|
}
|
|
35
46
|
|
|
@@ -42,8 +53,10 @@ export function EditorCanvas({
|
|
|
42
53
|
siteId,
|
|
43
54
|
locale,
|
|
44
55
|
darkMode,
|
|
56
|
+
tags = [],
|
|
45
57
|
backgroundColors,
|
|
46
58
|
featuredImage,
|
|
59
|
+
LayoutWrapper,
|
|
47
60
|
onTitleChange,
|
|
48
61
|
onHeroBlockUpdate,
|
|
49
62
|
onHeroBlockDelete,
|
|
@@ -62,97 +75,139 @@ export function EditorCanvas({
|
|
|
62
75
|
}
|
|
63
76
|
}, [title]);
|
|
64
77
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
/>
|
|
88
|
-
</div>
|
|
78
|
+
const renderPreviewContent = () => {
|
|
79
|
+
// Filter out hero block from content if it's already rendered in header
|
|
80
|
+
const mainContent = heroBlockDefinition && heroBlock
|
|
81
|
+
? contentBlocks.filter(b => b.type !== 'hero')
|
|
82
|
+
: contentBlocks;
|
|
83
|
+
|
|
84
|
+
const commonContext = {
|
|
85
|
+
siteId,
|
|
86
|
+
locale,
|
|
87
|
+
fallbackImage: featuredImage ? {
|
|
88
|
+
id: featuredImage.id,
|
|
89
|
+
src: featuredImage.src,
|
|
90
|
+
alt: featuredImage.alt,
|
|
91
|
+
} : undefined,
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<div className="space-y-8">
|
|
96
|
+
{!heroBlockDefinition && title && (
|
|
97
|
+
<h1 className="text-5xl font-serif font-medium leading-tight mb-12" style={{ color: 'var(--color-forest, var(--color-neutral-950))' }}>
|
|
98
|
+
{title}
|
|
99
|
+
</h1>
|
|
89
100
|
)}
|
|
90
101
|
|
|
91
|
-
{
|
|
102
|
+
{mainContent.length > 0 ? (
|
|
92
103
|
<div className="space-y-8">
|
|
93
|
-
{
|
|
104
|
+
{mainContent.map((block) => (
|
|
94
105
|
<BlockRenderer
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
locale,
|
|
99
|
-
// Pass featured image as fallback for hero block
|
|
100
|
-
// Only pass id and alt - plugin-images handles transforms
|
|
101
|
-
fallbackImage: featuredImage ? {
|
|
102
|
-
id: featuredImage.id,
|
|
103
|
-
alt: featuredImage.alt,
|
|
104
|
-
} : undefined,
|
|
105
|
-
}}
|
|
106
|
+
key={block.id}
|
|
107
|
+
block={block}
|
|
108
|
+
context={commonContext}
|
|
106
109
|
/>
|
|
107
|
-
)}
|
|
108
|
-
|
|
109
|
-
{!heroBlockDefinition && title && (
|
|
110
|
-
<h1 className="text-5xl font-serif font-medium text-neutral-950 dark:text-white leading-tight mb-12">
|
|
111
|
-
{title}
|
|
112
|
-
</h1>
|
|
113
|
-
)}
|
|
114
|
-
|
|
115
|
-
{contentBlocks.length > 0 ? (
|
|
116
|
-
<div className="space-y-8">
|
|
117
|
-
{contentBlocks.map((block) => (
|
|
118
|
-
<BlockRenderer
|
|
119
|
-
key={block.id}
|
|
120
|
-
block={block}
|
|
121
|
-
context={{ siteId, locale }}
|
|
122
|
-
/>
|
|
123
|
-
))}
|
|
124
|
-
</div>
|
|
125
|
-
) : (
|
|
126
|
-
<div className="text-center py-20 text-neutral-400 dark:text-neutral-500">
|
|
127
|
-
<p className="text-sm">No content blocks yet. Switch to Edit mode to add blocks.</p>
|
|
128
|
-
</div>
|
|
129
|
-
)}
|
|
110
|
+
))}
|
|
130
111
|
</div>
|
|
131
112
|
) : (
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
113
|
+
<div className="text-center py-20 text-neutral-400 dark:text-neutral-500">
|
|
114
|
+
<p className="text-sm">No content blocks yet. Switch to Edit mode to add blocks.</p>
|
|
115
|
+
</div>
|
|
116
|
+
)}
|
|
117
|
+
</div>
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const renderEditorContent = () => {
|
|
122
|
+
// Filter out hero block from content if it's already rendered in header
|
|
123
|
+
const mainBlocks = heroBlockDefinition && heroBlock
|
|
124
|
+
? contentBlocks.filter(b => b.type !== 'hero')
|
|
125
|
+
: contentBlocks;
|
|
145
126
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
127
|
+
return (
|
|
128
|
+
<div className="space-y-12">
|
|
129
|
+
{!heroBlockDefinition && (
|
|
130
|
+
<div className="mb-12">
|
|
131
|
+
<textarea
|
|
132
|
+
ref={titleRef}
|
|
133
|
+
rows={1}
|
|
134
|
+
value={title}
|
|
135
|
+
onChange={(e) => onTitleChange(e.target.value)}
|
|
136
|
+
placeholder="The title of your story..."
|
|
137
|
+
className="w-full bg-transparent border-none outline-none text-5xl md:text-7xl lg:text-9xl font-serif font-medium placeholder:text-neutral-500 dark:placeholder:text-neutral-500 resize-none leading-tight transition-colors duration-300 italic"
|
|
138
|
+
style={{ color: 'var(--color-forest, var(--color-neutral-950))' }}
|
|
154
139
|
/>
|
|
155
|
-
|
|
140
|
+
</div>
|
|
141
|
+
)}
|
|
142
|
+
|
|
143
|
+
<EditorBody
|
|
144
|
+
blocks={mainBlocks}
|
|
145
|
+
darkMode={darkMode}
|
|
146
|
+
backgroundColors={backgroundColors}
|
|
147
|
+
onBlockAdd={onBlockAdd}
|
|
148
|
+
onBlockUpdate={onBlockUpdate}
|
|
149
|
+
onBlockDelete={onBlockDelete}
|
|
150
|
+
onBlockMove={onBlockMove}
|
|
151
|
+
/>
|
|
152
|
+
</div>
|
|
153
|
+
);
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// Render Hero Block for Slot Injection
|
|
157
|
+
const heroElement = heroBlockDefinition && heroBlock ? (
|
|
158
|
+
isPreviewMode ? (
|
|
159
|
+
<BlockRenderer
|
|
160
|
+
block={heroBlock}
|
|
161
|
+
context={{
|
|
162
|
+
siteId,
|
|
163
|
+
locale,
|
|
164
|
+
fallbackImage: featuredImage ? {
|
|
165
|
+
id: featuredImage.id,
|
|
166
|
+
src: featuredImage.src,
|
|
167
|
+
alt: featuredImage.alt,
|
|
168
|
+
} : undefined,
|
|
169
|
+
}}
|
|
170
|
+
/>
|
|
171
|
+
) : (
|
|
172
|
+
<BlockWrapper
|
|
173
|
+
block={heroBlock}
|
|
174
|
+
onUpdate={onHeroBlockUpdate}
|
|
175
|
+
onDelete={onHeroBlockDelete}
|
|
176
|
+
onMoveUp={() => { }}
|
|
177
|
+
onMoveDown={() => { }}
|
|
178
|
+
/>
|
|
179
|
+
)
|
|
180
|
+
) : null;
|
|
181
|
+
|
|
182
|
+
return (
|
|
183
|
+
<div
|
|
184
|
+
data-theme={darkMode ? 'dark' : 'light'}
|
|
185
|
+
className="flex-1 overflow-y-auto overflow-x-hidden pb-40 px-4 lg:px-10 custom-scrollbar selection:bg-primary/20 dark:selection:bg-primary/30 min-h-0 transition-colors duration-300"
|
|
186
|
+
style={{
|
|
187
|
+
backgroundColor: darkMode
|
|
188
|
+
? (backgroundColors?.dark || '#0c0c0c')
|
|
189
|
+
: (backgroundColors?.light || '#ffffff')
|
|
190
|
+
}}
|
|
191
|
+
>
|
|
192
|
+
<div className={`${!LayoutWrapper ? 'mx-auto transition-all duration-500 max-w-[1600px] w-full px-2 pt-8' : ''}`}>
|
|
193
|
+
{LayoutWrapper ? (
|
|
194
|
+
<div data-theme={darkMode ? 'dark' : 'light'} data-dashboard="false" className="theme-reset contents">
|
|
195
|
+
<LayoutWrapper
|
|
196
|
+
header={heroElement}
|
|
197
|
+
isPreview={true}
|
|
198
|
+
isWrapper={true}
|
|
199
|
+
tags={tags}
|
|
200
|
+
>
|
|
201
|
+
{isPreviewMode ? renderPreviewContent() : renderEditorContent()}
|
|
202
|
+
</LayoutWrapper>
|
|
203
|
+
</div>
|
|
204
|
+
) : (
|
|
205
|
+
<div data-theme={darkMode ? 'dark' : 'light'} data-dashboard="false" className="theme-reset">
|
|
206
|
+
{heroElement}
|
|
207
|
+
<div className="max-w-[1600px] mx-auto px-4 sm:px-6 lg:px-8 py-6 prose prose-lg max-w-none prose-headings:font-serif">
|
|
208
|
+
{isPreviewMode ? renderPreviewContent() : renderEditorContent()}
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
156
211
|
)}
|
|
157
212
|
</div>
|
|
158
213
|
</div>
|
|
@@ -7,16 +7,32 @@ import type { BlockTypeDefinition } from '../../../types/block';
|
|
|
7
7
|
|
|
8
8
|
export interface EditorLibraryProps {
|
|
9
9
|
registeredBlocks: BlockTypeDefinition[];
|
|
10
|
-
onAddBlock: (
|
|
10
|
+
onAddBlock: (blockType: string) => void;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Editor Library Component
|
|
15
|
+
* Displays available blocks that can be added to the canvas
|
|
16
|
+
*/
|
|
13
17
|
export function EditorLibrary({ registeredBlocks, onAddBlock }: EditorLibraryProps) {
|
|
14
|
-
//
|
|
15
|
-
const allBlocks = registeredBlocks
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
// Categorize blocks
|
|
19
|
+
const allBlocks = registeredBlocks || [];
|
|
20
|
+
|
|
21
|
+
const textBlocks = allBlocks.filter(bl =>
|
|
22
|
+
bl.category === 'text' || bl.type === 'heading' || bl.type === 'paragraph' || bl.type === 'list'
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const mediaBlocks = allBlocks.filter(bl =>
|
|
26
|
+
bl.category === 'media' || bl.type === 'image' || bl.type === 'gallery' || bl.type === 'video'
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const layoutBlocks = allBlocks.filter(bl =>
|
|
30
|
+
bl.category === 'layout' || bl.type === 'section' || bl.type === 'columns' || bl.type === 'spacer'
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const customBlocks = allBlocks.filter(bl =>
|
|
34
|
+
!textBlocks.includes(bl) && !mediaBlocks.includes(bl) && !layoutBlocks.includes(bl)
|
|
35
|
+
);
|
|
20
36
|
|
|
21
37
|
return (
|
|
22
38
|
<div className="p-6 w-72 min-w-0 max-w-full">
|
|
@@ -108,10 +124,9 @@ export function EditorLibrary({ registeredBlocks, onAddBlock }: EditorLibraryPro
|
|
|
108
124
|
</div>
|
|
109
125
|
)}
|
|
110
126
|
|
|
111
|
-
{/* Empty State */}
|
|
112
127
|
{allBlocks.length === 0 && (
|
|
113
|
-
<div className="
|
|
114
|
-
<Library
|
|
128
|
+
<div className="flex flex-col items-center justify-center py-12 text-center">
|
|
129
|
+
<Library className="size-12 text-neutral-300 dark:text-neutral-700 mb-4" />
|
|
115
130
|
<p className="text-xs text-neutral-500 dark:text-neutral-400">
|
|
116
131
|
No blocks registered yet.
|
|
117
132
|
</p>
|