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