@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
package/src/index.tsx CHANGED
@@ -1,14 +1,12 @@
1
1
  /**
2
2
  * Plugin Blog - Main Entry Point
3
- * Block-Based Blog Management System
4
- * Multi-Tenant Architecture: Accepts custom blocks from client applications
3
+ * Simplified with Configuration Resolver
5
4
  */
6
5
 
7
6
  'use client';
8
7
 
9
8
  import React, { useMemo, useEffect } from 'react';
10
9
  import { EditorProvider } from './state/EditorContext';
11
- import { ClientBlockDefinition } from './types/block';
12
10
  import { PostManagerView } from './views/PostManager';
13
11
  import { CanvasEditorView } from './views/CanvasEditor';
14
12
  import { editorStateToAPI } from './lib/mappers/apiMapper';
@@ -16,324 +14,112 @@ import { SlugSEOManagerView } from './views/SlugSEO';
16
14
  import { PreviewBridgeView } from './views/Preview';
17
15
  import { SettingsView } from './views/Settings';
18
16
  import { useHeroBlockValidation, findHeroBlock } from './lib/utils/configValidation';
17
+ import { resolvePluginConfig } from './lib/utils/config-resolver';
18
+ import { ClientBlockDefinition } from './types/block';
19
19
 
20
- /**
21
- * Plugin Props Interface
22
- * Matches the PluginProps from @jhits/jhits-dashboard
23
- */
24
20
  export interface PluginProps {
25
21
  subPath: string[];
26
22
  siteId: string;
27
23
  locale: string;
28
- /** Custom blocks from client application (optional, can also come from window.__JHITS_PLUGIN_PROPS__) */
29
24
  customBlocks?: ClientBlockDefinition[];
30
- /** Enable dark mode for content area and wrappers (default: true) */
31
25
  darkMode?: boolean;
32
- /** Background colors for the editor */
33
- backgroundColors?: {
34
- /** Background color for light mode (REQUIRED) */
35
- light: string;
36
- /** Background color for dark mode (optional) */
37
- dark?: string;
38
- };
26
+ backgroundColors?: { light: string; dark?: string };
27
+ LayoutWrapper?: React.ComponentType<any>;
28
+ translations?: Record<string, any>;
39
29
  }
40
30
 
41
31
  /**
42
- * Main Router Component
43
- * Handles routing within the blog plugin
44
- *
45
- * Client Handshake:
46
- * - Client apps can pass customBlocks via props
47
- * - Or via window.__JHITS_PLUGIN_PROPS__['plugin-blog'].customBlocks
48
- * - The EditorProvider will automatically register these blocks
32
+ * Client-facing configuration type
33
+ * Allows partial overrides of plugin behavior
49
34
  */
