@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
package/dist/state/reducer.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Editor Reducer
|
|
3
|
-
* Pure function that handles state transitions
|
|
3
|
+
* Pure function that handles state transitions using tree utilities
|
|
4
4
|
*/
|
|
5
5
|
import { initialEditorState } from './types';
|
|
6
|
+
import { findNode, mapTree, filterTree, removeNode, addNodeToContainer } from '../lib/utils/tree';
|
|
7
|
+
import { blockRegistry } from '../registry/BlockRegistry';
|
|
8
|
+
import { slugify } from '../lib/utils/slugify';
|
|
6
9
|
/**
|
|
7
10
|
* Generate a unique block ID
|
|
8
11
|
*/
|
|
9
12
|
function generateBlockId() {
|
|
10
|
-
// Use crypto.randomUUID if available, otherwise fallback to timestamp-based
|
|
11
13
|
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
|
|
12
14
|
return crypto.randomUUID();
|
|
13
15
|
}
|
|
@@ -22,543 +24,172 @@ function cloneBlock(block) {
|
|
|
22
24
|
id: generateBlockId(),
|
|
23
25
|
data: { ...block.data },
|
|
24
26
|
meta: block.meta ? { ...block.meta } : undefined,
|
|
25
|
-
children: block.children
|
|
27
|
+
children: block.children && typeof block.children[0] === 'object'
|
|
26
28
|
? block.children.map(cloneBlock)
|
|
27
|
-
: [...block.children]
|
|
29
|
+
: block.children ? [...block.children] : undefined,
|
|
28
30
|
};
|
|
29
31
|
}
|
|
30
|
-
/**
|
|
31
|
-
* Find a block by ID recursively (including nested blocks)
|
|
32
|
-
*/
|
|
33
|
-
function findBlockById(blocks, id) {
|
|
34
|
-
for (const block of blocks) {
|
|
35
|
-
if (block.id === id) {
|
|
36
|
-
return block;
|
|
37
|
-
}
|
|
38
|
-
if (block.children && Array.isArray(block.children) && block.children.length > 0) {
|
|
39
|
-
// Check if children are Block objects or IDs
|
|
40
|
-
if (typeof block.children[0] === 'object') {
|
|
41
|
-
const found = findBlockById(block.children, id);
|
|
42
|
-
if (found)
|
|
43
|
-
return found;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Update blocks recursively to add a block to a container
|
|
51
|
-
*/
|
|
52
|
-
function addBlockToContainer(blocks, containerId, newBlock, index) {
|
|
53
|
-
return blocks.map(block => {
|
|
54
|
-
// Check if this is the container (exact match or column container like "block-123-col-0")
|
|
55
|
-
const isContainer = block.id === containerId;
|
|
56
|
-
const isColumnContainer = containerId.startsWith(`${block.id}-col-`);
|
|
57
|
-
if (isContainer) {
|
|
58
|
-
// Direct container match
|
|
59
|
-
const currentChildren = Array.isArray(block.children)
|
|
60
|
-
? (typeof block.children[0] === 'object'
|
|
61
|
-
? block.children
|
|
62
|
-
: [])
|
|
63
|
-
: [];
|
|
64
|
-
const updatedChildren = [...currentChildren];
|
|
65
|
-
if (index !== undefined && index >= 0 && index <= updatedChildren.length) {
|
|
66
|
-
updatedChildren.splice(index, 0, newBlock);
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
updatedChildren.push(newBlock);
|
|
70
|
-
}
|
|
71
|
-
return {
|
|
72
|
-
...block,
|
|
73
|
-
children: updatedChildren,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
else if (isColumnContainer) {
|
|
77
|
-
// Column container - extract column index and store in block meta
|
|
78
|
-
const columnIndex = parseInt(containerId.split('-col-')[1] || '0', 10);
|
|
79
|
-
newBlock.meta = {
|
|
80
|
-
...newBlock.meta,
|
|
81
|
-
columnIndex,
|
|
82
|
-
};
|
|
83
|
-
const currentChildren = Array.isArray(block.children)
|
|
84
|
-
? (typeof block.children[0] === 'object'
|
|
85
|
-
? block.children
|
|
86
|
-
: [])
|
|
87
|
-
: [];
|
|
88
|
-
const updatedChildren = [...currentChildren];
|
|
89
|
-
if (index !== undefined && index >= 0 && index <= updatedChildren.length) {
|
|
90
|
-
updatedChildren.splice(index, 0, newBlock);
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
updatedChildren.push(newBlock);
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
...block,
|
|
97
|
-
children: updatedChildren,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
// Recursively search nested blocks
|
|
101
|
-
if (block.children && Array.isArray(block.children) && block.children.length > 0) {
|
|
102
|
-
if (typeof block.children[0] === 'object') {
|
|
103
|
-
return {
|
|
104
|
-
...block,
|
|
105
|
-
children: addBlockToContainer(block.children, containerId, newBlock, index),
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return block;
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Update blocks recursively to update a nested block
|
|
114
|
-
*/
|
|
115
|
-
function updateNestedBlock(blocks, id, data) {
|
|
116
|
-
return blocks.map(block => {
|
|
117
|
-
if (block.id === id) {
|
|
118
|
-
return {
|
|
119
|
-
...block,
|
|
120
|
-
data: { ...block.data, ...data },
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
if (block.children && Array.isArray(block.children) && block.children.length > 0) {
|
|
124
|
-
if (typeof block.children[0] === 'object') {
|
|
125
|
-
return {
|
|
126
|
-
...block,
|
|
127
|
-
children: updateNestedBlock(block.children, id, data),
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return block;
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Update blocks recursively to delete a nested block
|
|
136
|
-
*/
|
|
137
|
-
function deleteNestedBlock(blocks, id) {
|
|
138
|
-
return blocks
|
|
139
|
-
.filter(block => block.id !== id)
|
|
140
|
-
.map(block => {
|
|
141
|
-
if (block.children && Array.isArray(block.children) && block.children.length > 0) {
|
|
142
|
-
if (typeof block.children[0] === 'object') {
|
|
143
|
-
return {
|
|
144
|
-
...block,
|
|
145
|
-
children: deleteNestedBlock(block.children, id),
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
return block;
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Find and remove a block from wherever it is (root or nested)
|
|
154
|
-
*/
|
|
155
|
-
function removeBlockFromTree(blocks, blockId) {
|
|
156
|
-
let removedBlock = null;
|
|
157
|
-
console.log('[removeBlockFromTree] Searching for block:', {
|
|
158
|
-
blockId,
|
|
159
|
-
rootBlocks: blocks.map(b => ({ id: b.id, type: b.type })),
|
|
160
|
-
});
|
|
161
|
-
// First check root level
|
|
162
|
-
const rootIndex = blocks.findIndex(b => b.id === blockId);
|
|
163
|
-
if (rootIndex !== -1) {
|
|
164
|
-
removedBlock = blocks[rootIndex];
|
|
165
|
-
console.log('[removeBlockFromTree] Found at root level:', {
|
|
166
|
-
blockId,
|
|
167
|
-
index: rootIndex,
|
|
168
|
-
block: { id: removedBlock.id, type: removedBlock.type },
|
|
169
|
-
});
|
|
170
|
-
return {
|
|
171
|
-
updatedBlocks: blocks.filter((_, i) => i !== rootIndex),
|
|
172
|
-
removedBlock,
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
// Then check nested blocks
|
|
176
|
-
const updatedBlocks = blocks.map(block => {
|
|
177
|
-
if (block.children && Array.isArray(block.children) && block.children.length > 0) {
|
|
178
|
-
if (typeof block.children[0] === 'object') {
|
|
179
|
-
const children = block.children;
|
|
180
|
-
const childIndex = children.findIndex(b => b.id === blockId);
|
|
181
|
-
if (childIndex !== -1) {
|
|
182
|
-
removedBlock = children[childIndex];
|
|
183
|
-
console.log('[removeBlockFromTree] Found in nested container:', {
|
|
184
|
-
blockId,
|
|
185
|
-
containerId: block.id,
|
|
186
|
-
containerType: block.type,
|
|
187
|
-
childIndex,
|
|
188
|
-
block: { id: removedBlock.id, type: removedBlock.type },
|
|
189
|
-
});
|
|
190
|
-
return {
|
|
191
|
-
...block,
|
|
192
|
-
children: children.filter((_, i) => i !== childIndex),
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
// Recursively search nested children
|
|
196
|
-
const { updatedBlocks: updatedChildren, removedBlock: foundBlock } = removeBlockFromTree(children, blockId);
|
|
197
|
-
if (foundBlock) {
|
|
198
|
-
removedBlock = foundBlock;
|
|
199
|
-
console.log('[removeBlockFromTree] Found in deeper nesting:', {
|
|
200
|
-
blockId,
|
|
201
|
-
containerId: block.id,
|
|
202
|
-
block: { id: removedBlock.id, type: removedBlock.type },
|
|
203
|
-
});
|
|
204
|
-
return {
|
|
205
|
-
...block,
|
|
206
|
-
children: updatedChildren,
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
return block;
|
|
212
|
-
});
|
|
213
|
-
if (!removedBlock) {
|
|
214
|
-
console.warn('[removeBlockFromTree] Block not found in tree:', { blockId });
|
|
215
|
-
}
|
|
216
|
-
return { updatedBlocks, removedBlock };
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Update blocks recursively to move a nested block within the same container
|
|
220
|
-
*/
|
|
221
|
-
function moveNestedBlock(blocks, containerId, blockId, newIndex) {
|
|
222
|
-
return blocks.map(block => {
|
|
223
|
-
if (block.id === containerId && block.children && Array.isArray(block.children)) {
|
|
224
|
-
const children = typeof block.children[0] === 'object'
|
|
225
|
-
? block.children
|
|
226
|
-
: [];
|
|
227
|
-
const currentIndex = children.findIndex(b => b.id === blockId);
|
|
228
|
-
if (currentIndex !== -1 && newIndex >= 0 && newIndex < children.length) {
|
|
229
|
-
const updatedChildren = [...children];
|
|
230
|
-
const [movedBlock] = updatedChildren.splice(currentIndex, 1);
|
|
231
|
-
updatedChildren.splice(newIndex, 0, movedBlock);
|
|
232
|
-
return {
|
|
233
|
-
...block,
|
|
234
|
-
children: updatedChildren,
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
if (block.children && Array.isArray(block.children) && block.children.length > 0) {
|
|
239
|
-
if (typeof block.children[0] === 'object') {
|
|
240
|
-
return {
|
|
241
|
-
...block,
|
|
242
|
-
children: moveNestedBlock(block.children, containerId, blockId, newIndex),
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
return block;
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Move a block to a container (handles cross-container moves)
|
|
251
|
-
*/
|
|
252
|
-
function moveBlockToContainer(blocks, blockId, containerId, newIndex) {
|
|
253
|
-
console.log('[moveBlockToContainer] Starting move:', {
|
|
254
|
-
blockId,
|
|
255
|
-
containerId,
|
|
256
|
-
newIndex,
|
|
257
|
-
});
|
|
258
|
-
// First, find and remove the block from wherever it is
|
|
259
|
-
const { updatedBlocks, removedBlock } = removeBlockFromTree(blocks, blockId);
|
|
260
|
-
if (!removedBlock) {
|
|
261
|
-
// Block not found, return unchanged
|
|
262
|
-
console.warn('[moveBlockToContainer] Block not found, cannot move');
|
|
263
|
-
return blocks;
|
|
264
|
-
}
|
|
265
|
-
console.log('[moveBlockToContainer] Block removed, now adding to container:', {
|
|
266
|
-
removedBlock: { id: removedBlock.id, type: removedBlock.type },
|
|
267
|
-
containerId,
|
|
268
|
-
newIndex,
|
|
269
|
-
});
|
|
270
|
-
// Handle column containers
|
|
271
|
-
const isColumnContainer = containerId.includes('-col-');
|
|
272
|
-
if (isColumnContainer) {
|
|
273
|
-
const [parentId, columnPart] = containerId.split('-col-');
|
|
274
|
-
const columnIndex = parseInt(columnPart || '0', 10);
|
|
275
|
-
removedBlock.meta = {
|
|
276
|
-
...removedBlock.meta,
|
|
277
|
-
columnIndex,
|
|
278
|
-
};
|
|
279
|
-
console.log('[moveBlockToContainer] Setting column index:', { columnIndex });
|
|
280
|
-
}
|
|
281
|
-
// Now add the block to the target container
|
|
282
|
-
const result = addBlockToContainer(updatedBlocks, containerId, removedBlock, newIndex);
|
|
283
|
-
console.log('[moveBlockToContainer] Move complete:', {
|
|
284
|
-
resultBlocks: result.map(b => ({ id: b.id, type: b.type })),
|
|
285
|
-
});
|
|
286
|
-
return result;
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Editor Reducer
|
|
290
|
-
* Handles all state transitions for the editor
|
|
291
|
-
*/
|
|
292
32
|
export function editorReducer(state, action) {
|
|
293
33
|
switch (action.type) {
|
|
294
34
|
case 'SET_BLOCKS':
|
|
295
|
-
return {
|
|
296
|
-
...state,
|
|
297
|
-
blocks: action.payload,
|
|
298
|
-
isDirty: true,
|
|
299
|
-
};
|
|
35
|
+
return { ...state, blocks: action.payload, isDirty: true };
|
|
300
36
|
case 'ADD_BLOCK': {
|
|
301
37
|
const { block, index, containerId } = action.payload;
|
|
38
|
+
const definition = blockRegistry.get(block.type);
|
|
302
39
|
const newBlock = {
|
|
303
40
|
...block,
|
|
304
41
|
id: block.id || generateBlockId(),
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
blocks
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
newBlocks.splice(index, 0, newBlock);
|
|
320
|
-
}
|
|
321
|
-
else {
|
|
322
|
-
newBlocks.push(newBlock);
|
|
323
|
-
}
|
|
324
|
-
return {
|
|
325
|
-
...state,
|
|
326
|
-
blocks: newBlocks,
|
|
327
|
-
selectedBlockId: newBlock.id,
|
|
328
|
-
isDirty: true,
|
|
329
|
-
};
|
|
42
|
+
// Initialize children as empty array if it's a container block
|
|
43
|
+
children: (definition?.isContainer && !block.children) ? [] : block.children
|
|
44
|
+
};
|
|
45
|
+
const updatedBlocks = containerId
|
|
46
|
+
? addNodeToContainer(state.blocks, containerId, newBlock, index)
|
|
47
|
+
: (() => {
|
|
48
|
+
const next = [...state.blocks];
|
|
49
|
+
if (index !== undefined && index >= 0 && index <= next.length)
|
|
50
|
+
next.splice(index, 0, newBlock);
|
|
51
|
+
else
|
|
52
|
+
next.push(newBlock);
|
|
53
|
+
return next;
|
|
54
|
+
})();
|
|
55
|
+
return { ...state, blocks: updatedBlocks, selectedBlockId: newBlock.id, isDirty: true };
|
|
330
56
|
}
|
|
331
57
|
case 'UPDATE_BLOCK': {
|
|
332
58
|
const { id, data } = action.payload;
|
|
333
|
-
// Check if block is at root level
|
|
334
|
-
const rootBlock = state.blocks.find(block => block.id === id);
|
|
335
|
-
if (rootBlock) {
|
|
336
|
-
const newBlocks = state.blocks.map(block => block.id === id
|
|
337
|
-
? {
|
|
338
|
-
...block,
|
|
339
|
-
data: { ...block.data, ...data },
|
|
340
|
-
}
|
|
341
|
-
: block);
|
|
342
|
-
return {
|
|
343
|
-
...state,
|
|
344
|
-
blocks: newBlocks,
|
|
345
|
-
isDirty: true,
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
|
-
// Otherwise, update nested block
|
|
349
|
-
const newBlocks = updateNestedBlock(state.blocks, id, data);
|
|
350
59
|
return {
|
|
351
60
|
...state,
|
|
352
|
-
blocks:
|
|
61
|
+
blocks: mapTree(state.blocks, node => node.id === id ? { ...node, data: { ...node.data, ...data } } : node),
|
|
353
62
|
isDirty: true,
|
|
354
63
|
};
|
|
355
64
|
}
|
|
356
65
|
case 'DELETE_BLOCK': {
|
|
357
66
|
const { id } = action.payload;
|
|
358
|
-
// Check if block is at root level
|
|
359
|
-
const rootBlock = state.blocks.find(block => block.id === id);
|
|
360
|
-
if (rootBlock) {
|
|
361
|
-
const newBlocks = state.blocks.filter(block => block.id !== id);
|
|
362
|
-
const wasSelected = state.selectedBlockId === id;
|
|
363
|
-
return {
|
|
364
|
-
...state,
|
|
365
|
-
blocks: newBlocks,
|
|
366
|
-
selectedBlockId: wasSelected ? null : state.selectedBlockId,
|
|
367
|
-
isDirty: true,
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
// Otherwise, delete nested block
|
|
371
|
-
const newBlocks = deleteNestedBlock(state.blocks, id);
|
|
372
|
-
const wasSelected = state.selectedBlockId === id;
|
|
373
67
|
return {
|
|
374
68
|
...state,
|
|
375
|
-
blocks:
|
|
376
|
-
selectedBlockId:
|
|
69
|
+
blocks: filterTree(state.blocks, node => node.id !== id),
|
|
70
|
+
selectedBlockId: state.selectedBlockId === id ? null : state.selectedBlockId,
|
|
377
71
|
isDirty: true,
|
|
378
72
|
};
|
|
379
73
|
}
|
|
380
74
|
case 'DUPLICATE_BLOCK': {
|
|
381
75
|
const { id } = action.payload;
|
|
382
|
-
const
|
|
383
|
-
if (
|
|
76
|
+
const blockToDup = findNode(state.blocks, id);
|
|
77
|
+
if (!blockToDup)
|
|
384
78
|
return state;
|
|
79
|
+
const duplicated = cloneBlock(blockToDup);
|
|
80
|
+
// 1. First find the parent container and current index
|
|
81
|
+
let targetContainerId = undefined;
|
|
82
|
+
let targetIndex = -1;
|
|
83
|
+
// Check root level
|
|
84
|
+
const rootIndex = state.blocks.findIndex(b => b.id === id);
|
|
85
|
+
if (rootIndex !== -1) {
|
|
86
|
+
targetIndex = rootIndex + 1;
|
|
385
87
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
88
|
+
else {
|
|
89
|
+
// Check nested levels to find parent and index
|
|
90
|
+
const findParentInfo = (nodes, parentId) => {
|
|
91
|
+
const idx = nodes.findIndex(n => n.id === id);
|
|
92
|
+
if (idx !== -1) {
|
|
93
|
+
targetContainerId = parentId;
|
|
94
|
+
targetIndex = idx + 1;
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
for (const node of nodes) {
|
|
98
|
+
if (node.children && Array.isArray(node.children) && typeof node.children[0] === 'object') {
|
|
99
|
+
if (findParentInfo(node.children, node.id))
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
};
|
|
105
|
+
findParentInfo(state.blocks);
|
|
106
|
+
}
|
|
107
|
+
if (targetIndex === -1)
|
|
108
|
+
return state;
|
|
109
|
+
const nextBlocks = targetContainerId
|
|
110
|
+
? addNodeToContainer(state.blocks, targetContainerId, duplicated, targetIndex)
|
|
111
|
+
: (() => {
|
|
112
|
+
const next = [...state.blocks];
|
|
113
|
+
next.splice(targetIndex, 0, duplicated);
|
|
114
|
+
return next;
|
|
115
|
+
})();
|
|
116
|
+
return { ...state, blocks: nextBlocks, selectedBlockId: duplicated.id, isDirty: true };
|
|
396
117
|
}
|
|
397
118
|
case 'MOVE_BLOCK': {
|
|
398
119
|
const { id, newIndex, containerId: rawContainerId } = action.payload;
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
// First check if block is already in this container
|
|
411
|
-
const containerBlock = findBlockById(state.blocks, containerId);
|
|
412
|
-
console.log('[Reducer] Container lookup:', {
|
|
413
|
-
containerId,
|
|
414
|
-
found: !!containerBlock,
|
|
415
|
-
hasChildren: containerBlock?.children ? Array.isArray(containerBlock.children) : false,
|
|
416
|
-
});
|
|
417
|
-
if (containerBlock && containerBlock.children && Array.isArray(containerBlock.children)) {
|
|
418
|
-
const children = typeof containerBlock.children[0] === 'object'
|
|
419
|
-
? containerBlock.children
|
|
420
|
-
: [];
|
|
421
|
-
const currentIndex = children.findIndex(b => b.id === id);
|
|
422
|
-
console.log('[Reducer] Block in container check:', {
|
|
423
|
-
blockId: id,
|
|
424
|
-
currentIndex,
|
|
425
|
-
containerChildren: children.map(b => ({ id: b.id, type: b.type })),
|
|
426
|
-
});
|
|
427
|
-
if (currentIndex !== -1) {
|
|
428
|
-
// Block is already in this container - move within container
|
|
429
|
-
console.log('[Reducer] Moving within container');
|
|
430
|
-
const newBlocks = moveNestedBlock(state.blocks, containerId, id, newIndex);
|
|
431
|
-
console.log('[Reducer] After move within container:', {
|
|
432
|
-
newRootBlocks: newBlocks.map(b => ({ id: b.id, type: b.type })),
|
|
433
|
-
});
|
|
434
|
-
return {
|
|
435
|
-
...state,
|
|
436
|
-
blocks: newBlocks,
|
|
437
|
-
isDirty: true,
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
// Block is not in this container - move it from wherever it is (root or nested)
|
|
442
|
-
console.log('[Reducer] Moving block to container from elsewhere');
|
|
443
|
-
const newBlocks = moveBlockToContainer(state.blocks, id, containerId, newIndex);
|
|
444
|
-
console.log('[Reducer] After move to container:', {
|
|
445
|
-
newRootBlocks: newBlocks.map(b => ({ id: b.id, type: b.type })),
|
|
446
|
-
});
|
|
447
|
-
return {
|
|
448
|
-
...state,
|
|
449
|
-
blocks: newBlocks,
|
|
450
|
-
isDirty: true,
|
|
451
|
-
};
|
|
120
|
+
const containerId = rawContainerId === 'root' ? undefined : rawContainerId;
|
|
121
|
+
// CRITICAL: Prevent moving a block into itself!
|
|
122
|
+
if (id === containerId) {
|
|
123
|
+
console.warn('[Reducer] MOVE_BLOCK aborted: Cannot move a block into itself', id);
|
|
124
|
+
return state;
|
|
125
|
+
}
|
|
126
|
+
// 1. Remove from current position
|
|
127
|
+
const { updatedNodes: afterRemove, removedNode } = removeNode(state.blocks, id);
|
|
128
|
+
if (!removedNode) {
|
|
129
|
+
console.error('[Reducer] MOVE_BLOCK failed: Node not found', id);
|
|
130
|
+
return state;
|
|
452
131
|
}
|
|
453
|
-
//
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
newIndex,
|
|
460
|
-
rootBlocksCount: state.blocks.length,
|
|
461
|
-
});
|
|
462
|
-
if (currentIndex !== -1) {
|
|
463
|
-
// Block is already at root level - move within root
|
|
464
|
-
if (newIndex < 0 || newIndex >= state.blocks.length) {
|
|
465
|
-
console.warn('[Reducer] Invalid newIndex for root move:', { newIndex, blocksLength: state.blocks.length });
|
|
466
|
-
return state;
|
|
132
|
+
// 2. Clear meta if moving to root
|
|
133
|
+
if (!containerId) {
|
|
134
|
+
if (removedNode.meta) {
|
|
135
|
+
const newMeta = { ...removedNode.meta };
|
|
136
|
+
delete newMeta.columnIndex;
|
|
137
|
+
removedNode.meta = newMeta;
|
|
467
138
|
}
|
|
468
|
-
console.log('[Reducer] Moving within root level');
|
|
469
|
-
const newBlocks = [...state.blocks];
|
|
470
|
-
const [movedBlock] = newBlocks.splice(currentIndex, 1);
|
|
471
|
-
newBlocks.splice(newIndex, 0, movedBlock);
|
|
472
|
-
console.log('[Reducer] After move within root:', {
|
|
473
|
-
newRootBlocks: newBlocks.map(b => ({ id: b.id, type: b.type })),
|
|
474
|
-
});
|
|
475
|
-
return {
|
|
476
|
-
...state,
|
|
477
|
-
blocks: newBlocks,
|
|
478
|
-
isDirty: true,
|
|
479
|
-
};
|
|
480
139
|
}
|
|
481
|
-
//
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
140
|
+
// 3. Add to new position with fallback
|
|
141
|
+
try {
|
|
142
|
+
const finalBlocks = containerId
|
|
143
|
+
? addNodeToContainer(afterRemove, containerId, removedNode, newIndex)
|
|
144
|
+
: (() => {
|
|
145
|
+
const next = [...afterRemove];
|
|
146
|
+
const safeIndex = Math.max(0, Math.min(newIndex, next.length));
|
|
147
|
+
next.splice(safeIndex, 0, removedNode);
|
|
148
|
+
return next;
|
|
149
|
+
})();
|
|
150
|
+
return { ...state, blocks: finalBlocks, isDirty: true };
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
console.error('[Reducer] MOVE_BLOCK failed to add to container:', error);
|
|
154
|
+
// CRITICAL FALLBACK: Re-insert at root so it doesn't disappear
|
|
155
|
+
const fallbackBlocks = [...afterRemove];
|
|
156
|
+
fallbackBlocks.push(removedNode);
|
|
157
|
+
return { ...state, blocks: fallbackBlocks, isDirty: true };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
case 'SET_TITLE': {
|
|
161
|
+
const title = action.payload;
|
|
162
|
+
const status = state.status;
|
|
163
|
+
let slug = slugify(title);
|
|
164
|
+
// Add draft suffix if not published to match API behavior
|
|
165
|
+
if (status !== 'published' && slug) {
|
|
166
|
+
// If it already has a draft suffix, keep it or generate new one
|
|
167
|
+
if (!state.slug.includes('-draft-')) {
|
|
168
|
+
slug = `${slug}-draft-${Date.now().toString().slice(-4)}`;
|
|
500
169
|
}
|
|
501
170
|
else {
|
|
502
|
-
|
|
171
|
+
// Just update the base part of the draft slug
|
|
172
|
+
const suffix = state.slug.split('-draft-')[1];
|
|
173
|
+
slug = `${slug}-draft-${suffix}`;
|
|
503
174
|
}
|
|
504
|
-
console.log('[Reducer] After move nested to root:', {
|
|
505
|
-
newRootBlocks: newBlocks.map(b => ({ id: b.id, type: b.type })),
|
|
506
|
-
insertedAt: newIndex >= 0 && newIndex <= updatedBlocks.length ? newIndex : newBlocks.length - 1,
|
|
507
|
-
});
|
|
508
|
-
return {
|
|
509
|
-
...state,
|
|
510
|
-
blocks: newBlocks,
|
|
511
|
-
isDirty: true,
|
|
512
|
-
};
|
|
513
175
|
}
|
|
514
|
-
|
|
515
|
-
return state;
|
|
176
|
+
return { ...state, title, slug, isDirty: true };
|
|
516
177
|
}
|
|
517
|
-
case '
|
|
178
|
+
case 'SET_SLUG': return { ...state, slug: action.payload, isDirty: true };
|
|
179
|
+
case 'SET_SEO': return { ...state, seo: { ...state.seo, ...action.payload }, isDirty: true };
|
|
180
|
+
case 'SET_METADATA': return { ...state, metadata: { ...state.metadata, ...action.payload }, isDirty: true };
|
|
181
|
+
case 'SET_STATUS': return { ...state, status: action.payload, isDirty: true };
|
|
182
|
+
case 'SET_FOCUS_MODE': return { ...state, focusMode: action.payload };
|
|
183
|
+
case 'SELECT_BLOCK': return { ...state, selectedBlockId: action.payload };
|
|
184
|
+
case 'DESELECT_BLOCK':
|
|
518
185
|
return {
|
|
519
186
|
...state,
|
|
520
|
-
|
|
521
|
-
isDirty: true,
|
|
522
|
-
};
|
|
523
|
-
case 'SET_SLUG':
|
|
524
|
-
return {
|
|
525
|
-
...state,
|
|
526
|
-
slug: action.payload,
|
|
527
|
-
isDirty: true,
|
|
528
|
-
};
|
|
529
|
-
case 'SET_SEO':
|
|
530
|
-
return {
|
|
531
|
-
...state,
|
|
532
|
-
seo: { ...state.seo, ...action.payload },
|
|
533
|
-
isDirty: true,
|
|
534
|
-
};
|
|
535
|
-
case 'SET_METADATA':
|
|
536
|
-
return {
|
|
537
|
-
...state,
|
|
538
|
-
metadata: { ...state.metadata, ...action.payload },
|
|
539
|
-
isDirty: true,
|
|
540
|
-
};
|
|
541
|
-
case 'SET_STATUS':
|
|
542
|
-
return {
|
|
543
|
-
...state,
|
|
544
|
-
status: action.payload,
|
|
545
|
-
isDirty: true,
|
|
546
|
-
};
|
|
547
|
-
case 'SET_FOCUS_MODE':
|
|
548
|
-
return {
|
|
549
|
-
...state,
|
|
550
|
-
focusMode: action.payload,
|
|
551
|
-
};
|
|
552
|
-
case 'SELECT_BLOCK':
|
|
553
|
-
return {
|
|
554
|
-
...state,
|
|
555
|
-
selectedBlockId: action.payload,
|
|
556
|
-
};
|
|
557
|
-
case 'SET_DRAGGED_BLOCK':
|
|
558
|
-
return {
|
|
559
|
-
...state,
|
|
560
|
-
draggedBlockId: action.payload,
|
|
187
|
+
selectedBlockId: state.selectedBlockId === action.payload ? null : state.selectedBlockId
|
|
561
188
|
};
|
|
189
|
+
case 'SET_DRAGGED_BLOCK': return { ...state, draggedBlockId: action.payload };
|
|
190
|
+
case 'MARK_CLEAN': return { ...state, isDirty: false };
|
|
191
|
+
case 'MARK_DIRTY': return { ...state, isDirty: true };
|
|
192
|
+
case 'SET_CURRENT_LANGUAGE': return { ...state, currentLanguage: action.payload };
|
|
562
193
|
case 'LOAD_POST': {
|
|
563
194
|
const post = action.payload;
|
|
564
195
|
return {
|
|
@@ -574,31 +205,7 @@ export function editorReducer(state, action) {
|
|
|
574
205
|
selectedBlockId: null,
|
|
575
206
|
};
|
|
576
207
|
}
|
|
577
|
-
case 'RESET_EDITOR':
|
|
578
|
-
|
|
579
|
-
...initialEditorState,
|
|
580
|
-
};
|
|
581
|
-
case 'MARK_CLEAN':
|
|
582
|
-
return {
|
|
583
|
-
...state,
|
|
584
|
-
isDirty: false,
|
|
585
|
-
};
|
|
586
|
-
case 'MARK_DIRTY':
|
|
587
|
-
return {
|
|
588
|
-
...state,
|
|
589
|
-
isDirty: true,
|
|
590
|
-
};
|
|
591
|
-
case 'SET_CURRENT_LANGUAGE':
|
|
592
|
-
return {
|
|
593
|
-
...state,
|
|
594
|
-
currentLanguage: action.payload,
|
|
595
|
-
};
|
|
596
|
-
case 'UNDO':
|
|
597
|
-
case 'REDO':
|
|
598
|
-
case 'SAVE_HISTORY':
|
|
599
|
-
// These are handled by the context, not the reducer
|
|
600
|
-
return state;
|
|
601
|
-
default:
|
|
602
|
-
return state;
|
|
208
|
+
case 'RESET_EDITOR': return { ...initialEditorState };
|
|
209
|
+
default: return state;
|
|
603
210
|
}
|
|
604
211
|
}
|