@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.
- package/package.json +58 -59
- package/src/api/categories.ts +0 -43
- package/src/api/check-title.ts +0 -60
- package/src/api/config-handler.ts +0 -76
- package/src/api/handler.ts +0 -418
- package/src/api/index.ts +0 -33
- package/src/api/route.ts +0 -116
- package/src/api/router.ts +0 -128
- package/src/api-server.ts +0 -11
- package/src/config.ts +0 -161
- package/src/hooks/index.d.ts +0 -8
- package/src/hooks/index.d.ts.map +0 -1
- package/src/hooks/index.js +0 -7
- package/src/hooks/index.ts +0 -9
- package/src/hooks/useBlog.d.ts +0 -31
- package/src/hooks/useBlog.d.ts.map +0 -1
- package/src/hooks/useBlog.js +0 -57
- package/src/hooks/useBlog.ts +0 -85
- package/src/hooks/useBlogs.d.ts +0 -39
- package/src/hooks/useBlogs.d.ts.map +0 -1
- package/src/hooks/useBlogs.js +0 -82
- package/src/hooks/useBlogs.ts +0 -123
- package/src/hooks/useCategories.d.ts +0 -9
- package/src/hooks/useCategories.d.ts.map +0 -1
- package/src/hooks/useCategories.js +0 -70
- package/src/hooks/useCategories.ts +0 -76
- package/src/index.d.ts +0 -55
- package/src/index.d.ts.map +0 -1
- package/src/index.js +0 -228
- package/src/index.server.ts +0 -14
- package/src/index.tsx +0 -335
- package/src/init.d.ts +0 -40
- package/src/init.d.ts.map +0 -1
- package/src/init.js +0 -41
- package/src/init.tsx +0 -63
- package/src/lib/blocks/BlockRenderer.d.ts +0 -54
- package/src/lib/blocks/BlockRenderer.d.ts.map +0 -1
- package/src/lib/blocks/BlockRenderer.js +0 -54
- package/src/lib/blocks/BlockRenderer.tsx +0 -141
- package/src/lib/blocks/index.ts +0 -6
- package/src/lib/config-storage.d.ts +0 -30
- package/src/lib/config-storage.d.ts.map +0 -1
- package/src/lib/config-storage.js +0 -31
- package/src/lib/config-storage.ts +0 -65
- package/src/lib/index.ts +0 -9
- package/src/lib/layouts/blocks/ColumnsBlock.d.ts +0 -25
- package/src/lib/layouts/blocks/ColumnsBlock.d.ts.map +0 -1
- package/src/lib/layouts/blocks/ColumnsBlock.js +0 -182
- package/src/lib/layouts/blocks/ColumnsBlock.tsx +0 -298
- package/src/lib/layouts/blocks/ColumnsBlock.tsx.tmp +0 -81
- package/src/lib/layouts/blocks/SectionBlock.d.ts +0 -25
- package/src/lib/layouts/blocks/SectionBlock.d.ts.map +0 -1
- package/src/lib/layouts/blocks/SectionBlock.js +0 -44
- package/src/lib/layouts/blocks/SectionBlock.tsx +0 -104
- package/src/lib/layouts/blocks/index.ts +0 -8
- package/src/lib/layouts/index.d.ts +0 -23
- package/src/lib/layouts/index.d.ts.map +0 -1
- package/src/lib/layouts/index.js +0 -45
- package/src/lib/layouts/index.ts +0 -52
- package/src/lib/layouts/registerLayoutBlocks.d.ts +0 -9
- package/src/lib/layouts/registerLayoutBlocks.d.ts.map +0 -1
- package/src/lib/layouts/registerLayoutBlocks.js +0 -60
- package/src/lib/layouts/registerLayoutBlocks.ts +0 -64
- package/src/lib/mappers/apiMapper.d.ts +0 -66
- package/src/lib/mappers/apiMapper.d.ts.map +0 -1
- package/src/lib/mappers/apiMapper.js +0 -191
- package/src/lib/mappers/apiMapper.ts +0 -254
- package/src/lib/migration/index.ts +0 -6
- package/src/lib/migration/mapper.ts +0 -140
- package/src/lib/rich-text/RichTextEditor.d.ts +0 -45
- package/src/lib/rich-text/RichTextEditor.d.ts.map +0 -1
- package/src/lib/rich-text/RichTextEditor.js +0 -564
- package/src/lib/rich-text/RichTextEditor.tsx +0 -826
- package/src/lib/rich-text/RichTextPreview.d.ts +0 -16
- package/src/lib/rich-text/RichTextPreview.d.ts.map +0 -1
- package/src/lib/rich-text/RichTextPreview.js +0 -144
- package/src/lib/rich-text/RichTextPreview.tsx +0 -210
- package/src/lib/rich-text/index.d.ts +0 -9
- package/src/lib/rich-text/index.d.ts.map +0 -1
- package/src/lib/rich-text/index.js +0 -6
- package/src/lib/rich-text/index.ts +0 -10
- package/src/lib/utils/blockHelpers.d.ts +0 -23
- package/src/lib/utils/blockHelpers.d.ts.map +0 -1
- package/src/lib/utils/blockHelpers.js +0 -65
- package/src/lib/utils/blockHelpers.ts +0 -72
- package/src/lib/utils/configValidation.d.ts +0 -23
- package/src/lib/utils/configValidation.d.ts.map +0 -1
- package/src/lib/utils/configValidation.js +0 -113
- package/src/lib/utils/configValidation.ts +0 -137
- package/src/lib/utils/index.ts +0 -8
- package/src/lib/utils/slugify.ts +0 -79
- package/src/registry/BlockRegistry.d.ts +0 -62
- package/src/registry/BlockRegistry.d.ts.map +0 -1
- package/src/registry/BlockRegistry.js +0 -112
- package/src/registry/BlockRegistry.ts +0 -139
- package/src/registry/index.d.ts +0 -6
- package/src/registry/index.d.ts.map +0 -1
- package/src/registry/index.js +0 -4
- package/src/registry/index.ts +0 -11
- package/src/state/EditorContext.d.ts +0 -45
- package/src/state/EditorContext.d.ts.map +0 -1
- package/src/state/EditorContext.js +0 -215
- package/src/state/EditorContext.tsx +0 -283
- package/src/state/index.d.ts +0 -7
- package/src/state/index.d.ts.map +0 -1
- package/src/state/index.js +0 -6
- package/src/state/index.ts +0 -8
- package/src/state/reducer.d.ts +0 -11
- package/src/state/reducer.d.ts.map +0 -1
- package/src/state/reducer.js +0 -443
- package/src/state/reducer.ts +0 -694
- package/src/state/types.d.ts +0 -162
- package/src/state/types.d.ts.map +0 -1
- package/src/state/types.js +0 -27
- package/src/state/types.ts +0 -160
- package/src/types/block.d.ts +0 -221
- package/src/types/block.d.ts.map +0 -1
- package/src/types/block.js +0 -6
- package/src/types/block.ts +0 -269
- package/src/types/index.d.ts +0 -8
- package/src/types/index.d.ts.map +0 -1
- package/src/types/index.js +0 -5
- package/src/types/index.ts +0 -17
- package/src/types/post.d.ts +0 -136
- package/src/types/post.d.ts.map +0 -1
- package/src/types/post.js +0 -5
- package/src/types/post.ts +0 -169
- package/src/utils/client.d.ts +0 -48
- package/src/utils/client.d.ts.map +0 -1
- package/src/utils/client.js +0 -77
- package/src/utils/client.ts +0 -122
- package/src/utils/index.ts +0 -7
- package/src/views/CanvasEditor/BlockWrapper.d.ts +0 -16
- package/src/views/CanvasEditor/BlockWrapper.d.ts.map +0 -1
- package/src/views/CanvasEditor/BlockWrapper.js +0 -276
- package/src/views/CanvasEditor/BlockWrapper.tsx +0 -522
- package/src/views/CanvasEditor/CanvasEditorView.d.ts +0 -14
- package/src/views/CanvasEditor/CanvasEditorView.d.ts.map +0 -1
- package/src/views/CanvasEditor/CanvasEditorView.js +0 -209
- package/src/views/CanvasEditor/CanvasEditorView.tsx +0 -337
- package/src/views/CanvasEditor/EditorBody.d.ts +0 -22
- package/src/views/CanvasEditor/EditorBody.d.ts.map +0 -1
- package/src/views/CanvasEditor/EditorBody.js +0 -505
- package/src/views/CanvasEditor/EditorBody.tsx +0 -665
- package/src/views/CanvasEditor/EditorHeader.d.ts +0 -18
- package/src/views/CanvasEditor/EditorHeader.d.ts.map +0 -1
- package/src/views/CanvasEditor/EditorHeader.js +0 -101
- package/src/views/CanvasEditor/EditorHeader.tsx +0 -268
- package/src/views/CanvasEditor/LayoutContainer.d.ts +0 -17
- package/src/views/CanvasEditor/LayoutContainer.d.ts.map +0 -1
- package/src/views/CanvasEditor/LayoutContainer.js +0 -222
- package/src/views/CanvasEditor/LayoutContainer.tsx +0 -322
- package/src/views/CanvasEditor/SaveConfirmationModal.d.ts +0 -13
- package/src/views/CanvasEditor/SaveConfirmationModal.d.ts.map +0 -1
- package/src/views/CanvasEditor/SaveConfirmationModal.js +0 -78
- package/src/views/CanvasEditor/SaveConfirmationModal.tsx +0 -233
- package/src/views/CanvasEditor/components/CustomBlockItem.d.ts +0 -14
- package/src/views/CanvasEditor/components/CustomBlockItem.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/CustomBlockItem.js +0 -44
- package/src/views/CanvasEditor/components/CustomBlockItem.tsx +0 -92
- package/src/views/CanvasEditor/components/EditorCanvas.d.ts +0 -29
- package/src/views/CanvasEditor/components/EditorCanvas.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/EditorCanvas.js +0 -32
- package/src/views/CanvasEditor/components/EditorCanvas.tsx +0 -160
- package/src/views/CanvasEditor/components/EditorLibrary.d.ts +0 -7
- package/src/views/CanvasEditor/components/EditorLibrary.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/EditorLibrary.js +0 -25
- package/src/views/CanvasEditor/components/EditorLibrary.tsx +0 -122
- package/src/views/CanvasEditor/components/EditorSidebar.d.ts +0 -13
- package/src/views/CanvasEditor/components/EditorSidebar.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/EditorSidebar.js +0 -20
- package/src/views/CanvasEditor/components/EditorSidebar.tsx +0 -181
- package/src/views/CanvasEditor/components/ErrorBanner.d.ts +0 -6
- package/src/views/CanvasEditor/components/ErrorBanner.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/ErrorBanner.js +0 -8
- package/src/views/CanvasEditor/components/ErrorBanner.tsx +0 -31
- package/src/views/CanvasEditor/components/FeaturedMediaSection.d.ts +0 -25
- package/src/views/CanvasEditor/components/FeaturedMediaSection.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/FeaturedMediaSection.js +0 -182
- package/src/views/CanvasEditor/components/FeaturedMediaSection.tsx +0 -341
- package/src/views/CanvasEditor/components/LibraryItem.d.ts +0 -14
- package/src/views/CanvasEditor/components/LibraryItem.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/LibraryItem.js +0 -43
- package/src/views/CanvasEditor/components/LibraryItem.tsx +0 -80
- package/src/views/CanvasEditor/components/PrivacySettingsSection.d.ts +0 -15
- package/src/views/CanvasEditor/components/PrivacySettingsSection.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/PrivacySettingsSection.js +0 -63
- package/src/views/CanvasEditor/components/PrivacySettingsSection.tsx +0 -212
- package/src/views/CanvasEditor/components/index.d.ts +0 -21
- package/src/views/CanvasEditor/components/index.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/index.js +0 -12
- package/src/views/CanvasEditor/components/index.ts +0 -28
- package/src/views/CanvasEditor/hooks/index.d.ts +0 -10
- package/src/views/CanvasEditor/hooks/index.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/index.js +0 -9
- package/src/views/CanvasEditor/hooks/index.ts +0 -10
- package/src/views/CanvasEditor/hooks/useHeroBlock.d.ts +0 -8
- package/src/views/CanvasEditor/hooks/useHeroBlock.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/useHeroBlock.js +0 -79
- package/src/views/CanvasEditor/hooks/useHeroBlock.ts +0 -103
- package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.d.ts +0 -3
- package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.js +0 -114
- package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.ts +0 -142
- package/src/views/CanvasEditor/hooks/usePostLoader.d.ts +0 -5
- package/src/views/CanvasEditor/hooks/usePostLoader.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/usePostLoader.js +0 -32
- package/src/views/CanvasEditor/hooks/usePostLoader.ts +0 -39
- package/src/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts +0 -2
- package/src/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/useRegisteredBlocks.js +0 -47
- package/src/views/CanvasEditor/hooks/useRegisteredBlocks.ts +0 -55
- package/src/views/CanvasEditor/hooks/useUnsavedChanges.d.ts +0 -25
- package/src/views/CanvasEditor/hooks/useUnsavedChanges.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/useUnsavedChanges.js +0 -285
- package/src/views/CanvasEditor/hooks/useUnsavedChanges.ts +0 -339
- package/src/views/CanvasEditor/index.d.ts +0 -16
- package/src/views/CanvasEditor/index.d.ts.map +0 -1
- package/src/views/CanvasEditor/index.js +0 -9
- package/src/views/CanvasEditor/index.ts +0 -16
- package/src/views/PostManager/EmptyState.d.ts +0 -10
- package/src/views/PostManager/EmptyState.d.ts.map +0 -1
- package/src/views/PostManager/EmptyState.js +0 -12
- package/src/views/PostManager/EmptyState.tsx +0 -42
- package/src/views/PostManager/PostActionsMenu.d.ts +0 -12
- package/src/views/PostManager/PostActionsMenu.d.ts.map +0 -1
- package/src/views/PostManager/PostActionsMenu.js +0 -58
- package/src/views/PostManager/PostActionsMenu.tsx +0 -112
- package/src/views/PostManager/PostCards.d.ts +0 -15
- package/src/views/PostManager/PostCards.d.ts.map +0 -1
- package/src/views/PostManager/PostCards.js +0 -79
- package/src/views/PostManager/PostCards.tsx +0 -197
- package/src/views/PostManager/PostFilters.d.ts +0 -16
- package/src/views/PostManager/PostFilters.d.ts.map +0 -1
- package/src/views/PostManager/PostFilters.js +0 -10
- package/src/views/PostManager/PostFilters.tsx +0 -95
- package/src/views/PostManager/PostManagerView.d.ts +0 -11
- package/src/views/PostManager/PostManagerView.d.ts.map +0 -1
- package/src/views/PostManager/PostManagerView.js +0 -174
- package/src/views/PostManager/PostManagerView.tsx +0 -289
- package/src/views/PostManager/PostStats.d.ts +0 -11
- package/src/views/PostManager/PostStats.d.ts.map +0 -1
- package/src/views/PostManager/PostStats.js +0 -46
- package/src/views/PostManager/PostStats.tsx +0 -81
- package/src/views/PostManager/PostTable.d.ts +0 -15
- package/src/views/PostManager/PostTable.d.ts.map +0 -1
- package/src/views/PostManager/PostTable.js +0 -79
- package/src/views/PostManager/PostTable.tsx +0 -230
- package/src/views/PostManager/index.d.ts +0 -12
- package/src/views/PostManager/index.d.ts.map +0 -1
- package/src/views/PostManager/index.js +0 -11
- package/src/views/PostManager/index.ts +0 -15
- package/src/views/Preview/PreviewBridgeView.d.ts +0 -12
- package/src/views/Preview/PreviewBridgeView.d.ts.map +0 -1
- package/src/views/Preview/PreviewBridgeView.js +0 -11
- package/src/views/Preview/PreviewBridgeView.tsx +0 -64
- package/src/views/Preview/index.d.ts +0 -6
- package/src/views/Preview/index.d.ts.map +0 -1
- package/src/views/Preview/index.js +0 -4
- package/src/views/Preview/index.ts +0 -7
- package/src/views/Settings/SettingsView.d.ts +0 -10
- package/src/views/Settings/SettingsView.d.ts.map +0 -1
- package/src/views/Settings/SettingsView.js +0 -111
- package/src/views/Settings/SettingsView.tsx +0 -298
- package/src/views/Settings/index.d.ts +0 -6
- package/src/views/Settings/index.d.ts.map +0 -1
- package/src/views/Settings/index.js +0 -4
- package/src/views/Settings/index.ts +0 -7
- package/src/views/SlugSEO/SlugSEOManagerView.d.ts +0 -12
- package/src/views/SlugSEO/SlugSEOManagerView.d.ts.map +0 -1
- package/src/views/SlugSEO/SlugSEOManagerView.js +0 -11
- package/src/views/SlugSEO/SlugSEOManagerView.tsx +0 -94
- package/src/views/SlugSEO/index.d.ts +0 -6
- package/src/views/SlugSEO/index.d.ts.map +0 -1
- package/src/views/SlugSEO/index.js +0 -4
- 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
|
-
}
|