@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,8 +1,10 @@
1
1
  'use client';
2
2
 
3
- import React from 'react';
4
- import { Globe, Search, Box } from 'lucide-react';
3
+ import React, { useState } from 'react';
4
+ import { Globe, Search, Box, Hash, X, Shield, Key, Users, Layout, Type, Image as ImageIcon } from 'lucide-react';
5
5
  import { FeaturedMediaSection, PrivacySettingsSection } from './index';
6
+ import { useEditor } from '../../../state/EditorContext';
7
+ import { useCategories } from '../../../hooks/useCategories';
6
8
  import type { Block } from '../../../types/block';
7
9
  import type { PostMetadata, SEOMetadata } from '../../../types/post';
8
10
 
@@ -25,157 +27,224 @@ export function EditorSidebar({
25
27
  onSEOUpdate,
26
28
  onMetadataUpdate,
27
29
  }: EditorSidebarProps) {
30
+ const [newTag, setNewTag] = useState('');
31
+ const { state } = useEditor();
32
+ const { categories: existingCategories } = useCategories(state.currentLanguage || undefined);
33
+
34
+ const handleTagAdd = (e: React.KeyboardEvent) => {
35
+ if (e.key === 'Enter' && newTag.trim()) {
36
+ const tag = newTag.trim();
37
+ if (!metadata.tags?.includes(tag)) {
38
+ onMetadataUpdate({
39
+ tags: [...(metadata.tags || []), tag]
40
+ });
41
+ }
42
+ setNewTag('');
43
+ }
44
+ };
45
+
46
+ const handleTagRemove = (tagToRemove: string) => {
47
+ onMetadataUpdate({
48
+ tags: (metadata.tags || []).filter(t => t !== tagToRemove)
49
+ });
50
+ };
51
+
28
52
  return (
29
- <div className="p-8 w-80 min-w-0 max-w-full space-y-12 overflow-y-auto max-h-full">
30
- {/* SEO Section */}
31
- <section>
32
- <div className="flex items-center gap-3 mb-6">
33
- <Search size={14} className="text-neutral-500 dark:text-neutral-400" />
34
- <label className="text-[10px] uppercase tracking-[0.2em] text-neutral-500 dark:text-neutral-400 font-black">
35
- SEO Settings
36
- </label>
53
+ <div className="p-8 w-96 min-w-0 max-w-full space-y-10 overflow-y-auto max-h-full custom-scrollbar">
54
+ {/* 1. PUBLISHING STATUS SECTION */}
55
+ <section className="p-6 bg-primary/5 border border-primary/20 rounded-[2rem] relative overflow-hidden">
56
+ <div className="absolute top-0 right-0 p-4 opacity-10">
57
+ <Globe size={60} className="text-primary" />
37
58
  </div>
38
- <div className="space-y-4">
39
- <div>
40
- <label className="text-[10px] text-neutral-500 dark:text-neutral-400 uppercase font-bold block mb-2">
41
- SEO Title
59
+ <div className="relative z-10">
60
+ <div className="flex items-center justify-between mb-4">
61
+ <label className="text-[10px] font-black text-primary uppercase tracking-[0.3em]">
62
+ Publication Status
42
63
  </label>
43
- <input
44
- type="text"
45
- value={seo.title || ''}
46
- onChange={(e) => onSEOUpdate({ title: e.target.value })}
47
- placeholder="SEO title (defaults to post title)"
48
- className="w-full px-3 py-2 text-xs bg-dashboard-card border border-dashboard-border rounded-lg outline-none focus:border-primary transition-all text-dashboard-text"
49
- />
50
- <p className="text-[9px] text-neutral-400 dark:text-neutral-500 mt-1">
51
- {seo.title?.length || 0} / 60 characters
52
- </p>
64
+ <span className={`px-3 py-1 rounded-full text-[9px] font-black uppercase tracking-widest border shadow-sm ${
65
+ status === 'published'
66
+ ? 'bg-emerald-500 text-white border-emerald-400'
67
+ : status === 'not-translated'
68
+ ? 'bg-blue-500 text-white border-blue-400'
69
+ : 'bg-amber-500 text-white border-amber-400'
70
+ }`}>
71
+ {status === 'not-translated' ? 'Not Translated' : status}
72
+ </span>
53
73
  </div>
54
- <div>
55
- <label className="text-[10px] text-neutral-500 dark:text-neutral-400 uppercase font-bold block mb-2">
56
- Meta Description
57
- </label>
58
- <textarea
59
- value={seo.description || ''}
60
- onChange={(e) => onSEOUpdate({ description: e.target.value })}
61
- placeholder="Brief description for search engines"
62
- rows={3}
63
- className="w-full px-3 py-2 text-xs bg-white dark:bg-neutral-900/50 border border-neutral-300 dark:border-neutral-700 rounded-lg outline-none focus:border-primary transition-all dark:text-neutral-100 resize-none"
64
- />
65
- <p className="text-[9px] text-neutral-400 dark:text-neutral-500 mt-1">
66
- {seo.description?.length || 0} / 160 characters
74
+ <div className="space-y-4">
75
+ <div className="bg-dashboard-card/50 p-4 rounded-2xl border border-dashboard-border/50">
76
+ <span className="text-[9px] font-black text-dashboard-text-secondary uppercase tracking-[0.2em] block mb-2">Live Endpoint</span>
77
+ <div className="text-[11px] font-mono text-dashboard-text leading-relaxed break-all bg-white/5 p-2 rounded-lg border border-white/5">
78
+ /blog/<span className="text-primary font-bold">{slug || 'untitled-publication'}</span>
79
+ </div>
80
+ </div>
81
+ <p className="text-[10px] text-dashboard-text-secondary leading-relaxed italic opacity-70">
82
+ {status === 'published'
83
+ ? 'This publication is live across all connected digital touchpoints.'
84
+ : status === 'not-translated'
85
+ ? 'This language edition has not been created yet. Save it as a draft to begin.'
86
+ : 'Your article is currently private. Only editorial staff can view and modify it.'}
67
87
  </p>
68
88
  </div>
69
- <div>
70
- <label className="text-[10px] text-neutral-500 dark:text-neutral-400 uppercase font-bold block mb-2">
71
- Keywords (comma-separated)
72
- </label>
73
- <input
74
- type="text"
75
- value={seo.keywords?.join(', ') || ''}
76
- onChange={(e) => {
77
- const keywords = e.target.value.split(',').map(k => k.trim()).filter(k => k);
78
- onSEOUpdate({ keywords });
79
- }}
80
- placeholder="keyword1, keyword2, keyword3"
81
- className="w-full px-3 py-2 text-xs bg-dashboard-card border border-dashboard-border rounded-lg outline-none focus:border-primary transition-all text-dashboard-text"
82
- />
83
- </div>
84
- <div>
85
- <label className="text-[10px] text-neutral-500 dark:text-neutral-400 uppercase font-bold block mb-2">
86
- Open Graph Image URL
87
- </label>
88
- <input
89
- type="url"
90
- value={seo.ogImage || ''}
91
- onChange={(e) => onSEOUpdate({ ogImage: e.target.value })}
92
- placeholder="https://example.com/image.jpg"
93
- className="w-full px-3 py-2 text-xs bg-dashboard-card border border-dashboard-border rounded-lg outline-none focus:border-primary transition-all text-dashboard-text"
94
- />
95
- </div>
96
89
  </div>
97
90
  </section>
98
91
 
99
- {/* Publishing Section */}
100
- <section className="pt-8 border-t border-neutral-200 dark:border-neutral-800">
101
- <div className="flex items-center gap-3 mb-6">
102
- <Globe size={14} className="text-neutral-500 dark:text-neutral-400" />
103
- <label className="text-[10px] uppercase tracking-[0.2em] text-neutral-500 dark:text-neutral-400 font-black">
104
- Publishing
92
+ {/* 2. CLASSIFICATION SECTION */}
93
+ <section className="space-y-6">
94
+ <div className="flex items-center gap-3">
95
+ <div className="size-8 rounded-xl bg-primary/10 flex items-center justify-center text-primary border border-primary/20">
96
+ <Box size={14} />
97
+ </div>
98
+ <label className="text-[10px] font-black text-dashboard-text uppercase tracking-[0.3em]">
99
+ Classification
105
100
  </label>
106
101
  </div>
107
- <div className="bg-dashboard-bg p-5 rounded-2xl border border-dashboard-border">
108
- <span className="text-[10px] text-neutral-500 dark:text-neutral-400 uppercase font-bold block mb-3">Slug / Permalink</span>
109
- <div className="text-xs font-mono break-all text-neutral-600 dark:text-neutral-400 leading-relaxed">
110
- /blog/<span className="text-neutral-950 dark:text-white bg-amber-50 dark:bg-amber-900/20 px-1 rounded">{slug || 'untitled-post'}</span>
102
+
103
+ <div className="space-y-4 p-6 bg-dashboard-card/30 rounded-[2rem] border border-dashboard-border/50">
104
+ <div className="group">
105
+ <label className="text-[9px] font-black text-dashboard-text-secondary uppercase tracking-[0.2em] mb-2 block px-1 group-focus-within:text-primary transition-colors">
106
+ Primary Category
107
+ </label>
108
+ <div className="relative">
109
+ <Layout size={12} className="absolute left-3.5 top-1/2 -translate-y-1/2 text-dashboard-text-secondary group-focus-within:text-primary transition-colors" />
110
+ <input
111
+ type="text"
112
+ list="category-suggestions"
113
+ value={metadata.categories?.[0] || ''}
114
+ onChange={(e) => onMetadataUpdate({ categories: e.target.value.trim() ? [e.target.value.trim()] : [] })}
115
+ placeholder="e.g. Technology, Lifestyle"
116
+ className="w-full pl-10 pr-4 py-3 bg-dashboard-bg/50 border border-dashboard-border/50 rounded-xl text-xs font-bold text-dashboard-text placeholder:text-dashboard-text-secondary/30 outline-none focus:border-primary/40 focus:bg-primary/[0.02] transition-all"
117
+ />
118
+ <datalist id="category-suggestions">
119
+ {existingCategories.map(cat => (
120
+ <option key={cat} value={cat} />
121
+ ))}
122
+ </datalist>
123
+ </div>
124
+ </div>
125
+
126
+ <div className="group">
127
+ <label className="text-[9px] font-black text-dashboard-text-secondary uppercase tracking-[0.2em] mb-2 block px-1 group-focus-within:text-primary transition-colors">
128
+ Article Tags
129
+ </label>
130
+ <div className="flex flex-wrap gap-2 mb-3">
131
+ {metadata.tags?.map((tag) => (
132
+ <span
133
+ key={tag}
134
+ className="inline-flex items-center gap-2 px-3 py-1.5 bg-primary/10 border border-primary/20 rounded-full text-[9px] font-black text-primary uppercase tracking-widest group/tag hover:bg-primary/20 transition-all"
135
+ >
136
+ {tag}
137
+ <button
138
+ onClick={() => handleTagRemove(tag)}
139
+ className="text-primary/40 hover:text-primary transition-colors"
140
+ >
141
+ <X size={10} strokeWidth={3} />
142
+ </button>
143
+ </span>
144
+ ))}
145
+ </div>
146
+ <div className="relative">
147
+ <Hash size={12} className="absolute left-3.5 top-1/2 -translate-y-1/2 text-dashboard-text-secondary group-focus-within:text-primary transition-colors" />
148
+ <input
149
+ type="text"
150
+ value={newTag}
151
+ onChange={(e) => setNewTag(e.target.value)}
152
+ onKeyDown={handleTagAdd}
153
+ placeholder="Add tag + Enter"
154
+ className="w-full pl-10 pr-4 py-3 bg-dashboard-bg/50 border border-dashboard-border/50 rounded-xl text-xs font-bold text-dashboard-text placeholder:text-dashboard-text-secondary/30 outline-none focus:border-primary/40 focus:bg-primary/[0.02] transition-all"
155
+ />
156
+ </div>
111
157
  </div>
112
158
  </div>
113
159
  </section>
114
160
 
115
- {/* Category Section */}
116
- <section className="pt-8 border-t border-neutral-200 dark:border-neutral-800">
117
- <div className="flex items-center gap-3 mb-6">
118
- <Box size={14} className="text-neutral-500 dark:text-neutral-400" />
119
- <label className="text-[10px] uppercase tracking-[0.2em] text-neutral-500 dark:text-neutral-400 font-black">
120
- Category
161
+ {/* 3. FEATURED MEDIA */}
162
+ <div className="p-6 bg-dashboard-card/30 rounded-[2rem] border border-dashboard-border/50">
163
+ <FeaturedMediaSection
164
+ featuredImage={metadata.featuredImage}
165
+ heroBlock={heroBlock}
166
+ slug={slug}
167
+ onUpdate={(image) => onMetadataUpdate({ featuredImage: image })}
168
+ />
169
+ </div>
170
+
171
+ {/* 4. SEO OPTIMIZATION */}
172
+ <section className="space-y-6">
173
+ <div className="flex items-center gap-3">
174
+ <div className="size-8 rounded-xl bg-primary/10 flex items-center justify-center text-primary border border-primary/20">
175
+ <Search size={14} />
176
+ </div>
177
+ <label className="text-[10px] font-black text-dashboard-text uppercase tracking-[0.3em]">
178
+ SEO & Meta
121
179
  </label>
122
180
  </div>
123
- <div className="space-y-4">
124
- <div>
125
- <label className="text-[10px] text-neutral-500 dark:text-neutral-400 uppercase font-bold block mb-2">
126
- Category
181
+
182
+ <div className="space-y-5 p-6 bg-dashboard-card/30 rounded-[2.5rem] border border-dashboard-border/50">
183
+ <div className="group">
184
+ <label className="text-[9px] font-black text-dashboard-text-secondary uppercase tracking-[0.2em] mb-2 block px-1 group-focus-within:text-primary transition-colors">
185
+ Search Engine Title
127
186
  </label>
128
187
  <input
129
188
  type="text"
130
- value={metadata.categories?.[0] || ''}
131
- onChange={(e) => {
132
- const category = e.target.value.trim();
133
- onMetadataUpdate({
134
- categories: category ? [category] : []
135
- });
136
- }}
137
- placeholder="Enter category (required for publishing)"
138
- className="w-full px-3 py-2 text-xs bg-dashboard-card border border-dashboard-border rounded-lg outline-none focus:border-primary transition-all text-dashboard-text"
189
+ value={seo.title || ''}
190
+ onChange={(e) => onSEOUpdate({ title: e.target.value })}
191
+ placeholder="Defaults to article title"
192
+ className="w-full px-4 py-3 bg-dashboard-bg/50 border border-dashboard-border/50 rounded-xl text-xs font-bold text-dashboard-text placeholder:text-dashboard-text-secondary/30 outline-none focus:border-primary/40 focus:bg-primary/[0.02] transition-all"
139
193
  />
140
- <p className="text-[9px] text-neutral-400 dark:text-neutral-500 mt-1">
141
- {metadata.categories?.[0] ? 'Category set' : 'No category set'}
142
- </p>
194
+ <div className="flex justify-between mt-1.5 px-1">
195
+ <p className="text-[8px] font-black text-dashboard-text-secondary uppercase opacity-40">Optimized: 60 chars</p>
196
+ <p className={`text-[9px] font-mono ${ (seo.title?.length || 0) > 60 ? 'text-red-500' : 'text-primary'}`}>
197
+ {seo.title?.length || 0}/60
198
+ </p>
199
+ </div>
143
200
  </div>
144
- </div>
145
- </section>
146
201
 
147
- {/* Featured Media Section */}
148
- <FeaturedMediaSection
149
- featuredImage={metadata.featuredImage}
150
- heroBlock={heroBlock}
151
- slug={slug}
152
- onUpdate={(image) => onMetadataUpdate({ featuredImage: image })}
153
- />
154
-
155
- {/* Privacy Settings Section */}
156
- <PrivacySettingsSection
157
- privacy={metadata.privacy}
158
- onUpdate={(privacy) => onMetadataUpdate({ privacy })}
159
- />
202
+ <div className="group">
203
+ <label className="text-[9px] font-black text-dashboard-text-secondary uppercase tracking-[0.2em] mb-2 block px-1 group-focus-within:text-primary transition-colors">
204
+ Meta Description
205
+ </label>
206
+ <textarea
207
+ value={seo.description || ''}
208
+ onChange={(e) => onSEOUpdate({ description: e.target.value })}
209
+ placeholder="Write a compelling summary..."
210
+ rows={4}
211
+ className="w-full px-4 py-3 bg-dashboard-bg/50 border border-dashboard-border/50 rounded-xl text-xs font-bold text-dashboard-text placeholder:text-dashboard-text-secondary/30 outline-none focus:border-primary/40 focus:bg-primary/[0.02] transition-all resize-none"
212
+ />
213
+ <div className="flex justify-between mt-1.5 px-1">
214
+ <p className="text-[8px] font-black text-dashboard-text-secondary uppercase opacity-40">Recommended: 160 chars</p>
215
+ <p className={`text-[9px] font-mono ${ (seo.description?.length || 0) > 160 ? 'text-red-500' : 'text-primary'}`}>
216
+ {seo.description?.length || 0}/160
217
+ </p>
218
+ </div>
219
+ </div>
160
220
 
161
- {/* Post Status Section */}
162
- <section className="pt-8 border-t border-neutral-200 dark:border-neutral-800">
163
- <div className="flex items-center justify-between mb-4">
164
- <label className="text-[10px] uppercase tracking-[0.2em] text-neutral-500 dark:text-neutral-400 font-black">
165
- Post Status
166
- </label>
167
- <span className="text-[10px] font-black text-amber-700 dark:text-amber-400 bg-amber-50 dark:bg-amber-900/20 px-2.5 py-1 rounded-full uppercase tracking-tighter">
168
- {status}
169
- </span>
221
+ <div className="group">
222
+ <label className="text-[9px] font-black text-dashboard-text-secondary uppercase tracking-[0.2em] mb-2 block px-1 group-focus-within:text-primary transition-colors">
223
+ Social Media Asset (OG Image)
224
+ </label>
225
+ <div className="relative">
226
+ <ImageIcon size={12} className="absolute left-3.5 top-1/2 -translate-y-1/2 text-dashboard-text-secondary group-focus-within:text-primary transition-colors" />
227
+ <input
228
+ type="url"
229
+ value={seo.ogImage || ''}
230
+ onChange={(e) => onSEOUpdate({ ogImage: e.target.value })}
231
+ placeholder="https://..."
232
+ className="w-full pl-10 pr-4 py-3 bg-dashboard-bg/50 border border-dashboard-border/50 rounded-xl text-xs font-bold text-dashboard-text placeholder:text-dashboard-text-secondary/30 outline-none focus:border-primary/40 focus:bg-primary/[0.02] transition-all"
233
+ />
234
+ </div>
235
+ </div>
170
236
  </div>
171
- <p className="text-[11px] text-neutral-500 dark:text-neutral-400 leading-relaxed italic">
172
- {status === 'draft'
173
- ? 'This post is private. Only you can see it until you hit publish.'
174
- : status === 'published'
175
- ? 'This post is live and visible to everyone.'
176
- : 'This post is scheduled for publication.'}
177
- </p>
178
237
  </section>
238
+
239
+ {/* 5. PRIVACY & SECURITY */}
240
+ <div className="p-6 bg-dashboard-card/30 rounded-[2.5rem] border border-dashboard-border/50">
241
+ <PrivacySettingsSection
242
+ privacy={metadata.privacy}
243
+ onUpdate={(privacy) => onMetadataUpdate({ privacy })}
244
+ />
245
+ </div>
246
+
247
+ <div className="pb-10" />
179
248
  </div>
180
249
  );
181
250
  }