@jhits/plugin-blog 0.0.9 → 0.0.11

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 (276) hide show
  1. package/package.json +58 -59
  2. package/src/api/categories.ts +0 -43
  3. package/src/api/check-title.ts +0 -60
  4. package/src/api/config-handler.ts +0 -76
  5. package/src/api/handler.ts +0 -418
  6. package/src/api/index.ts +0 -33
  7. package/src/api/route.ts +0 -116
  8. package/src/api/router.ts +0 -128
  9. package/src/api-server.ts +0 -11
  10. package/src/config.ts +0 -161
  11. package/src/hooks/index.d.ts +0 -8
  12. package/src/hooks/index.d.ts.map +0 -1
  13. package/src/hooks/index.js +0 -7
  14. package/src/hooks/index.ts +0 -9
  15. package/src/hooks/useBlog.d.ts +0 -31
  16. package/src/hooks/useBlog.d.ts.map +0 -1
  17. package/src/hooks/useBlog.js +0 -57
  18. package/src/hooks/useBlog.ts +0 -85
  19. package/src/hooks/useBlogs.d.ts +0 -39
  20. package/src/hooks/useBlogs.d.ts.map +0 -1
  21. package/src/hooks/useBlogs.js +0 -82
  22. package/src/hooks/useBlogs.ts +0 -123
  23. package/src/hooks/useCategories.d.ts +0 -9
  24. package/src/hooks/useCategories.d.ts.map +0 -1
  25. package/src/hooks/useCategories.js +0 -70
  26. package/src/hooks/useCategories.ts +0 -76
  27. package/src/index.d.ts +0 -55
  28. package/src/index.d.ts.map +0 -1
  29. package/src/index.js +0 -228
  30. package/src/index.server.ts +0 -14
  31. package/src/index.tsx +0 -335
  32. package/src/init.d.ts +0 -40
  33. package/src/init.d.ts.map +0 -1
  34. package/src/init.js +0 -41
  35. package/src/init.tsx +0 -63
  36. package/src/lib/blocks/BlockRenderer.d.ts +0 -54
  37. package/src/lib/blocks/BlockRenderer.d.ts.map +0 -1
  38. package/src/lib/blocks/BlockRenderer.js +0 -54
  39. package/src/lib/blocks/BlockRenderer.tsx +0 -141
  40. package/src/lib/blocks/index.ts +0 -6
  41. package/src/lib/config-storage.d.ts +0 -30
  42. package/src/lib/config-storage.d.ts.map +0 -1
  43. package/src/lib/config-storage.js +0 -31
  44. package/src/lib/config-storage.ts +0 -65
  45. package/src/lib/index.ts +0 -9
  46. package/src/lib/layouts/blocks/ColumnsBlock.d.ts +0 -25
  47. package/src/lib/layouts/blocks/ColumnsBlock.d.ts.map +0 -1
  48. package/src/lib/layouts/blocks/ColumnsBlock.js +0 -182
  49. package/src/lib/layouts/blocks/ColumnsBlock.tsx +0 -298
  50. package/src/lib/layouts/blocks/ColumnsBlock.tsx.tmp +0 -81
  51. package/src/lib/layouts/blocks/SectionBlock.d.ts +0 -25
  52. package/src/lib/layouts/blocks/SectionBlock.d.ts.map +0 -1
  53. package/src/lib/layouts/blocks/SectionBlock.js +0 -44
  54. package/src/lib/layouts/blocks/SectionBlock.tsx +0 -104
  55. package/src/lib/layouts/blocks/index.ts +0 -8
  56. package/src/lib/layouts/index.d.ts +0 -23
  57. package/src/lib/layouts/index.d.ts.map +0 -1
  58. package/src/lib/layouts/index.js +0 -45
  59. package/src/lib/layouts/index.ts +0 -52
  60. package/src/lib/layouts/registerLayoutBlocks.d.ts +0 -9
  61. package/src/lib/layouts/registerLayoutBlocks.d.ts.map +0 -1
  62. package/src/lib/layouts/registerLayoutBlocks.js +0 -60
  63. package/src/lib/layouts/registerLayoutBlocks.ts +0 -64
  64. package/src/lib/mappers/apiMapper.d.ts +0 -66
  65. package/src/lib/mappers/apiMapper.d.ts.map +0 -1
  66. package/src/lib/mappers/apiMapper.js +0 -191
  67. package/src/lib/mappers/apiMapper.ts +0 -254
  68. package/src/lib/migration/index.ts +0 -6
  69. package/src/lib/migration/mapper.ts +0 -140
  70. package/src/lib/rich-text/RichTextEditor.d.ts +0 -45
  71. package/src/lib/rich-text/RichTextEditor.d.ts.map +0 -1
  72. package/src/lib/rich-text/RichTextEditor.js +0 -564
  73. package/src/lib/rich-text/RichTextEditor.tsx +0 -826
  74. package/src/lib/rich-text/RichTextPreview.d.ts +0 -16
  75. package/src/lib/rich-text/RichTextPreview.d.ts.map +0 -1
  76. package/src/lib/rich-text/RichTextPreview.js +0 -144
  77. package/src/lib/rich-text/RichTextPreview.tsx +0 -210
  78. package/src/lib/rich-text/index.d.ts +0 -9
  79. package/src/lib/rich-text/index.d.ts.map +0 -1
  80. package/src/lib/rich-text/index.js +0 -6
  81. package/src/lib/rich-text/index.ts +0 -10
  82. package/src/lib/utils/blockHelpers.d.ts +0 -23
  83. package/src/lib/utils/blockHelpers.d.ts.map +0 -1
  84. package/src/lib/utils/blockHelpers.js +0 -65
  85. package/src/lib/utils/blockHelpers.ts +0 -72
  86. package/src/lib/utils/configValidation.d.ts +0 -23
  87. package/src/lib/utils/configValidation.d.ts.map +0 -1
  88. package/src/lib/utils/configValidation.js +0 -113
  89. package/src/lib/utils/configValidation.ts +0 -137
  90. package/src/lib/utils/index.ts +0 -8
  91. package/src/lib/utils/slugify.ts +0 -79
  92. package/src/registry/BlockRegistry.d.ts +0 -62
  93. package/src/registry/BlockRegistry.d.ts.map +0 -1
  94. package/src/registry/BlockRegistry.js +0 -112
  95. package/src/registry/BlockRegistry.ts +0 -139
  96. package/src/registry/index.d.ts +0 -6
  97. package/src/registry/index.d.ts.map +0 -1
  98. package/src/registry/index.js +0 -4
  99. package/src/registry/index.ts +0 -11
  100. package/src/state/EditorContext.d.ts +0 -45
  101. package/src/state/EditorContext.d.ts.map +0 -1
  102. package/src/state/EditorContext.js +0 -215
  103. package/src/state/EditorContext.tsx +0 -283
  104. package/src/state/index.d.ts +0 -7
  105. package/src/state/index.d.ts.map +0 -1
  106. package/src/state/index.js +0 -6
  107. package/src/state/index.ts +0 -8
  108. package/src/state/reducer.d.ts +0 -11
  109. package/src/state/reducer.d.ts.map +0 -1
  110. package/src/state/reducer.js +0 -443
  111. package/src/state/reducer.ts +0 -694
  112. package/src/state/types.d.ts +0 -162
  113. package/src/state/types.d.ts.map +0 -1
  114. package/src/state/types.js +0 -27
  115. package/src/state/types.ts +0 -160
  116. package/src/types/block.d.ts +0 -221
  117. package/src/types/block.d.ts.map +0 -1
  118. package/src/types/block.js +0 -6
  119. package/src/types/block.ts +0 -269
  120. package/src/types/index.d.ts +0 -8
  121. package/src/types/index.d.ts.map +0 -1
  122. package/src/types/index.js +0 -5
  123. package/src/types/index.ts +0 -17
  124. package/src/types/post.d.ts +0 -136
  125. package/src/types/post.d.ts.map +0 -1
  126. package/src/types/post.js +0 -5
  127. package/src/types/post.ts +0 -169
  128. package/src/utils/client.d.ts +0 -48
  129. package/src/utils/client.d.ts.map +0 -1
  130. package/src/utils/client.js +0 -77
  131. package/src/utils/client.ts +0 -122
  132. package/src/utils/index.ts +0 -7
  133. package/src/views/CanvasEditor/BlockWrapper.d.ts +0 -16
  134. package/src/views/CanvasEditor/BlockWrapper.d.ts.map +0 -1
  135. package/src/views/CanvasEditor/BlockWrapper.js +0 -276
  136. package/src/views/CanvasEditor/BlockWrapper.tsx +0 -522
  137. package/src/views/CanvasEditor/CanvasEditorView.d.ts +0 -14
  138. package/src/views/CanvasEditor/CanvasEditorView.d.ts.map +0 -1
  139. package/src/views/CanvasEditor/CanvasEditorView.js +0 -209
  140. package/src/views/CanvasEditor/CanvasEditorView.tsx +0 -337
  141. package/src/views/CanvasEditor/EditorBody.d.ts +0 -22
  142. package/src/views/CanvasEditor/EditorBody.d.ts.map +0 -1
  143. package/src/views/CanvasEditor/EditorBody.js +0 -505
  144. package/src/views/CanvasEditor/EditorBody.tsx +0 -665
  145. package/src/views/CanvasEditor/EditorHeader.d.ts +0 -18
  146. package/src/views/CanvasEditor/EditorHeader.d.ts.map +0 -1
  147. package/src/views/CanvasEditor/EditorHeader.js +0 -101
  148. package/src/views/CanvasEditor/EditorHeader.tsx +0 -268
  149. package/src/views/CanvasEditor/LayoutContainer.d.ts +0 -17
  150. package/src/views/CanvasEditor/LayoutContainer.d.ts.map +0 -1
  151. package/src/views/CanvasEditor/LayoutContainer.js +0 -222
  152. package/src/views/CanvasEditor/LayoutContainer.tsx +0 -322
  153. package/src/views/CanvasEditor/SaveConfirmationModal.d.ts +0 -13
  154. package/src/views/CanvasEditor/SaveConfirmationModal.d.ts.map +0 -1
  155. package/src/views/CanvasEditor/SaveConfirmationModal.js +0 -78
  156. package/src/views/CanvasEditor/SaveConfirmationModal.tsx +0 -233
  157. package/src/views/CanvasEditor/components/CustomBlockItem.d.ts +0 -14
  158. package/src/views/CanvasEditor/components/CustomBlockItem.d.ts.map +0 -1
  159. package/src/views/CanvasEditor/components/CustomBlockItem.js +0 -44
  160. package/src/views/CanvasEditor/components/CustomBlockItem.tsx +0 -92
  161. package/src/views/CanvasEditor/components/EditorCanvas.d.ts +0 -29
  162. package/src/views/CanvasEditor/components/EditorCanvas.d.ts.map +0 -1
  163. package/src/views/CanvasEditor/components/EditorCanvas.js +0 -32
  164. package/src/views/CanvasEditor/components/EditorCanvas.tsx +0 -160
  165. package/src/views/CanvasEditor/components/EditorLibrary.d.ts +0 -7
  166. package/src/views/CanvasEditor/components/EditorLibrary.d.ts.map +0 -1
  167. package/src/views/CanvasEditor/components/EditorLibrary.js +0 -25
  168. package/src/views/CanvasEditor/components/EditorLibrary.tsx +0 -122
  169. package/src/views/CanvasEditor/components/EditorSidebar.d.ts +0 -13
  170. package/src/views/CanvasEditor/components/EditorSidebar.d.ts.map +0 -1
  171. package/src/views/CanvasEditor/components/EditorSidebar.js +0 -20
  172. package/src/views/CanvasEditor/components/EditorSidebar.tsx +0 -181
  173. package/src/views/CanvasEditor/components/ErrorBanner.d.ts +0 -6
  174. package/src/views/CanvasEditor/components/ErrorBanner.d.ts.map +0 -1
  175. package/src/views/CanvasEditor/components/ErrorBanner.js +0 -8
  176. package/src/views/CanvasEditor/components/ErrorBanner.tsx +0 -31
  177. package/src/views/CanvasEditor/components/FeaturedMediaSection.d.ts +0 -25
  178. package/src/views/CanvasEditor/components/FeaturedMediaSection.d.ts.map +0 -1
  179. package/src/views/CanvasEditor/components/FeaturedMediaSection.js +0 -182
  180. package/src/views/CanvasEditor/components/FeaturedMediaSection.tsx +0 -341
  181. package/src/views/CanvasEditor/components/LibraryItem.d.ts +0 -14
  182. package/src/views/CanvasEditor/components/LibraryItem.d.ts.map +0 -1
  183. package/src/views/CanvasEditor/components/LibraryItem.js +0 -43
  184. package/src/views/CanvasEditor/components/LibraryItem.tsx +0 -80
  185. package/src/views/CanvasEditor/components/PrivacySettingsSection.d.ts +0 -15
  186. package/src/views/CanvasEditor/components/PrivacySettingsSection.d.ts.map +0 -1
  187. package/src/views/CanvasEditor/components/PrivacySettingsSection.js +0 -63
  188. package/src/views/CanvasEditor/components/PrivacySettingsSection.tsx +0 -212
  189. package/src/views/CanvasEditor/components/index.d.ts +0 -21
  190. package/src/views/CanvasEditor/components/index.d.ts.map +0 -1
  191. package/src/views/CanvasEditor/components/index.js +0 -12
  192. package/src/views/CanvasEditor/components/index.ts +0 -28
  193. package/src/views/CanvasEditor/hooks/index.d.ts +0 -10
  194. package/src/views/CanvasEditor/hooks/index.d.ts.map +0 -1
  195. package/src/views/CanvasEditor/hooks/index.js +0 -9
  196. package/src/views/CanvasEditor/hooks/index.ts +0 -10
  197. package/src/views/CanvasEditor/hooks/useHeroBlock.d.ts +0 -8
  198. package/src/views/CanvasEditor/hooks/useHeroBlock.d.ts.map +0 -1
  199. package/src/views/CanvasEditor/hooks/useHeroBlock.js +0 -79
  200. package/src/views/CanvasEditor/hooks/useHeroBlock.ts +0 -103
  201. package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.d.ts +0 -3
  202. package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.d.ts.map +0 -1
  203. package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.js +0 -114
  204. package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.ts +0 -142
  205. package/src/views/CanvasEditor/hooks/usePostLoader.d.ts +0 -5
  206. package/src/views/CanvasEditor/hooks/usePostLoader.d.ts.map +0 -1
  207. package/src/views/CanvasEditor/hooks/usePostLoader.js +0 -32
  208. package/src/views/CanvasEditor/hooks/usePostLoader.ts +0 -39
  209. package/src/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts +0 -2
  210. package/src/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts.map +0 -1
  211. package/src/views/CanvasEditor/hooks/useRegisteredBlocks.js +0 -47
  212. package/src/views/CanvasEditor/hooks/useRegisteredBlocks.ts +0 -55
  213. package/src/views/CanvasEditor/hooks/useUnsavedChanges.d.ts +0 -25
  214. package/src/views/CanvasEditor/hooks/useUnsavedChanges.d.ts.map +0 -1
  215. package/src/views/CanvasEditor/hooks/useUnsavedChanges.js +0 -285
  216. package/src/views/CanvasEditor/hooks/useUnsavedChanges.ts +0 -339
  217. package/src/views/CanvasEditor/index.d.ts +0 -16
  218. package/src/views/CanvasEditor/index.d.ts.map +0 -1
  219. package/src/views/CanvasEditor/index.js +0 -9
  220. package/src/views/CanvasEditor/index.ts +0 -16
  221. package/src/views/PostManager/EmptyState.d.ts +0 -10
  222. package/src/views/PostManager/EmptyState.d.ts.map +0 -1
  223. package/src/views/PostManager/EmptyState.js +0 -12
  224. package/src/views/PostManager/EmptyState.tsx +0 -42
  225. package/src/views/PostManager/PostActionsMenu.d.ts +0 -12
  226. package/src/views/PostManager/PostActionsMenu.d.ts.map +0 -1
  227. package/src/views/PostManager/PostActionsMenu.js +0 -58
  228. package/src/views/PostManager/PostActionsMenu.tsx +0 -112
  229. package/src/views/PostManager/PostCards.d.ts +0 -15
  230. package/src/views/PostManager/PostCards.d.ts.map +0 -1
  231. package/src/views/PostManager/PostCards.js +0 -79
  232. package/src/views/PostManager/PostCards.tsx +0 -197
  233. package/src/views/PostManager/PostFilters.d.ts +0 -16
  234. package/src/views/PostManager/PostFilters.d.ts.map +0 -1
  235. package/src/views/PostManager/PostFilters.js +0 -10
  236. package/src/views/PostManager/PostFilters.tsx +0 -95
  237. package/src/views/PostManager/PostManagerView.d.ts +0 -11
  238. package/src/views/PostManager/PostManagerView.d.ts.map +0 -1
  239. package/src/views/PostManager/PostManagerView.js +0 -174
  240. package/src/views/PostManager/PostManagerView.tsx +0 -289
  241. package/src/views/PostManager/PostStats.d.ts +0 -11
  242. package/src/views/PostManager/PostStats.d.ts.map +0 -1
  243. package/src/views/PostManager/PostStats.js +0 -46
  244. package/src/views/PostManager/PostStats.tsx +0 -81
  245. package/src/views/PostManager/PostTable.d.ts +0 -15
  246. package/src/views/PostManager/PostTable.d.ts.map +0 -1
  247. package/src/views/PostManager/PostTable.js +0 -79
  248. package/src/views/PostManager/PostTable.tsx +0 -230
  249. package/src/views/PostManager/index.d.ts +0 -12
  250. package/src/views/PostManager/index.d.ts.map +0 -1
  251. package/src/views/PostManager/index.js +0 -11
  252. package/src/views/PostManager/index.ts +0 -15
  253. package/src/views/Preview/PreviewBridgeView.d.ts +0 -12
  254. package/src/views/Preview/PreviewBridgeView.d.ts.map +0 -1
  255. package/src/views/Preview/PreviewBridgeView.js +0 -11
  256. package/src/views/Preview/PreviewBridgeView.tsx +0 -64
  257. package/src/views/Preview/index.d.ts +0 -6
  258. package/src/views/Preview/index.d.ts.map +0 -1
  259. package/src/views/Preview/index.js +0 -4
  260. package/src/views/Preview/index.ts +0 -7
  261. package/src/views/Settings/SettingsView.d.ts +0 -10
  262. package/src/views/Settings/SettingsView.d.ts.map +0 -1
  263. package/src/views/Settings/SettingsView.js +0 -111
  264. package/src/views/Settings/SettingsView.tsx +0 -298
  265. package/src/views/Settings/index.d.ts +0 -6
  266. package/src/views/Settings/index.d.ts.map +0 -1
  267. package/src/views/Settings/index.js +0 -4
  268. package/src/views/Settings/index.ts +0 -7
  269. package/src/views/SlugSEO/SlugSEOManagerView.d.ts +0 -12
  270. package/src/views/SlugSEO/SlugSEOManagerView.d.ts.map +0 -1
  271. package/src/views/SlugSEO/SlugSEOManagerView.js +0 -11
  272. package/src/views/SlugSEO/SlugSEOManagerView.tsx +0 -94
  273. package/src/views/SlugSEO/index.d.ts +0 -6
  274. package/src/views/SlugSEO/index.d.ts.map +0 -1
  275. package/src/views/SlugSEO/index.js +0 -4
  276. package/src/views/SlugSEO/index.ts +0 -7