35
+ export type BlogPluginConfig = Partial<Omit<PluginProps, 'subPath' | 'siteId' | 'locale'>> & {
36
+ customBlocks?: ClientBlockDefinition[];
37
+ darkMode?: boolean;
38
+ backgroundColors?: { light: string; dark?: string };
39
+ LayoutWrapper?: React.ComponentType<any>;
40
+ translations?: Record<string, any>;
41
+ };
42
+
50
43
  export default function BlogPlugin(props: PluginProps) {
51
- const { subPath, siteId, locale, customBlocks: propsCustomBlocks, darkMode: propsDarkMode, backgroundColors: propsBackgroundColors } = props;
52
-
53
- // Get custom blocks from props or window global (client app injection point)
54
- const customBlocks = useMemo(() => {
55
- // First, try props
56
- if (propsCustomBlocks && propsCustomBlocks.length > 0) {
57
- return propsCustomBlocks;
58
- }
59
-
60
- // Fallback to window global (for client app injection)
61
- if (typeof window !== 'undefined' && (window as any).__JHITS_PLUGIN_PROPS__) {
62
- const pluginProps = (window as any).__JHITS_PLUGIN_PROPS__['plugin-blog'];
63
- if (pluginProps?.customBlocks) {
64
- return pluginProps.customBlocks as ClientBlockDefinition[];
65
- }
66
- }
67
-
68
- return [];
69
- }, [propsCustomBlocks]);
70
-
71
- // Get dark mode setting from props, localStorage (dev settings), or window global
72
- // Priority: localStorage (dev) > props > window global > default
73
- const darkMode = useMemo(() => {
74
- // First, check localStorage for dev settings (highest priority for dev)
75
- if (typeof window !== 'undefined') {
76
- try {
77
- const saved = localStorage.getItem('__JHITS_PLUGIN_BLOG_CONFIG__');
78
- if (saved) {
79
- const config = JSON.parse(saved);
80
- if (config.darkMode !== undefined) {
81
- return config.darkMode as boolean;
82
- }
83
- }
84
- } catch (e) {
85
- // Ignore localStorage errors
86
- }
87
- }
88
-
89
- // Then try props
90
- if (propsDarkMode !== undefined) {
91
- return propsDarkMode;
92
- }
93
-
94
- // Fallback to window global if prop not provided
95
- if (typeof window !== 'undefined' && (window as any).__JHITS_PLUGIN_PROPS__) {
96
- const pluginProps = (window as any).__JHITS_PLUGIN_PROPS__['plugin-blog'];
97
- if (pluginProps?.darkMode !== undefined) {
98
- return pluginProps.darkMode as boolean;
99
- }
100
- }
101
-
102
- return true; // Default to dark mode enabled
103
- }, [propsDarkMode]);
104
-
105
- // Get background colors from props, localStorage (dev settings), or window global
106
- // Priority: localStorage (dev) > props > window global
107
- const backgroundColors = useMemo(() => {
108
- // First, check localStorage for dev settings (highest priority for dev)
109
- if (typeof window !== 'undefined') {
110
- try {
111
- const saved = localStorage.getItem('__JHITS_PLUGIN_BLOG_CONFIG__');
112
- if (saved) {
113
- const config = JSON.parse(saved);
114
- if (config.backgroundColors) {
115
- return config.backgroundColors;
116
- }
117
- }
118
- } catch (e) {
119
- // Ignore localStorage errors
120
- }
121
- }
122
-
123
- // Then try props
124
- if (propsBackgroundColors) {
125
- return propsBackgroundColors;
126
- }
127
-
128
- // Fallback to window global
129
- if (typeof window !== 'undefined' && (window as any).__JHITS_PLUGIN_PROPS__) {
130
- const pluginProps = (window as any).__JHITS_PLUGIN_PROPS__['plugin-blog'];
131
- if (pluginProps?.backgroundColors) {
132
- return pluginProps.backgroundColors as { light: string; dark?: string };
133
- }
134
- }
135
-
136
- return undefined;
137
- }, [propsBackgroundColors]);
44
+ const { subPath, siteId, locale } = props;
138
45
 
46
+ // Resolve configuration from multiple sources (Props, Window, Storage)
47
+ const config = useMemo(() => resolvePluginConfig(props), [props]);
139
48
  const route = subPath[0] || 'posts';
140
49
 
141
- // Validate hero block configuration (only checks when needed)
142
- useHeroBlockValidation(route, customBlocks, propsCustomBlocks);
50
+ // Validate hero block configuration
51
+ useHeroBlockValidation(route, config.customBlocks, props.customBlocks);
143
52
 
144
- // Get hero block definition for logging/debugging (only for routes that need it)
145
- const heroBlockDefinition = useMemo(() => {
146
- const needsHeroBlock = route === 'editor' || route === 'new' || route === 'preview';
147
- return needsHeroBlock ? findHeroBlock(customBlocks) : undefined;
148
- }, [customBlocks, route]);
149
-
150
- // Listen for config updates from settings screen
53
+ // Listen for config updates from settings
151
54
  useEffect(() => {
152
55
  if (typeof window === 'undefined') return;
153
-
154
- const handleConfigUpdate = () => {
155
- // Reload page to apply changes (simplest way to ensure all components pick up new values)
156
- window.location.reload();
157
- };
158
-
56
+ const handleConfigUpdate = () => window.location.reload();
159
57
  window.addEventListener('blog-plugin-config-updated', handleConfigUpdate as EventListener);
160
- return () => {
161
- window.removeEventListener('blog-plugin-config-updated', handleConfigUpdate as EventListener);
162
- };
58
+ return () => window.removeEventListener('blog-plugin-config-updated', handleConfigUpdate as EventListener);
163
59
  }, []);
164
-
165
- if (heroBlockDefinition !== undefined) {
166
- console.log('[BlogPlugin] Hero block definition:', heroBlockDefinition ? 'found' : 'not found (REQUIRED)');
167
- }
168
60
 
169
- // Route to appropriate view
61
+ // Helper to render editor with provider
62
+ const renderEditor = (postId?: string) => (
63
+ <EditorProvider
64
+ customBlocks={config.customBlocks}
65
+ darkMode={config.darkMode}
66
+ backgroundColors={config.backgroundColors}
67
+ translations={config.translations}
68
+ onSave={async (state, heroBlock) => {
69
+ const originalSlug = postId || state.slug || state.postId;
70
+ if (!originalSlug && route !== 'new') throw new Error('No post identifier');
71
+
72
+ const apiData = editorStateToAPI(state, undefined, heroBlock);
73
+ const isNew = route === 'new';
74
+ const url = isNew ? '/api/plugin-blog/new' : `/api/plugin-blog/${originalSlug}`;
75
+
76
+ const response = await fetch(`${url}?language=${state.currentLanguage || locale}`, {
77
+ method: isNew ? 'POST' : 'PUT',
78
+ headers: { 'Content-Type': 'application/json' },
79
+ credentials: 'include',
80
+ body: JSON.stringify(apiData),
81
+ });
82
+
83
+ if (!response.ok) throw new Error('Save failed');
84
+ const result = await response.json();
85
+ if (result.slug && result.slug !== originalSlug) {
86
+ window.history.replaceState(null, '', `/dashboard/blog/editor/${result.slug}`);
87
+ }
88
+ return result;
89
+ }}
90
+ >
91
+ <CanvasEditorView
92
+ postId={postId || undefined}
93
+ siteId={siteId}
94
+ locale={locale}
95
+ LayoutWrapper={config.LayoutWrapper}
96
+ />
97
+ </EditorProvider>
98
+ );
99
+
170
100
  switch (route) {
171
- case 'posts':
172
- return <PostManagerView siteId={siteId} locale={locale} />;
173
-
174
- case 'editor':
175
- const postId = subPath[1]; // This is actually the slug, not the ID
176
- return (
177
- <EditorProvider
178
- customBlocks={customBlocks}
179
- darkMode={darkMode}
180
- backgroundColors={backgroundColors}
181
- onSave={async (state, heroBlock) => {
182
- // Save to API - update existing post
183
- // Use the route postId (original slug) to identify which blog to update
184
- // If route postId is missing, use state.slug or state.postId as fallback
185
- const originalSlug = postId || state.slug || state.postId;
186
- if (!originalSlug) {
187
- throw new Error('Cannot save: no post identifier available. Please reload the page.');
188
- }
189
- const language = state.currentLanguage || locale;
190
- console.log('[BlogPlugin] Saving post with slug:', originalSlug, 'language:', language);
191
- const apiData = editorStateToAPI(state, undefined, heroBlock);
192
- const response = await fetch(`/api/plugin-blog/${originalSlug}?language=${language}`, {
193
- method: 'PUT',
194
- headers: { 'Content-Type': 'application/json' },
195
- credentials: 'include', // Include cookies for authentication
196
- body: JSON.stringify(apiData),
197
- });
198
- if (!response.ok) {
199
- const error = await response.json();
200
- console.error('[BlogPlugin] Save failed:', {
201
- status: response.status,
202
- statusText: response.statusText,
203
- error,
204
- missingFields: error.missingFields,
205
- });
206
- // Provide more detailed error message if available
207
- const errorMessage = error.message || error.error || 'Failed to save post';
208
- const missingFieldsMsg = error.missingFields && error.missingFields.length > 0
209
- ? ` Missing: ${error.missingFields.join(', ')}`
210
- : '';
211
- throw new Error(errorMessage + missingFieldsMsg);
212
- }
213
- const result = await response.json();
214
- // If the slug changed, update the URL
215
- if (result.slug && result.slug !== originalSlug) {
216
- window.history.replaceState(null, '', `/dashboard/blog/editor/${result.slug}`);
217
- }
218
- return result;
219
- }}
220
- >
221
- <CanvasEditorView postId={postId} siteId={siteId} locale={locale} darkMode={darkMode} backgroundColors={backgroundColors} />
222
- </EditorProvider>
223
- );
224
-
225
- case 'new':
226
- return (
227
- <EditorProvider
228
- customBlocks={customBlocks}
229
- darkMode={darkMode}
230
- backgroundColors={backgroundColors}
231
- onSave={async (state) => {
232
- // Save to API - create new post
233
- const language = state.currentLanguage || locale;
234
- const apiData = editorStateToAPI(state);
235
- const response = await fetch(`/api/plugin-blog/new?language=${language}`, {
236
- method: 'POST',
237
- headers: { 'Content-Type': 'application/json' },
238
- credentials: 'include', // Include cookies for authentication
239
- body: JSON.stringify(apiData),
240
- });
241
- if (!response.ok) {
242
- const error = await response.json();
243
- throw new Error(error.message || 'Failed to create post');
244
- }
245
- const result = await response.json();
246
- // Update the URL to the new post's slug
247
- if (result.slug) {
248
- window.history.replaceState(null, '', `/dashboard/blog/editor/${result.slug}`);
249
- }
250
- return result;
251
- }}
252
- >
253
- <CanvasEditorView siteId={siteId} locale={locale} darkMode={darkMode} backgroundColors={backgroundColors} />
254
- </EditorProvider>
255
- );
256
-
257
- case 'seo':
258
- const seoPostId = subPath[1];
259
- return <SlugSEOManagerView postId={seoPostId} siteId={siteId} locale={locale} />;
260
-
261
- case 'preview':
262
- const previewPostId = subPath[1];
263
- return <PreviewBridgeView postId={previewPostId} siteId={siteId} locale={locale} />;
264
-
101
+ case 'posts': return <PostManagerView siteId={siteId} locale={locale} />;
102
+ case 'editor': return renderEditor(subPath[1]);
103
+ case 'new': return renderEditor();
104
+ case 'seo': return <SlugSEOManagerView postId={subPath[1]} siteId={siteId} locale={locale} />;
105
+ case 'preview': return <PreviewBridgeView postId={subPath[1]} siteId={siteId} locale={locale} />;
265
106
  case 'settings':
266
- case 'install':
267
- return <SettingsView siteId={siteId} locale={locale} />;
268
-
269
- default:
270
- return <PostManagerView siteId={siteId} locale={locale} />;
107
+ case 'install': return <SettingsView siteId={siteId} locale={locale} />;
108
+ default: return <PostManagerView siteId={siteId} locale={locale} />;
271
109
  }
272
110
  }
