@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,19 +1,37 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Globe, Search, Box } from 'lucide-react';
3
+ import { useState } from 'react';
4
+ import { Globe, Search, Box, Hash, X, Layout, Image as ImageIcon } from 'lucide-react';
4
5
  import { FeaturedMediaSection, PrivacySettingsSection } from './index';
6
+ import { useEditor } from '../../../state/EditorContext';
7
+ import { useCategories } from '../../../hooks/useCategories';
5
8
  export function EditorSidebar({ slug, seo, metadata, heroBlock, status, onSEOUpdate, onMetadataUpdate, }) {
6
- return (_jsxs("div", { className: "p-8 w-80 min-w-0 max-w-full space-y-12 overflow-y-auto max-h-full", children: [_jsxs("section", { children: [_jsxs("div", { className: "flex items-center gap-3 mb-6", children: [_jsx(Search, { size: 14, className: "text-neutral-500 dark:text-neutral-400" }), _jsx("label", { className: "text-[10px] uppercase tracking-[0.2em] text-neutral-500 dark:text-neutral-400 font-black", children: "SEO Settings" })] }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { className: "text-[10px] text-neutral-500 dark:text-neutral-400 uppercase font-bold block mb-2", children: "SEO Title" }), _jsx("input", { type: "text", value: seo.title || '', onChange: (e) => onSEOUpdate({ title: e.target.value }), placeholder: "SEO title (defaults to post title)", 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" }), _jsxs("p", { className: "text-[9px] text-neutral-400 dark:text-neutral-500 mt-1", children: [seo.title?.length || 0, " / 60 characters"] })] }), _jsxs("div", { children: [_jsx("label", { className: "text-[10px] text-neutral-500 dark:text-neutral-400 uppercase font-bold block mb-2", children: "Meta Description" }), _jsx("textarea", { value: seo.description || '', onChange: (e) => onSEOUpdate({ description: e.target.value }), placeholder: "Brief description for search engines", rows: 3, 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" }), _jsxs("p", { className: "text-[9px] text-neutral-400 dark:text-neutral-500 mt-1", children: [seo.description?.length || 0, " / 160 characters"] })] }), _jsxs("div", { children: [_jsx("label", { className: "text-[10px] text-neutral-500 dark:text-neutral-400 uppercase font-bold block mb-2", children: "Keywords (comma-separated)" }), _jsx("input", { type: "text", value: seo.keywords?.join(', ') || '', onChange: (e) => {
7
- const keywords = e.target.value.split(',').map(k => k.trim()).filter(k => k);
8
- onSEOUpdate({ keywords });
9
- }, placeholder: "keyword1, keyword2, keyword3", 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" })] }), _jsxs("div", { children: [_jsx("label", { className: "text-[10px] text-neutral-500 dark:text-neutral-400 uppercase font-bold block mb-2", children: "Open Graph Image URL" }), _jsx("input", { type: "url", value: seo.ogImage || '', onChange: (e) => onSEOUpdate({ ogImage: e.target.value }), placeholder: "https://example.com/image.jpg", 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" })] })] })] }), _jsxs("section", { className: "pt-8 border-t border-neutral-200 dark:border-neutral-800", children: [_jsxs("div", { className: "flex items-center gap-3 mb-6", children: [_jsx(Globe, { size: 14, className: "text-neutral-500 dark:text-neutral-400" }), _jsx("label", { className: "text-[10px] uppercase tracking-[0.2em] text-neutral-500 dark:text-neutral-400 font-black", children: "Publishing" })] }), _jsxs("div", { className: "bg-dashboard-bg p-5 rounded-2xl border border-dashboard-border", children: [_jsx("span", { className: "text-[10px] text-neutral-500 dark:text-neutral-400 uppercase font-bold block mb-3", children: "Slug / Permalink" }), _jsxs("div", { className: "text-xs font-mono break-all text-neutral-600 dark:text-neutral-400 leading-relaxed", children: ["/blog/", _jsx("span", { className: "text-neutral-950 dark:text-white bg-amber-50 dark:bg-amber-900/20 px-1 rounded", children: slug || 'untitled-post' })] })] })] }), _jsxs("section", { className: "pt-8 border-t border-neutral-200 dark:border-neutral-800", children: [_jsxs("div", { className: "flex items-center gap-3 mb-6", children: [_jsx(Box, { size: 14, className: "text-neutral-500 dark:text-neutral-400" }), _jsx("label", { className: "text-[10px] uppercase tracking-[0.2em] text-neutral-500 dark:text-neutral-400 font-black", children: "Category" })] }), _jsx("div", { className: "space-y-4", children: _jsxs("div", { children: [_jsx("label", { className: "text-[10px] text-neutral-500 dark:text-neutral-400 uppercase font-bold block mb-2", children: "Category" }), _jsx("input", { type: "text", value: metadata.categories?.[0] || '', onChange: (e) => {
10
- const category = e.target.value.trim();
11
- onMetadataUpdate({
12
- categories: category ? [category] : []
13
- });
14
- }, placeholder: "Enter category (required for publishing)", 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" }), _jsx("p", { className: "text-[9px] text-neutral-400 dark:text-neutral-500 mt-1", children: metadata.categories?.[0] ? 'Category set' : 'No category set' })] }) })] }), _jsx(FeaturedMediaSection, { featuredImage: metadata.featuredImage, heroBlock: heroBlock, slug: slug, onUpdate: (image) => onMetadataUpdate({ featuredImage: image }) }), _jsx(PrivacySettingsSection, { privacy: metadata.privacy, onUpdate: (privacy) => onMetadataUpdate({ privacy }) }), _jsxs("section", { className: "pt-8 border-t border-neutral-200 dark:border-neutral-800", children: [_jsxs("div", { className: "flex items-center justify-between mb-4", children: [_jsx("label", { className: "text-[10px] uppercase tracking-[0.2em] text-neutral-500 dark:text-neutral-400 font-black", children: "Post Status" }), _jsx("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", children: status })] }), _jsx("p", { className: "text-[11px] text-neutral-500 dark:text-neutral-400 leading-relaxed italic", children: status === 'draft'
15
- ? 'This post is private. Only you can see it until you hit publish.'
16
- : status === 'published'
17
- ? 'This post is live and visible to everyone.'
18
- : 'This post is scheduled for publication.' })] })] }));
9
+ const [newTag, setNewTag] = useState('');
10
+ const { state } = useEditor();
11
+ const { categories: existingCategories } = useCategories(state.currentLanguage || undefined);
12
+ const handleTagAdd = (e) => {
13
+ if (e.key === 'Enter' && newTag.trim()) {
14
+ const tag = newTag.trim();
15
+ if (!metadata.tags?.includes(tag)) {
16
+ onMetadataUpdate({
17
+ tags: [...(metadata.tags || []), tag]
18
+ });
19
+ }
20
+ setNewTag('');
21
+ }
22
+ };
23
+ const handleTagRemove = (tagToRemove) => {
24
+ onMetadataUpdate({
25
+ tags: (metadata.tags || []).filter(t => t !== tagToRemove)
26
+ });
27
+ };
28
+ return (_jsxs("div", { className: "p-8 w-96 min-w-0 max-w-full space-y-10 overflow-y-auto max-h-full custom-scrollbar", children: [_jsxs("section", { className: "p-6 bg-primary/5 border border-primary/20 rounded-[2rem] relative overflow-hidden", children: [_jsx("div", { className: "absolute top-0 right-0 p-4 opacity-10", children: _jsx(Globe, { size: 60, className: "text-primary" }) }), _jsxs("div", { className: "relative z-10", children: [_jsxs("div", { className: "flex items-center justify-between mb-4", children: [_jsx("label", { className: "text-[10px] font-black text-primary uppercase tracking-[0.3em]", children: "Publication Status" }), _jsx("span", { className: `px-3 py-1 rounded-full text-[9px] font-black uppercase tracking-widest border shadow-sm ${status === 'published'
29
+ ? 'bg-emerald-500 text-white border-emerald-400'
30
+ : status === 'not-translated'
31
+ ? 'bg-blue-500 text-white border-blue-400'
32
+ : 'bg-amber-500 text-white border-amber-400'}`, children: status === 'not-translated' ? 'Not Translated' : status })] }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "bg-dashboard-card/50 p-4 rounded-2xl border border-dashboard-border/50", children: [_jsx("span", { className: "text-[9px] font-black text-dashboard-text-secondary uppercase tracking-[0.2em] block mb-2", children: "Live Endpoint" }), _jsxs("div", { className: "text-[11px] font-mono text-dashboard-text leading-relaxed break-all bg-white/5 p-2 rounded-lg border border-white/5", children: ["/blog/", _jsx("span", { className: "text-primary font-bold", children: slug || 'untitled-publication' })] })] }), _jsx("p", { className: "text-[10px] text-dashboard-text-secondary leading-relaxed italic opacity-70", children: status === 'published'
33
+ ? 'This publication is live across all connected digital touchpoints.'
34
+ : status === 'not-translated'
35
+ ? 'This language edition has not been created yet. Save it as a draft to begin.'
36
+ : 'Your article is currently private. Only editorial staff can view and modify it.' })] })] })] }), _jsxs("section", { className: "space-y-6", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "size-8 rounded-xl bg-primary/10 flex items-center justify-center text-primary border border-primary/20", children: _jsx(Box, { size: 14 }) }), _jsx("label", { className: "text-[10px] font-black text-dashboard-text uppercase tracking-[0.3em]", children: "Classification" })] }), _jsxs("div", { className: "space-y-4 p-6 bg-dashboard-card/30 rounded-[2rem] border border-dashboard-border/50", children: [_jsxs("div", { className: "group", children: [_jsx("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", children: "Primary Category" }), _jsxs("div", { className: "relative", children: [_jsx(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" }), _jsx("input", { type: "text", list: "category-suggestions", value: metadata.categories?.[0] || '', onChange: (e) => onMetadataUpdate({ categories: e.target.value.trim() ? [e.target.value.trim()] : [] }), placeholder: "e.g. Technology, Lifestyle", 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" }), _jsx("datalist", { id: "category-suggestions", children: existingCategories.map(cat => (_jsx("option", { value: cat }, cat))) })] })] }), _jsxs("div", { className: "group", children: [_jsx("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", children: "Article Tags" }), _jsx("div", { className: "flex flex-wrap gap-2 mb-3", children: metadata.tags?.map((tag) => (_jsxs("span", { 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", children: [tag, _jsx("button", { onClick: () => handleTagRemove(tag), className: "text-primary/40 hover:text-primary transition-colors", children: _jsx(X, { size: 10, strokeWidth: 3 }) })] }, tag))) }), _jsxs("div", { className: "relative", children: [_jsx(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" }), _jsx("input", { type: "text", value: newTag, onChange: (e) => setNewTag(e.target.value), onKeyDown: handleTagAdd, placeholder: "Add tag + Enter", 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" })] })] })] })] }), _jsx("div", { className: "p-6 bg-dashboard-card/30 rounded-[2rem] border border-dashboard-border/50", children: _jsx(FeaturedMediaSection, { featuredImage: metadata.featuredImage, heroBlock: heroBlock, slug: slug, onUpdate: (image) => onMetadataUpdate({ featuredImage: image }) }) }), _jsxs("section", { className: "space-y-6", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "size-8 rounded-xl bg-primary/10 flex items-center justify-center text-primary border border-primary/20", children: _jsx(Search, { size: 14 }) }), _jsx("label", { className: "text-[10px] font-black text-dashboard-text uppercase tracking-[0.3em]", children: "SEO & Meta" })] }), _jsxs("div", { className: "space-y-5 p-6 bg-dashboard-card/30 rounded-[2.5rem] border border-dashboard-border/50", children: [_jsxs("div", { className: "group", children: [_jsx("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", children: "Search Engine Title" }), _jsx("input", { type: "text", value: seo.title || '', onChange: (e) => onSEOUpdate({ title: e.target.value }), placeholder: "Defaults to article title", 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" }), _jsxs("div", { className: "flex justify-between mt-1.5 px-1", children: [_jsx("p", { className: "text-[8px] font-black text-dashboard-text-secondary uppercase opacity-40", children: "Optimized: 60 chars" }), _jsxs("p", { className: `text-[9px] font-mono ${(seo.title?.length || 0) > 60 ? 'text-red-500' : 'text-primary'}`, children: [seo.title?.length || 0, "/60"] })] })] }), _jsxs("div", { className: "group", children: [_jsx("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", children: "Meta Description" }), _jsx("textarea", { value: seo.description || '', onChange: (e) => onSEOUpdate({ description: e.target.value }), placeholder: "Write a compelling summary...", rows: 4, 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" }), _jsxs("div", { className: "flex justify-between mt-1.5 px-1", children: [_jsx("p", { className: "text-[8px] font-black text-dashboard-text-secondary uppercase opacity-40", children: "Recommended: 160 chars" }), _jsxs("p", { className: `text-[9px] font-mono ${(seo.description?.length || 0) > 160 ? 'text-red-500' : 'text-primary'}`, children: [seo.description?.length || 0, "/160"] })] })] }), _jsxs("div", { className: "group", children: [_jsx("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", children: "Social Media Asset (OG Image)" }), _jsxs("div", { className: "relative", children: [_jsx(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" }), _jsx("input", { type: "url", value: seo.ogImage || '', onChange: (e) => onSEOUpdate({ ogImage: e.target.value }), placeholder: "https://...", 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" })] })] })] })] }), _jsx("div", { className: "p-6 bg-dashboard-card/30 rounded-[2.5rem] border border-dashboard-border/50", children: _jsx(PrivacySettingsSection, { privacy: metadata.privacy, onUpdate: (privacy) => onMetadataUpdate({ privacy }) }) }), _jsx("div", { className: "pb-10" })] }));
19
37
  }
@@ -15,11 +15,5 @@ export interface FeaturedMediaSectionProps {
15
15
  slug?: string;
16
16
  onUpdate: (image: FeaturedImage | undefined) => void;
17
17
  }
18
- /**
19
- * Featured Media Section Component
20
- * Handles featured image selection - completely independent from hero image
21
- * Featured image is a thumbnail used for blog post cards
22
- * Hero image is separate and managed in the hero block
23
- */
24
18
  export declare function FeaturedMediaSection({ featuredImage, heroBlock, slug, onUpdate, }: FeaturedMediaSectionProps): import("react/jsx-runtime").JSX.Element;
25
19
  //# sourceMappingURL=FeaturedMediaSection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FeaturedMediaSection.d.ts","sourceRoot":"","sources":["../../../../src/views/CanvasEditor/components/FeaturedMediaSection.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,WAAW,aAAa;IAE1B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,yBAAyB;IACtC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,SAAS,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,KAAK,IAAI,CAAC;CACxD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,aAAa,EACb,SAAS,EACT,IAAI,EACJ,QAAQ,GACX,EAAE,yBAAyB,2CA0S3B"}
1
+ {"version":3,"file":"FeaturedMediaSection.d.ts","sourceRoot":"","sources":["../../../../src/views/CanvasEditor/components/FeaturedMediaSection.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,WAAW,aAAa;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,yBAAyB;IACtC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,SAAS,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,KAAK,IAAI,CAAC;CACxD;AAED,wBAAgB,oBAAoB,CAAC,EACjC,aAAa,EACb,SAAS,EACT,IAAI,EACJ,QAAQ,GACX,EAAE,yBAAyB,2CAgL3B"}
@@ -2,72 +2,35 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useCallback, useEffect } from 'react';
4
4
  import { createPortal } from 'react-dom';
5
- import { Image as ImageIcon, Plus, X } from 'lucide-react';
5
+ import { Image as ImageIcon, Plus, X, Edit2, Trash2 } from 'lucide-react';
6
6
  import { ImagePicker, Image } from '@jhits/plugin-images';
7
- /**
8
- * Featured Media Section Component
9
- * Handles featured image selection - completely independent from hero image
10
- * Featured image is a thumbnail used for blog post cards
11
- * Hero image is separate and managed in the hero block
12
- */
13
7
  export function FeaturedMediaSection({ featuredImage, heroBlock, slug, onUpdate, }) {
14
8
  const [showImagePicker, setShowImagePicker] = useState(false);
15
9
  const [openEditorDirectly, setOpenEditorDirectly] = useState(false);
16
10
  const [mounted, setMounted] = useState(false);
17
- // Handle SSR - ensure we only render portal on client
18
- useEffect(() => {
19
- setMounted(true);
20
- }, []);
21
- // Create semantic ID for this featured image - plugin-images will handle everything
11
+ useEffect(() => { setMounted(true); }, []);
22
12
  const semanticId = slug ? `blog-featured-${slug}` : `blog-featured-${Date.now()}`;
23
- // Use semantic ID from featuredImage if it exists, otherwise use generated one
24
- // IMPORTANT: Always use the actual id from featuredImage if available, otherwise the semanticId
25
- // This ensures the id is stable and doesn't change on re-renders
26
13
  const imageId = featuredImage?.id || semanticId;
27
- // Ensure featuredImage always has an id when it exists
28
- // This prevents the "missing featured image" issue on save
29
14
  useEffect(() => {
30
15
  if (featuredImage && !featuredImage.id) {
31
- // If featuredImage exists but has no id, set it to the semanticId
32
- onUpdate({
33
- ...featuredImage,
34
- id: semanticId,
35
- });
16
+ onUpdate({ ...featuredImage, id: semanticId });
36
17
  }
37
18
  }, [featuredImage, semanticId, onUpdate]);
38
- // Get transform values from featuredImage or use defaults
39
19
  const brightness = featuredImage?.brightness ?? 100;
40
20
  const blur = featuredImage?.blur ?? 0;
41
21
  const scale = featuredImage?.scale ?? 1.0;
42
22
  const positionX = featuredImage?.positionX ?? 0;
43
23
  const positionY = featuredImage?.positionY ?? 0;
44
- // Handle image selection - create initial mapping and update blog metadata with semantic ID
45
- // Plugin-images Image component will automatically resolve the semantic ID when it renders
46
24
  const handleImageChange = useCallback(async (image) => {
47
25
  if (image) {
48
- // Extract filename from image URL for reference
49
26
  const isUploadedImage = image.url.startsWith('/api/uploads/');
50
27
  let filename = image.filename;
51
- if (!filename && isUploadedImage) {
52
- // Extract filename from URL if not provided
28
+ if (!filename && isUploadedImage)
53
29
  filename = image.url.split('/api/uploads/')[1]?.split('?')[0] || image.id;
54
- }
55
- else if (!filename) {
56
- // For external URLs, use the image ID or extract from URL
30
+ else if (!filename)
57
31
  filename = image.id || image.url.split('/').pop()?.split('?')[0] || `external-${Date.now()}`;
58
- }
59
- // Create initial mapping in plugin-images API immediately
60
- // This ensures the semantic ID resolves correctly
61
32
  try {
62
- const saveData = {
63
- id: imageId,
64
- filename: filename,
65
- scale: 1.0,
66
- positionX: 0,
67
- positionY: 0,
68
- brightness: 100,
69
- blur: 0,
70
- };
33
+ const saveData = { id: imageId, filename, scale: 1.0, positionX: 0, positionY: 0, brightness: 100, blur: 0 };
71
34
  await fetch('/api/plugin-images/resolve', {
72
35
  method: 'POST',
73
36
  headers: { 'Content-Type': 'application/json' },
@@ -75,35 +38,20 @@ export function FeaturedMediaSection({ featuredImage, heroBlock, slug, onUpdate,
75
38
  });
76
39
  }
77
40
  catch (error) {
78
- console.error('[FeaturedMediaSection] Failed to create initial mapping:', error);
79
- // Continue anyway - the mapping might be created later
41
+ console.error(error);
80
42
  }
81
- // Update blog metadata with semantic ID
82
- onUpdate({
83
- id: imageId,
84
- alt: image.alt || image.filename,
85
- brightness: 100,
86
- blur: 0,
87
- scale: 1.0,
88
- positionX: 0,
89
- positionY: 0,
90
- isCustom: true,
91
- });
43
+ onUpdate({ id: imageId, alt: image.alt || image.filename, brightness: 100, blur: 0, scale: 1.0, positionX: 0, positionY: 0, isCustom: true });
92
44
  }
93
45
  else {
94
- // If removed, set to undefined
95
46
  onUpdate(undefined);
96
47
  }
97
48
  setShowImagePicker(false);
98
49
  }, [imageId, onUpdate]);
99
- // Handle editor save from ImagePicker - save to plugin-images API
100
50
  const handleEditorSave = useCallback(async (finalScale, finalPositionX, finalPositionY, finalBrightness, finalBlur) => {
101
51
  if (!featuredImage?.id)
102
52
  return;
103
- // Reset the auto-open flag immediately to prevent reopening
104
53
  setOpenEditorDirectly(false);
105
- // Get the actual filename from the API (resolve the semantic ID)
106
- let filename = imageId; // Fallback to semantic ID
54
+ let filename = imageId;
107
55
  try {
108
56
  const response = await fetch(`/api/plugin-images/resolve?id=${encodeURIComponent(imageId)}`);
109
57
  if (response.ok) {
@@ -112,88 +60,29 @@ export function FeaturedMediaSection({ featuredImage, heroBlock, slug, onUpdate,
112
60
  }
113
61
  }
114
62
  catch (error) {
115
- console.error('Failed to resolve filename:', error);
63
+ console.error(error);
116
64
  }
117
- // Normalize position values
118
65
  const normalizedPositionX = finalPositionX === -50 ? 0 : finalPositionX;
119
66
  const normalizedPositionY = finalPositionY === -50 ? 0 : finalPositionY;
120
67
  const finalBrightnessValue = finalBrightness ?? brightness;
121
68
  const finalBlurValue = finalBlur ?? blur;
122
- // Save to plugin-images API
123
69
  try {
124
- const saveData = {
125
- id: imageId,
126
- filename: filename,
127
- scale: finalScale,
128
- positionX: normalizedPositionX,
129
- positionY: normalizedPositionY,
130
- brightness: finalBrightnessValue,
131
- blur: finalBlurValue,
132
- };
70
+ const saveData = { id: imageId, filename, scale: finalScale, positionX: normalizedPositionX, positionY: normalizedPositionY, brightness: finalBrightnessValue, blur: finalBlurValue };
133
71
  const response = await fetch('/api/plugin-images/resolve', {
134
72
  method: 'POST',
135
73
  headers: { 'Content-Type': 'application/json' },
136
74
  body: JSON.stringify(saveData),
137
75
  });
138
76
  if (response.ok) {
139
- // Update local featured image data - ensure id is preserved
140
- onUpdate({
141
- ...featuredImage,
142
- id: featuredImage.id || imageId, // Ensure id is always preserved
143
- scale: finalScale,
144
- positionX: normalizedPositionX,
145
- positionY: normalizedPositionY,
146
- brightness: finalBrightnessValue,
147
- blur: finalBlurValue,
148
- });
149
- // Dispatch event to notify Image components
150
- window.dispatchEvent(new CustomEvent('image-mapping-updated', {
151
- detail: saveData
152
- }));
77
+ onUpdate({ ...featuredImage, id: featuredImage.id || imageId, scale: finalScale, positionX: normalizedPositionX, positionY: normalizedPositionY, brightness: finalBrightnessValue, blur: finalBlurValue });
78
+ window.dispatchEvent(new CustomEvent('image-mapping-updated', { detail: saveData }));
153
79
  }
154
80
  }
155
81
  catch (error) {
156
- console.error('Failed to save image transform:', error);
82
+ console.error(error);
157
83
  }
158
84
  }, [imageId, featuredImage, brightness, blur, onUpdate]);
159
- return (_jsxs("section", { children: [_jsxs("div", { className: "flex items-center gap-3 mb-6", children: [_jsx(ImageIcon, { size: 14, className: "text-neutral-500 dark:text-neutral-400" }), _jsx("label", { className: "text-[10px] uppercase tracking-[0.2em] text-neutral-500 dark:text-neutral-400 font-black", children: "Featured Media" })] }), featuredImage?.id ? (_jsxs("div", { className: "relative group", children: [_jsxs("div", { className: "relative aspect-[16/10] bg-dashboard-bg rounded-3xl overflow-hidden border border-dashboard-border group/image", children: [_jsx(Image, { id: imageId, alt: featuredImage?.alt || 'Featured image', fill: true, className: "object-cover w-full h-full", editable: false, ...{
160
- brightness,
161
- blur,
162
- scale,
163
- positionX,
164
- positionY,
165
- } }), _jsx("button", { onClick: () => {
166
- setOpenEditorDirectly(true);
167
- setShowImagePicker(true);
168
- }, className: "absolute inset-0 z-30 flex items-center justify-center opacity-0 group-hover/image:opacity-100 transition-all duration-300 bg-neutral-900/40 dark:bg-neutral-900/60 backdrop-blur-[2px]", children: _jsxs("div", { className: "flex items-center gap-2 px-4 py-2 bg-white dark:bg-neutral-800 rounded-full shadow-xl", children: [_jsx(ImageIcon, { size: 14, className: "text-primary" }), _jsx("span", { className: "text-[10px] font-bold uppercase tracking-widest", children: "Edit" })] }) })] }), _jsxs("div", { className: "mt-2 flex items-center gap-3", children: [_jsx("button", { onClick: () => setShowImagePicker(true), className: "text-[10px] text-neutral-600 dark:text-neutral-400 hover:text-primary font-bold uppercase tracking-wider", children: "Change Image" }), _jsx("span", { className: "text-[10px] text-neutral-400", children: "\u2022" }), _jsx("button", { onClick: () => onUpdate(undefined), className: "text-[10px] text-red-500 dark:text-red-400 hover:text-red-700 dark:hover:text-red-300 font-bold uppercase tracking-wider", children: "Remove Image" })] })] })) : (_jsxs("div", { className: "group relative aspect-[16/10] bg-dashboard-bg rounded-3xl border-2 border-dashed border-dashboard-border flex flex-col items-center justify-center text-neutral-400 dark:text-neutral-500 hover:bg-dashboard-card hover:border-primary cursor-pointer transition-all duration-300", onClick: () => setShowImagePicker(true), children: [_jsx(Plus, { size: 24, strokeWidth: 1, className: "mb-3 group-hover:scale-110 transition-transform" }), _jsx("span", { className: "text-[9px] font-black uppercase tracking-widest", children: "Assign Image" })] })), showImagePicker && mounted && createPortal(_jsx("div", { className: "fixed inset-0 z-[100] flex items-center justify-center bg-black/50 backdrop-blur-sm", onClick: () => {
169
- setShowImagePicker(false);
170
- setOpenEditorDirectly(false); // Reset flag when closing
171
- }, children: _jsxs("div", { className: "bg-white dark:bg-neutral-900 rounded-2xl w-full max-w-2xl mx-4 p-6 shadow-2xl max-h-[90vh] overflow-y-auto", onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "flex items-center justify-between mb-6", children: [_jsx("h3", { className: "text-lg font-bold text-neutral-900 dark:text-neutral-100", children: openEditorDirectly ? 'Edit Featured Image' : 'Select Featured Image' }), _jsx("button", { onClick: () => {
172
- setShowImagePicker(false);
173
- setOpenEditorDirectly(false); // Reset flag when closing
174
- }, className: "p-2 hover:bg-dashboard-bg dark:hover:bg-neutral-800 rounded-lg transition-colors text-neutral-700 dark:text-neutral-300 hover:text-neutral-900 dark:hover:text-white", "aria-label": "Close", children: _jsx(X, { size: 20, className: "transition-colors" }) })] }), _jsx(ImagePicker, { value: featuredImage?.id ? imageId : undefined, onChange: handleImageChange, brightness: brightness, blur: blur, ...{
175
- scale,
176
- positionX,
177
- positionY,
178
- }, onBrightnessChange: (val) => {
179
- // Update local state only - don't trigger save
180
- if (featuredImage) {
181
- onUpdate({
182
- ...featuredImage,
183
- id: featuredImage.id || imageId, // Ensure id is preserved
184
- brightness: val,
185
- });
186
- }
187
- }, onBlurChange: (val) => {
188
- // Update local state only - don't trigger save
189
- if (featuredImage) {
190
- onUpdate({
191
- ...featuredImage,
192
- id: featuredImage.id || imageId, // Ensure id is preserved
193
- blur: val,
194
- });
195
- }
196
- }, onEditorSave: handleEditorSave, darkMode: false, showEffects: true, aspectRatio: "16/10" // Thumbnail aspect ratio for blog cards
197
- , borderRadius: "rounded-3xl", objectFit: "cover" // Cover for thumbnails
198
- , objectPosition: "center" })] }) }), document.body)] }));
85
+ return (_jsxs("section", { children: [_jsxs("div", { className: "flex items-center gap-3 mb-6", children: [_jsx("div", { className: "size-8 rounded-xl bg-primary/10 flex items-center justify-center text-primary border border-primary/20", children: _jsx(ImageIcon, { size: 14 }) }), _jsx("label", { className: "text-[10px] font-black text-dashboard-text uppercase tracking-[0.3em]", children: "Visual Identity" })] }), featuredImage?.id ? (_jsxs("div", { className: "relative group", children: [_jsxs("div", { className: "relative aspect-[16/10] bg-dashboard-bg rounded-3xl overflow-hidden border border-dashboard-border group/image shadow-inner", children: [_jsx(Image, { id: imageId, alt: featuredImage?.alt || 'Featured image', fill: true, className: "object-cover w-full h-full group-hover:scale-105 transition-transform duration-700", editable: false, ...{ brightness, blur, scale, positionX, positionY } }), _jsx("div", { className: "absolute inset-0 z-30 flex items-center justify-center opacity-0 group-hover/image:opacity-100 transition-all duration-500 bg-black/20 backdrop-blur-[2px]", children: _jsxs("button", { onClick: () => { setOpenEditorDirectly(true); setShowImagePicker(true); }, className: "flex items-center gap-2 px-5 py-2.5 bg-white text-black rounded-full shadow-2xl hover:scale-105 active:scale-95 transition-all", children: [_jsx(Edit2, { size: 12, className: "fill-current" }), _jsx("span", { className: "text-[10px] font-black uppercase tracking-widest", children: "Adjust View" })] }) })] }), _jsxs("div", { className: "mt-4 flex items-center justify-between px-1", children: [_jsxs("button", { onClick: () => setShowImagePicker(true), className: "text-[9px] font-black uppercase tracking-[0.2em] text-primary hover:text-primary/80 transition-colors flex items-center gap-1.5", children: [_jsx(Plus, { size: 10, strokeWidth: 3 }), "Replace"] }), _jsxs("button", { onClick: () => onUpdate(undefined), className: "text-[9px] font-black uppercase tracking-[0.2em] text-red-500/60 hover:text-red-500 transition-colors flex items-center gap-1.5", children: [_jsx(Trash2, { size: 10 }), "Detach"] })] })] })) : (_jsxs("div", { className: "group relative aspect-[16/10] bg-dashboard-bg/50 rounded-[2.5rem] border-2 border-dashed border-dashboard-border/50 flex flex-col items-center justify-center text-dashboard-text-secondary/40 hover:bg-primary/[0.02] hover:border-primary/40 cursor-pointer transition-all duration-500 shadow-inner", onClick: () => setShowImagePicker(true), children: [_jsx("div", { className: "size-14 rounded-full bg-dashboard-card flex items-center justify-center border border-dashboard-border group-hover:scale-110 group-hover:border-primary/20 transition-all duration-500 mb-4 shadow-sm", children: _jsx(ImageIcon, { size: 24, strokeWidth: 1.5, className: "group-hover:text-primary transition-colors" }) }), _jsx("span", { className: "text-[10px] font-black uppercase tracking-[0.3em] group-hover:text-primary transition-colors", children: "Assign Visual" })] })), showImagePicker && mounted && createPortal(_jsxs("div", { className: "fixed inset-0 z-[9999] flex items-center justify-center p-6", onClick: () => { setShowImagePicker(false); setOpenEditorDirectly(false); }, children: [_jsx("div", { className: "absolute inset-0 bg-black/60 backdrop-blur-md" }), _jsxs("div", { className: "relative bg-dashboard-bg border border-dashboard-border rounded-[3rem] w-full max-w-3xl overflow-hidden shadow-2xl animate-in zoom-in-95 duration-300 flex flex-col max-h-full", onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "p-8 border-b border-dashboard-border flex items-center justify-between", children: [_jsxs("div", { children: [_jsxs("h3", { className: "text-2xl font-black text-dashboard-text uppercase tracking-tighter", children: [openEditorDirectly ? 'Perfecting' : 'Curating', " Image"] }), _jsx("p", { className: "text-xs text-dashboard-text-secondary italic mt-1", children: "Select or adjust the featured visual for your article." })] }), _jsx("button", { onClick: () => { setShowImagePicker(false); setOpenEditorDirectly(false); }, className: "size-12 flex items-center justify-center bg-dashboard-card border border-dashboard-border rounded-2xl hover:text-red-500 hover:border-red-500/20 transition-all", children: _jsx(X, { size: 20 }) })] }), _jsx("div", { className: "flex-1 overflow-y-auto p-8 custom-scrollbar", children: _jsx(ImagePicker, { value: featuredImage?.id ? imageId : undefined, onChange: handleImageChange, brightness: brightness, blur: blur, ...{ scale, positionX, positionY }, onBrightnessChange: (val) => { if (featuredImage)
86
+ onUpdate({ ...featuredImage, id: featuredImage.id || imageId, brightness: val }); }, onBlurChange: (val) => { if (featuredImage)
87
+ onUpdate({ ...featuredImage, id: featuredImage.id || imageId, blur: val }); }, onEditorSave: handleEditorSave, darkMode: true, showEffects: true, aspectRatio: "16/10", borderRadius: "rounded-[2rem]", objectFit: "cover", objectPosition: "center" }) })] })] }), document.body)] }));
199
88
  }
@@ -0,0 +1,9 @@
1
+ export interface JSONInspectorProps {
2
+ data: any;
3
+ }
4
+ /**
5
+ * Dev-only JSON Inspector
6
+ * Displays the current state of the blog post in a formatted JSON view
7
+ */
8
+ export declare function JSONInspector({ data }: JSONInspectorProps): import("react/jsx-runtime").JSX.Element | null;
9
+ //# sourceMappingURL=JSONInspector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JSONInspector.d.ts","sourceRoot":"","sources":["../../../../src/views/CanvasEditor/components/JSONInspector.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,kBAAkB;IAC/B,IAAI,EAAE,GAAG,CAAC;CACb;AA+BD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,EAAE,kBAAkB,kDAkFzD"}
@@ -0,0 +1,56 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useState, useMemo } from 'react';
4
+ import { Code, X, Copy, Check } from 'lucide-react';
5
+ /**
6
+ * Simple JSON Syntax Highlighter
7
+ */
8
+ function highlightJSON(json) {
9
+ if (!json)
10
+ return null;
11
+ // Convert to string and escape HTML
12
+ const escaped = json
13
+ .replace(/&/g, '&')
14
+ .replace(/</g, '&lt;')
15
+ .replace(/>/g, '&gt;');
16
+ return escaped.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
17
+ let cls = 'text-orange-400'; // number
18
+ if (/^"/.test(match)) {
19
+ if (/:$/.test(match)) {
20
+ cls = 'text-blue-400'; // key
21
+ }
22
+ else {
23
+ cls = 'text-green-400'; // string
24
+ }
25
+ }
26
+ else if (/true|false/.test(match)) {
27
+ cls = 'text-purple-400'; // boolean
28
+ }
29
+ else if (/null/.test(match)) {
30
+ cls = 'text-neutral-500'; // null
31
+ }
32
+ return `<span class="${cls}">${match}</span>`;
33
+ });
34
+ }
35
+ /**
36
+ * Dev-only JSON Inspector
37
+ * Displays the current state of the blog post in a formatted JSON view
38
+ */
39
+ export function JSONInspector({ data }) {
40
+ const [isOpen, setIsOpen] = useState(false);
41
+ const [copied, setCopied] = useState(false);
42
+ // Memoize the highlighted HTML to prevent re-parsing on every render
43
+ const highlightedHTML = useMemo(() => {
44
+ const jsonString = JSON.stringify(data, null, 2);
45
+ return highlightJSON(jsonString);
46
+ }, [data]);
47
+ // Only visible in development mode
48
+ if (process.env.NODE_ENV !== 'development')
49
+ return null;
50
+ const handleCopy = () => {
51
+ navigator.clipboard.writeText(JSON.stringify(data, null, 2));
52
+ setCopied(true);
53
+ setTimeout(() => setCopied(false), 2000);
54
+ };
55
+ return (_jsxs(_Fragment, { children: [_jsxs("button", { onClick: () => setIsOpen(true), className: "fixed bottom-8 right-8 z-[100] bg-neutral-900 dark:bg-white text-white dark:text-neutral-900 px-5 py-3 rounded-2xl shadow-2xl hover:scale-105 active:scale-95 transition-all flex items-center gap-3 border border-white/10 dark:border-neutral-200", title: "Inspect JSON (Dev Only)", children: [_jsx("div", { className: "size-2 rounded-full bg-green-500 animate-pulse" }), _jsx(Code, { size: 18, strokeWidth: 2.5 }), _jsx("span", { className: "text-[10px] font-black uppercase tracking-[0.2em]", children: "Inspect JSON" })] }), isOpen && (_jsx("div", { className: "fixed inset-0 z-[110] bg-black/60 backdrop-blur-md flex items-center justify-center p-6 md:p-12 animate-in fade-in duration-300", children: _jsxs("div", { className: "bg-white dark:bg-neutral-900 rounded-[2.5rem] w-full max-w-5xl h-[85vh] flex flex-col overflow-hidden shadow-[0_32px_64px_-12px_rgba(0,0,0,0.5)] border border-neutral-200 dark:border-neutral-800 animate-in zoom-in-95 duration-300", children: [_jsxs("div", { className: "px-8 py-6 border-b border-neutral-100 dark:border-neutral-800 flex justify-between items-center bg-neutral-50/50 dark:bg-neutral-800/50 shrink-0", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-3 mb-1", children: [_jsx("h3", { className: "font-black uppercase tracking-tighter text-2xl text-neutral-900 dark:text-white", children: "Blog Data" }), _jsx("span", { className: "px-2 py-0.5 rounded-md bg-primary/10 text-primary text-[9px] font-black uppercase tracking-widest", children: "Dev Tool" })] }), _jsx("p", { className: "text-[10px] text-neutral-500 font-bold uppercase tracking-widest", children: "Raw state inspector for debugging purposes" })] }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("button", { onClick: handleCopy, className: "flex items-center gap-2 px-5 py-2.5 bg-neutral-100 dark:bg-neutral-800 hover:bg-neutral-200 dark:hover:bg-neutral-700 rounded-xl text-[10px] font-black uppercase tracking-widest transition-all", children: [copied ? _jsx(Check, { size: 14, className: "text-green-500" }) : _jsx(Copy, { size: 14 }), copied ? 'Copied' : 'Copy JSON'] }), _jsx("button", { onClick: () => setIsOpen(false), className: "p-2 hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-full transition-colors text-neutral-400 hover:text-neutral-900 dark:hover:text-white", children: _jsx(X, { size: 28, strokeWidth: 1.5 }) })] })] }), _jsx("div", { className: "flex-1 min-h-0 w-full bg-[#0d0d0d] overflow-y-auto overflow-x-hidden custom-scrollbar", children: _jsx("pre", { className: "p-8 font-mono text-[13px] leading-relaxed text-neutral-300 whitespace-pre-wrap break-all", dangerouslySetInnerHTML: { __html: highlightedHTML || '' } }) }), _jsxs("div", { className: "px-8 py-4 bg-neutral-50 dark:bg-neutral-800/30 border-t border-neutral-100 dark:border-neutral-800 flex justify-between items-center text-[9px] font-bold text-neutral-400 uppercase tracking-widest shrink-0", children: [_jsxs("span", { children: ["Blocks Count: ", data.blocks?.length || 0] }), _jsxs("span", { children: ["Status: ", data.status || 'Unknown'] })] })] }) }))] }));
56
+ }
@@ -9,7 +9,7 @@ export function LibraryItem({ icon, label, blockType, description, onAddBlock })
9
9
  const [hasDragged, setHasDragged] = useState(false);
10
10
  const mouseDownRef = useRef(null);
11
11
  const handleDragStart = (e) => {
12
- e.dataTransfer.setData('block-type', blockType);
12
+ e.dataTransfer.setData('blockType', blockType);
13
13
  e.dataTransfer.effectAllowed = 'move';
14
14
  setHasDragged(true); // Mark as dragged when drag starts
15
15
  };
@@ -39,5 +39,5 @@ export function LibraryItem({ icon, label, blockType, description, onAddBlock })
39
39
  mouseDownRef.current = null;
40
40
  setTimeout(() => setHasDragged(false), 100);
41
41
  };
42
- return (_jsxs("div", { draggable: true, onDragStart: handleDragStart, onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onClick: handleClick, className: "flex flex-col items-center justify-center p-5 rounded-2xl border border-dashboard-border bg-dashboard-card hover:border-primary hover:shadow-xl hover:shadow-primary/5 transition-all cursor-pointer group", children: [_jsx("div", { className: "text-neutral-400 dark:text-neutral-500 group-hover:text-primary dark:group-hover:text-primary mb-3 transition-colors duration-300", children: React.cloneElement(icon, { strokeWidth: 1.5 }) }), _jsx("span", { className: "text-[9px] font-black uppercase tracking-[0.15em] text-neutral-600 dark:text-neutral-400 group-hover:text-neutral-950 dark:group-hover:text-white transition-colors", children: label })] }));
42
+ return (_jsxs("div", { draggable: true, onDragStart: handleDragStart, onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onClick: handleClick, className: "flex flex-col items-center justify-center p-6 rounded-[2rem] border border-dashboard-border/50 bg-dashboard-card/30 backdrop-blur-sm hover:border-primary/40 hover:bg-primary/[0.02] hover:shadow-2xl hover:shadow-primary/10 hover:scale-[1.05] transition-all duration-500 cursor-grab active:cursor-grabbing group", children: [_jsx("div", { className: "text-dashboard-text-secondary group-hover:text-primary transition-all duration-500 group-hover:scale-110 mb-4", children: React.cloneElement(icon, { strokeWidth: 1.5, size: 24 }) }), _jsx("span", { className: "text-[9px] font-black uppercase tracking-[0.2em] text-dashboard-text-secondary group-hover:text-dashboard-text transition-colors text-center leading-tight", children: label })] }));
43
43
  }
@@ -7,9 +7,5 @@ export interface PrivacySettingsSectionProps {
7
7
  privacy?: PrivacySettings;
8
8
  onUpdate: (privacy: PrivacySettings) => void;
9
9
  }
10
- /**
11
- * Privacy Settings Section Component
12
- * Handles privacy settings: private, password-protected, share with users
13
- */
14
10
  export declare function PrivacySettingsSection({ privacy, onUpdate, }: PrivacySettingsSectionProps): import("react/jsx-runtime").JSX.Element;
15
11
  //# sourceMappingURL=PrivacySettingsSection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PrivacySettingsSection.d.ts","sourceRoot":"","sources":["../../../../src/views/CanvasEditor/components/PrivacySettingsSection.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,2BAA2B;IACxC,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;CAChD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,EACnC,OAAO,EACP,QAAQ,GACX,EAAE,2BAA2B,2CA2L7B"}
1
+ {"version":3,"file":"PrivacySettingsSection.d.ts","sourceRoot":"","sources":["../../../../src/views/CanvasEditor/components/PrivacySettingsSection.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,2BAA2B;IACxC,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;CAChD;AAED,wBAAgB,sBAAsB,CAAC,EACnC,OAAO,EACP,QAAQ,GACX,EAAE,2BAA2B,2CA6I7B"}
@@ -1,30 +1,24 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect } from 'react';
4
- import { Shield, Key, Users } from 'lucide-react';
5
- /**
6
- * Privacy Settings Section Component
7
- * Handles privacy settings: private, password-protected, share with users
8
- */
4
+ import { Shield, Key, Users, Lock, Unlock } from 'lucide-react';
9
5
  export function PrivacySettingsSection({ privacy, onUpdate, }) {
10
6
  const [users, setUsers] = useState([]);
11
7
  const [loadingUsers, setLoadingUsers] = useState(false);
12
8
  const [showPasswordInput, setShowPasswordInput] = useState(false);
13
9
  const [passwordValue, setPasswordValue] = useState(privacy?.password || '');
14
10
  const [showUserSelector, setShowUserSelector] = useState(false);
15
- // Fetch users from plugin-users
16
11
  useEffect(() => {
17
12
  const fetchUsers = async () => {
18
13
  try {
19
14
  setLoadingUsers(true);
20
15
  const res = await fetch('/api/users');
21
16
  const data = await res.json();
22
- if (Array.isArray(data)) {
17
+ if (Array.isArray(data))
23
18
  setUsers(data);
24
- }
25
19
  }
26
20
  catch (err) {
27
- console.error('Failed to load users', err);
21
+ console.error(err);
28
22
  }
29
23
  finally {
30
24
  setLoadingUsers(false);
@@ -36,35 +30,19 @@ export function PrivacySettingsSection({ privacy, onUpdate, }) {
36
30
  onUpdate({
37
31
  ...privacy,
38
32
  isPrivate,
39
- // Clear password and shared users if making public
40
33
  ...(isPrivate ? {} : { password: undefined, sharedWithUsers: undefined }),
41
34
  });
42
35
  };
43
36
  const handlePasswordChange = (password) => {
44
37
  setPasswordValue(password);
45
- onUpdate({
46
- ...privacy,
47
- password: password || undefined,
48
- });
38
+ onUpdate({ ...privacy, password: password || undefined });
49
39
  };
50
40
  const handleUserToggle = (userId) => {
51
41
  const currentUsers = privacy?.sharedWithUsers || [];
52
42
  const newUsers = currentUsers.includes(userId)
53
43
  ? currentUsers.filter(id => id !== userId)
54
44
  : [...currentUsers, userId];
55
- onUpdate({
56
- ...privacy,
57
- sharedWithUsers: newUsers.length > 0 ? newUsers : undefined,
58
- });
45
+ onUpdate({ ...privacy, sharedWithUsers: newUsers.length > 0 ? newUsers : undefined });
59
46
  };
60
- return (_jsxs("section", { className: "pt-8 border-t border-neutral-200 dark:border-neutral-800", children: [_jsxs("div", { className: "flex items-center gap-3 mb-6", children: [_jsx(Shield, { size: 14, className: "text-neutral-500 dark:text-neutral-400" }), _jsx("label", { className: "text-[10px] uppercase tracking-[0.2em] text-neutral-500 dark:text-neutral-400 font-black", children: "Privacy Settings" })] }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("label", { className: "text-[10px] text-neutral-700 dark:text-neutral-300 font-bold block mb-1", children: "Make Private" }), _jsx("p", { className: "text-[9px] text-neutral-500 dark:text-neutral-400", children: "Hide from public view" })] }), _jsx("button", { onClick: () => handlePrivacyToggle(!privacy?.isPrivate), className: `relative w-12 h-6 rounded-full transition-colors ${privacy?.isPrivate ? 'bg-primary' : 'bg-neutral-300 dark:bg-neutral-700'}`, children: _jsx("div", { className: `absolute top-1 left-1 w-4 h-4 bg-white rounded-full transition-transform ${privacy?.isPrivate ? 'translate-x-6' : 'translate-x-0'}` }) })] }), privacy?.isPrivate && (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("label", { className: "text-[10px] text-neutral-700 dark:text-neutral-300 font-bold block mb-1", children: "Password Protection" }), _jsx("p", { className: "text-[9px] text-neutral-500 dark:text-neutral-400", children: "Require password to view" })] }), _jsx("button", { onClick: () => {
61
- setShowPasswordInput(!showPasswordInput);
62
- if (!showPasswordInput && !privacy.password) {
63
- setPasswordValue('');
64
- }
65
- }, className: `p-1.5 rounded-lg transition-colors ${privacy.password || showPasswordInput
66
- ? 'bg-primary/10 text-primary'
67
- : 'bg-neutral-100 dark:bg-neutral-800 text-neutral-400'}`, children: _jsx(Key, { size: 14 }) })] }), (showPasswordInput || privacy.password) && (_jsx("input", { type: "password", value: passwordValue, onChange: (e) => handlePasswordChange(e.target.value), placeholder: "Enter password", 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" }))] })), privacy?.isPrivate && (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("label", { className: "text-[10px] text-neutral-700 dark:text-neutral-300 font-bold block mb-1", children: "Share with Users" }), _jsx("p", { className: "text-[9px] text-neutral-500 dark:text-neutral-400", children: "Grant access to specific users" })] }), _jsx("button", { onClick: () => setShowUserSelector(!showUserSelector), className: `p-1.5 rounded-lg transition-colors ${(privacy.sharedWithUsers?.length || 0) > 0 || showUserSelector
68
- ? 'bg-primary/10 text-primary'
69
- : 'bg-neutral-100 dark:bg-neutral-800 text-neutral-400'}`, children: _jsx(Users, { size: 14 }) })] }), showUserSelector && (_jsx("div", { className: "bg-dashboard-bg rounded-lg p-3 border border-dashboard-border max-h-48 overflow-y-auto", children: loadingUsers ? (_jsx("p", { className: "text-[10px] text-neutral-500 dark:text-neutral-400", children: "Loading users..." })) : users.length === 0 ? (_jsx("p", { className: "text-[10px] text-neutral-500 dark:text-neutral-400", children: "No users found" })) : (_jsx("div", { className: "space-y-2", children: users.map((user) => (_jsxs("label", { className: "flex items-center gap-2 cursor-pointer hover:bg-dashboard-bg p-2 rounded transition-colors", children: [_jsx("input", { type: "checkbox", checked: privacy.sharedWithUsers?.includes(user._id) || false, onChange: () => handleUserToggle(user._id), className: "rounded border-neutral-300 dark:border-neutral-700 text-primary focus:ring-primary" }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("p", { className: "text-[10px] font-bold text-neutral-700 dark:text-neutral-300 truncate", children: user.name }), _jsx("p", { className: "text-[9px] text-neutral-500 dark:text-neutral-400 truncate", children: user.email })] })] }, user._id))) })) })), privacy.sharedWithUsers && privacy.sharedWithUsers.length > 0 && (_jsxs("p", { className: "text-[9px] text-neutral-500 dark:text-neutral-400", children: ["Shared with ", privacy.sharedWithUsers.length, " user", privacy.sharedWithUsers.length !== 1 ? 's' : ''] }))] }))] })] }));
47
+ return (_jsxs("section", { className: "space-y-6", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "size-8 rounded-xl bg-primary/10 flex items-center justify-center text-primary border border-primary/20", children: _jsx(Shield, { size: 14 }) }), _jsx("label", { className: "text-[10px] font-black text-dashboard-text uppercase tracking-[0.3em]", children: "Privacy & Security" })] }), _jsxs("div", { className: "space-y-4", children: [_jsx("div", { className: `p-4 rounded-[1.5rem] border transition-all duration-500 ${privacy?.isPrivate ? 'bg-primary/5 border-primary/20 shadow-sm' : 'bg-dashboard-bg/50 border-dashboard-border/50'}`, children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: `size-10 rounded-xl flex items-center justify-center border transition-all ${privacy?.isPrivate ? 'bg-primary text-white border-primary/20' : 'bg-dashboard-card text-dashboard-text-secondary border-dashboard-border'}`, children: privacy?.isPrivate ? _jsx(Lock, { size: 16 }) : _jsx(Unlock, { size: 16 }) }), _jsxs("div", { children: [_jsx("label", { className: "text-[10px] font-black text-dashboard-text uppercase tracking-widest", children: "Restrict Access" }), _jsx("p", { className: "text-[9px] text-dashboard-text-secondary italic opacity-60", children: "Hide from public view" })] })] }), _jsx("button", { onClick: () => handlePrivacyToggle(!privacy?.isPrivate), className: `relative w-12 h-6 rounded-full transition-colors ${privacy?.isPrivate ? 'bg-primary' : 'bg-dashboard-card border border-dashboard-border'}`, children: _jsx("div", { className: `absolute top-1 left-1 size-4 rounded-full transition-transform ${privacy?.isPrivate ? 'translate-x-6 bg-white shadow-sm' : 'translate-x-0 bg-dashboard-text-secondary/30'}` }) })] }) }), privacy?.isPrivate && (_jsxs("div", { className: "space-y-3 animate-in fade-in slide-in-from-top-2 duration-300", children: [_jsxs("div", { className: "group", children: [_jsx("div", { className: "flex items-center justify-between mb-2 px-1", children: _jsxs("label", { className: "text-[9px] font-black text-dashboard-text-secondary uppercase tracking-widest group-focus-within:text-primary transition-colors flex items-center gap-2", children: [_jsx(Key, { size: 10 }), " Password Layer"] }) }), _jsx("input", { type: "password", value: passwordValue, onChange: (e) => handlePasswordChange(e.target.value), placeholder: "Set viewing password...", className: "w-full px-4 py-2.5 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" })] }), _jsxs("div", { className: "pt-2", children: [_jsxs("button", { onClick: () => setShowUserSelector(!showUserSelector), className: `w-full flex items-center justify-between p-3 rounded-xl border transition-all ${showUserSelector ? 'bg-primary/10 border-primary/30 text-primary' : 'bg-dashboard-card/50 border-dashboard-border/50 text-dashboard-text-secondary hover:border-primary/30'}`, children: [_jsxs("div", { className: "flex items-center gap-2 text-[9px] font-black uppercase tracking-widest", children: [_jsx(Users, { size: 12 }), _jsx("span", { children: "Grant Personal Access" })] }), _jsx("span", { className: "text-[10px] font-bold opacity-60 bg-white/5 px-2 py-0.5 rounded-full", children: privacy.sharedWithUsers?.length || 0 })] }), showUserSelector && (_jsx("div", { className: "mt-3 bg-dashboard-bg/80 backdrop-blur-xl rounded-2xl border border-dashboard-border/50 overflow-hidden animate-in fade-in slide-in-from-top-2 duration-300", children: _jsx("div", { className: "max-h-48 overflow-y-auto p-2 custom-scrollbar space-y-1", children: loadingUsers ? (_jsx("div", { className: "p-4 text-center animate-pulse text-[10px] font-black text-primary/40 uppercase tracking-widest", children: "Scanning Network..." })) : users.map((user) => (_jsxs("label", { className: "flex items-center gap-3 p-2 rounded-xl hover:bg-primary/5 cursor-pointer transition-all group/user", children: [_jsx("input", { type: "checkbox", checked: privacy.sharedWithUsers?.includes(user._id) || false, onChange: () => handleUserToggle(user._id), className: "size-4 rounded border-dashboard-border text-primary focus:ring-primary/20 bg-dashboard-card" }), _jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [_jsx("div", { className: "size-7 rounded-lg bg-dashboard-card border border-dashboard-border flex items-center justify-center text-[10px] font-black overflow-hidden shrink-0", children: user.image ? _jsx("img", { src: user.image, className: "size-full object-cover", crossOrigin: "anonymous" }) : user.name[0] }), _jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-[10px] font-black text-dashboard-text uppercase truncate", children: user.name }), _jsx("p", { className: "text-[8px] text-dashboard-text-secondary truncate opacity-60 italic", children: user.email })] })] })] }, user._id))) }) }))] })] }))] })] }));
70
48
  }
@@ -18,4 +18,6 @@ export { EditorCanvas } from './EditorCanvas';
18
18
  export type { EditorCanvasProps } from './EditorCanvas';
19
19
  export { EditorSidebar } from './EditorSidebar';
20
20
  export type { EditorSidebarProps } from './EditorSidebar';
21
+ export { JSONInspector } from './JSONInspector';
22
+ export type { JSONInspectorProps } from './JSONInspector';
21
23
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/views/CanvasEditor/components/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,yBAAyB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvF,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,YAAY,EAAE,2BAA2B,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE7F,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/views/CanvasEditor/components/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,yBAAyB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvF,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,YAAY,EAAE,2BAA2B,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE7F,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC1G,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -10,3 +10,4 @@ export { ErrorBanner } from './ErrorBanner';
10
10
  export { EditorLibrary } from './EditorLibrary';
11
11
  export { EditorCanvas } from './EditorCanvas';
12
12
  export { EditorSidebar } from './EditorSidebar';
13
+ export { JSONInspector } from './JSONInspector';
@@ -1 +1 @@
1
- {"version":3,"file":"useHeroBlock.d.ts","sourceRoot":"","sources":["../../../../src/views/CanvasEditor/hooks/useHeroBlock.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAUxD,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,GAAG,EAAE;;;;EAyFvE"}
1
+ {"version":3,"file":"useHeroBlock.d.ts","sourceRoot":"","sources":["../../../../src/views/CanvasEditor/hooks/useHeroBlock.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAUxD,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,GAAG,EAAE;;;;EAsFvE"}