@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,212 +0,0 @@
1
- 'use client';
2
-
3
- import React, { useState, useEffect } from 'react';
4
- import { Shield, Key, Users } from 'lucide-react';
5
-
6
- export interface PrivacySettings {
7
- isPrivate?: boolean;
8
- password?: string;
9
- sharedWithUsers?: string[];
10
- }
11
-
12
- export interface PrivacySettingsSectionProps {
13
- privacy?: PrivacySettings;
14
- onUpdate: (privacy: PrivacySettings) => void;
15
- }
16
-
17
- /**
18
- * Privacy Settings Section Component
19
- * Handles privacy settings: private, password-protected, share with users
20
- */
21
- export function PrivacySettingsSection({
22
- privacy,
23
- onUpdate,
24
- }: PrivacySettingsSectionProps) {
25
- const [users, setUsers] = useState<Array<{ _id: string; name: string; email: string }>>([]);
26
- const [loadingUsers, setLoadingUsers] = useState(false);
27
- const [showPasswordInput, setShowPasswordInput] = useState(false);
28
- const [passwordValue, setPasswordValue] = useState(privacy?.password || '');
29
- const [showUserSelector, setShowUserSelector] = useState(false);
30
-
31
- // Fetch users from plugin-users
32
- useEffect(() => {
33
- const fetchUsers = async () => {
34
- try {
35
- setLoadingUsers(true);
36
- const res = await fetch('/api/users');
37
- const data = await res.json();
38
- if (Array.isArray(data)) {
39
- setUsers(data);
40
- }
41
- } catch (err) {
42
- console.error('Failed to load users', err);
43
- } finally {
44
- setLoadingUsers(false);
45
- }
46
- };
47
- fetchUsers();
48
- }, []);
49
-
50
- const handlePrivacyToggle = (isPrivate: boolean) => {
51
- onUpdate({
52
- ...privacy,
53
- isPrivate,
54
- // Clear password and shared users if making public
55
- ...(isPrivate ? {} : { password: undefined, sharedWithUsers: undefined }),
56
- });
57
- };
58
-
59
- const handlePasswordChange = (password: string) => {
60
- setPasswordValue(password);
61
- onUpdate({
62
- ...privacy,
63
- password: password || undefined,
64
- });
65
- };
66
-
67
- const handleUserToggle = (userId: string) => {
68
- const currentUsers = privacy?.sharedWithUsers || [];
69
- const newUsers = currentUsers.includes(userId)
70
- ? currentUsers.filter(id => id !== userId)
71
- : [...currentUsers, userId];
72
- onUpdate({
73
- ...privacy,
74
- sharedWithUsers: newUsers.length > 0 ? newUsers : undefined,
75
- });
76
- };
77
-
78
- return (
79
- <section className="pt-8 border-t border-neutral-200 dark:border-neutral-800">
80
- <div className="flex items-center gap-3 mb-6">
81
- <Shield size={14} className="text-neutral-500 dark:text-neutral-400" />
82
- <label className="text-[10px] uppercase tracking-[0.2em] text-neutral-500 dark:text-neutral-400 font-black">
83
- Privacy Settings
84
- </label>
85
- </div>
86
- <div className="space-y-4">
87
- {/* Private Toggle */}
88
- <div className="flex items-center justify-between">
89
- <div>
90
- <label className="text-[10px] text-neutral-700 dark:text-neutral-300 font-bold block mb-1">
91
- Make Private
92
- </label>
93
- <p className="text-[9px] text-neutral-500 dark:text-neutral-400">
94
- Hide from public view
95
- </p>
96
- </div>
97
- <button
98
- onClick={() => handlePrivacyToggle(!privacy?.isPrivate)}
99
- className={`relative w-12 h-6 rounded-full transition-colors ${privacy?.isPrivate ? 'bg-primary' : 'bg-neutral-300 dark:bg-neutral-700'
100
- }`}
101
- >
102
- <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'
103
- }`} />
104
- </button>
105
- </div>
106
-
107
- {/* Password Protection */}
108
- {privacy?.isPrivate && (
109
- <div className="space-y-2">
110
- <div className="flex items-center justify-between">
111
- <div>
112
- <label className="text-[10px] text-neutral-700 dark:text-neutral-300 font-bold block mb-1">
113
- Password Protection
114
- </label>
115
- <p className="text-[9px] text-neutral-500 dark:text-neutral-400">
116
- Require password to view
117
- </p>
118
- </div>
119
- <button
120
- onClick={() => {
121
- setShowPasswordInput(!showPasswordInput);
122
- if (!showPasswordInput && !privacy.password) {
123
- setPasswordValue('');
124
- }
125
- }}
126
- className={`p-1.5 rounded-lg transition-colors ${privacy.password || showPasswordInput
127
- ? 'bg-primary/10 text-primary'
128
- : 'bg-neutral-100 dark:bg-neutral-800 text-neutral-400'
129
- }`}
130
- >
131
- <Key size={14} />
132
- </button>
133
- </div>
134
- {(showPasswordInput || privacy.password) && (
135
- <input
136
- type="password"
137
- value={passwordValue}
138
- onChange={(e) => handlePasswordChange(e.target.value)}
139
- placeholder="Enter password"
140
- 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"
141
- />
142
- )}
143
- </div>
144
- )}
145
-
146
- {/* Share with Users */}
147
- {privacy?.isPrivate && (
148
- <div className="space-y-2">
149
- <div className="flex items-center justify-between">
150
- <div>
151
- <label className="text-[10px] text-neutral-700 dark:text-neutral-300 font-bold block mb-1">
152
- Share with Users
153
- </label>
154
- <p className="text-[9px] text-neutral-500 dark:text-neutral-400">
155
- Grant access to specific users
156
- </p>
157
- </div>
158
- <button
159
- onClick={() => setShowUserSelector(!showUserSelector)}
160
- className={`p-1.5 rounded-lg transition-colors ${(privacy.sharedWithUsers?.length || 0) > 0 || showUserSelector
161
- ? 'bg-primary/10 text-primary'
162
- : 'bg-neutral-100 dark:bg-neutral-800 text-neutral-400'
163
- }`}
164
- >
165
- <Users size={14} />
166
- </button>
167
- </div>
168
- {showUserSelector && (
169
- <div className="bg-dashboard-bg rounded-lg p-3 border border-dashboard-border max-h-48 overflow-y-auto">
170
- {loadingUsers ? (
171
- <p className="text-[10px] text-neutral-500 dark:text-neutral-400">Loading users...</p>
172
- ) : users.length === 0 ? (
173
- <p className="text-[10px] text-neutral-500 dark:text-neutral-400">No users found</p>
174
- ) : (
175
- <div className="space-y-2">
176
- {users.map((user) => (
177
- <label
178
- key={user._id}
179
- className="flex items-center gap-2 cursor-pointer hover:bg-dashboard-bg p-2 rounded transition-colors"
180
- >
181
- <input
182
- type="checkbox"
183
- checked={privacy.sharedWithUsers?.includes(user._id) || false}
184
- onChange={() => handleUserToggle(user._id)}
185
- className="rounded border-neutral-300 dark:border-neutral-700 text-primary focus:ring-primary"
186
- />
187
- <div className="flex-1 min-w-0">
188
- <p className="text-[10px] font-bold text-neutral-700 dark:text-neutral-300 truncate">
189
- {user.name}
190
- </p>
191
- <p className="text-[9px] text-neutral-500 dark:text-neutral-400 truncate">
192
- {user.email}
193
- </p>
194
- </div>
195
- </label>
196
- ))}
197
- </div>
198
- )}
199
- </div>
200
- )}
201
- {privacy.sharedWithUsers && privacy.sharedWithUsers.length > 0 && (
202
- <p className="text-[9px] text-neutral-500 dark:text-neutral-400">
203
- Shared with {privacy.sharedWithUsers.length} user{privacy.sharedWithUsers.length !== 1 ? 's' : ''}
204
- </p>
205
- )}
206
- </div>
207
- )}
208
- </div>
209
- </section>
210
- );
211
- }
212
-
@@ -1,21 +0,0 @@
1
- /**
2
- * Canvas Editor Components
3
- * Exports all components used in the Canvas Editor
4
- */
5
- export { LibraryItem } from './LibraryItem';
6
- export type { LibraryItemProps } from './LibraryItem';
7
- export { CustomBlockItem } from './CustomBlockItem';
8
- export type { CustomBlockItemProps } from './CustomBlockItem';
9
- export { FeaturedMediaSection } from './FeaturedMediaSection';
10
- export type { FeaturedMediaSectionProps, FeaturedImage } from './FeaturedMediaSection';
11
- export { PrivacySettingsSection } from './PrivacySettingsSection';
12
- export type { PrivacySettingsSectionProps, PrivacySettings } from './PrivacySettingsSection';
13
- export { ErrorBanner } from './ErrorBanner';
14
- export type { ErrorBannerProps } from './ErrorBanner';
15
- export { EditorLibrary } from './EditorLibrary';
16
- export type { EditorLibraryProps } from './EditorLibrary';
17
- export { EditorCanvas } from './EditorCanvas';
18
- export type { EditorCanvasProps } from './EditorCanvas';
19
- export { EditorSidebar } from './EditorSidebar';
20
- export type { EditorSidebarProps } from './EditorSidebar';
21
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["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,12 +0,0 @@
1
- /**
2
- * Canvas Editor Components
3
- * Exports all components used in the Canvas Editor
4
- */
5
- export { LibraryItem } from './LibraryItem';
6
- export { CustomBlockItem } from './CustomBlockItem';
7
- export { FeaturedMediaSection } from './FeaturedMediaSection';
8
- export { PrivacySettingsSection } from './PrivacySettingsSection';
9
- export { ErrorBanner } from './ErrorBanner';
10
- export { EditorLibrary } from './EditorLibrary';
11
- export { EditorCanvas } from './EditorCanvas';
12
- export { EditorSidebar } from './EditorSidebar';
@@ -1,28 +0,0 @@
1
- /**
2
- * Canvas Editor Components
3
- * Exports all components used in the Canvas Editor
4
- */
5
-
6
- export { LibraryItem } from './LibraryItem';
7
- export type { LibraryItemProps } from './LibraryItem';
8
-
9
- export { CustomBlockItem } from './CustomBlockItem';
10
- export type { CustomBlockItemProps } from './CustomBlockItem';
11
-
12
- export { FeaturedMediaSection } from './FeaturedMediaSection';
13
- export type { FeaturedMediaSectionProps, FeaturedImage } from './FeaturedMediaSection';
14
-
15
- export { PrivacySettingsSection } from './PrivacySettingsSection';
16
- export type { PrivacySettingsSectionProps, PrivacySettings } from './PrivacySettingsSection';
17
-
18
- export { ErrorBanner } from './ErrorBanner';
19
- export type { ErrorBannerProps } from './ErrorBanner';
20
-
21
- export { EditorLibrary } from './EditorLibrary';
22
- export type { EditorLibraryProps } from './EditorLibrary';
23
-
24
- export { EditorCanvas } from './EditorCanvas';
25
- export type { EditorCanvasProps } from './EditorCanvas';
26
-
27
- export { EditorSidebar } from './EditorSidebar';
28
- export type { EditorSidebarProps } from './EditorSidebar';
@@ -1,10 +0,0 @@
1
- /**
2
- * Canvas Editor Hooks
3
- * Exports all custom hooks used in the Canvas Editor
4
- */
5
- export { usePostLoader } from './usePostLoader';
6
- export { useHeroBlock } from './useHeroBlock';
7
- export { useRegisteredBlocks } from './useRegisteredBlocks';
8
- export { useKeyboardShortcuts } from './useKeyboardShortcuts';
9
- export { useUnsavedChanges } from './useUnsavedChanges';
10
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -1,9 +0,0 @@
1
- /**
2
- * Canvas Editor Hooks
3
- * Exports all custom hooks used in the Canvas Editor
4
- */
5
- export { usePostLoader } from './usePostLoader';
6
- export { useHeroBlock } from './useHeroBlock';
7
- export { useRegisteredBlocks } from './useRegisteredBlocks';
8
- export { useKeyboardShortcuts } from './useKeyboardShortcuts';
9
- export { useUnsavedChanges } from './useUnsavedChanges';
@@ -1,10 +0,0 @@
1
- /**
2
- * Canvas Editor Hooks
3
- * Exports all custom hooks used in the Canvas Editor
4
- */
5
-
6
- export { usePostLoader } from './usePostLoader';
7
- export { useHeroBlock } from './useHeroBlock';
8
- export { useRegisteredBlocks } from './useRegisteredBlocks';
9
- export { useKeyboardShortcuts } from './useKeyboardShortcuts';
10
- export { useUnsavedChanges } from './useUnsavedChanges';
@@ -1,8 +0,0 @@
1
- import type { Block } from '../../../types/block';
2
- import type { EditorState } from '../../../state/types';
3
- export declare function useHeroBlock(state: EditorState, registeredBlocks: any[]): {
4
- heroBlock: Block | null;
5
- setHeroBlock: import("react").Dispatch<import("react").SetStateAction<Block | null>>;
6
- heroBlockDefinition: import("../../..").BlockTypeDefinition | undefined;
7
- };
8
- //# sourceMappingURL=useHeroBlock.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useHeroBlock.d.ts","sourceRoot":"","sources":["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,79 +0,0 @@
1
- import { useState, useEffect, useMemo } from 'react';
2
- import { blockRegistry } from '../../../registry/BlockRegistry';
3
- // Generate a unique block ID
4
- function generateBlockId() {
5
- if (typeof crypto !== 'undefined' && crypto.randomUUID) {
6
- return crypto.randomUUID();
7
- }
8
- return `block-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
9
- }
10
- export function useHeroBlock(state, registeredBlocks) {
11
- const [heroBlock, setHeroBlock] = useState(null);
12
- // Get Hero block definition from registered blocks (REQUIRED)
13
- const heroBlockDefinition = useMemo(() => {
14
- return blockRegistry.get('hero');
15
- }, [registeredBlocks]);
16
- // Initialize hero block if Hero block definition exists
17
- useEffect(() => {
18
- if (heroBlockDefinition) {
19
- // Get default data from block definition
20
- const heroData = heroBlockDefinition.defaultData || {};
21
- // Initialize hero block only if it doesn't exist yet
22
- setHeroBlock(prev => {
23
- if (!prev) {
24
- // First, try to find hero block in contentBlocks (from loaded post)
25
- const heroBlockFromContent = state.blocks.find(block => block.type === 'hero');
26
- if (heroBlockFromContent) {
27
- return heroBlockFromContent;
28
- }
29
- // If no hero block in contentBlocks, initialize from defaults
30
- // Hero image and featured image are completely independent - no syncing
31
- const initialData = Object.assign(Object.assign({}, heroData), { title: state.title || heroData.title || '', summary: state.metadata.excerpt || heroData.summary || '', image: heroData.image });
32
- return {
33
- id: generateBlockId(),
34
- type: 'hero',
35
- data: initialData,
36
- };
37
- }
38
- // Keep existing hero block data - let the Edit component manage it
39
- return prev;
40
- });
41
- }
42
- else {
43
- setHeroBlock(null);
44
- }
45
- }, [heroBlockDefinition, state.blocks, state.title, state.metadata.excerpt]);
46
- // Sync hero block with editor state when post is loaded (for existing posts)
47
- // BUT: Never sync image from featured image to hero - they are independent
48
- // Only sync title, summary, and category
49
- useEffect(() => {
50
- var _a, _b, _c, _d, _e, _f, _g;
51
- if (heroBlock && heroBlockDefinition && state.postId) {
52
- // Only update if the hero block data doesn't match the editor state
53
- // This prevents overwriting user edits with stale data
54
- const currentTitle = ((_a = heroBlock.data) === null || _a === void 0 ? void 0 : _a.title) || '';
55
- const currentSummary = ((_b = heroBlock.data) === null || _b === void 0 ? void 0 : _b.summary) || '';
56
- const currentCategory = ((_c = heroBlock.data) === null || _c === void 0 ? void 0 : _c.category) || '';
57
- const stateTitle = state.title || '';
58
- const stateSummary = state.metadata.excerpt || '';
59
- const stateCategory = ((_d = state.metadata.categories) === null || _d === void 0 ? void 0 : _d[0]) || '';
60
- // Check if hero block is out of sync with editor state
61
- // NOTE: We do NOT sync image anymore - hero and featured image are independent
62
- const titleMismatch = currentTitle !== stateTitle;
63
- const summaryMismatch = currentSummary !== stateSummary;
64
- const categoryMismatch = currentCategory !== stateCategory;
65
- // Only update title, summary, and category - NEVER update image
66
- // The hero block image should come from contentBlocks, not from featured image
67
- if ((titleMismatch || summaryMismatch || categoryMismatch) && (stateTitle || stateSummary || stateCategory)) {
68
- setHeroBlock(Object.assign(Object.assign({}, heroBlock), { data: Object.assign(Object.assign({}, heroBlock.data), { title: stateTitle || ((_e = heroBlock.data) === null || _e === void 0 ? void 0 : _e.title) || '', summary: stateSummary || ((_f = heroBlock.data) === null || _f === void 0 ? void 0 : _f.summary) || '',
69
- // DO NOT sync image - keep hero block's own image
70
- category: stateCategory || ((_g = heroBlock.data) === null || _g === void 0 ? void 0 : _g.category) || '' }) }));
71
- }
72
- }
73
- }, [state.postId, state.title, state.metadata.excerpt, state.metadata.categories, heroBlockDefinition, heroBlock]);
74
- return {
75
- heroBlock,
76
- setHeroBlock,
77
- heroBlockDefinition,
78
- };
79
- }
@@ -1,103 +0,0 @@
1
- import { useState, useEffect, useMemo } from 'react';
2
- import { blockRegistry } from '../../../registry/BlockRegistry';
3
- import type { Block } from '../../../types/block';
4
- import type { EditorState } from '../../../state/types';
5
-
6
- // Generate a unique block ID
7
- function generateBlockId(): string {
8
- if (typeof crypto !== 'undefined' && crypto.randomUUID) {
9
- return crypto.randomUUID();
10
- }
11
- return `block-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
12
- }
13
-
14
- export function useHeroBlock(state: EditorState, registeredBlocks: any[]) {
15
- const [heroBlock, setHeroBlock] = useState<Block | null>(null);
16
-
17
- // Get Hero block definition from registered blocks (REQUIRED)
18
- const heroBlockDefinition = useMemo(() => {
19
- return blockRegistry.get('hero');
20
- }, [registeredBlocks]);
21
-
22
- // Initialize hero block if Hero block definition exists
23
- useEffect(() => {
24
- if (heroBlockDefinition) {
25
- // Get default data from block definition
26
- const heroData = heroBlockDefinition.defaultData || {};
27
-
28
- // Initialize hero block only if it doesn't exist yet
29
- setHeroBlock(prev => {
30
- if (!prev) {
31
- // First, try to find hero block in contentBlocks (from loaded post)
32
- const heroBlockFromContent = state.blocks.find(block => block.type === 'hero');
33
-
34
- if (heroBlockFromContent) {
35
- return heroBlockFromContent;
36
- }
37
-
38
- // If no hero block in contentBlocks, initialize from defaults
39
- // Hero image and featured image are completely independent - no syncing
40
- const initialData = {
41
- ...heroData,
42
- title: state.title || heroData.title || '',
43
- summary: state.metadata.excerpt || heroData.summary || '',
44
- image: heroData.image, // Use default image, not featured image
45
- };
46
- return {
47
- id: generateBlockId(),
48
- type: 'hero',
49
- data: initialData,
50
- };
51
- }
52
- // Keep existing hero block data - let the Edit component manage it
53
- return prev;
54
- });
55
- } else {
56
- setHeroBlock(null);
57
- }
58
- }, [heroBlockDefinition, state.blocks, state.title, state.metadata.excerpt]);
59
-
60
- // Sync hero block with editor state when post is loaded (for existing posts)
61
- // BUT: Never sync image from featured image to hero - they are independent
62
- // Only sync title, summary, and category
63
- useEffect(() => {
64
- if (heroBlock && heroBlockDefinition && state.postId) {
65
- // Only update if the hero block data doesn't match the editor state
66
- // This prevents overwriting user edits with stale data
67
- const currentTitle = (heroBlock.data as any)?.title || '';
68
- const currentSummary = (heroBlock.data as any)?.summary || '';
69
- const currentCategory = (heroBlock.data as any)?.category || '';
70
-
71
- const stateTitle = state.title || '';
72
- const stateSummary = state.metadata.excerpt || '';
73
- const stateCategory = state.metadata.categories?.[0] || '';
74
-
75
- // Check if hero block is out of sync with editor state
76
- // NOTE: We do NOT sync image anymore - hero and featured image are independent
77
- const titleMismatch = currentTitle !== stateTitle;
78
- const summaryMismatch = currentSummary !== stateSummary;
79
- const categoryMismatch = currentCategory !== stateCategory;
80
-
81
- // Only update title, summary, and category - NEVER update image
82
- // The hero block image should come from contentBlocks, not from featured image
83
- if ((titleMismatch || summaryMismatch || categoryMismatch) && (stateTitle || stateSummary || stateCategory)) {
84
- setHeroBlock({
85
- ...heroBlock,
86
- data: {
87
- ...heroBlock.data,
88
- title: stateTitle || (heroBlock.data as any)?.title || '',
89
- summary: stateSummary || (heroBlock.data as any)?.summary || '',
90
- // DO NOT sync image - keep hero block's own image
91
- category: stateCategory || (heroBlock.data as any)?.category || '',
92
- },
93
- });
94
- }
95
- }
96
- }, [state.postId, state.title, state.metadata.excerpt, state.metadata.categories, heroBlockDefinition, heroBlock]);
97
-
98
- return {
99
- heroBlock,
100
- setHeroBlock,
101
- heroBlockDefinition,
102
- };
103
- }
@@ -1,3 +0,0 @@
1
- import type { EditorState } from '../../../state/types';
2
- export declare function useKeyboardShortcuts(state: EditorState, dispatch: (action: any) => void, canUndo: boolean, canRedo: boolean, undo: () => void, redo: () => void): void;
3
- //# sourceMappingURL=useKeyboardShortcuts.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useKeyboardShortcuts.d.ts","sourceRoot":"","sources":["useKeyboardShortcuts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAUxD,wBAAgB,oBAAoB,CAChC,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,EAC/B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,IAAI,EAChB,IAAI,EAAE,MAAM,IAAI,QA2HnB"}
@@ -1,114 +0,0 @@
1
- import { useEffect } from 'react';
2
- // Generate a unique block ID
3
- function generateBlockId() {
4
- if (typeof crypto !== 'undefined' && crypto.randomUUID) {
5
- return crypto.randomUUID();
6
- }
7
- return `block-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
8
- }
9
- export function useKeyboardShortcuts(state, dispatch, canUndo, canRedo, undo, redo) {
10
- useEffect(() => {
11
- const handleKeyDown = (e) => {
12
- // Don't handle shortcuts if user is typing in an input/textarea/contentEditable
13
- const target = e.target;
14
- const isEditableElement = target.tagName === 'INPUT' ||
15
- target.tagName === 'TEXTAREA' ||
16
- target.isContentEditable ||
17
- target.closest('input, textarea, [contenteditable="true"]');
18
- // Check for Ctrl+Z / Cmd+Z (Undo)
19
- if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) {
20
- if (!isEditableElement) {
21
- e.preventDefault();
22
- e.stopPropagation();
23
- if (canUndo) {
24
- undo();
25
- }
26
- return;
27
- }
28
- }
29
- // Check for Ctrl+Shift+Z / Cmd+Shift+Z or Ctrl+Y / Cmd+Y (Redo)
30
- if (((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'z') || ((e.ctrlKey || e.metaKey) && e.key === 'y')) {
31
- if (!isEditableElement) {
32
- e.preventDefault();
33
- e.stopPropagation();
34
- if (canRedo) {
35
- redo();
36
- }
37
- return;
38
- }
39
- }
40
- // Check for Ctrl+V (Windows/Linux) or Cmd+V (Mac)
41
- if ((e.ctrlKey || e.metaKey) && e.key === 'v') {
42
- // Don't paste if user is typing in an input/textarea/contentEditable
43
- const target = e.target;
44
- const isEditableElement = target.tagName === 'INPUT' ||
45
- target.tagName === 'TEXTAREA' ||
46
- target.isContentEditable ||
47
- target.closest('input, textarea, [contenteditable="true"]');
48
- if (isEditableElement) {
49
- return; // Let the browser handle paste in editable elements
50
- }
51
- // Check if there's a copied block
52
- if (typeof window !== 'undefined') {
53
- const copiedBlockJson = localStorage.getItem('__BLOG_EDITOR_COPIED_BLOCK__');
54
- if (copiedBlockJson) {
55
- try {
56
- e.preventDefault();
57
- e.stopPropagation();
58
- const copiedBlock = JSON.parse(copiedBlockJson);
59
- // Clone a block with new IDs (recursive for nested blocks)
60
- const cloneBlock = (blockToClone) => {
61
- const cloned = Object.assign(Object.assign({}, blockToClone), { id: generateBlockId(), data: Object.assign({}, blockToClone.data), meta: blockToClone.meta ? Object.assign({}, blockToClone.meta) : undefined });
62
- // Handle children if they exist
63
- if (blockToClone.children) {
64
- if (Array.isArray(blockToClone.children) && blockToClone.children.length > 0) {
65
- if (typeof blockToClone.children[0] === 'object') {
66
- cloned.children = blockToClone.children.map(cloneBlock);
67
- }
68
- else {
69
- // If children are IDs, find and clone the actual blocks
70
- const allBlocks = state.blocks;
71
- const childIds = blockToClone.children;
72
- const childBlocks = childIds
73
- .map((childId) => allBlocks.find(b => b.id === childId))
74
- .filter((b) => b !== undefined);
75
- cloned.children = childBlocks.map(cloneBlock);
76
- }
77
- }
78
- }
79
- return cloned;
80
- };
81
- const pastedBlock = cloneBlock(copiedBlock);
82
- // Find where to paste - use hovered block or selected block, or paste at end
83
- const hoveredBlockId = window.__BLOG_EDITOR_HOVERED_BLOCK_ID__;
84
- const targetBlockId = hoveredBlockId || state.selectedBlockId;
85
- let pasteIndex;
86
- if (targetBlockId) {
87
- const targetIndex = state.blocks.findIndex(b => b.id === targetBlockId);
88
- if (targetIndex !== -1) {
89
- pasteIndex = targetIndex + 1;
90
- }
91
- }
92
- // Dispatch ADD_BLOCK with the full block structure
93
- dispatch({
94
- type: 'ADD_BLOCK',
95
- payload: {
96
- block: pastedBlock,
97
- index: pasteIndex,
98
- containerId: undefined
99
- }
100
- });
101
- }
102
- catch (error) {
103
- console.error('Failed to paste block:', error);
104
- }
105
- }
106
- }
107
- }
108
- };
109
- window.addEventListener('keydown', handleKeyDown);
110
- return () => {
111
- window.removeEventListener('keydown', handleKeyDown);
112
- };
113
- }, [state.blocks, state.selectedBlockId, dispatch, canUndo, canRedo, undo, redo]);
114
- }