@jhits/plugin-blog 0.0.19 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/categories.d.ts.map +1 -1
- package/dist/api/categories.js +42 -38
- package/dist/api/handler.d.ts +1 -26
- package/dist/api/handler.d.ts.map +1 -1
- package/dist/api/handler.js +81 -490
- package/dist/api/router.d.ts +0 -5
- package/dist/api/router.d.ts.map +1 -1
- package/dist/api/router.js +8 -35
- package/dist/api/service.d.ts +80 -0
- package/dist/api/service.d.ts.map +1 -0
- package/dist/api/service.js +219 -0
- package/dist/hooks/useAutoSave.d.ts +10 -0
- package/dist/hooks/useAutoSave.d.ts.map +1 -0
- package/dist/hooks/useAutoSave.js +57 -0
- package/dist/hooks/useCategories.d.ts +1 -1
- package/dist/hooks/useCategories.d.ts.map +1 -1
- package/dist/hooks/useCategories.js +15 -46
- package/dist/index.d.ts +24 -31
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -201
- package/dist/init.d.ts +20 -7
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +8 -7
- package/dist/lib/blocks/BlockRenderer.d.ts.map +1 -1
- package/dist/lib/layouts/blocks/ColumnsBlock.d.ts.map +1 -1
- package/dist/lib/layouts/blocks/ColumnsBlock.js +30 -113
- package/dist/lib/layouts/blocks/SectionBlock.d.ts.map +1 -1
- package/dist/lib/layouts/blocks/SectionBlock.js +9 -21
- package/dist/lib/layouts/index.d.ts +3 -3
- package/dist/lib/layouts/index.js +4 -4
- package/dist/lib/mappers/apiMapper.d.ts +10 -0
- package/dist/lib/mappers/apiMapper.d.ts.map +1 -1
- package/dist/lib/mappers/apiMapper.js +47 -32
- package/dist/lib/rich-text/RichTextEditor.d.ts +4 -2
- package/dist/lib/rich-text/RichTextEditor.d.ts.map +1 -1
- package/dist/lib/rich-text/RichTextEditor.js +12 -9
- package/dist/lib/utils/config-resolver.d.ts +28 -0
- package/dist/lib/utils/config-resolver.d.ts.map +1 -0
- package/dist/lib/utils/config-resolver.js +46 -0
- package/dist/lib/utils/tree.d.ts +29 -0
- package/dist/lib/utils/tree.d.ts.map +1 -0
- package/dist/lib/utils/tree.js +129 -0
- package/dist/state/EditorContext.d.ts +3 -25
- package/dist/state/EditorContext.d.ts.map +1 -1
- package/dist/state/EditorContext.js +124 -174
- package/dist/state/reducer.d.ts +1 -5
- package/dist/state/reducer.d.ts.map +1 -1
- package/dist/state/reducer.js +128 -521
- package/dist/state/types.d.ts +12 -1
- package/dist/state/types.d.ts.map +1 -1
- package/dist/types/block.d.ts +9 -0
- package/dist/types/block.d.ts.map +1 -1
- package/dist/types/post.d.ts +17 -1
- package/dist/types/post.d.ts.map +1 -1
- package/dist/views/CanvasEditor/BlockWrapper.d.ts +5 -6
- package/dist/views/CanvasEditor/BlockWrapper.d.ts.map +1 -1
- package/dist/views/CanvasEditor/BlockWrapper.js +56 -264
- package/dist/views/CanvasEditor/CanvasEditorView.d.ts +5 -3
- package/dist/views/CanvasEditor/CanvasEditorView.d.ts.map +1 -1
- package/dist/views/CanvasEditor/CanvasEditorView.js +55 -315
- package/dist/views/CanvasEditor/EditorBody.d.ts +6 -8
- package/dist/views/CanvasEditor/EditorBody.d.ts.map +1 -1
- package/dist/views/CanvasEditor/EditorBody.js +34 -482
- package/dist/views/CanvasEditor/EditorHeader.d.ts.map +1 -1
- package/dist/views/CanvasEditor/EditorHeader.js +27 -63
- package/dist/views/CanvasEditor/LayoutContainer.d.ts.map +1 -1
- package/dist/views/CanvasEditor/LayoutContainer.js +49 -70
- package/dist/views/CanvasEditor/components/CustomBlockItem.js +1 -1
- package/dist/views/CanvasEditor/components/EditorCanvas.d.ts +15 -3
- package/dist/views/CanvasEditor/components/EditorCanvas.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/EditorCanvas.js +40 -18
- package/dist/views/CanvasEditor/components/EditorLibrary.d.ts +5 -1
- package/dist/views/CanvasEditor/components/EditorLibrary.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/EditorLibrary.js +11 -7
- package/dist/views/CanvasEditor/components/EditorSidebar.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/EditorSidebar.js +32 -14
- package/dist/views/CanvasEditor/components/FeaturedMediaSection.d.ts +0 -6
- package/dist/views/CanvasEditor/components/FeaturedMediaSection.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/FeaturedMediaSection.js +17 -128
- package/dist/views/CanvasEditor/components/JSONInspector.d.ts +9 -0
- package/dist/views/CanvasEditor/components/JSONInspector.d.ts.map +1 -0
- package/dist/views/CanvasEditor/components/JSONInspector.js +56 -0
- package/dist/views/CanvasEditor/components/LibraryItem.js +2 -2
- package/dist/views/CanvasEditor/components/PrivacySettingsSection.d.ts +0 -4
- package/dist/views/CanvasEditor/components/PrivacySettingsSection.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/PrivacySettingsSection.js +6 -28
- package/dist/views/CanvasEditor/components/index.d.ts +2 -0
- package/dist/views/CanvasEditor/components/index.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/index.js +1 -0
- package/dist/views/CanvasEditor/hooks/useHeroBlock.d.ts.map +1 -1
- package/dist/views/CanvasEditor/hooks/useHeroBlock.js +15 -18
- package/dist/views/CanvasEditor/hooks/usePostLoader.d.ts +3 -0
- package/dist/views/CanvasEditor/hooks/usePostLoader.d.ts.map +1 -1
- package/dist/views/CanvasEditor/hooks/usePostLoader.js +12 -13
- package/dist/views/CanvasEditor/hooks/useUnsavedChanges.js +0 -4
- package/dist/views/PostManager/EmptyState.d.ts +1 -1
- package/dist/views/PostManager/EmptyState.js +4 -4
- package/dist/views/PostManager/FilterDropdown.d.ts +21 -0
- package/dist/views/PostManager/FilterDropdown.d.ts.map +1 -0
- package/dist/views/PostManager/FilterDropdown.js +28 -0
- package/dist/views/PostManager/LanguageFlags.d.ts.map +1 -1
- package/dist/views/PostManager/LanguageFlags.js +4 -1
- package/dist/views/PostManager/PostCards.d.ts.map +1 -1
- package/dist/views/PostManager/PostCards.js +23 -40
- package/dist/views/PostManager/PostFilters.d.ts.map +1 -1
- package/dist/views/PostManager/PostFilters.js +34 -3
- package/dist/views/PostManager/PostManagerView.d.ts +1 -2
- package/dist/views/PostManager/PostManagerView.d.ts.map +1 -1
- package/dist/views/PostManager/PostManagerView.js +30 -96
- package/dist/views/PostManager/PostStats.d.ts.map +1 -1
- package/dist/views/PostManager/PostStats.js +10 -10
- package/dist/views/PostManager/PostTable.d.ts.map +1 -1
- package/dist/views/PostManager/PostTable.js +23 -40
- package/dist/views/Settings/SettingsView.d.ts +1 -1
- package/dist/views/Settings/SettingsView.d.ts.map +1 -1
- package/dist/views/Settings/SettingsView.js +12 -39
- package/dist/views/SlugSEO/SlugSEOManagerView.d.ts.map +1 -1
- package/dist/views/SlugSEO/SlugSEOManagerView.js +2 -2
- package/package.json +42 -6
- package/src/api/categories.ts +48 -52
- package/src/api/handler.ts +87 -594
- package/src/api/router.ts +15 -65
- package/src/api/service.ts +241 -0
- package/src/hooks/useAutoSave.ts +64 -0
- package/src/hooks/useCategories.ts +19 -47
- package/src/index.tsx +79 -293
- package/src/init.tsx +24 -11
- package/src/lib/blocks/BlockRenderer.tsx +1 -0
- package/src/lib/layouts/blocks/ColumnsBlock.tsx +60 -173
- package/src/lib/layouts/blocks/SectionBlock.tsx +22 -26
- package/src/lib/layouts/index.ts +4 -4
- package/src/lib/mappers/apiMapper.ts +63 -32
- package/src/lib/rich-text/RichTextEditor.tsx +16 -9
- package/src/lib/utils/config-resolver.ts +64 -0
- package/src/lib/utils/tree.ts +150 -0
- package/src/state/EditorContext.tsx +153 -232
- package/src/state/reducer.ts +141 -606
- package/src/state/types.ts +14 -1
- package/src/types/block.ts +10 -0
- package/src/types/post.ts +19 -1
- package/src/views/CanvasEditor/BlockWrapper.tsx +130 -460
- package/src/views/CanvasEditor/CanvasEditorView.tsx +145 -420
- package/src/views/CanvasEditor/EditorBody.tsx +98 -610
- package/src/views/CanvasEditor/EditorHeader.tsx +176 -196
- package/src/views/CanvasEditor/LayoutContainer.tsx +74 -89
- package/src/views/CanvasEditor/components/CustomBlockItem.tsx +7 -8
- package/src/views/CanvasEditor/components/EditorCanvas.tsx +139 -84
- package/src/views/CanvasEditor/components/EditorLibrary.tsx +25 -10
- package/src/views/CanvasEditor/components/EditorSidebar.tsx +196 -127
- package/src/views/CanvasEditor/components/FeaturedMediaSection.tsx +78 -210
- package/src/views/CanvasEditor/components/JSONInspector.tsx +125 -0
- package/src/views/CanvasEditor/components/LibraryItem.tsx +5 -6
- package/src/views/CanvasEditor/components/PrivacySettingsSection.tsx +73 -124
- package/src/views/CanvasEditor/components/index.ts +2 -1
- package/src/views/CanvasEditor/hooks/useHeroBlock.ts +15 -18
- package/src/views/CanvasEditor/hooks/usePostLoader.ts +21 -13
- package/src/views/CanvasEditor/hooks/useUnsavedChanges.ts +4 -4
- package/src/views/PostManager/EmptyState.tsx +9 -10
- package/src/views/PostManager/FilterDropdown.tsx +95 -0
- package/src/views/PostManager/LanguageFlags.tsx +6 -2
- package/src/views/PostManager/PostCards.tsx +127 -133
- package/src/views/PostManager/PostFilters.tsx +73 -68
- package/src/views/PostManager/PostManagerView.tsx +132 -179
- package/src/views/PostManager/PostStats.tsx +21 -20
- package/src/views/PostManager/PostTable.tsx +137 -165
- package/src/views/Settings/SettingsView.tsx +64 -180
- package/src/views/SlugSEO/SlugSEOManagerView.tsx +59 -44
- package/src/hooks/index.d.ts +0 -8
- package/src/hooks/index.d.ts.map +0 -1
- package/src/hooks/useBlog.d.ts +0 -31
- package/src/hooks/useBlog.d.ts.map +0 -1
- package/src/hooks/useBlogs.d.ts +0 -39
- package/src/hooks/useBlogs.d.ts.map +0 -1
- package/src/hooks/useCategories.d.ts +0 -9
- package/src/hooks/useCategories.d.ts.map +0 -1
- package/src/lib/blocks/BlockRenderer.d.ts +0 -54
- package/src/lib/blocks/BlockRenderer.d.ts.map +0 -1
- package/src/lib/config-storage.d.ts +0 -30
- package/src/lib/config-storage.d.ts.map +0 -1
- 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/SectionBlock.d.ts +0 -25
- package/src/lib/layouts/blocks/SectionBlock.d.ts.map +0 -1
- package/src/lib/layouts/index.d.ts +0 -23
- package/src/lib/layouts/index.d.ts.map +0 -1
- package/src/lib/layouts/registerLayoutBlocks.d.ts +0 -9
- package/src/lib/layouts/registerLayoutBlocks.d.ts.map +0 -1
- package/src/lib/mappers/apiMapper.d.ts +0 -66
- package/src/lib/mappers/apiMapper.d.ts.map +0 -1
- 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/RichTextPreview.d.ts +0 -16
- package/src/lib/rich-text/RichTextPreview.d.ts.map +0 -1
- package/src/lib/rich-text/index.d.ts +0 -9
- package/src/lib/rich-text/index.d.ts.map +0 -1
- package/src/lib/utils/blockHelpers.d.ts +0 -23
- package/src/lib/utils/blockHelpers.d.ts.map +0 -1
- package/src/lib/utils/configValidation.d.ts +0 -23
- package/src/lib/utils/configValidation.d.ts.map +0 -1
- package/src/registry/BlockRegistry.d.ts +0 -62
- package/src/registry/BlockRegistry.d.ts.map +0 -1
- package/src/registry/index.d.ts +0 -6
- package/src/registry/index.d.ts.map +0 -1
- package/src/state/EditorContext.d.ts +0 -45
- package/src/state/EditorContext.d.ts.map +0 -1
- package/src/state/index.d.ts +0 -7
- package/src/state/index.d.ts.map +0 -1
- package/src/state/reducer.d.ts +0 -11
- package/src/state/reducer.d.ts.map +0 -1
- package/src/state/types.d.ts +0 -162
- package/src/state/types.d.ts.map +0 -1
- package/src/types/block.d.ts +0 -221
- package/src/types/block.d.ts.map +0 -1
- package/src/types/index.d.ts +0 -8
- package/src/types/index.d.ts.map +0 -1
- package/src/types/post.d.ts +0 -136
- package/src/types/post.d.ts.map +0 -1
- package/src/utils/client.d.ts +0 -48
- package/src/utils/client.d.ts.map +0 -1
- package/src/views/CanvasEditor/BlockWrapper.d.ts +0 -16
- package/src/views/CanvasEditor/BlockWrapper.d.ts.map +0 -1
- package/src/views/CanvasEditor/CanvasEditorView.d.ts +0 -14
- package/src/views/CanvasEditor/CanvasEditorView.d.ts.map +0 -1
- package/src/views/CanvasEditor/EditorBody.d.ts +0 -22
- package/src/views/CanvasEditor/EditorBody.d.ts.map +0 -1
- package/src/views/CanvasEditor/EditorHeader.d.ts +0 -18
- package/src/views/CanvasEditor/EditorHeader.d.ts.map +0 -1
- package/src/views/CanvasEditor/LayoutContainer.d.ts +0 -17
- package/src/views/CanvasEditor/LayoutContainer.d.ts.map +0 -1
- package/src/views/CanvasEditor/SaveConfirmationModal.d.ts +0 -13
- package/src/views/CanvasEditor/SaveConfirmationModal.d.ts.map +0 -1
- 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/EditorCanvas.d.ts +0 -29
- package/src/views/CanvasEditor/components/EditorCanvas.d.ts.map +0 -1
- 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/EditorSidebar.d.ts +0 -13
- package/src/views/CanvasEditor/components/EditorSidebar.d.ts.map +0 -1
- 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/FeaturedMediaSection.d.ts +0 -25
- package/src/views/CanvasEditor/components/FeaturedMediaSection.d.ts.map +0 -1
- 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/PrivacySettingsSection.d.ts +0 -15
- package/src/views/CanvasEditor/components/PrivacySettingsSection.d.ts.map +0 -1
- 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/hooks/index.d.ts +0 -10
- package/src/views/CanvasEditor/hooks/index.d.ts.map +0 -1
- 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/useKeyboardShortcuts.d.ts +0 -3
- package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.d.ts.map +0 -1
- 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/useRegisteredBlocks.d.ts +0 -2
- package/src/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts.map +0 -1
- 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/index.d.ts +0 -16
- package/src/views/CanvasEditor/index.d.ts.map +0 -1
- package/src/views/PostManager/EmptyState.d.ts +0 -10
- package/src/views/PostManager/EmptyState.d.ts.map +0 -1
- package/src/views/PostManager/PostActionsMenu.d.ts +0 -12
- package/src/views/PostManager/PostActionsMenu.d.ts.map +0 -1
- package/src/views/PostManager/PostCards.d.ts +0 -15
- package/src/views/PostManager/PostCards.d.ts.map +0 -1
- package/src/views/PostManager/PostFilters.d.ts +0 -16
- package/src/views/PostManager/PostFilters.d.ts.map +0 -1
- package/src/views/PostManager/PostManagerView.d.ts +0 -11
- package/src/views/PostManager/PostManagerView.d.ts.map +0 -1
- package/src/views/PostManager/PostStats.d.ts +0 -11
- package/src/views/PostManager/PostStats.d.ts.map +0 -1
- package/src/views/PostManager/PostTable.d.ts +0 -15
- package/src/views/PostManager/PostTable.d.ts.map +0 -1
- package/src/views/PostManager/index.d.ts +0 -12
- package/src/views/PostManager/index.d.ts.map +0 -1
- package/src/views/Preview/PreviewBridgeView.d.ts +0 -12
- package/src/views/Preview/PreviewBridgeView.d.ts.map +0 -1
- package/src/views/Preview/index.d.ts +0 -6
- package/src/views/Preview/index.d.ts.map +0 -1
- package/src/views/Settings/SettingsView.d.ts +0 -10
- package/src/views/Settings/SettingsView.d.ts.map +0 -1
- package/src/views/Settings/index.d.ts +0 -6
- package/src/views/Settings/index.d.ts.map +0 -1
- package/src/views/SlugSEO/SlugSEOManagerView.d.ts +0 -12
- package/src/views/SlugSEO/SlugSEOManagerView.d.ts.map +0 -1
- package/src/views/SlugSEO/index.d.ts +0 -6
- package/src/views/SlugSEO/index.d.ts.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useState } from 'react';
|
|
4
|
-
import { ArrowLeft, Library, Settings2, Clock, Edit, Eye,
|
|
4
|
+
import { ArrowLeft, Library, Settings2, Save, Clock, Edit, Eye, Plus, ChevronDown, CheckCircle2 } from 'lucide-react';
|
|
5
5
|
import { useEditor } from '../../state/EditorContext';
|
|
6
6
|
import { SaveConfirmationModal } from './SaveConfirmationModal';
|
|
7
7
|
export function EditorHeader({ isLibraryOpen, onLibraryToggle, isPreviewMode, onPreviewToggle, isSidebarOpen, onSidebarToggle, isSaving, onSave, onSaveError, autoSaveEnabled = false, onAutoSaveToggle, isDirty = false, autoSaveCountdown = null, autoSaveStatus = 'idle', languages = [], currentLanguage = 'en', onLanguageChange, onAddLanguage, }) {
|
|
@@ -18,100 +18,64 @@ export function EditorHeader({ isLibraryOpen, onLibraryToggle, isPreviewMode, on
|
|
|
18
18
|
fr: 'Français',
|
|
19
19
|
es: 'Español',
|
|
20
20
|
};
|
|
21
|
-
const
|
|
21
|
+
const getFlagUrl = (lang) => {
|
|
22
|
+
const mapping = {
|
|
23
|
+
en: 'gb', nl: 'nl', sv: 'se', de: 'de', fr: 'fr', es: 'es'
|
|
24
|
+
};
|
|
25
|
+
return `https://flagcdn.com/w40/${(mapping[lang] || lang).toLowerCase()}.png`;
|
|
26
|
+
};
|
|
27
|
+
const allCreatedLanguages = Array.from(new Set([...languages, currentLanguage]));
|
|
28
|
+
const availableToAdd = ['en', 'nl', 'sv', 'de', 'fr', 'es'].filter(lang => !allCreatedLanguages.includes(lang));
|
|
22
29
|
const handleSaveDraftClick = () => {
|
|
23
30
|
setSaveAsDraft(true);
|
|
24
|
-
setSaveError(null);
|
|
31
|
+
setSaveError(null);
|
|
25
32
|
setShowConfirmModal(true);
|
|
26
33
|
};
|
|
27
34
|
const handlePublishClick = () => {
|
|
28
35
|
setSaveAsDraft(false);
|
|
29
|
-
setSaveError(null);
|
|
36
|
+
setSaveError(null);
|
|
30
37
|
setShowConfirmModal(true);
|
|
31
38
|
};
|
|
32
39
|
const handleConfirmSave = async () => {
|
|
33
40
|
try {
|
|
34
|
-
const targetStatus = saveAsDraft ? 'draft' : 'published';
|
|
35
|
-
console.log('[EditorHeader] Starting save process...', { saveAsDraft, targetStatus, currentStatus: state.status });
|
|
36
|
-
// Set status before saving - ensure state is updated
|
|
37
41
|
if (saveAsDraft) {
|
|
38
42
|
dispatch({ type: 'SET_STATUS', payload: 'draft' });
|
|
39
43
|
}
|
|
40
44
|
else {
|
|
41
45
|
dispatch({ type: 'SET_STATUS', payload: 'published' });
|
|
42
46
|
}
|
|
43
|
-
// Wait longer to ensure state update propagates through the reducer and context
|
|
44
|
-
// React state updates are asynchronous, so we need to wait for the state to actually update
|
|
45
47
|
await new Promise(resolve => setTimeout(resolve, 150));
|
|
46
|
-
// Verify status was updated
|
|
47
|
-
console.log('[EditorHeader] Status after update:', state.status, 'Expected:', targetStatus);
|
|
48
48
|
await onSave(!saveAsDraft);
|
|
49
|
-
console.log('[EditorHeader] Post saved successfully');
|
|
50
|
-
// Clear any previous errors
|
|
51
49
|
setSaveError(null);
|
|
52
|
-
// Modal will show success message and close automatically
|
|
53
50
|
}
|
|
54
51
|
catch (error) {
|
|
55
|
-
console.error('[EditorHeader] Failed to save post:', error);
|
|
56
|
-
// Extract user-friendly error message
|
|
57
52
|
let errorMessage = error.message || 'Failed to save post';
|
|
58
|
-
// Make error messages more user-friendly
|
|
59
|
-
if (errorMessage.includes('Missing required fields')) {
|
|
60
|
-
// Keep the detailed message about missing fields
|
|
61
|
-
errorMessage = errorMessage.replace('Missing required fields for publishing:', 'To publish, please fill in:');
|
|
62
|
-
}
|
|
63
|
-
else if (errorMessage.includes('All required fields')) {
|
|
64
|
-
errorMessage = 'To publish, please fill in all required fields: summary, featured image, category, and content.';
|
|
65
|
-
}
|
|
66
|
-
else if (errorMessage.includes('Unauthorized')) {
|
|
67
|
-
errorMessage = 'You are not authorized to save this post. Please log in again.';
|
|
68
|
-
}
|
|
69
|
-
else if (errorMessage.includes('Failed to save')) {
|
|
70
|
-
errorMessage = 'Unable to save the post. Please check your connection and try again.';
|
|
71
|
-
}
|
|
72
53
|
setSaveError(errorMessage);
|
|
73
54
|
onSaveError(errorMessage);
|
|
74
|
-
// Re-throw the error so the modal knows it failed and doesn't show success
|
|
75
55
|
throw error;
|
|
76
56
|
}
|
|
77
57
|
};
|
|
78
|
-
return (_jsxs("div", { className: "flex items-center justify-between px-
|
|
58
|
+
return (_jsxs("div", { className: "flex items-center justify-between px-4 lg:px-8 py-3 lg:py-4 bg-dashboard-bg/80 backdrop-blur-xl border-b border-dashboard-border/50 flex-none shrink-0 z-50", children: [_jsxs("div", { className: "flex items-center gap-3 lg:gap-6", children: [_jsx("button", { onClick: () => {
|
|
79
59
|
if (isDirty) {
|
|
80
|
-
|
|
81
|
-
if (!confirmed) {
|
|
60
|
+
if (!window.confirm('You have unsaved changes. Leave anyway?'))
|
|
82
61
|
return;
|
|
83
|
-
}
|
|
84
62
|
}
|
|
85
63
|
window.location.href = '/dashboard/blog';
|
|
86
|
-
}, className: "
|
|
87
|
-
|
|
64
|
+
}, className: "size-9 lg:size-10 flex items-center justify-center bg-dashboard-card border border-dashboard-border rounded-xl text-dashboard-text-secondary hover:text-primary hover:border-primary/30 transition-all active:scale-95 shadow-sm", children: _jsx(ArrowLeft, { className: "size-[18px] lg:size-[20px]" }) }), _jsx("div", { className: "h-6 lg:h-8 w-px bg-dashboard-border/30" }), _jsxs("button", { onClick: onLibraryToggle, className: `flex items-center gap-2 lg:gap-3 px-3 lg:px-5 py-2 lg:py-2.5 rounded-xl text-[10px] font-black uppercase tracking-[0.2em] transition-all border ${isLibraryOpen
|
|
65
|
+
? 'bg-primary text-white border-primary/20 shadow-lg shadow-primary/20'
|
|
66
|
+
: 'bg-dashboard-card text-dashboard-text-secondary border-dashboard-border hover:border-primary/30'}`, children: [_jsx(Library, { size: 16 }), _jsx("span", { className: "hidden xl:inline", children: "Blocks Library" }), _jsx("span", { className: "xl:hidden hidden lg:inline text-[8px]", children: "Blocks" })] }), languages.length > 0 && onLanguageChange && (_jsxs("div", { className: "relative group", children: [_jsxs("button", { onClick: () => setShowLanguageDropdown(!showLanguageDropdown), className: "flex items-center gap-2 lg:gap-3 px-3 lg:px-4 py-2 lg:py-2.5 bg-dashboard-card border border-dashboard-border rounded-xl hover:border-primary/30 transition-all shadow-sm", children: [_jsx("img", { src: getFlagUrl(currentLanguage), className: "w-4 h-2.5 lg:w-5 lg:h-3.5 object-cover rounded-sm border border-white/20", alt: "" }), _jsx("span", { className: "text-[10px] font-black uppercase tracking-widest text-dashboard-text-secondary", children: currentLanguage.toUpperCase() }), _jsx(ChevronDown, { className: `size-[12px] lg:size-[14px] text-dashboard-text-secondary transition-transform ${showLanguageDropdown ? 'rotate-180' : ''}` })] }), showLanguageDropdown && (_jsxs("div", { className: "absolute top-full left-0 mt-3 p-2 bg-dashboard-bg/95 backdrop-blur-2xl border border-dashboard-border rounded-2xl shadow-2xl z-[100] min-w-[180px] animate-in fade-in zoom-in-95 duration-200", children: [_jsx("label", { className: "px-3 py-2 text-[8px] font-black text-dashboard-text-secondary uppercase tracking-[0.3em] block border-b border-dashboard-border/30 mb-1", children: "Switch Edition" }), allCreatedLanguages.map(lang => (_jsxs("button", { onClick: () => {
|
|
67
|
+
onLanguageChange(lang);
|
|
68
|
+
setShowLanguageDropdown(false);
|
|
69
|
+
}, className: `w-full flex items-center gap-3 px-3 py-2.5 rounded-xl transition-all ${lang === currentLanguage
|
|
70
|
+
? 'bg-primary/10 text-primary font-bold'
|
|
71
|
+
: 'text-dashboard-text-secondary hover:bg-white/5 hover:text-dashboard-text'}`, children: [_jsx("img", { src: getFlagUrl(lang), className: "w-4 h-3 object-cover rounded-sm", alt: "" }), _jsx("span", { className: "text-[10px] font-black uppercase tracking-widest", children: languageLabels[lang] || lang.toUpperCase() })] }, lang))), availableToAdd.length > 0 && onAddLanguage && (_jsxs(_Fragment, { children: [_jsx("div", { className: "my-2 border-t border-dashboard-border/30 mx-2" }), _jsx("label", { className: "px-3 py-2 text-[8px] font-black text-dashboard-text-secondary uppercase tracking-[0.3em] block mb-1", children: "Add Edition" }), availableToAdd.map(lang => (_jsxs("button", { onClick: () => {
|
|
72
|
+
onAddLanguage(lang);
|
|
88
73
|
setShowLanguageDropdown(false);
|
|
89
|
-
}, className:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}, className: "w-full text-left px-3 py-2 text-[10px] uppercase tracking-wider text-neutral-600 dark:text-neutral-400 hover:bg-dashboard-bg hover:text-dashboard-text transition-colors", children: ["+ ", languageLabels[lang] || lang.toUpperCase()] }, lang)))] }))] }))] })] }))] }), _jsxs("div", { className: "flex items-center gap-4", children: [onAutoSaveToggle && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("button", { onClick: () => onAutoSaveToggle(!autoSaveEnabled), className: `relative flex items-center gap-2 px-3 py-1.5 rounded-full text-[10px] uppercase tracking-widest font-bold transition-all ${autoSaveEnabled
|
|
95
|
-
? 'bg-primary/20 text-primary border border-primary/30'
|
|
96
|
-
: 'bg-dashboard-bg text-neutral-600 dark:text-neutral-400 border border-dashboard-border hover:text-neutral-950 dark:hover:text-white'}`, title: autoSaveEnabled ? 'Auto-save enabled (saves after 10s of inactivity)' : 'Click to enable auto-save', children: [_jsx(Clock, { size: 12, className: autoSaveEnabled && autoSaveStatus !== 'saving' ? 'animate-pulse' : '' }), _jsx("span", { children: "Auto-save" }), _jsx("span", { className: `ml-1 text-[9px] ${autoSaveEnabled ? 'text-primary' : 'text-neutral-500 dark:text-neutral-400'}`, children: autoSaveEnabled ? 'ON' : 'OFF' }), autoSaveEnabled && isDirty && (_jsxs("span", { className: "ml-1.5 text-[9px] font-bold tabular-nums", children: [autoSaveStatus === 'saving' && (_jsx("span", { className: "text-primary animate-pulse", children: "Saving..." })), autoSaveStatus === 'saved' && (_jsx("span", { className: "text-green-500 dark:text-green-400", children: "Saved!" })), autoSaveStatus === 'error' && (_jsx("span", { className: "text-red-500 dark:text-red-400", children: "Error" })), autoSaveStatus === 'idle' && autoSaveCountdown !== null && (_jsxs("span", { className: "text-primary/70", children: [autoSaveCountdown, "s"] }))] }))] }), isDirty && !autoSaveEnabled && (_jsx("span", { className: "text-[10px] text-amber-500 dark:text-amber-400 font-bold uppercase tracking-widest animate-pulse", children: "Unsaved" }))] })), _jsxs("div", { className: "flex items-center bg-dashboard-bg border border-dashboard-border rounded-full p-1 gap-1", children: [_jsxs("button", { onClick: () => {
|
|
97
|
-
if (isPreviewMode) {
|
|
98
|
-
onPreviewToggle();
|
|
99
|
-
}
|
|
100
|
-
}, className: `flex items-center gap-1.5 px-3 py-1.5 rounded-full text-[10px] uppercase tracking-widest font-bold transition-all ${!isPreviewMode
|
|
101
|
-
? 'bg-primary text-white shadow-sm'
|
|
102
|
-
: 'text-neutral-600 dark:text-neutral-400 hover:text-neutral-950 dark:hover:text-white'}`, title: "Edit mode - Make changes to your post", children: [_jsx(Edit, { size: 12, strokeWidth: 2.5 }), _jsx("span", { children: "Edit" })] }), _jsxs("button", { onClick: () => {
|
|
103
|
-
if (!isPreviewMode) {
|
|
104
|
-
onPreviewToggle();
|
|
105
|
-
}
|
|
106
|
-
}, className: `flex items-center gap-1.5 px-3 py-1.5 rounded-full text-[10px] uppercase tracking-widest font-bold transition-all ${isPreviewMode
|
|
107
|
-
? 'bg-primary text-white shadow-sm'
|
|
108
|
-
: 'text-neutral-600 dark:text-neutral-400 hover:text-neutral-950 dark:hover:text-white'}`, title: "Preview mode - See how your post will look", children: [_jsx(Eye, { size: 12, strokeWidth: 2.5 }), _jsx("span", { children: "Preview" })] })] }), (state.status === 'draft' || !state.postId) && (_jsx("button", { onClick: handleSaveDraftClick, disabled: isSaving, className: `px-4 py-2 border-2 border-dashboard-border text-dashboard-text rounded-full text-[10px] font-bold uppercase tracking-widest transition-all ${isSaving
|
|
109
|
-
? 'opacity-50 cursor-not-allowed'
|
|
110
|
-
: 'hover:bg-dashboard-bg'}`, children: isSaving ? 'Saving...' : 'Save Draft' })), _jsx("button", { onClick: handlePublishClick, disabled: isSaving, className: `px-6 py-2 bg-primary text-white rounded-full text-[10px] font-bold uppercase tracking-widest transition-all shadow-lg shadow-primary/20 ${isSaving
|
|
111
|
-
? 'opacity-50 cursor-not-allowed'
|
|
112
|
-
: 'hover:bg-primary/90'}`, children: isSaving ? 'Saving...' : state.status === 'published' ? 'Update Post' : 'Publish Post' }), _jsx("button", { onClick: onSidebarToggle, className: `p-2 rounded-full transition-colors ${isSidebarOpen
|
|
113
|
-
? 'bg-dashboard-bg text-dashboard-text'
|
|
114
|
-
: 'text-neutral-500 dark:text-neutral-400 hover:bg-dashboard-bg'}`, children: _jsx(Settings2, { size: 18 }) })] }), _jsx(SaveConfirmationModal, { isOpen: showConfirmModal, onClose: () => {
|
|
74
|
+
}, className: "w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-dashboard-text-secondary hover:bg-primary/10 hover:text-primary transition-all group/add", children: [_jsxs("div", { className: "relative", children: [_jsx("img", { src: getFlagUrl(lang), className: "w-4 h-3 object-cover rounded-sm opacity-60 group-hover/add:opacity-100 transition-opacity", alt: "" }), _jsx("div", { className: "absolute -top-1 -right-1 size-2 bg-primary rounded-full border border-dashboard-bg flex items-center justify-center text-[6px] text-white font-bold", children: "+" })] }), _jsx("span", { className: "text-[10px] font-black uppercase tracking-widest", children: languageLabels[lang] || lang.toUpperCase() })] }, lang)))] }))] }))] }))] }), _jsxs("div", { className: "hidden md:flex items-center gap-2 lg:gap-4", children: [state.status === 'published' && (_jsxs("div", { className: "flex items-center gap-2 px-3 lg:px-4 py-1.5 bg-emerald-500/10 border border-emerald-500/20 rounded-full text-emerald-500", children: [_jsx(CheckCircle2, { size: 12, className: "animate-pulse" }), _jsx("span", { className: "text-[9px] font-black uppercase tracking-[0.2em] hidden lg:inline", children: "Live Edition" }), _jsx("span", { className: "text-[9px] font-black uppercase tracking-[0.2em] lg:hidden", children: "Live" })] })), state.status === 'not-translated' && (_jsxs("div", { className: "flex items-center gap-2 px-3 lg:px-4 py-1.5 bg-blue-500/10 border border-blue-500/20 rounded-full text-blue-500", children: [_jsx(Plus, { size: 12 }), _jsx("span", { className: "text-[9px] font-black uppercase tracking-[0.2em] hidden lg:inline", children: "New Edition" }), _jsx("span", { className: "text-[9px] font-black uppercase tracking-[0.2em] lg:hidden", children: "New" })] })), isDirty && !autoSaveEnabled && (_jsxs("div", { className: "flex items-center gap-2 px-3 lg:px-4 py-1.5 bg-amber-500/10 border border-amber-500/20 rounded-full text-amber-500 animate-pulse", children: [_jsx(Clock, { size: 12 }), _jsx("span", { className: "text-[9px] font-black uppercase tracking-[0.2em] hidden lg:inline", children: "Unsaved Edits" }), _jsx("span", { className: "text-[9px] font-black uppercase tracking-[0.2em] lg:hidden", children: "Dirty" })] }))] }), _jsxs("div", { className: "flex items-center gap-2 lg:gap-4", children: [onAutoSaveToggle && (_jsxs("button", { onClick: () => onAutoSaveToggle(!autoSaveEnabled), className: `group flex items-center gap-2 lg:gap-3 px-3 lg:px-4 py-2 lg:py-2.5 rounded-xl border transition-all ${autoSaveEnabled
|
|
75
|
+
? 'bg-primary/10 border-primary/30 text-primary'
|
|
76
|
+
: 'bg-dashboard-card border border-dashboard-border text-dashboard-text-secondary'}`, children: [_jsx(Clock, { size: 14, className: autoSaveEnabled && autoSaveStatus === 'saving' ? 'animate-spin' : '' }), _jsx("span", { className: "text-[9px] font-black uppercase tracking-widest hidden lg:inline", children: autoSaveStatus === 'saving' ? 'Syncing...' : 'Auto-Sync' }), _jsx("div", { className: `size-1.5 rounded-full ${autoSaveEnabled ? 'bg-primary animate-pulse' : 'bg-dashboard-text-secondary/30'}` })] })), _jsxs("div", { className: "flex items-center bg-dashboard-card border border-dashboard-border rounded-xl p-1 shadow-inner", children: [_jsxs("button", { onClick: () => isPreviewMode && onPreviewToggle(), className: `flex items-center gap-2 px-3 lg:px-4 py-1.5 lg:py-2 rounded-lg text-[10px] font-black uppercase tracking-widest transition-all ${!isPreviewMode ? 'bg-primary text-white shadow-md' : 'text-dashboard-text-secondary hover:text-dashboard-text'}`, children: [_jsx(Edit, { size: 12 }), _jsx("span", { className: "hidden sm:inline", children: "Edit" })] }), _jsxs("button", { onClick: () => !isPreviewMode && onPreviewToggle(), className: `flex items-center gap-2 px-3 lg:px-4 py-1.5 lg:py-2 rounded-lg text-[10px] font-black uppercase tracking-widest transition-all ${isPreviewMode ? 'bg-primary text-white shadow-md' : 'text-dashboard-text-secondary hover:text-dashboard-text'}`, children: [_jsx(Eye, { size: 12 }), _jsx("span", { className: "hidden sm:inline", children: "View" })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [state.status !== 'published' && (_jsxs("button", { onClick: handleSaveDraftClick, disabled: isSaving, className: "px-4 lg:px-6 py-2 lg:py-2.5 bg-dashboard-card border border-dashboard-border text-dashboard-text-secondary rounded-xl text-[10px] font-black uppercase tracking-[0.2em] hover:border-primary/30 transition-all active:scale-95", children: [_jsx("span", { className: "hidden lg:inline", children: isSaving ? '...' : 'Save Draft' }), _jsx("span", { className: "lg:hidden", children: isSaving ? '...' : 'Draft' })] })), _jsxs("button", { onClick: handlePublishClick, disabled: isSaving, className: "px-5 lg:px-8 py-2 lg:py-2.5 bg-primary text-white rounded-xl text-[10px] font-black uppercase tracking-[0.3em] shadow-xl shadow-primary/20 hover:scale-[1.02] active:scale-95 transition-all", children: [_jsx("span", { className: "hidden lg:inline", children: isSaving ? 'Publishing...' : state.status === 'published' ? 'Update Live' : 'Go Live' }), _jsx(Save, { size: 14, className: "lg:hidden" })] })] }), _jsx("button", { onClick: onSidebarToggle, className: `size-9 lg:size-10 flex items-center justify-center rounded-xl transition-all border ${isSidebarOpen
|
|
77
|
+
? 'bg-primary/10 border-primary/30 text-primary shadow-lg shadow-primary/10'
|
|
78
|
+
: 'bg-dashboard-card border border-dashboard-border text-dashboard-text-secondary hover:border-primary/30'}`, children: _jsx(Settings2, { className: "size-[18px] lg:size-[20px]" }) })] }), _jsx(SaveConfirmationModal, { isOpen: showConfirmModal, onClose: () => {
|
|
115
79
|
setShowConfirmModal(false);
|
|
116
80
|
setSaveAsDraft(false);
|
|
117
81
|
setSaveError(null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LayoutContainer.d.ts","sourceRoot":"","sources":["../../../src/views/CanvasEditor/LayoutContainer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAI1C,MAAM,WAAW,oBAAoB;IACjC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACvE,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACvF,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,eAAe,CAAC,EAC5B,MAAM,EACN,WAAW,EACX,UAAU,EACV,aAAa,EACb,aAAa,EACb,WAAW,EACX,SAAc,EACd,UAA+B,GAClC,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"LayoutContainer.d.ts","sourceRoot":"","sources":["../../../src/views/CanvasEditor/LayoutContainer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAI1C,MAAM,WAAW,oBAAoB;IACjC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACvE,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACvF,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,eAAe,CAAC,EAC5B,MAAM,EACN,WAAW,EACX,UAAU,EACV,aAAa,EACb,aAAa,EACb,WAAW,EACX,SAAc,EACd,UAA+B,GAClC,EAAE,oBAAoB,2CAwOtB"}
|
|
@@ -9,7 +9,7 @@ import { Plus } from 'lucide-react';
|
|
|
9
9
|
import { BlockWrapper } from './BlockWrapper';
|
|
10
10
|
import { useEditor } from '../../state/EditorContext';
|
|
11
11
|
export function LayoutContainer({ blocks, containerId, onBlockAdd, onBlockUpdate, onBlockDelete, onBlockMove, className = '', emptyLabel = 'Drop blocks here', }) {
|
|
12
|
-
const { darkMode } = useEditor();
|
|
12
|
+
const { darkMode, helpers } = useEditor();
|
|
13
13
|
// --- State ---
|
|
14
14
|
const [dragOverIndex, setDragOverIndex] = useState(null);
|
|
15
15
|
const [dropAtEnd, setDropAtEnd] = useState(false);
|
|
@@ -21,27 +21,34 @@ export function LayoutContainer({ blocks, containerId, onBlockAdd, onBlockUpdate
|
|
|
21
21
|
const dropAtEndRef = useRef(false);
|
|
22
22
|
// --- Cleanup & Event Listeners ---
|
|
23
23
|
useEffect(() => {
|
|
24
|
-
const resetState = () => {
|
|
24
|
+
const resetState = (e) => {
|
|
25
|
+
// Only reset if this is the container that was actually being dragged over
|
|
26
|
+
// or if it's a global dragend event
|
|
25
27
|
setDropIndicatorPosition(null);
|
|
26
28
|
setDragOverIndex(null);
|
|
27
29
|
setDropAtEnd(false);
|
|
28
|
-
dropAtEndRef.current = false;
|
|
30
|
+
dropAtEndRef.current = false;
|
|
29
31
|
setIsDragging(false);
|
|
30
|
-
// Clear global dragged block ID on dragend (in case drag was cancelled)
|
|
31
|
-
if (typeof window !== 'undefined') {
|
|
32
|
-
window.__DRAGGED_BLOCK_ID__ = null;
|
|
33
|
-
}
|
|
34
32
|
};
|
|
35
33
|
const container = containerRef.current;
|
|
36
34
|
if (container) {
|
|
37
35
|
container.addEventListener('clear-drop-indicator', resetState);
|
|
38
|
-
|
|
36
|
+
// Listen for dragend on the document but ONLY if we are currently dragging
|
|
37
|
+
const handleGlobalDragEnd = () => {
|
|
38
|
+
if (isDragging) {
|
|
39
|
+
resetState(new Event('dragend'));
|
|
40
|
+
if (typeof window !== 'undefined') {
|
|
41
|
+
window.__DRAGGED_BLOCK_ID__ = null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
document.addEventListener('dragend', handleGlobalDragEnd);
|
|
39
46
|
return () => {
|
|
40
47
|
container.removeEventListener('clear-drop-indicator', resetState);
|
|
41
|
-
document.removeEventListener('dragend',
|
|
48
|
+
document.removeEventListener('dragend', handleGlobalDragEnd);
|
|
42
49
|
};
|
|
43
50
|
}
|
|
44
|
-
}, []);
|
|
51
|
+
}, [isDragging]);
|
|
45
52
|
// --- Drag & Drop Logic ---
|
|
46
53
|
const handleDragOverBlock = (e, index, element) => {
|
|
47
54
|
e.preventDefault();
|
|
@@ -119,65 +126,32 @@ export function LayoutContainer({ blocks, containerId, onBlockAdd, onBlockUpdate
|
|
|
119
126
|
const handleDrop = (e, index) => {
|
|
120
127
|
e.preventDefault();
|
|
121
128
|
e.stopPropagation();
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
|
|
129
|
+
// MATCHING KEYS: use blockId and blockType (not hyphenated)
|
|
130
|
+
const blockId = e.dataTransfer.getData('blockId') || window.__DRAGGED_BLOCK_ID__ || e.dataTransfer.getData('text/plain');
|
|
131
|
+
const blockType = e.dataTransfer.getData('blockType');
|
|
132
|
+
// Clear the global dragged block ID immediately
|
|
125
133
|
if (typeof window !== 'undefined') {
|
|
126
134
|
window.__DRAGGED_BLOCK_ID__ = null;
|
|
127
135
|
}
|
|
128
|
-
// Logic: index is null when dropping on the container background (appends to end)
|
|
129
|
-
// When dropAtEnd is true, we want to place it AFTER the block at index, so targetIndex = index + 1
|
|
130
|
-
// When dropAtEnd is false, we want to place it BEFORE the block at index, so targetIndex = index
|
|
131
|
-
// Use ref to get the latest value (React state updates are async)
|
|
132
136
|
const isDropAtEnd = dropAtEndRef.current;
|
|
133
137
|
let targetIndex = index === null ? blocks.length : (isDropAtEnd ? index + 1 : index);
|
|
134
138
|
if (blockId) {
|
|
135
139
|
const currentIndex = blocks.findIndex(b => b.id === blockId);
|
|
136
140
|
if (currentIndex !== -1) {
|
|
137
|
-
// Moving within
|
|
141
|
+
// Moving within same container
|
|
138
142
|
let finalMoveIndex = targetIndex;
|
|
139
143
|
if (currentIndex < targetIndex) {
|
|
140
|
-
|
|
141
|
-
if (isDropAtEnd) {
|
|
142
|
-
// Dropping below: we want it at index + 1 in the original array
|
|
143
|
-
// If currentIndex <= index: after removal, block at index stays at index, so we want index + 1 = targetIndex
|
|
144
|
-
// If index < currentIndex < targetIndex: after removal, we still want index + 1, but since we removed
|
|
145
|
-
// an item before targetIndex, the position targetIndex in original = targetIndex - 1 in new array
|
|
146
|
-
if (index !== null && currentIndex <= index) {
|
|
147
|
-
// Item is at or before target block - no adjustment needed
|
|
148
|
-
finalMoveIndex = targetIndex;
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
// Item is after target block but before targetIndex - need to adjust
|
|
152
|
-
finalMoveIndex = targetIndex - 1;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
// Dropping above: targetIndex = index means "before the block at index"
|
|
157
|
-
// After removal, if currentIndex < index, the block at index shifts to index - 1,
|
|
158
|
-
// so we want it at index - 1 in the new array.
|
|
159
|
-
finalMoveIndex = targetIndex - 1;
|
|
160
|
-
}
|
|
144
|
+
finalMoveIndex = targetIndex - 1;
|
|
161
145
|
}
|
|
162
|
-
// If currentIndex >= targetIndex, no adjustment needed (moving backward or same position)
|
|
163
|
-
console.log('[LayoutContainer] Drop calculation:', {
|
|
164
|
-
blockId,
|
|
165
|
-
index,
|
|
166
|
-
dropAtEnd: isDropAtEnd,
|
|
167
|
-
currentIndex,
|
|
168
|
-
targetIndex,
|
|
169
|
-
finalMoveIndex,
|
|
170
|
-
blocksCount: blocks.length
|
|
171
|
-
});
|
|
172
146
|
onBlockMove(blockId, Math.max(0, finalMoveIndex), containerId);
|
|
173
147
|
}
|
|
174
148
|
else {
|
|
175
|
-
// Moving from
|
|
149
|
+
// Moving from different container
|
|
176
150
|
onBlockMove(blockId, targetIndex, containerId);
|
|
177
151
|
}
|
|
178
152
|
}
|
|
179
153
|
else if (blockType) {
|
|
180
|
-
// Adding new block
|
|
154
|
+
// Adding new block
|
|
181
155
|
onBlockAdd(blockType, targetIndex, containerId);
|
|
182
156
|
}
|
|
183
157
|
// Clean up
|
|
@@ -191,32 +165,37 @@ export function LayoutContainer({ blocks, containerId, onBlockAdd, onBlockUpdate
|
|
|
191
165
|
else
|
|
192
166
|
blockRefs.current.delete(id);
|
|
193
167
|
};
|
|
194
|
-
return (_jsxs("div", { ref: containerRef, "data-layout-container": containerId, className: `relative flex flex-col min-h-[40px] transition-colors ${className}`,
|
|
168
|
+
return (_jsxs("div", { ref: containerRef, "data-layout-container": containerId, className: `relative flex flex-col min-h-[40px] transition-colors pb-2 ${className}`, onDragEnter: (e) => {
|
|
169
|
+
e.preventDefault();
|
|
170
|
+
e.stopPropagation();
|
|
171
|
+
setIsDragging(true);
|
|
172
|
+
}, onDragOver: (e) => {
|
|
173
|
+
e.preventDefault();
|
|
174
|
+
e.stopPropagation();
|
|
175
|
+
setIsDragging(true);
|
|
176
|
+
}, onDrop: (e) => handleDrop(e, null), onDragLeave: (e) => {
|
|
195
177
|
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
178
|
+
setIsDragging(false);
|
|
196
179
|
setDropIndicatorPosition(null);
|
|
197
180
|
}
|
|
198
|
-
}, children: [dropIndicatorPosition && isDragging && (_jsx(DropIndicator, { position: dropIndicatorPosition, darkMode: darkMode })), blocks.length === 0 ? (_jsx(EmptyState, { isDragging: isDragging, darkMode: darkMode, label: emptyLabel })) : (blocks.map((block, index) => (_jsx("div", { ref: setBlockRef(block.id), onDragOver: (e) => handleDragOverBlock(e, index, blockRefs.current.get(block.id)), onDrop: (e) => handleDrop(e, index), className: "relative mb-4 last:mb-0", children: _jsx(BlockWrapper, { block: block, onUpdate: (data) => onBlockUpdate(block.id, data, containerId), onDelete: () => onBlockDelete(block.id, containerId), onMoveUp: index > 0 ? () => onBlockMove(block.id, index - 1, containerId) : undefined, onMoveDown: index < blocks.length - 1 ? () => onBlockMove(block.id, index + 1, containerId) : undefined
|
|
181
|
+
}, children: [dropIndicatorPosition && isDragging && (_jsx(DropIndicator, { position: dropIndicatorPosition, darkMode: darkMode })), blocks.length === 0 ? (_jsx(EmptyState, { isDragging: isDragging, darkMode: darkMode, label: emptyLabel })) : (blocks.map((block, index) => (_jsx("div", { ref: setBlockRef(block.id), onDragOver: (e) => handleDragOverBlock(e, index, blockRefs.current.get(block.id)), onDrop: (e) => handleDrop(e, index), className: "relative mb-4 last:mb-0", children: _jsx(BlockWrapper, { block: block, onUpdate: (data) => onBlockUpdate(block.id, data, containerId), onDelete: () => onBlockDelete(block.id, containerId), onDuplicate: () => helpers.duplicateBlock(block.id), onMoveUp: index > 0 ? () => onBlockMove(block.id, index - 1, containerId) : undefined, onMoveDown: index < blocks.length - 1 ? () => onBlockMove(block.id, index + 1, containerId) : undefined,
|
|
182
|
+
// Essential for nested rendering: pass children and handlers to the Edit component
|
|
183
|
+
childBlocks: Array.isArray(block.children) && typeof block.children[0] === 'object' ? block.children : [], onChildBlockAdd: (type, idx, cid) => onBlockAdd(type, idx ?? 0, cid || containerId), onChildBlockUpdate: (bid, data, cid) => onBlockUpdate(bid, data, cid || containerId), onChildBlockDelete: (bid, cid) => onBlockDelete(bid, cid || containerId), onChildBlockMove: (bid, idx, cid) => onBlockMove(bid, idx, cid || containerId) }) }, block.id))))] }));
|
|
199
184
|
}
|
|
200
185
|
/**
|
|
201
|
-
* Visual
|
|
186
|
+
* Visual Components
|
|
202
187
|
*/
|
|
203
188
|
function DropIndicator({ position, darkMode }) {
|
|
204
|
-
return (_jsxs("div", { className: "absolute z-50 pointer-events-none", style: {
|
|
205
|
-
top:
|
|
206
|
-
left:
|
|
207
|
-
width:
|
|
208
|
-
height: '
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
${darkMode ? 'bg-primary' : 'bg-primary'}` }), _jsx("div", { className: "absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2", children: _jsx("div", { className: "w-6 h-6 rounded-full flex items-center justify-center bg-primary shadow-lg", children: _jsx("div", { className: "w-2 h-2 rounded-full bg-white" }) }) })] }));
|
|
189
|
+
return (_jsxs("div", { className: "absolute z-50 pointer-events-none transition-all duration-150 ease-out", style: {
|
|
190
|
+
top: position.top,
|
|
191
|
+
left: position.left,
|
|
192
|
+
width: position.width,
|
|
193
|
+
height: '4px',
|
|
194
|
+
marginTop: '-2px', // Center on the line
|
|
195
|
+
}, children: [_jsx("div", { className: "w-full h-full bg-primary rounded-full shadow-[0_0_8px_rgba(var(--primary-rgb),0.5)] animate-pulse" }), _jsx("div", { className: "absolute left-0 top-1/2 -translate-y-1/2 -translate-x-1 w-2 h-2 rounded-full bg-primary" }), _jsx("div", { className: "absolute right-0 top-1/2 -translate-y-1/2 translate-x-1 w-2 h-2 rounded-full bg-primary" })] }));
|
|
212
196
|
}
|
|
213
|
-
/**
|
|
214
|
-
* Placeholder when the container is empty
|
|
215
|
-
*/
|
|
216
197
|
function EmptyState({ isDragging, darkMode, label }) {
|
|
217
|
-
return (_jsxs("div", { className: `flex flex-col items-center justify-center py-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
: isDragging ? 'border-primary/50 bg-primary/5' : 'border-neutral-200 bg-neutral-50/30'}`, children: [_jsx("div", { className: `p-3 rounded-full mb-3 ${darkMode ? 'bg-neutral-800' : 'bg-neutral-100'}`, children: _jsx(Plus, { size: 20, className: isDragging ? 'text-primary' : 'text-neutral-400' }) }), _jsx("p", { className: `text-xs font-black uppercase tracking-wider
|
|
221
|
-
${isDragging ? 'text-primary' : 'text-neutral-500'}`, children: isDragging ? 'Drop Block Here' : label })] }));
|
|
198
|
+
return (_jsxs("div", { className: `flex flex-col items-center justify-center py-10 rounded-2xl border-2 border-dashed transition-all duration-300 ${isDragging
|
|
199
|
+
? 'border-primary bg-primary/5 scale-[0.98]'
|
|
200
|
+
: 'border-neutral-200 dark:border-neutral-800 bg-neutral-50/50 dark:bg-neutral-900/20'}`, children: [_jsx(Plus, { size: 24, className: `mb-2 transition-colors ${isDragging ? 'text-primary' : 'text-neutral-300 dark:text-neutral-700'}` }), _jsx("span", { className: `text-[10px] font-bold uppercase tracking-widest ${isDragging ? 'text-primary' : 'text-neutral-400 dark:text-neutral-600'}`, children: label })] }));
|
|
222
201
|
}
|
|
@@ -40,5 +40,5 @@ export function CustomBlockItem({ blockType, name, description, icon, onAddBlock
|
|
|
40
40
|
mouseDownRef.current = null;
|
|
41
41
|
setTimeout(() => setHasDragged(false), 100);
|
|
42
42
|
};
|
|
43
|
-
return (_jsxs("div", { draggable: true, onDragStart: handleDragStart, onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onClick: handleClick, className: "p-
|
|
43
|
+
return (_jsxs("div", { draggable: true, onDragStart: handleDragStart, onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onClick: handleClick, className: "p-5 rounded-[1.5rem] border border-dashboard-border/50 bg-dashboard-card/30 backdrop-blur-sm hover:border-primary/40 hover:bg-primary/[0.02] hover:shadow-2xl hover:shadow-primary/10 transition-all duration-500 cursor-grab active:cursor-grabbing group", title: description, children: [_jsxs("div", { className: "flex items-center justify-between mb-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "text-dashboard-text-secondary group-hover:text-primary transition-all duration-500 group-hover:scale-110", children: icon }), _jsx("span", { className: "text-[10px] font-black uppercase tracking-[0.2em] text-dashboard-text-secondary group-hover:text-dashboard-text transition-colors", children: name })] }), _jsx(GripVertical, { size: 14, className: "text-dashboard-text-secondary/30 group-hover:text-primary transition-colors" })] }), description && (_jsx("p", { className: "text-[9px] text-dashboard-text-secondary/60 leading-relaxed line-clamp-2 italic font-medium", children: description }))] }));
|
|
44
44
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import React from 'react';
|
|
1
2
|
import type { Block } from '../../../types/block';
|
|
2
3
|
import type { BlockTypeDefinition } from '../../../types/block';
|
|
3
4
|
export interface EditorCanvasProps {
|
|
@@ -9,21 +10,32 @@ export interface EditorCanvasProps {
|
|
|
9
10
|
siteId: string;
|
|
10
11
|
locale: string;
|
|
11
12
|
darkMode: boolean;
|
|
13
|
+
tags?: string[];
|
|
12
14
|
backgroundColors?: {
|
|
13
15
|
light: string;
|
|
14
16
|
dark?: string;
|
|
15
17
|
};
|
|
16
18
|
featuredImage?: {
|
|
17
19
|
id?: string;
|
|
20
|
+
src?: string;
|
|
18
21
|
alt?: string;
|
|
19
22
|
};
|
|
23
|
+
LayoutWrapper?: React.ComponentType<{
|
|
24
|
+
children: React.ReactNode;
|
|
25
|
+
header?: React.ReactNode;
|
|
26
|
+
footer?: React.ReactNode;
|
|
27
|
+
heroImage?: React.ReactNode;
|
|
28
|
+
isPreview?: boolean;
|
|
29
|
+
isWrapper?: boolean;
|
|
30
|
+
tags?: string[];
|
|
31
|
+
}>;
|
|
20
32
|
onTitleChange: (title: string) => void;
|
|
21
33
|
onHeroBlockUpdate: (data: Partial<Block['data']>) => void;
|
|
22
34
|
onHeroBlockDelete: () => void;
|
|
23
35
|
onBlockAdd: (type: string, index: number, containerId?: string) => void;
|
|
24
|
-
onBlockUpdate: (id: string, data: Partial<Block['data']
|
|
25
|
-
onBlockDelete: (id: string) => void;
|
|
36
|
+
onBlockUpdate: (id: string, data: Partial<Block['data']>, containerId?: string) => void;
|
|
37
|
+
onBlockDelete: (id: string, containerId?: string) => void;
|
|
26
38
|
onBlockMove: (id: string, newIndex: number, containerId?: string) => void;
|
|
27
39
|
}
|
|
28
|
-
export declare function EditorCanvas({ isPreviewMode, heroBlock, heroBlockDefinition, contentBlocks, title, siteId, locale, darkMode, backgroundColors, featuredImage, onTitleChange, onHeroBlockUpdate, onHeroBlockDelete, onBlockAdd, onBlockUpdate, onBlockDelete, onBlockMove, }: EditorCanvasProps): import("react/jsx-runtime").JSX.Element;
|
|
40
|
+
export declare function EditorCanvas({ isPreviewMode, heroBlock, heroBlockDefinition, contentBlocks, title, siteId, locale, darkMode, tags, backgroundColors, featuredImage, LayoutWrapper, onTitleChange, onHeroBlockUpdate, onHeroBlockDelete, onBlockAdd, onBlockUpdate, onBlockDelete, onBlockMove, }: EditorCanvasProps): import("react/jsx-runtime").JSX.Element;
|
|
29
41
|
//# sourceMappingURL=EditorCanvas.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditorCanvas.d.ts","sourceRoot":"","sources":["../../../../src/views/CanvasEditor/components/EditorCanvas.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"EditorCanvas.d.ts","sourceRoot":"","sources":["../../../../src/views/CanvasEditor/components/EditorCanvas.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAIjD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,MAAM,WAAW,iBAAiB;IAC9B,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,KAAK,GAAG,IAAI,CAAC;IACxB,mBAAmB,EAAE,mBAAmB,GAAG,SAAS,CAAC;IACrD,aAAa,EAAE,KAAK,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,gBAAgB,CAAC,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,aAAa,CAAC,EAAE;QACZ,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;QAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;QACzB,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;QACzB,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;QAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC,CAAC;IACH,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,iBAAiB,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,CAAC;IAC1D,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACxE,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACxF,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7E;AAED,wBAAgB,YAAY,CAAC,EACzB,aAAa,EACb,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,KAAK,EACL,MAAM,EACN,MAAM,EACN,QAAQ,EACR,IAAS,EACT,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,aAAa,EACb,WAAW,GACd,EAAE,iBAAiB,2CAoJnB"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useRef, useEffect } from 'react';
|
|
4
4
|
import { BlockWrapper } from '../BlockWrapper';
|
|
5
5
|
import { EditorBody } from '../EditorBody';
|
|
6
6
|
import { BlockRenderer } from '../../../lib/blocks/BlockRenderer';
|
|
7
|
-
export function EditorCanvas({ isPreviewMode, heroBlock, heroBlockDefinition, contentBlocks, title, siteId, locale, darkMode, backgroundColors, featuredImage, onTitleChange, onHeroBlockUpdate, onHeroBlockDelete, onBlockAdd, onBlockUpdate, onBlockDelete, onBlockMove, }) {
|
|
7
|
+
export function EditorCanvas({ isPreviewMode, heroBlock, heroBlockDefinition, contentBlocks, title, siteId, locale, darkMode, tags = [], backgroundColors, featuredImage, LayoutWrapper, onTitleChange, onHeroBlockUpdate, onHeroBlockDelete, onBlockAdd, onBlockUpdate, onBlockDelete, onBlockMove, }) {
|
|
8
8
|
const titleRef = useRef(null);
|
|
9
9
|
// Handle Title Auto-resize
|
|
10
10
|
useEffect(() => {
|
|
@@ -13,20 +13,42 @@ export function EditorCanvas({ isPreviewMode, heroBlock, heroBlockDefinition, co
|
|
|
13
13
|
titleRef.current.style.height = `${titleRef.current.scrollHeight}px`;
|
|
14
14
|
}
|
|
15
15
|
}, [title]);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
16
|
+
const renderPreviewContent = () => {
|
|
17
|
+
// Filter out hero block from content if it's already rendered in header
|
|
18
|
+
const mainContent = heroBlockDefinition && heroBlock
|
|
19
|
+
? contentBlocks.filter(b => b.type !== 'hero')
|
|
20
|
+
: contentBlocks;
|
|
21
|
+
const commonContext = {
|
|
22
|
+
siteId,
|
|
23
|
+
locale,
|
|
24
|
+
fallbackImage: featuredImage ? {
|
|
25
|
+
id: featuredImage.id,
|
|
26
|
+
src: featuredImage.src,
|
|
27
|
+
alt: featuredImage.alt,
|
|
28
|
+
} : undefined,
|
|
29
|
+
};
|
|
30
|
+
return (_jsxs("div", { className: "space-y-8", children: [!heroBlockDefinition && title && (_jsx("h1", { className: "text-5xl font-serif font-medium leading-tight mb-12", style: { color: 'var(--color-forest, var(--color-neutral-950))' }, children: title })), mainContent.length > 0 ? (_jsx("div", { className: "space-y-8", children: mainContent.map((block) => (_jsx(BlockRenderer, { block: block, context: commonContext }, block.id))) })) : (_jsx("div", { className: "text-center py-20 text-neutral-400 dark:text-neutral-500", children: _jsx("p", { className: "text-sm", children: "No content blocks yet. Switch to Edit mode to add blocks." }) }))] }));
|
|
31
|
+
};
|
|
32
|
+
const renderEditorContent = () => {
|
|
33
|
+
// Filter out hero block from content if it's already rendered in header
|
|
34
|
+
const mainBlocks = heroBlockDefinition && heroBlock
|
|
35
|
+
? contentBlocks.filter(b => b.type !== 'hero')
|
|
36
|
+
: contentBlocks;
|
|
37
|
+
return (_jsxs("div", { className: "space-y-12", children: [!heroBlockDefinition && (_jsx("div", { className: "mb-12", children: _jsx("textarea", { ref: titleRef, rows: 1, value: title, onChange: (e) => onTitleChange(e.target.value), placeholder: "The title of your story...", className: "w-full bg-transparent border-none outline-none text-5xl md:text-7xl lg:text-9xl font-serif font-medium placeholder:text-neutral-500 dark:placeholder:text-neutral-500 resize-none leading-tight transition-colors duration-300 italic", style: { color: 'var(--color-forest, var(--color-neutral-950))' } }) })), _jsx(EditorBody, { blocks: mainBlocks, darkMode: darkMode, backgroundColors: backgroundColors, onBlockAdd: onBlockAdd, onBlockUpdate: onBlockUpdate, onBlockDelete: onBlockDelete, onBlockMove: onBlockMove })] }));
|
|
38
|
+
};
|
|
39
|
+
// Render Hero Block for Slot Injection
|
|
40
|
+
const heroElement = heroBlockDefinition && heroBlock ? (isPreviewMode ? (_jsx(BlockRenderer, { block: heroBlock, context: {
|
|
41
|
+
siteId,
|
|
42
|
+
locale,
|
|
43
|
+
fallbackImage: featuredImage ? {
|
|
44
|
+
id: featuredImage.id,
|
|
45
|
+
src: featuredImage.src,
|
|
46
|
+
alt: featuredImage.alt,
|
|
47
|
+
} : undefined,
|
|
48
|
+
} })) : (_jsx(BlockWrapper, { block: heroBlock, onUpdate: onHeroBlockUpdate, onDelete: onHeroBlockDelete, onMoveUp: () => { }, onMoveDown: () => { } }))) : null;
|
|
49
|
+
return (_jsx("div", { "data-theme": darkMode ? 'dark' : 'light', className: "flex-1 overflow-y-auto overflow-x-hidden pb-40 px-4 lg:px-10 custom-scrollbar selection:bg-primary/20 dark:selection:bg-primary/30 min-h-0 transition-colors duration-300", style: {
|
|
50
|
+
backgroundColor: darkMode
|
|
51
|
+
? (backgroundColors?.dark || '#0c0c0c')
|
|
52
|
+
: (backgroundColors?.light || '#ffffff')
|
|
53
|
+
}, children: _jsx("div", { className: `${!LayoutWrapper ? 'mx-auto transition-all duration-500 max-w-[1600px] w-full px-2 pt-8' : ''}`, children: LayoutWrapper ? (_jsx("div", { "data-theme": darkMode ? 'dark' : 'light', "data-dashboard": "false", className: "theme-reset contents", children: _jsx(LayoutWrapper, { header: heroElement, isPreview: true, isWrapper: true, tags: tags, children: isPreviewMode ? renderPreviewContent() : renderEditorContent() }) })) : (_jsxs("div", { "data-theme": darkMode ? 'dark' : 'light', "data-dashboard": "false", className: "theme-reset", children: [heroElement, _jsx("div", { className: "max-w-[1600px] mx-auto px-4 sm:px-6 lg:px-8 py-6 prose prose-lg max-w-none prose-headings:font-serif", children: isPreviewMode ? renderPreviewContent() : renderEditorContent() })] })) }) }));
|
|
32
54
|
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { BlockTypeDefinition } from '../../../types/block';
|
|
2
2
|
export interface EditorLibraryProps {
|
|
3
3
|
registeredBlocks: BlockTypeDefinition[];
|
|
4
|
-
onAddBlock: (
|
|
4
|
+
onAddBlock: (blockType: string) => void;
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* Editor Library Component
|
|
8
|
+
* Displays available blocks that can be added to the canvas
|
|
9
|
+
*/
|
|
6
10
|
export declare function EditorLibrary({ registeredBlocks, onAddBlock }: EditorLibraryProps): import("react/jsx-runtime").JSX.Element;
|
|
7
11
|
//# sourceMappingURL=EditorLibrary.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditorLibrary.d.ts","sourceRoot":"","sources":["../../../../src/views/CanvasEditor/components/EditorLibrary.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,MAAM,WAAW,kBAAkB;IAC/B,gBAAgB,EAAE,mBAAmB,EAAE,CAAC;IACxC,UAAU,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"EditorLibrary.d.ts","sourceRoot":"","sources":["../../../../src/views/CanvasEditor/components/EditorLibrary.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,MAAM,WAAW,kBAAkB;IAC/B,gBAAgB,EAAE,mBAAmB,EAAE,CAAC;IACxC,UAAU,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,EAAE,kBAAkB,2CAwHjF"}
|
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Library, Image as ImageIcon, LayoutTemplate, Type, Box } from 'lucide-react';
|
|
4
4
|
import { LibraryItem, CustomBlockItem } from './index';
|
|
5
|
+
/**
|
|
6
|
+
* Editor Library Component
|
|
7
|
+
* Displays available blocks that can be added to the canvas
|
|
8
|
+
*/
|
|
5
9
|
export function EditorLibrary({ registeredBlocks, onAddBlock }) {
|
|
6
|
-
//
|
|
7
|
-
const allBlocks = registeredBlocks
|
|
8
|
-
const textBlocks = allBlocks.filter(
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
10
|
+
// Categorize blocks
|
|
11
|
+
const allBlocks = registeredBlocks || [];
|
|
12
|
+
const textBlocks = allBlocks.filter(bl => bl.category === 'text' || bl.type === 'heading' || bl.type === 'paragraph' || bl.type === 'list');
|
|
13
|
+
const mediaBlocks = allBlocks.filter(bl => bl.category === 'media' || bl.type === 'image' || bl.type === 'gallery' || bl.type === 'video');
|
|
14
|
+
const layoutBlocks = allBlocks.filter(bl => bl.category === 'layout' || bl.type === 'section' || bl.type === 'columns' || bl.type === 'spacer');
|
|
15
|
+
const customBlocks = allBlocks.filter(bl => !textBlocks.includes(bl) && !mediaBlocks.includes(bl) && !layoutBlocks.includes(bl));
|
|
12
16
|
return (_jsxs("div", { className: "p-6 w-72 min-w-0 max-w-full", children: [textBlocks.length > 0 && (_jsxs("div", { className: "mb-10", children: [_jsx("h3", { className: "text-[10px] uppercase tracking-[0.2em] text-neutral-500 dark:text-neutral-400 font-black mb-6", children: "Text" }), _jsx("div", { className: "grid grid-cols-2 gap-3", children: textBlocks.map((block) => {
|
|
13
17
|
const IconComponent = block.icon || block.components.Icon || Type;
|
|
14
18
|
return (_jsx(LibraryItem, { icon: _jsx(IconComponent, { size: 16 }), label: block.name, blockType: block.type, description: block.description, onAddBlock: onAddBlock }, block.type));
|
|
@@ -21,5 +25,5 @@ export function EditorLibrary({ registeredBlocks, onAddBlock }) {
|
|
|
21
25
|
}) })] })), customBlocks.length > 0 && (_jsxs("div", { children: [_jsx("h3", { className: "text-[10px] uppercase tracking-[0.2em] text-neutral-500 dark:text-neutral-400 font-black mb-6", children: "Custom Blocks" }), _jsx("div", { className: "space-y-3", children: customBlocks.map((block) => {
|
|
22
26
|
const IconComponent = block.icon || block.components.Icon || Box;
|
|
23
27
|
return (_jsx(CustomBlockItem, { blockType: block.type, name: block.name, description: block.description, icon: _jsx(IconComponent, { size: 14 }), onAddBlock: onAddBlock }, block.type));
|
|
24
|
-
}) })] })), allBlocks.length === 0 && (_jsxs("div", { className: "
|
|
28
|
+
}) })] })), allBlocks.length === 0 && (_jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [_jsx(Library, { className: "size-12 text-neutral-300 dark:text-neutral-700 mb-4" }), _jsx("p", { className: "text-xs text-neutral-500 dark:text-neutral-400", children: "No blocks registered yet." })] }))] }));
|
|
25
29
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditorSidebar.d.ts","sourceRoot":"","sources":["../../../../src/views/CanvasEditor/components/EditorSidebar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"EditorSidebar.d.ts","sourceRoot":"","sources":["../../../../src/views/CanvasEditor/components/EditorSidebar.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAErE,MAAM,WAAW,kBAAkB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,WAAW,CAAC;IACjB,QAAQ,EAAE,YAAY,CAAC;IACvB,SAAS,EAAE,KAAK,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IACjD,gBAAgB,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;CAC/D;AAED,wBAAgB,aAAa,CAAC,EAC1B,IAAI,EACJ,GAAG,EACH,QAAQ,EACR,SAAS,EACT,MAAM,EACN,WAAW,EACX,gBAAgB,GACnB,EAAE,kBAAkB,2CA6NpB"}
|