@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,7 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import React, { useState } from 'react';
4
- import { ArrowLeft, Library, Settings2, Save, Clock, Edit, Eye, Globe, Plus, ChevronDown } from 'lucide-react';
4
+ import { ArrowLeft, Library, Settings2, Save, Clock, Edit, Eye, Globe, Plus, ChevronDown, CheckCircle2 } from 'lucide-react';
5
5
  import { useEditor } from '../../state/EditorContext';
6
6
  import { SaveConfirmationModal } from './SaveConfirmationModal';
7
7
 
@@ -61,268 +61,249 @@ export function EditorHeader({
61
61
  es: 'Español',
62
62
  };
63
63
 
64
- const availableToAdd = ['en', 'nl', 'sv', 'de', 'fr', 'es'].filter(lang => !languages.includes(lang));
64
+ const getFlagUrl = (lang: string) => {
65
+ const mapping: Record<string, string> = {
66
+ en: 'gb', nl: 'nl', sv: 'se', de: 'de', fr: 'fr', es: 'es'
67
+ };
68
+ return `https://flagcdn.com/w40/${(mapping[lang] || lang).toLowerCase()}.png`;
69
+ };
70
+
71
+ const allCreatedLanguages = Array.from(new Set([...languages, currentLanguage]));
72
+ const availableToAdd = ['en', 'nl', 'sv', 'de', 'fr', 'es'].filter(lang => !allCreatedLanguages.includes(lang));
73
+
74
+
65
75
 
66
76
  const handleSaveDraftClick = () => {
67
77
  setSaveAsDraft(true);
68
- setSaveError(null); // Clear any previous errors
78
+ setSaveError(null);
69
79
  setShowConfirmModal(true);
70
80
  };
71
81
 
72
82
  const handlePublishClick = () => {
73
83
  setSaveAsDraft(false);
74
- setSaveError(null); // Clear any previous errors
84
+ setSaveError(null);
75
85
  setShowConfirmModal(true);
76
86
  };
77
87
 
78
88
  const handleConfirmSave = async () => {
79
89
  try {
80
- const targetStatus = saveAsDraft ? 'draft' : 'published';
81
- console.log('[EditorHeader] Starting save process...', { saveAsDraft, targetStatus, currentStatus: state.status });
82
-
83
- // Set status before saving - ensure state is updated
84
90
  if (saveAsDraft) {
85
91
  dispatch({ type: 'SET_STATUS', payload: 'draft' });
86
92
  } else {
87
93
  dispatch({ type: 'SET_STATUS', payload: 'published' });
88
94
  }
89
-
90
- // Wait longer to ensure state update propagates through the reducer and context
91
- // React state updates are asynchronous, so we need to wait for the state to actually update
92
95
  await new Promise(resolve => setTimeout(resolve, 150));
93
-
94
- // Verify status was updated
95
- console.log('[EditorHeader] Status after update:', state.status, 'Expected:', targetStatus);
96
-
97
96
  await onSave(!saveAsDraft);
98
- console.log('[EditorHeader] Post saved successfully');
99
- // Clear any previous errors
100
97
  setSaveError(null);
101
- // Modal will show success message and close automatically
102
98
  } catch (error: any) {
103
- console.error('[EditorHeader] Failed to save post:', error);
104
- // Extract user-friendly error message
105
99
  let errorMessage = error.message || 'Failed to save post';
106
-
107
- // Make error messages more user-friendly
108
- if (errorMessage.includes('Missing required fields')) {
109
- // Keep the detailed message about missing fields
110
- errorMessage = errorMessage.replace('Missing required fields for publishing:', 'To publish, please fill in:');
111
- } else if (errorMessage.includes('All required fields')) {
112
- errorMessage = 'To publish, please fill in all required fields: summary, featured image, category, and content.';
113
- } else if (errorMessage.includes('Unauthorized')) {
114
- errorMessage = 'You are not authorized to save this post. Please log in again.';
115
- } else if (errorMessage.includes('Failed to save')) {
116
- errorMessage = 'Unable to save the post. Please check your connection and try again.';
117
- }
118
-
119
100
  setSaveError(errorMessage);
120
101
  onSaveError(errorMessage);
121
- // Re-throw the error so the modal knows it failed and doesn't show success
122
102
  throw error;
123
103
  }
124
104
  };
125
105
 
126
106
  return (
127
- <div className="flex items-center justify-between px-6 py-3 bg-dashboard-sidebar backdrop-blur-md border-b border-dashboard-border flex-none shrink-0">
128
- <div className="flex items-center gap-6">
107
+ <div className="flex items-center justify-between px-4 lg:px-8 py-3 lg:py-4 bg-dashboard-bg/80 backdrop-blur-xl border-b border-dashboard-border/50 flex-none shrink-0 z-50">
108
+ {/* Left Section: Navigation & Library */}
109
+ <div className="flex items-center gap-3 lg:gap-6">
129
110
  <button
130
111
  onClick={() => {
131
112
  if (isDirty) {
132
- const confirmed = window.confirm(
133
- 'You have unsaved changes. Are you sure you want to leave? Your changes will be lost.'
134
- );
135
- if (!confirmed) {
136
- return;
137
- }
113
+ if (!window.confirm('You have unsaved changes. Leave anyway?')) return;
138
114
  }
139
115
  window.location.href = '/dashboard/blog';
140
116
  }}
141
- className="text-neutral-500 dark:text-neutral-400 hover:text-neutral-950 dark:hover:text-white transition-colors"
117
+ className="size-9 lg:size-10 flex items-center justify-center bg-dashboard-card border border-dashboard-border rounded-xl text-dashboard-text-secondary hover:text-primary hover:border-primary/30 transition-all active:scale-95 shadow-sm"
142
118
  >
143
- <ArrowLeft size={20} strokeWidth={1.5} />
119
+ <ArrowLeft className="size-[18px] lg:size-[20px]" />
144
120
  </button>
145
- <div className="h-4 w-[1px] bg-neutral-300 dark:border-neutral-700" />
121
+
122
+ <div className="h-6 lg:h-8 w-px bg-dashboard-border/30" />
123
+
146
124
  <button
147
125
  onClick={onLibraryToggle}
148
- className={`flex items-center gap-2 text-[10px] uppercase tracking-widest font-black transition-all ${isLibraryOpen ? 'text-dashboard-text' : 'text-neutral-500 dark:text-neutral-400'
149
- }`}
126
+ className={`flex items-center gap-2 lg:gap-3 px-3 lg:px-5 py-2 lg:py-2.5 rounded-xl text-[10px] font-black uppercase tracking-[0.2em] transition-all border ${
127
+ isLibraryOpen
128
+ ? 'bg-primary text-white border-primary/20 shadow-lg shadow-primary/20'
129
+ : 'bg-dashboard-card text-dashboard-text-secondary border-dashboard-border hover:border-primary/30'
130
+ }`}
150
131
  >
151
- <Library size={16} strokeWidth={1.5} />
152
- Library
132
+ <Library size={16} />
133
+ <span className="hidden xl:inline">Blocks Library</span>
134
+ <span className="xl:hidden hidden lg:inline text-[8px]">Blocks</span>
153
135
  </button>
136
+
154
137
  {/* Language Switcher */}
155
138
  {languages.length > 0 && onLanguageChange && (
156
- <>
157
- <div className="h-4 w-[1px] bg-neutral-300 dark:border-neutral-700" />
158
- <div className="relative">
159
- <button
160
- onClick={() => setShowLanguageDropdown(!showLanguageDropdown)}
161
- className="flex items-center gap-2 px-3 py-2 text-[10px] uppercase tracking-widest font-bold bg-dashboard-card border border-dashboard-border rounded-lg text-neutral-600 dark:text-neutral-400 hover:text-dashboard-text hover:border-primary/50 transition-all shadow-sm"
162
- >
163
- <Globe size={14} strokeWidth={1.5} />
164
- <span>{languageLabels[currentLanguage] || currentLanguage.toUpperCase()}</span>
165
- <ChevronDown size={12} className={`transition-transform ${showLanguageDropdown ? 'rotate-180' : ''}`} />
166
- </button>
167
- {showLanguageDropdown && (
168
- <div className="absolute top-full left-0 mt-2 py-1 bg-dashboard-card border border-dashboard-border rounded-lg shadow-xl z-[9999] min-w-[160px] overflow-hidden">
169
- <div className="px-3 py-2 text-[9px] text-neutral-500 uppercase tracking-wider border-b border-dashboard-border">
170
- Beschikbare Talen
171
- </div>
172
- {languages.map(lang => (
173
- <button
174
- key={lang}
175
- onClick={() => {
176
- onLanguageChange(lang);
177
- setShowLanguageDropdown(false);
178
- }}
179
- className={`w-full text-left px-3 py-2 text-[10px] uppercase tracking-wider transition-colors ${lang === currentLanguage
180
- ? 'bg-primary/10 text-primary font-bold'
181
- : 'text-neutral-600 dark:text-neutral-400 hover:bg-dashboard-bg hover:text-dashboard-text'
182
- }`}
183
- >
184
- {languageLabels[lang] || lang.toUpperCase()}
185
- </button>
186
- ))}
187
- {availableToAdd.length > 0 && onAddLanguage && (
188
- <>
189
- <div className="my-1 border-t border-dashboard-border" />
190
- <div className="px-3 py-1 text-[9px] text-neutral-500 uppercase tracking-wider">
191
- Add Language
192
- </div>
193
- {availableToAdd.slice(0, 3).map(lang => (
194
- <button
195
- key={lang}
196
- onClick={() => {
197
- onAddLanguage(lang);
198
- setShowLanguageDropdown(false);
199
- }}
200
- className="w-full text-left px-3 py-2 text-[10px] uppercase tracking-wider text-neutral-600 dark:text-neutral-400 hover:bg-dashboard-bg hover:text-dashboard-text transition-colors"
201
- >
202
- + {languageLabels[lang] || lang.toUpperCase()}
203
- </button>
204
- ))}
205
- </>
206
- )}
207
- </div>
208
- )}
209
- </div>
210
- </>
211
- )}
212
- </div>
213
-
214
- <div className="flex items-center gap-4">
215
- {/* Auto-save Toggle */}
216
- {onAutoSaveToggle && (
217
- <div className="flex items-center gap-2">
139
+ <div className="relative group">
218
140
  <button
219
- onClick={() => onAutoSaveToggle(!autoSaveEnabled)}
220
- className={`relative flex items-center gap-2 px-3 py-1.5 rounded-full text-[10px] uppercase tracking-widest font-bold transition-all ${autoSaveEnabled
221
- ? 'bg-primary/20 text-primary border border-primary/30'
222
- : 'bg-dashboard-bg text-neutral-600 dark:text-neutral-400 border border-dashboard-border hover:text-neutral-950 dark:hover:text-white'
223
- }`}
224
- title={autoSaveEnabled ? 'Auto-save enabled (saves after 10s of inactivity)' : 'Click to enable auto-save'}
141
+ onClick={() => setShowLanguageDropdown(!showLanguageDropdown)}
142
+ className="flex items-center gap-2 lg:gap-3 px-3 lg:px-4 py-2 lg:py-2.5 bg-dashboard-card border border-dashboard-border rounded-xl hover:border-primary/30 transition-all shadow-sm"
225
143
  >
226
- <Clock size={12} className={autoSaveEnabled && autoSaveStatus !== 'saving' ? 'animate-pulse' : ''} />
227
- <span>Auto-save</span>
228
- <span className={`ml-1 text-[9px] ${autoSaveEnabled ? 'text-primary' : 'text-neutral-500 dark:text-neutral-400'}`}>
229
- {autoSaveEnabled ? 'ON' : 'OFF'}
144
+ <img src={getFlagUrl(currentLanguage)} className="w-4 h-2.5 lg:w-5 lg:h-3.5 object-cover rounded-sm border border-white/20" alt="" />
145
+ <span className="text-[10px] font-black uppercase tracking-widest text-dashboard-text-secondary">
146
+ {currentLanguage.toUpperCase()}
230
147
  </span>
231
- {/* Countdown or Status */}
232
- {autoSaveEnabled && isDirty && (
233
- <span className="ml-1.5 text-[9px] font-bold tabular-nums">
234
- {autoSaveStatus === 'saving' && (
235
- <span className="text-primary animate-pulse">Saving...</span>
236
- )}
237
- {autoSaveStatus === 'saved' && (
238
- <span className="text-green-500 dark:text-green-400">Saved!</span>
239
- )}
240
- {autoSaveStatus === 'error' && (
241
- <span className="text-red-500 dark:text-red-400">Error</span>
242
- )}
243
- {autoSaveStatus === 'idle' && autoSaveCountdown !== null && (
244
- <span className="text-primary/70">{autoSaveCountdown}s</span>
245
- )}
246
- </span>
247
- )}
148
+ <ChevronDown className={`size-[12px] lg:size-[14px] text-dashboard-text-secondary transition-transform ${showLanguageDropdown ? 'rotate-180' : ''}`} />
248
149
  </button>
249
- {/* Unsaved Changes Indicator - only show when auto-save is off */}
250
- {isDirty && !autoSaveEnabled && (
251
- <span className="text-[10px] text-amber-500 dark:text-amber-400 font-bold uppercase tracking-widest animate-pulse">
252
- Unsaved
253
- </span>
150
+
151
+ {showLanguageDropdown && (
152
+ <div className="absolute top-full left-0 mt-3 p-2 bg-dashboard-bg/95 backdrop-blur-2xl border border-dashboard-border rounded-2xl shadow-2xl z-[100] min-w-[180px] animate-in fade-in zoom-in-95 duration-200">
153
+ <label className="px-3 py-2 text-[8px] font-black text-dashboard-text-secondary uppercase tracking-[0.3em] block border-b border-dashboard-border/30 mb-1">
154
+ Switch Edition
155
+ </label>
156
+ {allCreatedLanguages.map(lang => (
157
+ <button
158
+ key={lang}
159
+ onClick={() => {
160
+ onLanguageChange(lang);
161
+ setShowLanguageDropdown(false);
162
+ }}
163
+ className={`w-full flex items-center gap-3 px-3 py-2.5 rounded-xl transition-all ${
164
+ lang === currentLanguage
165
+ ? 'bg-primary/10 text-primary font-bold'
166
+ : 'text-dashboard-text-secondary hover:bg-white/5 hover:text-dashboard-text'
167
+ }`}
168
+ >
169
+ <img src={getFlagUrl(lang)} className="w-4 h-3 object-cover rounded-sm" alt="" />
170
+ <span className="text-[10px] font-black uppercase tracking-widest">{languageLabels[lang] || lang.toUpperCase()}</span>
171
+ </button>
172
+ ))}
173
+
174
+ {availableToAdd.length > 0 && onAddLanguage && (
175
+ <>
176
+ <div className="my-2 border-t border-dashboard-border/30 mx-2" />
177
+ <label className="px-3 py-2 text-[8px] font-black text-dashboard-text-secondary uppercase tracking-[0.3em] block mb-1">
178
+ Add Edition
179
+ </label>
180
+ {availableToAdd.map(lang => (
181
+ <button
182
+ key={lang}
183
+ onClick={() => {
184
+ onAddLanguage(lang);
185
+ setShowLanguageDropdown(false);
186
+ }}
187
+ className="w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-dashboard-text-secondary hover:bg-primary/10 hover:text-primary transition-all group/add"
188
+ >
189
+ <div className="relative">
190
+ <img src={getFlagUrl(lang)} className="w-4 h-3 object-cover rounded-sm opacity-60 group-hover/add:opacity-100 transition-opacity" alt="" />
191
+ <div className="absolute -top-1 -right-1 size-2 bg-primary rounded-full border border-dashboard-bg flex items-center justify-center text-[6px] text-white font-bold">
192
+ +
193
+ </div>
194
+ </div>
195
+ <span className="text-[10px] font-black uppercase tracking-widest">{languageLabels[lang] || lang.toUpperCase()}</span>
196
+ </button>
197
+ ))}
198
+ </>
199
+ )}
200
+ </div>
254
201
  )}
255
202
  </div>
256
203
  )}
257
- {/* Edit/Preview Toggle - Segmented Control Style */}
258
- <div className="flex items-center bg-dashboard-bg border border-dashboard-border rounded-full p-1 gap-1">
204
+ </div>
205
+
206
+ {/* Middle Section: Status */}
207
+ <div className="hidden md:flex items-center gap-2 lg:gap-4">
208
+ {state.status === 'published' && (
209
+ <div className="flex items-center gap-2 px-3 lg:px-4 py-1.5 bg-emerald-500/10 border border-emerald-500/20 rounded-full text-emerald-500">
210
+ <CheckCircle2 size={12} className="animate-pulse" />
211
+ <span className="text-[9px] font-black uppercase tracking-[0.2em] hidden lg:inline">Live Edition</span>
212
+ <span className="text-[9px] font-black uppercase tracking-[0.2em] lg:hidden">Live</span>
213
+ </div>
214
+ )}
215
+ {state.status === 'not-translated' && (
216
+ <div className="flex items-center gap-2 px-3 lg:px-4 py-1.5 bg-blue-500/10 border border-blue-500/20 rounded-full text-blue-500">
217
+ <Plus size={12} />
218
+ <span className="text-[9px] font-black uppercase tracking-[0.2em] hidden lg:inline">New Edition</span>
219
+ <span className="text-[9px] font-black uppercase tracking-[0.2em] lg:hidden">New</span>
220
+ </div>
221
+ )}
222
+ {isDirty && !autoSaveEnabled && (
223
+ <div className="flex items-center gap-2 px-3 lg:px-4 py-1.5 bg-amber-500/10 border border-amber-500/20 rounded-full text-amber-500 animate-pulse">
224
+ <Clock size={12} />
225
+ <span className="text-[9px] font-black uppercase tracking-[0.2em] hidden lg:inline">Unsaved Edits</span>
226
+ <span className="text-[9px] font-black uppercase tracking-[0.2em] lg:hidden">Dirty</span>
227
+ </div>
228
+ )}
229
+ </div>
230
+
231
+ {/* Right Section: Controls & Save */}
232
+ <div className="flex items-center gap-2 lg:gap-4">
233
+ {/* Auto-save */}
234
+ {onAutoSaveToggle && (
259
235
  <button
260
- onClick={() => {
261
- if (isPreviewMode) {
262
- onPreviewToggle();
263
- }
264
- }}
265
- className={`flex items-center gap-1.5 px-3 py-1.5 rounded-full text-[10px] uppercase tracking-widest font-bold transition-all ${!isPreviewMode
266
- ? 'bg-primary text-white shadow-sm'
267
- : 'text-neutral-600 dark:text-neutral-400 hover:text-neutral-950 dark:hover:text-white'
268
- }`}
269
- title="Edit mode - Make changes to your post"
236
+ onClick={() => onAutoSaveToggle(!autoSaveEnabled)}
237
+ className={`group flex items-center gap-2 lg:gap-3 px-3 lg:px-4 py-2 lg:py-2.5 rounded-xl border transition-all ${
238
+ autoSaveEnabled
239
+ ? 'bg-primary/10 border-primary/30 text-primary'
240
+ : 'bg-dashboard-card border border-dashboard-border text-dashboard-text-secondary'
241
+ }`}
270
242
  >
271
- <Edit size={12} strokeWidth={2.5} />
272
- <span>Edit</span>
243
+ <Clock size={14} className={autoSaveEnabled && autoSaveStatus === 'saving' ? 'animate-spin' : ''} />
244
+ <span className="text-[9px] font-black uppercase tracking-widest hidden lg:inline">
245
+ {autoSaveStatus === 'saving' ? 'Syncing...' : 'Auto-Sync'}
246
+ </span>
247
+ <div className={`size-1.5 rounded-full ${autoSaveEnabled ? 'bg-primary animate-pulse' : 'bg-dashboard-text-secondary/30'}`} />
248
+ </button>
249
+ )}
250
+
251
+ {/* Edit/Preview Toggle */}
252
+ <div className="flex items-center bg-dashboard-card border border-dashboard-border rounded-xl p-1 shadow-inner">
253
+ <button
254
+ onClick={() => isPreviewMode && onPreviewToggle()}
255
+ className={`flex items-center gap-2 px-3 lg:px-4 py-1.5 lg:py-2 rounded-lg text-[10px] font-black uppercase tracking-widest transition-all ${
256
+ !isPreviewMode ? 'bg-primary text-white shadow-md' : 'text-dashboard-text-secondary hover:text-dashboard-text'
257
+ }`}
258
+ >
259
+ <Edit size={12} />
260
+ <span className="hidden sm:inline">Edit</span>
273
261
  </button>
274
262
  <button
275
- onClick={() => {
276
- if (!isPreviewMode) {
277
- onPreviewToggle();
278
- }
279
- }}
280
- className={`flex items-center gap-1.5 px-3 py-1.5 rounded-full text-[10px] uppercase tracking-widest font-bold transition-all ${isPreviewMode
281
- ? 'bg-primary text-white shadow-sm'
282
- : 'text-neutral-600 dark:text-neutral-400 hover:text-neutral-950 dark:hover:text-white'
283
- }`}
284
- title="Preview mode - See how your post will look"
263
+ onClick={() => !isPreviewMode && onPreviewToggle()}
264
+ className={`flex items-center gap-2 px-3 lg:px-4 py-1.5 lg:py-2 rounded-lg text-[10px] font-black uppercase tracking-widest transition-all ${
265
+ isPreviewMode ? 'bg-primary text-white shadow-md' : 'text-dashboard-text-secondary hover:text-dashboard-text'
266
+ }`}
285
267
  >
286
- <Eye size={12} strokeWidth={2.5} />
287
- <span>Preview</span>
268
+ <Eye size={12} />
269
+ <span className="hidden sm:inline">View</span>
288
270
  </button>
289
271
  </div>
290
- {/* Save Draft Button - Always visible for drafts and new posts */}
291
- {(state.status === 'draft' || !state.postId) && (
272
+
273
+ {/* Save Options */}
274
+ <div className="flex items-center gap-2">
275
+ {state.status !== 'published' && (
276
+ <button
277
+ onClick={handleSaveDraftClick}
278
+ disabled={isSaving}
279
+ className="px-4 lg:px-6 py-2 lg:py-2.5 bg-dashboard-card border border-dashboard-border text-dashboard-text-secondary rounded-xl text-[10px] font-black uppercase tracking-[0.2em] hover:border-primary/30 transition-all active:scale-95"
280
+ >
281
+ <span className="hidden lg:inline">{isSaving ? '...' : 'Save Draft'}</span>
282
+ <span className="lg:hidden">{isSaving ? '...' : 'Draft'}</span>
283
+ </button>
284
+ )}
292
285
  <button
293
- onClick={handleSaveDraftClick}
286
+ onClick={handlePublishClick}
294
287
  disabled={isSaving}
295
- className={`px-4 py-2 border-2 border-dashboard-border text-dashboard-text rounded-full text-[10px] font-bold uppercase tracking-widest transition-all ${isSaving
296
- ? 'opacity-50 cursor-not-allowed'
297
- : 'hover:bg-dashboard-bg'
298
- }`}
288
+ className="px-5 lg:px-8 py-2 lg:py-2.5 bg-primary text-white rounded-xl text-[10px] font-black uppercase tracking-[0.3em] shadow-xl shadow-primary/20 hover:scale-[1.02] active:scale-95 transition-all"
299
289
  >
300
- {isSaving ? 'Saving...' : 'Save Draft'}
290
+ <span className="hidden lg:inline">{isSaving ? 'Publishing...' : state.status === 'published' ? 'Update Live' : 'Go Live'}</span>
291
+ <Save size={14} className="lg:hidden" />
301
292
  </button>
302
- )}
303
- {/* Publish/Update Button */}
304
- <button
305
- onClick={handlePublishClick}
306
- disabled={isSaving}
307
- className={`px-6 py-2 bg-primary text-white rounded-full text-[10px] font-bold uppercase tracking-widest transition-all shadow-lg shadow-primary/20 ${isSaving
308
- ? 'opacity-50 cursor-not-allowed'
309
- : 'hover:bg-primary/90'
310
- }`}
311
- >
312
- {isSaving ? 'Saving...' : state.status === 'published' ? 'Update Post' : 'Publish Post'}
313
- </button>
293
+ </div>
294
+
314
295
  <button
315
296
  onClick={onSidebarToggle}
316
- className={`p-2 rounded-full transition-colors ${isSidebarOpen
317
- ? 'bg-dashboard-bg text-dashboard-text'
318
- : 'text-neutral-500 dark:text-neutral-400 hover:bg-dashboard-bg'
319
- }`}
297
+ className={`size-9 lg:size-10 flex items-center justify-center rounded-xl transition-all border ${
298
+ isSidebarOpen
299
+ ? 'bg-primary/10 border-primary/30 text-primary shadow-lg shadow-primary/10'
300
+ : 'bg-dashboard-card border border-dashboard-border text-dashboard-text-secondary hover:border-primary/30'
301
+ }`}
320
302
  >
321
- <Settings2 size={18} />
303
+ <Settings2 className="size-[18px] lg:size-[20px]" />
322
304
  </button>
323
305
  </div>
324
306
 
325
- {/* Save Confirmation Modal */}
326
307
  <SaveConfirmationModal
327
308
  isOpen={showConfirmModal}
328
309
  onClose={() => {
@@ -340,4 +321,3 @@ export function EditorHeader({
340
321
  </div>
341
322
  );
342
323
  }
343
-