273
111
 
274
-
275
- // Export for use as default
276
112
  export { BlogPlugin as Index };
277
-
278
- // Export types for client applications
279
- export type {
280
- Block,
281
- BlockTypeDefinition,
282
- ClientBlockDefinition,
283
- RichTextFormattingConfig,
284
- BlockEditProps,
285
- BlockPreviewProps,
286
- IBlockComponent,
287
- } from './types';
288
-
289
- // Export post types
290
- export type {
291
- SEOMetadata,
292
- PublicationData,
293
- PostStatus,
294
- PostMetadata,
295
- BlogPost,
296
- PostListItem,
297
- PostFilterOptions,
298
- BlogPostLanguageContent,
299
- BlogPostLanguages,
300
- } from './types/post';
301
-
302
- // Export initialization utility for easy setup
113
+ // ... Re-export other symbols as needed (keeping existing exports from original file)
114
+ export type { Block, ClientBlockDefinition, BlockEditProps, BlockPreviewProps, BlockTypeDefinition, IBlockComponent } from './types';
115
+ export type { SEOMetadata, PublicationData, BlogPost, PostListItem, PostStatus } from './types';
303
116
  export { initBlogPlugin } from './init';
304
- export type { BlogPluginConfig } from './init';
305
-
306
- // Export rich text components for client applications
307
117
  export { RichTextEditor, RichTextPreview } from './lib/rich-text';