@@ -1,181 +0,0 @@
1
- 'use client';
2
-
3
- import React from 'react';
4
- import { Globe, Search, Box } from 'lucide-react';
5
- import { FeaturedMediaSection, PrivacySettingsSection } from './index';
6
- import type { Block } from '../../../types/block';
7
- import type { PostMetadata, SEOMetadata } from '../../../types/post';
8
-
9
- export interface EditorSidebarProps {
10
- slug: string;
11
- seo: SEOMetadata;
12
- metadata: PostMetadata;
13
- heroBlock: Block | null;
14
- status: string;
15
- onSEOUpdate: (seo: Partial<SEOMetadata>) => void;
16
- onMetadataUpdate: (metadata: Partial<PostMetadata>) => void;
17
- }
18
-
19
- export function EditorSidebar({
20
- slug,
21
- seo,
22
- metadata,
23
- heroBlock,
24
- status,
25
- onSEOUpdate,
26
- onMetadataUpdate,
27
- }: EditorSidebarProps) {
28
- 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>
37
- </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
42
- </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>
53
- </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
67
- </p>
68
- </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
- </div>
97
- </section>
98
-
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
105
- </label>
106
- </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>
111
- </div>
112
- </div>
113
- </section>
114
-
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
121
- </label>
122
- </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
127
- </label>
128
- <input
129
- 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"
139
- />
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>
143
- </div>
144
- </div>
145
- </section>
146
-
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
- />
160
-
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>
170
- </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
- </section>
179
- </div>
180
- );
181
- }
@@ -1,6 +0,0 @@
1
- export interface ErrorBannerProps {
2
- error: string | null;
3
- onDismiss: () => void;
4
- }
5
- export declare function ErrorBanner({ error, onDismiss }: ErrorBannerProps): import("react/jsx-runtime").JSX.Element | null;
6
- //# sourceMappingURL=ErrorBanner.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ErrorBanner.d.ts","sourceRoot":"","sources":["ErrorBanner.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC7B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,gBAAgB,kDAoBjE"}
@@ -1,8 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { AlertTriangle, X } from 'lucide-react';
4
- export function ErrorBanner({ error, onDismiss }) {
5
- if (!error)
6
- return null;
7
- return (_jsxs("div", { className: "bg-red-50 dark:bg-red-900/20 border-b border-red-200 dark:border-red-800 px-6 py-3 flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3 flex-1", children: [_jsx(AlertTriangle, { className: "text-red-600 dark:text-red-400 flex-shrink-0", size: 20 }), _jsx("p", { className: "text-red-800 dark:text-red-300 text-sm font-medium", children: error })] }), _jsx("button", { onClick: onDismiss, className: "text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-200 transition-colors", "aria-label": "Dismiss error", children: _jsx(X, { size: 18 }) })] }));
8
- }
@@ -1,31 +0,0 @@
1
- 'use client';
2
-
3
- import React from 'react';
4
- import { AlertTriangle, X } from 'lucide-react';
5
-
6
- export interface ErrorBannerProps {
7
- error: string | null;
8
- onDismiss: () => void;
9
- }
10
-
11
- export function ErrorBanner({ error, onDismiss }: ErrorBannerProps) {
12
- if (!error) return null;
13
-
14
- return (
15
- <div className="bg-red-50 dark:bg-red-900/20 border-b border-red-200 dark:border-red-800 px-6 py-3 flex items-center justify-between">
16
- <div className="flex items-center gap-3 flex-1">
17
- <AlertTriangle className="text-red-600 dark:text-red-400 flex-shrink-0" size={20} />
18
- <p className="text-red-800 dark:text-red-300 text-sm font-medium">
19
- {error}
20
- </p>
21
- </div>
22
- <button
23
- onClick={onDismiss}
24
- className="text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-200 transition-colors"
25
- aria-label="Dismiss error"
26
- >
27
- <X size={18} />
28
- </button>
29
- </div>
30
- );
31
- }
@@ -1,25 +0,0 @@
1
- import type { Block } from '../../../types/block';
2
- export interface FeaturedImage {
3
- id?: string;
4
- alt?: string;
5
- brightness?: number;
6
- blur?: number;
7
- scale?: number;
8
- positionX?: number;
9
- positionY?: number;
10
- isCustom?: boolean;
11
- }
12
- export interface FeaturedMediaSectionProps {
13
- featuredImage?: FeaturedImage;
14
- heroBlock?: Block | null;
15
- slug?: string;
16
- onUpdate: (image: FeaturedImage | undefined) => void;
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
- export declare function FeaturedMediaSection({ featuredImage, heroBlock, slug, onUpdate, }: FeaturedMediaSectionProps): import("react/jsx-runtime").JSX.Element;
25
- //# sourceMappingURL=FeaturedMediaSection.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"FeaturedMediaSection.d.ts","sourceRoot":"","sources":["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,182 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useState, useCallback, useEffect } from 'react';
4
- import { createPortal } from 'react-dom';
5
- import { Image as ImageIcon, Plus, X } from 'lucide-react';
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
- export function FeaturedMediaSection({ featuredImage, heroBlock, slug, onUpdate, }) {
14
- var _a, _b, _c, _d, _e;
15
- const [showImagePicker, setShowImagePicker] = useState(false);
16
- const [openEditorDirectly, setOpenEditorDirectly] = useState(false);
17
- const [mounted, setMounted] = useState(false);
18
- // Handle SSR - ensure we only render portal on client
19
- useEffect(() => {
20
- setMounted(true);
21
- }, []);
22
- // Create semantic ID for this featured image - plugin-images will handle everything
23
- const semanticId = slug ? `blog-featured-${slug}` : `blog-featured-${Date.now()}`;
24
- // Use semantic ID from featuredImage if it exists, otherwise use generated one
25
- // IMPORTANT: Always use the actual id from featuredImage if available, otherwise the semanticId
26
- // This ensures the id is stable and doesn't change on re-renders
27
- const imageId = (featuredImage === null || featuredImage === void 0 ? void 0 : featuredImage.id) || semanticId;
28
- // Ensure featuredImage always has an id when it exists
29
- // This prevents the "missing featured image" issue on save
30
- useEffect(() => {
31
- if (featuredImage && !featuredImage.id) {
32
- // If featuredImage exists but has no id, set it to the semanticId
33
- onUpdate(Object.assign(Object.assign({}, featuredImage), { id: semanticId }));
34
- }
35
- }, [featuredImage, semanticId, onUpdate]);
36
- // Get transform values from featuredImage or use defaults
37
- const brightness = (_a = featuredImage === null || featuredImage === void 0 ? void 0 : featuredImage.brightness) !== null && _a !== void 0 ? _a : 100;
38
- const blur = (_b = featuredImage === null || featuredImage === void 0 ? void 0 : featuredImage.blur) !== null && _b !== void 0 ? _b : 0;
39
- const scale = (_c = featuredImage === null || featuredImage === void 0 ? void 0 : featuredImage.scale) !== null && _c !== void 0 ? _c : 1.0;
40
- const positionX = (_d = featuredImage === null || featuredImage === void 0 ? void 0 : featuredImage.positionX) !== null && _d !== void 0 ? _d : 0;
41
- const positionY = (_e = featuredImage === null || featuredImage === void 0 ? void 0 : featuredImage.positionY) !== null && _e !== void 0 ? _e : 0;
42
- // Handle image selection - create initial mapping and update blog metadata with semantic ID
43
- // Plugin-images Image component will automatically resolve the semantic ID when it renders
44
- const handleImageChange = useCallback(async (image) => {
45
- var _a, _b;
46
- if (image) {
47
- // Extract filename from image URL for reference
48
- const isUploadedImage = image.url.startsWith('/api/uploads/');
49
- let filename = image.filename;
50
- if (!filename && isUploadedImage) {
51
- // Extract filename from URL if not provided
52
- filename = ((_a = image.url.split('/api/uploads/')[1]) === null || _a === void 0 ? void 0 : _a.split('?')[0]) || image.id;
53
- }
54
- else if (!filename) {
55
- // For external URLs, use the image ID or extract from URL
56
- filename = image.id || ((_b = image.url.split('/').pop()) === null || _b === void 0 ? void 0 : _b.split('?')[0]) || `external-${Date.now()}`;
57
- }
58
- // Create initial mapping in plugin-images API immediately
59
- // This ensures the semantic ID resolves correctly
60
- try {
61
- const saveData = {
62
- id: imageId,
63
- filename: filename,
64
- scale: 1.0,
65
- positionX: 0,
66
- positionY: 0,
67
- brightness: 100,
68
- blur: 0,
69
- };
70
- await fetch('/api/plugin-images/resolve', {
71
- method: 'POST',
72
- headers: { 'Content-Type': 'application/json' },
73
- body: JSON.stringify(saveData),
74
- });
75
- }
76
- catch (error) {
77
- console.error('[FeaturedMediaSection] Failed to create initial mapping:', error);
78
- // Continue anyway - the mapping might be created later
79
- }
80
- // Update blog metadata with semantic ID
81
- onUpdate({
82
- id: imageId,
83
- alt: image.alt || image.filename,
84
- brightness: 100,
85
- blur: 0,
86
- scale: 1.0,
87
- positionX: 0,
88
- positionY: 0,
89
- isCustom: true,
90
- });
91
- }
92
- else {
93
- // If removed, set to undefined
94
- onUpdate(undefined);
95
- }
96
- setShowImagePicker(false);
97
- }, [imageId, onUpdate]);
98
- // Handle editor save from ImagePicker - save to plugin-images API
99
- const handleEditorSave = useCallback(async (finalScale, finalPositionX, finalPositionY, finalBrightness, finalBlur) => {
100
- if (!(featuredImage === null || featuredImage === void 0 ? void 0 : featuredImage.id))
101
- return;
102
- // Reset the auto-open flag immediately to prevent reopening
103
- setOpenEditorDirectly(false);
104
- // Get the actual filename from the API (resolve the semantic ID)
105
- let filename = imageId; // Fallback to semantic ID
106
- try {
107
- const response = await fetch(`/api/plugin-images/resolve?id=${encodeURIComponent(imageId)}`);
108
- if (response.ok) {
109
- const data = await response.json();
110
- filename = data.filename || imageId;
111
- }
112
- }
113
- catch (error) {
114
- console.error('Failed to resolve filename:', error);
115
- }
116
- // Normalize position values
117
- const normalizedPositionX = finalPositionX === -50 ? 0 : finalPositionX;
118
- const normalizedPositionY = finalPositionY === -50 ? 0 : finalPositionY;
119
- const finalBrightnessValue = finalBrightness !== null && finalBrightness !== void 0 ? finalBrightness : brightness;
120
- const finalBlurValue = finalBlur !== null && finalBlur !== void 0 ? finalBlur : blur;
121
- // Save to plugin-images API
122
- try {
123
- const saveData = {
124
- id: imageId,
125
- filename: filename,
126
- scale: finalScale,
127
- positionX: normalizedPositionX,
128
- positionY: normalizedPositionY,
129
- brightness: finalBrightnessValue,
130
- blur: finalBlurValue,
131
- };
132
- const response = await fetch('/api/plugin-images/resolve', {
133
- method: 'POST',
134
- headers: { 'Content-Type': 'application/json' },
135
- body: JSON.stringify(saveData),
136
- });
137
- if (response.ok) {
138
- // Update local featured image data - ensure id is preserved
139
- onUpdate(Object.assign(Object.assign({}, featuredImage), { id: featuredImage.id || imageId, scale: finalScale, positionX: normalizedPositionX, positionY: normalizedPositionY, brightness: finalBrightnessValue, blur: finalBlurValue }));
140
- // Dispatch event to notify Image components
141
- window.dispatchEvent(new CustomEvent('image-mapping-updated', {
142
- detail: saveData
143
- }));
144
- }
145
- }
146
- catch (error) {
147
- console.error('Failed to save image transform:', error);
148
- }
149
- }, [imageId, featuredImage, brightness, blur, onUpdate]);
150
- 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 === null || featuredImage === void 0 ? void 0 : 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, Object.assign({ id: imageId, alt: (featuredImage === null || featuredImage === void 0 ? void 0 : featuredImage.alt) || 'Featured image', fill: true, className: "object-cover w-full h-full", editable: false }, {
151
- brightness,
152
- blur,
153
- scale,
154
- positionX,
155
- positionY,
156
- })), _jsx("button", { onClick: () => {
157
- setOpenEditorDirectly(true);
158
- setShowImagePicker(true);
159
- }, 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: () => {
160
- setShowImagePicker(false);
161
- setOpenEditorDirectly(false); // Reset flag when closing
162
- }, 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: () => {
163
- setShowImagePicker(false);
164
- setOpenEditorDirectly(false); // Reset flag when closing
165
- }, 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, Object.assign({ value: (featuredImage === null || featuredImage === void 0 ? void 0 : featuredImage.id) ? imageId : undefined, onChange: handleImageChange, brightness: brightness, blur: blur }, {
166
- scale,
167
- positionX,
168
- positionY,
169
- }, { onBrightnessChange: (val) => {
170
- // Update local state only - don't trigger save
171
- if (featuredImage) {
172
- onUpdate(Object.assign(Object.assign({}, featuredImage), { id: featuredImage.id || imageId, brightness: val }));
173
- }
174
- }, onBlurChange: (val) => {
175
- // Update local state only - don't trigger save
176
- if (featuredImage) {
177
- onUpdate(Object.assign(Object.assign({}, featuredImage), { id: featuredImage.id || imageId, blur: val }));
178
- }
179
- }, onEditorSave: handleEditorSave, darkMode: false, showEffects: true, aspectRatio: "16/10" // Thumbnail aspect ratio for blog cards
180
- , borderRadius: "rounded-3xl", objectFit: "cover" // Cover for thumbnails
181
- , objectPosition: "center" }))] }) }), document.body)] }));
182
- }