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