@jhits/plugin-blog 0.0.18 → 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 -500
- 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 -604
- 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
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
'use client';
|
|
7
7
|
|
|
8
8
|
import React from 'react';
|
|
9
|
-
import { Plus, Trash2 } from 'lucide-react';
|
|
10
9
|
import { BlockEditProps, BlockPreviewProps } from '../../../types/block';
|
|
11
10
|
import { LayoutContainer } from '../../../views/CanvasEditor/LayoutContainer';
|
|
12
11
|
import { COLUMN_LAYOUTS, ColumnLayout } from '../index';
|
|
@@ -31,117 +30,49 @@ export const ColumnsEdit: React.FC<BlockEditProps & {
|
|
|
31
30
|
onChildBlockDelete,
|
|
32
31
|
onChildBlockMove,
|
|
33
32
|
}) => {
|
|
33
|
+
// Filter out hero block from being rendered inside containers
|
|
34
|
+
const blocks = childBlocks.filter(b => b.type !== 'hero');
|
|
35
|
+
|
|
34
36
|
// Support both old layout-based system and new dynamic column count
|
|
35
37
|
const columnCount = block.data.columnCount as number | undefined;
|
|
36
38
|
const layout: ColumnLayout | undefined = block.data.layout as ColumnLayout | undefined;
|
|
37
39
|
|
|
38
|
-
// Determine number of columns: use columnCount if set, otherwise derive from layout
|
|
39
40
|
let numColumns: number;
|
|
40
|
-
let gridClass: string;
|
|
41
41
|
let columnWidths: number[];
|
|
42
42
|
|
|
43
|
-
// Grid class mapping for Tailwind (must be explicit for dynamic classes)
|
|
44
|
-
const gridClassMap: Record<number, string> = {
|
|
45
|
-
1: 'grid-cols-1',
|
|
46
|
-
2: 'grid-cols-2',
|
|
47
|
-
3: 'grid-cols-3',
|
|
48
|
-
4: 'grid-cols-4',
|
|
49
|
-
5: 'grid-cols-5',
|
|
50
|
-
6: 'grid-cols-6',
|
|
51
|
-
};
|
|
52
|
-
|
|
53
43
|
if (columnCount !== undefined && columnCount > 0) {
|
|
54
|
-
// Dynamic column system
|
|
55
44
|
numColumns = columnCount;
|
|
56
|
-
// Create equal-width columns
|
|
57
45
|
const widthPercent = Math.floor(100 / numColumns);
|
|
58
46
|
columnWidths = Array(numColumns).fill(widthPercent);
|
|
59
|
-
// Use explicit grid class from map, fallback to inline style if needed
|
|
60
|
-
gridClass = gridClassMap[numColumns] || `grid-cols-${numColumns}`;
|
|
61
47
|
} else if (layout && COLUMN_LAYOUTS[layout]) {
|
|
62
|
-
// Legacy layout-based system
|
|
63
48
|
const layoutConfig = COLUMN_LAYOUTS[layout];
|
|
64
49
|
numColumns = layoutConfig.widths.length;
|
|
65
|
-
gridClass = layoutConfig.grid;
|
|
66
50
|
columnWidths = layoutConfig.widths;
|
|
67
51
|
} else {
|
|
68
|
-
// Default to 2 columns
|
|
69
52
|
numColumns = 2;
|
|
70
|
-
gridClass = 'grid-cols-2';
|
|
71
53
|
columnWidths = [50, 50];
|
|
72
54
|
}
|
|
73
55
|
|
|
74
|
-
// Split child blocks into columns based on columnIndex in meta, or round-robin
|
|
75
56
|
const columns: Block[][] = Array.from({ length: numColumns }, () => []);
|
|
76
|
-
|
|
57
|
+
blocks.forEach((childBlock) => {
|
|
77
58
|
const columnIndex = childBlock.meta?.columnIndex;
|
|
78
59
|
if (typeof columnIndex === 'number' && columnIndex >= 0 && columnIndex < numColumns) {
|
|
79
60
|
columns[columnIndex].push(childBlock);
|
|
80
61
|
} else {
|
|
81
|
-
|
|
82
|
-
const index = childBlocks.indexOf(childBlock);
|
|
62
|
+
const index = blocks.indexOf(childBlock);
|
|
83
63
|
columns[index % numColumns].push(childBlock);
|
|
84
64
|
}
|
|
85
65
|
});
|
|
86
66
|
|
|
87
|
-
// Get column widths from data or use equal widths
|
|
88
67
|
const storedWidths = block.data.columnWidths as number[] | undefined;
|
|
89
68
|
const currentWidths = storedWidths && storedWidths.length === numColumns
|
|
90
69
|
? storedWidths
|
|
91
|
-
: columnWidths;
|
|
92
|
-
|
|
93
|
-
// Add column handler
|
|
94
|
-
const addColumn = () => {
|
|
95
|
-
if (numColumns >= 4) return; // Max 4 columns
|
|
96
|
-
const newColumnCount = numColumns + 1;
|
|
97
|
-
// Calculate new equal widths
|
|
98
|
-
const newWidthPercent = Math.floor(100 / newColumnCount);
|
|
99
|
-
const newWidths = Array(newColumnCount).fill(newWidthPercent);
|
|
100
|
-
onUpdate({
|
|
101
|
-
...block.data,
|
|
102
|
-
columnCount: newColumnCount,
|
|
103
|
-
columnWidths: newWidths,
|
|
104
|
-
// Clear layout if using dynamic columns
|
|
105
|
-
layout: undefined,
|
|
106
|
-
});
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// Delete column handler
|
|
110
|
-
const deleteColumn = (colIndex: number) => {
|
|
111
|
-
if (numColumns <= 1) return; // Don't allow deleting the last column
|
|
112
|
-
|
|
113
|
-
// Move blocks from deleted column to the last column (or previous column if deleting last)
|
|
114
|
-
const blocksToMove = columns[colIndex] || [];
|
|
115
|
-
const targetColumnIndex = colIndex === numColumns - 1 ? numColumns - 2 : numColumns - 1;
|
|
116
|
-
const targetColumn = columns[targetColumnIndex] || [];
|
|
117
|
-
|
|
118
|
-
// Move each block to the target column using moveBlock (which will update meta.columnIndex)
|
|
119
|
-
blocksToMove.forEach((blockToMove, blockIndex) => {
|
|
120
|
-
const newIndex = targetColumn.length + blockIndex;
|
|
121
|
-
onChildBlockMove(blockToMove.id, newIndex, `${block.id}-col-${targetColumnIndex}`);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
// Update column count and widths after moving blocks
|
|
125
|
-
const newColumnCount = numColumns - 1;
|
|
126
|
-
// Remove the deleted column's width and redistribute
|
|
127
|
-
const newWidths = currentWidths.filter((_, i) => i !== colIndex);
|
|
128
|
-
// Normalize to ensure they sum to 100
|
|
129
|
-
const total = newWidths.reduce((sum, w) => sum + w, 0);
|
|
130
|
-
const normalizedWidths = newWidths.map(w => Math.round((w / total) * 100));
|
|
131
|
-
|
|
132
|
-
onUpdate({
|
|
133
|
-
...block.data,
|
|
134
|
-
columnCount: newColumnCount,
|
|
135
|
-
columnWidths: normalizedWidths,
|
|
136
|
-
layout: undefined,
|
|
137
|
-
});
|
|
138
|
-
};
|
|
70
|
+
: columnWidths;
|
|
139
71
|
|
|
140
72
|
return (
|
|
141
|
-
<div className="rounded-xl bg-
|
|
142
|
-
{/* Column Grid */}
|
|
73
|
+
<div className="rounded-xl bg-transparent relative">
|
|
143
74
|
<div
|
|
144
|
-
className="grid gap-
|
|
75
|
+
className="grid gap-2 p-1"
|
|
145
76
|
style={{
|
|
146
77
|
gridTemplateColumns: currentWidths.map(w => `${w}%`).join(' '),
|
|
147
78
|
}}
|
|
@@ -149,61 +80,33 @@ export const ColumnsEdit: React.FC<BlockEditProps & {
|
|
|
149
80
|
{Array.from({ length: numColumns }).map((_, colIndex) => (
|
|
150
81
|
<div
|
|
151
82
|
key={colIndex}
|
|
152
|
-
className={`group/col min-h-[
|
|
83
|
+
className={`group/col min-h-[100px] rounded-xl border border-dashed transition-all relative ${isSelected
|
|
153
84
|
? 'border-primary/20'
|
|
154
|
-
: 'border-
|
|
85
|
+
: 'border-neutral-200 dark:border-neutral-800'
|
|
155
86
|
}`}
|
|
156
87
|
>
|
|
157
|
-
<div className="p-
|
|
88
|
+
<div className="p-1">
|
|
158
89
|
<div className="mb-3 flex items-center justify-between">
|
|
159
|
-
<span className="text-[10px] font-black uppercase tracking-widest text-
|
|
90
|
+
<span className="text-[10px] font-black uppercase tracking-widest text-neutral-400 dark:text-neutral-600">
|
|
160
91
|
Column {colIndex + 1}
|
|
161
92
|
</span>
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
{
|
|
167
|
-
{
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
className="opacity-0 group-hover/col:opacity-100 p-1 text-neutral-400 hover:text-red-500 transition-all rounded"
|
|
174
|
-
title="Delete Column"
|
|
175
|
-
aria-label="Delete Column"
|
|
176
|
-
>
|
|
177
|
-
<Trash2 size={10} />
|
|
178
|
-
</button>
|
|
179
|
-
)}
|
|
180
|
-
</div>
|
|
93
|
+
</div>
|
|
94
|
+
<div data-layout-container={`${block.id}-col-${colIndex}`}>
|
|
95
|
+
<LayoutContainer
|
|
96
|
+
blocks={columns[colIndex]}
|
|
97
|
+
containerId={`${block.id}-col-${colIndex}`}
|
|
98
|
+
onBlockAdd={onChildBlockAdd}
|
|
99
|
+
onBlockUpdate={onChildBlockUpdate}
|
|
100
|
+
onBlockDelete={onChildBlockDelete}
|
|
101
|
+
onBlockMove={onChildBlockMove}
|
|
102
|
+
emptyLabel="Drop blocks here"
|
|
103
|
+
/>
|
|
181
104
|
</div>
|
|
182
105
|
|
|
183
|
-
<LayoutContainer
|
|
184
|
-
blocks={columns[colIndex] || []}
|
|
185
|
-
containerId={`${block.id}-col-${colIndex}`}
|
|
186
|
-
onBlockAdd={onChildBlockAdd}
|
|
187
|
-
onBlockUpdate={onChildBlockUpdate}
|
|
188
|
-
onBlockDelete={onChildBlockDelete}
|
|
189
|
-
onBlockMove={onChildBlockMove}
|
|
190
|
-
emptyLabel={`Drop blocks in column ${colIndex + 1}`}
|
|
191
|
-
/>
|
|
192
106
|
</div>
|
|
193
107
|
</div>
|
|
194
108
|
))}
|
|
195
109
|
</div>
|
|
196
|
-
|
|
197
|
-
{/* Add Column Button - Similar to table, pinned top right */}
|
|
198
|
-
{numColumns < 4 && (
|
|
199
|
-
<button
|
|
200
|
-
onClick={addColumn}
|
|
201
|
-
className="absolute top-0 right-0 h-8 w-8 flex items-center justify-center bg-white border-l border-b border-gray-200 text-primary hover:bg-primary hover:text-white transition-all z-10 rounded-br-xl"
|
|
202
|
-
title="Add Column"
|
|
203
|
-
>
|
|
204
|
-
<Plus size={16} />
|
|
205
|
-
</button>
|
|
206
|
-
)}
|
|
207
110
|
</div>
|
|
208
111
|
);
|
|
209
112
|
};
|
|
@@ -214,85 +117,69 @@ export const ColumnsEdit: React.FC<BlockEditProps & {
|
|
|
214
117
|
export const ColumnsPreview: React.FC<BlockPreviewProps & {
|
|
215
118
|
childBlocks?: Block[];
|
|
216
119
|
renderChild?: (block: Block) => React.ReactNode;
|
|
217
|
-
}> = ({ block, childBlocks = [], renderChild
|
|
218
|
-
//
|
|
120
|
+
}> = ({ block, context, childBlocks = [], renderChild }) => {
|
|
121
|
+
// Filter out hero block from children
|
|
122
|
+
const rawChildren = childBlocks.length > 0
|
|
123
|
+
? childBlocks
|
|
124
|
+
: (block.children && Array.isArray(block.children) && typeof block.children[0] === 'object'
|
|
125
|
+
? block.children as Block[]
|
|
126
|
+
: []);
|
|
127
|
+
|
|
128
|
+
const children = rawChildren.filter(b => b.type !== 'hero');
|
|
129
|
+
|
|
219
130
|
const columnCount = block.data.columnCount as number | undefined;
|
|
220
131
|
const layout: ColumnLayout | undefined = block.data.layout as ColumnLayout | undefined;
|
|
221
132
|
|
|
222
|
-
// Determine number of columns: use columnCount if set, otherwise derive from layout
|
|
223
133
|
let numColumns: number;
|
|
224
|
-
let
|
|
225
|
-
|
|
226
|
-
// Grid class mapping for Tailwind (must be explicit for dynamic classes)
|
|
227
|
-
const gridClassMap: Record<number, string> = {
|
|
228
|
-
1: 'grid-cols-1',
|
|
229
|
-
2: 'grid-cols-2',
|
|
230
|
-
3: 'grid-cols-3',
|
|
231
|
-
4: 'grid-cols-4',
|
|
232
|
-
5: 'grid-cols-5',
|
|
233
|
-
6: 'grid-cols-6',
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
// Get column widths
|
|
237
|
-
const storedWidths = block.data.columnWidths as number[] | undefined;
|
|
134
|
+
let columnWidths: number[];
|
|
238
135
|
|
|
239
136
|
if (columnCount !== undefined && columnCount > 0) {
|
|
240
|
-
// Dynamic column system
|
|
241
137
|
numColumns = columnCount;
|
|
242
|
-
|
|
138
|
+
const widthPercent = Math.floor(100 / numColumns);
|
|
139
|
+
columnWidths = Array(numColumns).fill(widthPercent);
|
|
243
140
|
} else if (layout && COLUMN_LAYOUTS[layout]) {
|
|
244
|
-
// Legacy layout-based system
|
|
245
141
|
const layoutConfig = COLUMN_LAYOUTS[layout];
|
|
246
142
|
numColumns = layoutConfig.widths.length;
|
|
247
|
-
|
|
143
|
+
columnWidths = layoutConfig.widths;
|
|
248
144
|
} else {
|
|
249
|
-
// Default to 2 columns
|
|
250
145
|
numColumns = 2;
|
|
251
|
-
|
|
146
|
+
columnWidths = [50, 50];
|
|
252
147
|
}
|
|
253
|
-
|
|
254
|
-
// Use stored widths if available, otherwise use equal widths
|
|
255
|
-
const columnWidths = storedWidths && storedWidths.length === numColumns
|
|
256
|
-
? storedWidths
|
|
257
|
-
: Array(numColumns).fill(Math.floor(100 / numColumns));
|
|
258
148
|
|
|
259
|
-
// If childBlocks are provided, use them; otherwise get from block.children
|
|
260
|
-
const children = childBlocks.length > 0
|
|
261
|
-
? childBlocks
|
|
262
|
-
: (block.children && Array.isArray(block.children) && typeof block.children[0] === 'object'
|
|
263
|
-
? block.children as Block[]
|
|
264
|
-
: []);
|
|
265
|
-
|
|
266
|
-
// Split child blocks into columns based on columnIndex in meta, or round-robin
|
|
267
149
|
const columns: Block[][] = Array.from({ length: numColumns }, () => []);
|
|
268
150
|
children.forEach((childBlock) => {
|
|
269
151
|
const columnIndex = childBlock.meta?.columnIndex;
|
|
270
152
|
if (typeof columnIndex === 'number' && columnIndex >= 0 && columnIndex < numColumns) {
|
|
271
153
|
columns[columnIndex].push(childBlock);
|
|
272
154
|
} else {
|
|
273
|
-
// Fallback to round-robin if no columnIndex specified
|
|
274
155
|
const index = children.indexOf(childBlock);
|
|
275
156
|
columns[index % numColumns].push(childBlock);
|
|
276
157
|
}
|
|
277
158
|
});
|
|
278
159
|
|
|
160
|
+
const storedWidths = block.data.columnWidths as number[] | undefined;
|
|
161
|
+
const currentWidths = storedWidths && storedWidths.length === numColumns
|
|
162
|
+
? storedWidths
|
|
163
|
+
: columnWidths;
|
|
164
|
+
|
|
279
165
|
return (
|
|
280
|
-
<div
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
{
|
|
289
|
-
|
|
290
|
-
{
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
166
|
+
<div className="w-full">
|
|
167
|
+
<div
|
|
168
|
+
className="grid gap-8"
|
|
169
|
+
style={{
|
|
170
|
+
gridTemplateColumns: currentWidths.map(w => `${w}%`).join(' '),
|
|
171
|
+
}}
|
|
172
|
+
>
|
|
173
|
+
{columns.map((colBlocks, colIdx) => (
|
|
174
|
+
<div key={colIdx} className="w-full">
|
|
175
|
+
{colBlocks.map((childBlock) => (
|
|
176
|
+
<React.Fragment key={childBlock.id}>
|
|
177
|
+
{renderChild?.(childBlock)}
|
|
178
|
+
</React.Fragment>
|
|
179
|
+
))}
|
|
180
|
+
</div>
|
|
181
|
+
))}
|
|
182
|
+
</div>
|
|
295
183
|
</div>
|
|
296
184
|
);
|
|
297
185
|
};
|
|
298
|
-
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import React from 'react';
|
|
9
9
|
import { BlockEditProps, BlockPreviewProps } from '../../../types/block';
|
|
10
10
|
import { LayoutContainer } from '../../../views/CanvasEditor/LayoutContainer';
|
|
11
|
-
import {
|
|
11
|
+
import { LAYOUT_BACKGROUNDS } from '../index';
|
|
12
12
|
import { Block } from '../../../types/block';
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -32,31 +32,26 @@ export const SectionEdit: React.FC<BlockEditProps & {
|
|
|
32
32
|
}) => {
|
|
33
33
|
const background = (block.data.background as keyof typeof LAYOUT_BACKGROUNDS) || 'DEFAULT';
|
|
34
34
|
|
|
35
|
+
// Filter out hero block from being rendered inside containers
|
|
36
|
+
const blocks = childBlocks.filter(b => b.type !== 'hero');
|
|
37
|
+
|
|
35
38
|
return (
|
|
36
39
|
<div
|
|
37
|
-
className={`rounded-
|
|
38
|
-
? 'bg-primary/5'
|
|
39
|
-
|
|
40
|
-
} ${LAYOUT_BACKGROUNDS[background]}`}
|
|
41
|
-
onDragStart={(e) => {
|
|
42
|
-
// Prevent section from being dragged when dragging nested blocks
|
|
43
|
-
// Check if the drag started on a nested block wrapper
|
|
44
|
-
const nestedBlockWrapper = (e.target as HTMLElement).closest('[data-block-wrapper]');
|
|
45
|
-
if (nestedBlockWrapper) {
|
|
46
|
-
const nestedBlockId = nestedBlockWrapper.getAttribute('data-block-id');
|
|
47
|
-
// If dragging a nested block, prevent the section's drag handler from firing
|
|
48
|
-
if (nestedBlockId && nestedBlockId !== block.id) {
|
|
49
|
-
e.stopPropagation();
|
|
50
|
-
e.preventDefault();
|
|
51
|
-
console.log('[SectionBlock] Preventing section drag, nested block is being dragged:', nestedBlockId);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}}
|
|
40
|
+
className={`rounded-3xl transition-all relative group/section ${
|
|
41
|
+
isSelected ? 'ring-2 ring-primary/20 bg-primary/5' : 'border border-dashed border-neutral-200 dark:border-neutral-800'
|
|
42
|
+
} ${LAYOUT_BACKGROUNDS[background]}`}
|
|
55
43
|
>
|
|
44
|
+
{/* Section Identifier Tag */}
|
|
45
|
+
<div className="absolute -top-3 left-8 px-2 py-0.5 bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-800 rounded-md z-20 pointer-events-none transition-opacity opacity-40 group-hover/section:opacity-100">
|
|
46
|
+
<span className="text-[8px] font-black uppercase tracking-widest text-neutral-400 dark:text-neutral-500">
|
|
47
|
+
Section Container
|
|
48
|
+
</span>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
56
51
|
{/* Nested Content */}
|
|
57
|
-
<div className={`px-8 py-
|
|
52
|
+
<div className={`px-8 py-6`} data-layout-container={block.id}>
|
|
58
53
|
<LayoutContainer
|
|
59
|
-
blocks={
|
|
54
|
+
blocks={blocks}
|
|
60
55
|
containerId={block.id}
|
|
61
56
|
onBlockAdd={onChildBlockAdd}
|
|
62
57
|
onBlockUpdate={onChildBlockUpdate}
|
|
@@ -75,15 +70,17 @@ export const SectionEdit: React.FC<BlockEditProps & {
|
|
|
75
70
|
export const SectionPreview: React.FC<BlockPreviewProps & {
|
|
76
71
|
childBlocks?: Block[];
|
|
77
72
|
renderChild?: (block: Block) => React.ReactNode;
|
|
78
|
-
}> = ({ block, childBlocks = [], renderChild
|
|
73
|
+
}> = ({ block, context, childBlocks = [], renderChild }) => {
|
|
79
74
|
const background = (block.data.background as keyof typeof LAYOUT_BACKGROUNDS) || 'DEFAULT';
|
|
80
75
|
|
|
81
|
-
//
|
|
82
|
-
const
|
|
76
|
+
// Filter out hero block from children
|
|
77
|
+
const rawChildren = childBlocks.length > 0
|
|
83
78
|
? childBlocks
|
|
84
79
|
: (block.children && Array.isArray(block.children) && typeof block.children[0] === 'object'
|
|
85
80
|
? block.children as Block[]
|
|
86
81
|
: []);
|
|
82
|
+
|
|
83
|
+
const children = rawChildren.filter(b => b.type !== 'hero');
|
|
87
84
|
|
|
88
85
|
return (
|
|
89
86
|
<section className={`w-full ${LAYOUT_BACKGROUNDS[background]}`}>
|
|
@@ -95,10 +92,9 @@ export const SectionPreview: React.FC<BlockPreviewProps & {
|
|
|
95
92
|
</React.Fragment>
|
|
96
93
|
))
|
|
97
94
|
) : (
|
|
98
|
-
<div className="text-gray-400 text-sm italic">Empty section</div>
|
|
95
|
+
children.length > 0 ? null : <div className="text-gray-400 text-sm italic">Empty section</div>
|
|
99
96
|
)}
|
|
100
97
|
</div>
|
|
101
98
|
</section>
|
|
102
99
|
);
|
|
103
100
|
};
|
|
104
|
-
|
package/src/lib/layouts/index.ts
CHANGED
|
@@ -12,12 +12,12 @@ export const LAYOUT_CONSTANTS = {
|
|
|
12
12
|
BORDER_RADIUS: '2rem', // 32px - Consistent rounded corners
|
|
13
13
|
} as const;
|
|
14
14
|
|
|
15
|
-
// Background Colors (
|
|
15
|
+
// Background Colors (Theme-aware - integrates with client website theme)
|
|
16
16
|
export const LAYOUT_BACKGROUNDS = {
|
|
17
|
-
DEFAULT: 'bg-
|
|
18
|
-
NEUTRAL: 'bg-neutral-50',
|
|
17
|
+
DEFAULT: 'bg-transparent',
|
|
18
|
+
NEUTRAL: 'bg-neutral-50 dark:bg-neutral-900/50',
|
|
19
19
|
SAGE: 'bg-primary/5',
|
|
20
|
-
CREAM: 'bg-amber-50/50',
|
|
20
|
+
CREAM: 'bg-amber-50/50 dark:bg-orange-950/10',
|
|
21
21
|
} as const;
|
|
22
22
|
|
|
23
23
|
// Column Layout Presets
|
|
@@ -41,6 +41,11 @@ export interface APIBlogDocument {
|
|
|
41
41
|
canonicalUrl?: string;
|
|
42
42
|
};
|
|
43
43
|
authorId?: string;
|
|
44
|
+
author?: {
|
|
45
|
+
name: string;
|
|
46
|
+
image?: string;
|
|
47
|
+
displayRole?: string;
|
|
48
|
+
};
|
|
44
49
|
createdAt?: string | Date;
|
|
45
50
|
updatedAt?: string | Date;
|
|
46
51
|
// Multilingual fields
|
|
@@ -59,6 +64,11 @@ export interface APIBlogDocument {
|
|
|
59
64
|
};
|
|
60
65
|
availableLanguages?: string[];
|
|
61
66
|
lang?: string;
|
|
67
|
+
status?: PostStatus;
|
|
68
|
+
publication?: {
|
|
69
|
+
status: PostStatus;
|
|
70
|
+
date?: string | Date;
|
|
71
|
+
};
|
|
62
72
|
metadata?: {
|
|
63
73
|
lang?: string;
|
|
64
74
|
};
|
|
@@ -72,7 +82,7 @@ export function apiToBlogPost(doc: APIBlogDocument): BlogPost {
|
|
|
72
82
|
|
|
73
83
|
// Use contentBlocks if available, otherwise fallback to content (legacy)
|
|
74
84
|
// Hero block is included in contentBlocks
|
|
75
|
-
const blocks = doc.contentBlocks || [];
|
|
85
|
+
const blocks = doc.contentBlocks || doc.content || [];
|
|
76
86
|
|
|
77
87
|
// Convert publication data
|
|
78
88
|
const publicationDate = doc.publicationData?.date
|
|
@@ -106,9 +116,18 @@ export function apiToBlogPost(doc: APIBlogDocument): BlogPost {
|
|
|
106
116
|
privacy: undefined, // Privacy settings not in API yet
|
|
107
117
|
};
|
|
108
118
|
|
|
109
|
-
// Convert publication data -
|
|
110
|
-
|
|
111
|
-
|
|
119
|
+
// Convert publication data - strictly isolate per-language status
|
|
120
|
+
// 1. Prefer specific language status from 'publication.status'
|
|
121
|
+
// 2. Fallback to top-level 'status' if provided by specific language endpoint
|
|
122
|
+
// 3. Defaults to 'draft'
|
|
123
|
+
let apiStatus: string = doc.publication?.status || doc.status || 'concept';
|
|
124
|
+
|
|
125
|
+
// If we're missing translation, force draft
|
|
126
|
+
if (apiStatus === 'not-translated' || apiStatus === 'concept') {
|
|
127
|
+
apiStatus = 'draft';
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const normalizedStatus = apiStatus as PostStatus;
|
|
112
131
|
|
|
113
132
|
const publication = {
|
|
114
133
|
status: normalizedStatus as PostStatus,
|
|
@@ -119,6 +138,12 @@ export function apiToBlogPost(doc: APIBlogDocument): BlogPost {
|
|
|
119
138
|
: undefined,
|
|
120
139
|
};
|
|
121
140
|
|
|
141
|
+
const author = doc.author ? {
|
|
142
|
+
name: doc.author.name,
|
|
143
|
+
image: doc.author.image,
|
|
144
|
+
displayRole: doc.author.displayRole,
|
|
145
|
+
} : undefined;
|
|
146
|
+
|
|
122
147
|
return {
|
|
123
148
|
id,
|
|
124
149
|
title: doc.title,
|
|
@@ -126,8 +151,10 @@ export function apiToBlogPost(doc: APIBlogDocument): BlogPost {
|
|
|
126
151
|
blocks,
|
|
127
152
|
seo,
|
|
128
153
|
publication,
|
|
154
|
+
author,
|
|
129
155
|
metadata,
|
|
130
156
|
languages: doc.languages,
|
|
157
|
+
availableLanguages: doc.availableLanguages || (doc.languages ? Object.keys(doc.languages) : []),
|
|
131
158
|
createdAt: doc.createdAt
|
|
132
159
|
? (typeof doc.createdAt === 'string' ? doc.createdAt : doc.createdAt.toISOString())
|
|
133
160
|
: new Date().toISOString(),
|
|
@@ -192,11 +219,7 @@ export function editorStateToAPI(state: {
|
|
|
192
219
|
// Map status: draft -> concept, published -> published, everything else stays as-is
|
|
193
220
|
const apiStatus = state.status === 'draft' ? 'concept' : state.status;
|
|
194
221
|
|
|
195
|
-
|
|
196
|
-
editorStatus: state.status,
|
|
197
|
-
apiStatus: apiStatus,
|
|
198
|
-
willBePublished: apiStatus === 'published'
|
|
199
|
-
});
|
|
222
|
+
|
|
200
223
|
|
|
201
224
|
// Try to get category from metadata first, then check hero block
|
|
202
225
|
let category: string | undefined = undefined;
|
|
@@ -213,43 +236,51 @@ export function editorStateToAPI(state: {
|
|
|
213
236
|
}
|
|
214
237
|
}
|
|
215
238
|
|
|
216
|
-
|
|
217
|
-
fromMetadata: state.metadata.categories?.[0],
|
|
218
|
-
fromHeroBlock: (heroBlock || state.blocks.find(b => b.type === 'hero'))?.data ? ((heroBlock || state.blocks.find(b => b.type === 'hero'))!.data as any).category : undefined,
|
|
219
|
-
finalCategory: category,
|
|
220
|
-
hasHeroBlock: !!heroBlock,
|
|
221
|
-
heroBlockImage: heroBlock?.data ? (heroBlock.data as any)?.image : undefined,
|
|
222
|
-
});
|
|
239
|
+
|
|
223
240
|
|
|
224
241
|
// Include hero block in contentBlocks if it exists
|
|
225
|
-
// Filter out any existing hero blocks from state.blocks first, then add the current hero block
|
|
226
242
|
const contentBlocksWithoutHero = state.blocks.filter(block => block.type !== 'hero');
|
|
227
243
|
const allBlocks = heroBlock
|
|
228
244
|
? [heroBlock, ...contentBlocksWithoutHero]
|
|
229
245
|
: contentBlocksWithoutHero;
|
|
246
|
+
|
|
247
|
+
// Try to get featured image from metadata first, then check hero block
|
|
248
|
+
let featuredImage = state.metadata.featuredImage;
|
|
249
|
+
if (!featuredImage?.id?.trim()) {
|
|
250
|
+
const heroBlockToCheck = heroBlock || state.blocks.find(block => block.type === 'hero');
|
|
251
|
+
if (heroBlockToCheck && heroBlockToCheck.data && typeof heroBlockToCheck.data === 'object') {
|
|
252
|
+
const heroImageId = (heroBlockToCheck.data as any).imageId;
|
|
253
|
+
if (heroImageId && typeof heroImageId === 'string' && heroImageId.trim()) {
|
|
254
|
+
featuredImage = {
|
|
255
|
+
id: heroImageId.trim(),
|
|
256
|
+
alt: state.title,
|
|
257
|
+
isCustom: false
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
230
262
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
});
|
|
263
|
+
// Try to get summary from hero block first, then metadata
|
|
264
|
+
let summary = state.metadata.excerpt;
|
|
265
|
+
const heroBlockToCheck = heroBlock || state.blocks.find(block => block.type === 'hero');
|
|
266
|
+
if (heroBlockToCheck && heroBlockToCheck.data && typeof heroBlockToCheck.data === 'object') {
|
|
267
|
+
const heroDesc = (heroBlockToCheck.data as any).description;
|
|
268
|
+
if (heroDesc && typeof heroDesc === 'string' && heroDesc.trim()) {
|
|
269
|
+
summary = heroDesc.trim();
|
|
270
|
+
}
|
|
271
|
+
}
|
|
241
272
|
|
|
242
273
|
return {
|
|
243
274
|
title: state.title,
|
|
244
275
|
slug: state.slug,
|
|
245
276
|
contentBlocks: allBlocks,
|
|
246
|
-
summary:
|
|
277
|
+
summary: summary,
|
|
247
278
|
// Only save semantic ID (id) and alt - plugin-images handles transform data
|
|
248
279
|
// Only create image object if id exists and is not empty
|
|
249
|
-
image:
|
|
250
|
-
id:
|
|
251
|
-
alt:
|
|
252
|
-
isCustom:
|
|
280
|
+
image: featuredImage?.id?.trim() ? {
|
|
281
|
+
id: featuredImage.id.trim(),
|
|
282
|
+
alt: featuredImage.alt || '',
|
|
283
|
+
isCustom: featuredImage.isCustom,
|
|
253
284
|
// Don't save transform fields - plugin-images API handles those
|
|
254
285
|
} : undefined,
|
|
255
286
|
categoryTags: {
|