308
- export type { RichTextEditorProps, RichTextPreviewProps } from './lib/rich-text';
309
-
310
- // Export hooks for client applications
311
- export { useBlogs, useBlog } from './hooks';
312
- export type { UseBlogsOptions, UseBlogsResult, UseBlogOptions, UseBlogResult } from './hooks';
313
-
314
- // Export client utilities
315
- export { fetchBlogs, fetchBlog } from './utils/client';
316
- export type { FetchBlogsOptions, FetchBlogsResult, FetchBlogOptions } from './utils/client';
317
-
318
- // Export block rendering components
319
- export { BlockRenderer, BlocksRenderer } from './lib/blocks/BlockRenderer';
320
-
321
- // Export block registry
118
+ export { useBlogs, useBlog, useCategories } from './hooks';
322
119
  export { blockRegistry } from './registry';
323
-
324
- // Export layout block registration
325
- export { registerLayoutBlocks } from './lib/layouts/registerLayoutBlocks';
326
-
327
- // Export config storage utilities
328
- export { getPluginConfig, savePluginConfig } from './lib/config-storage';
329
-
330
- // Export editor state management
331
120
  export { EditorProvider, useEditor } from './state/EditorContext';
332
- export type { EditorProviderProps, EditorState, EditorContextValue } from './state';
333
-
334
- // Export hooks
335
- export { useCategories } from './hooks/useCategories';
336
-
337
- // Note: API handlers are server-only and exported from ./index.ts (server entry point)
338
- // They are NOT exported here to prevent client/server context mixing
339
-
121
+ export type { EditorProviderProps } from './state/EditorContext';
122
+ export type { EditorState, EditorContextValue } from './state/types';
123
+ export { BlockRenderer, BlocksRenderer } from './lib/blocks/BlockRenderer';
124
+ export { ColumnsPreview } from './lib/layouts/blocks/ColumnsBlock';
125
+ export { registerLayoutBlocks } from './lib/layouts/registerLayoutBlocks';
package/src/init.tsx CHANGED
@@ -32,17 +32,29 @@ export interface BlogPluginConfig {
32
32
  /** Background color for dark mode (optional) - CSS color value (hex, rgb, or named color) */
33
33
  dark?: string;
34
34
  };
35
- }
35
+ /** Optional layout wrapper for 1:1 preview (injected by client app) */
36
+ LayoutWrapper?: React.ComponentType<{
37
+ children: React.ReactNode;
38
+ header?: React.ReactNode;
39
+ footer?: React.ReactNode;
40
+ title?: string;
41
+ excerpt?: string;
42
+ category?: string;
43
+ date?: string;
44
+ thumbnail?: string;
45
+ isPreview?: boolean;
46
+ }>;
47
+ }
36
48
 
37
- /**
38
- * Initialize the blog plugin with client configuration
39
- *
40
- * This function sets up the window global that the plugin reads from automatically.
41
- * Call this once when your app loads, before the plugin is rendered.
42
- *
43
- * @param config - Blog plugin configuration (customBlocks, darkMode, etc.)
44
- */
45
- export function initBlogPlugin(config: BlogPluginConfig): void {
49
+ /**
50
+ * Initialize the blog plugin with client configuration
51
+ *
52
+ * This function sets up the window global that the plugin reads from automatically.
53
+ * Call this once when your app loads, before the plugin is rendered.
54
+ *
55
+ * @param config - Blog plugin configuration (customBlocks, darkMode, etc.)
56
+ */
57
+ export function initBlogPlugin(config: BlogPluginConfig): void {
46
58
  if (typeof window === 'undefined') {
47
59
  // Server-side: no-op
48
60
  return;
@@ -58,6 +70,7 @@ export function initBlogPlugin(config: BlogPluginConfig): void {
58
70
  customBlocks: config.customBlocks || [],
59
71
  darkMode: config.darkMode !== undefined ? config.darkMode : true, // Default to true
60
72
  backgroundColors: config.backgroundColors || undefined,
73
+ LayoutWrapper: config.LayoutWrapper || undefined,
61
74
  };
62
- }
75
+ }
63
76
 
@@ -123,6 +123,7 @@ export function BlocksRenderer({
123
123
  renderProps,
124
124
  wrapper: Wrapper,
125
125
  }: BlocksRendererProps) {
126
+
126
127
  const content = blocks.map((block, index) => (
127
128
  <BlockRenderer
128
129
  key={block.id || index}