@jhits/plugin-newsletter 0.0.16 → 0.0.17
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/email-utils.d.ts.map +1 -1
- package/dist/api/email-utils.js +45 -4
- package/dist/api/handlers/send-newsletter.d.ts.map +1 -1
- package/dist/api/handlers/send-newsletter.js +54 -6
- package/dist/api/handlers/settings.d.ts.map +1 -1
- package/dist/api/handlers/settings.js +51 -1
- package/dist/index.d.ts +27 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -122
- package/dist/lib/blocks/BlockRenderer.d.ts.map +1 -1
- package/dist/lib/blocks/BlockRenderer.js +14 -2
- package/dist/lib/email/EmailRenderer.d.ts +1 -0
- package/dist/lib/email/EmailRenderer.d.ts.map +1 -1
- package/dist/lib/email/EmailRenderer.js +31 -19
- package/dist/lib/utils/config-resolver.d.ts +33 -0
- package/dist/lib/utils/config-resolver.d.ts.map +1 -0
- package/dist/lib/utils/config-resolver.js +47 -0
- package/dist/registry/BlockRegistry.d.ts +9 -1
- package/dist/registry/BlockRegistry.d.ts.map +1 -1
- package/dist/registry/BlockRegistry.js +126 -8
- package/dist/state/EditorContext.d.ts +11 -1
- package/dist/state/EditorContext.d.ts.map +1 -1
- package/dist/state/EditorContext.js +23 -5
- package/dist/state/types.d.ts +12 -0
- 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/newsletter.d.ts +2 -0
- package/dist/types/newsletter.d.ts.map +1 -1
- package/dist/views/CanvasEditor/BlockWrapper.d.ts.map +1 -1
- package/dist/views/CanvasEditor/BlockWrapper.js +24 -3
- package/dist/views/CanvasEditor/CanvasEditorView.d.ts.map +1 -1
- package/dist/views/CanvasEditor/CanvasEditorView.js +77 -17
- package/dist/views/CanvasEditor/EditorBody.d.ts.map +1 -1
- package/dist/views/CanvasEditor/EditorBody.js +1 -1
- package/dist/views/CanvasEditor/components/EditorCanvas.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/EditorCanvas.js +158 -100
- package/dist/views/CanvasEditor/components/EditorSidebar.d.ts +3 -1
- package/dist/views/CanvasEditor/components/EditorSidebar.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/EditorSidebar.js +3 -3
- package/dist/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts +1 -1
- package/dist/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts.map +1 -1
- package/dist/views/CanvasEditor/hooks/useRegisteredBlocks.js +6 -40
- package/dist/views/components/DomainPromptModal.d.ts +13 -0
- package/dist/views/components/DomainPromptModal.d.ts.map +1 -0
- package/dist/views/components/DomainPromptModal.js +58 -0
- package/dist/views/components/SendNewsletterModal.d.ts.map +1 -1
- package/dist/views/components/SendNewsletterModal.js +91 -22
- package/dist/views/components/SmtpSettingsModal.d.ts.map +1 -1
- package/dist/views/components/SmtpSettingsModal.js +10 -0
- package/dist/views/components/TestEmailModal.d.ts.map +1 -1
- package/dist/views/components/TestEmailModal.js +86 -17
- package/package.json +53 -9
- package/src/api/email-utils.ts +53 -4
- package/src/api/handlers/send-newsletter.ts +65 -6
- package/src/api/handlers/settings.ts +60 -2
- package/src/index.tsx +49 -155
- package/src/lib/blocks/BlockRenderer.tsx +16 -2
- package/src/lib/email/EmailRenderer.tsx +31 -20
- package/src/lib/utils/config-resolver.ts +71 -0
- package/src/registry/BlockRegistry.tsx +255 -0
- package/src/state/EditorContext.tsx +43 -8
- package/src/state/types.ts +16 -0
- package/src/types/block.ts +10 -0
- package/src/types/newsletter.ts +3 -0
- package/src/views/CanvasEditor/BlockWrapper.tsx +27 -2
- package/src/views/CanvasEditor/CanvasEditorView.tsx +142 -61
- package/src/views/CanvasEditor/EditorBody.tsx +17 -13
- package/src/views/CanvasEditor/components/EditorCanvas.tsx +178 -115
- package/src/views/CanvasEditor/components/EditorSidebar.tsx +57 -2
- package/src/views/CanvasEditor/hooks/useRegisteredBlocks.ts +6 -45
- package/src/views/components/DomainPromptModal.tsx +160 -0
- package/src/views/components/SendNewsletterModal.tsx +270 -184
- package/src/views/components/SmtpSettingsModal.tsx +11 -0
- package/src/views/components/TestEmailModal.tsx +235 -149
- package/src/registry/BlockRegistry.ts +0 -53
|
@@ -12,7 +12,9 @@ import { useEditor } from '../../state/EditorContext';
|
|
|
12
12
|
import { SlashCommandDetector } from './components/SlashCommandDetector';
|
|
13
13
|
export function BlockWrapper({ block, onUpdate, onDelete, onMoveUp, onMoveDown, allBlocks = [], slashCommand, blockIndex, onAddBlockBelow, }) {
|
|
14
14
|
const [isHovered, setIsHovered] = useState(false);
|
|
15
|
-
const { state } = useEditor();
|
|
15
|
+
const { state, translations, registeredBlockTypes } = useEditor();
|
|
16
|
+
// We use the block definition from registry
|
|
17
|
+
// The component will re-render when registeredBlockTypes changes
|
|
16
18
|
const blockDefinition = blockRegistry.get(block.type);
|
|
17
19
|
// Check if this is a container block
|
|
18
20
|
const isContainer = isContainerBlock(block, blockRegistry);
|
|
@@ -25,6 +27,19 @@ export function BlockWrapper({ block, onUpdate, onDelete, onMoveUp, onMoveDown,
|
|
|
25
27
|
return (_jsx("div", { className: "p-4 border border-red-300 dark:border-red-700 rounded-lg bg-red-50 dark:bg-red-900/20", children: _jsxs("p", { className: "text-sm text-red-600 dark:text-red-400", children: ["Unknown block type: ", block.type] }) }));
|
|
26
28
|
}
|
|
27
29
|
const EditComponent = blockDefinition.components.Edit;
|
|
30
|
+
// Helper to check if block is empty (for easier deletion)
|
|
31
|
+
const isBlockEmpty = () => {
|
|
32
|
+
if (block.type === 'paragraph' || block.type === 'heading') {
|
|
33
|
+
const text = block.data.text || '';
|
|
34
|
+
const html = block.data.html || '';
|
|
35
|
+
return text.trim() === '' && html.trim() === '';
|
|
36
|
+
}
|
|
37
|
+
if (block.type === 'list') {
|
|
38
|
+
const items = block.data.items || [];
|
|
39
|
+
return items.length === 0 || (items.length === 1 && (typeof items[0] === 'string' ? items[0].trim() === '' : items[0].text?.trim() === ''));
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
42
|
+
};
|
|
28
43
|
// Store block ID when hovering for paste context
|
|
29
44
|
useEffect(() => {
|
|
30
45
|
if (isHovered) {
|
|
@@ -35,9 +50,15 @@ export function BlockWrapper({ block, onUpdate, onDelete, onMoveUp, onMoveDown,
|
|
|
35
50
|
}, [isHovered, block.id]);
|
|
36
51
|
return (_jsxs("div", { className: "group relative flex items-start gap-1 py-0.5", onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), "data-block-wrapper": true, "data-block-id": block.id, children: [_jsx("div", { className: "flex-1 min-w-0 email-block-content", children: block.type === 'paragraph' && slashCommand ? (_jsx(SlashCommandDetector, { blockId: block.id, blockIndex: blockIndex || 0, blockType: block.type, content: block.data.html || block.data.text || '', onContentChange: (content) => {
|
|
37
52
|
onUpdate({ html: content, text: content.replace(/<[^>]*>/g, '') });
|
|
38
|
-
}, slashCommand: slashCommand, onAddBlockBelow: onAddBlockBelow, children: _jsx("div", { className: "email-block-wrapper", children: _jsx(EditComponent, { block: block, onUpdate: onUpdate, onDelete: onDelete, isSelected: state.selectedBlockId === block.id, childBlocks: childBlocks
|
|
53
|
+
}, slashCommand: slashCommand, onAddBlockBelow: onAddBlockBelow, children: _jsx("div", { className: "email-block-wrapper", children: _jsx(EditComponent, { block: block, onUpdate: onUpdate, onDelete: onDelete, isSelected: state.selectedBlockId === block.id, childBlocks: childBlocks, context: {
|
|
54
|
+
locale: state.metadata.lang || 'en',
|
|
55
|
+
translations
|
|
56
|
+
} }) }) })) : (_jsx("div", { className: "email-block-wrapper", children: _jsx(EditComponent, { block: block, onUpdate: onUpdate, onDelete: onDelete, isSelected: state.selectedBlockId === block.id, childBlocks: childBlocks, context: {
|
|
57
|
+
locale: state.metadata.lang || 'en',
|
|
58
|
+
translations
|
|
59
|
+
} }) })) }), _jsx("div", { className: `flex-shrink-0 w-6 flex items-start justify-center pt-1 transition-opacity duration-150 ${isHovered ? 'opacity-100' : 'opacity-0'}`, children: _jsx("button", { onClick: (e) => {
|
|
39
60
|
e.stopPropagation();
|
|
40
|
-
if (confirm('Delete this block?')) {
|
|
61
|
+
if (isBlockEmpty() || confirm('Delete this block?')) {
|
|
41
62
|
onDelete();
|
|
42
63
|
}
|
|
43
64
|
}, className: "p-1 -mr-1 hover:bg-red-50 dark:hover:bg-red-900/20 rounded transition-colors", title: "Delete block", children: _jsx(Trash2, { size: 16, className: "text-neutral-400 dark:text-neutral-500 hover:text-red-500 dark:hover:text-red-400 transition-colors" }) }) })] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CanvasEditorView.d.ts","sourceRoot":"","sources":["../../../src/views/CanvasEditor/CanvasEditorView.tsx"],"names":[],"mappings":"AAeA,MAAM,WAAW,qBAAqB;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,gBAAgB,CAAC,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,oDAAoD;IACpD,cAAc,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,wBAAgB,gBAAgB,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,qBAAqB,
|
|
1
|
+
{"version":3,"file":"CanvasEditorView.d.ts","sourceRoot":"","sources":["../../../src/views/CanvasEditor/CanvasEditorView.tsx"],"names":[],"mappings":"AAeA,MAAM,WAAW,qBAAqB;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,gBAAgB,CAAC,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,oDAAoD;IACpD,cAAc,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,wBAAgB,gBAAgB,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,qBAAqB,2CA6Z1J"}
|
|
@@ -11,7 +11,7 @@ import { useSlashCommand } from './hooks/useSlashCommand';
|
|
|
11
11
|
import { useNewsletterLoader, useRegisteredBlocks, useKeyboardShortcuts } from './hooks';
|
|
12
12
|
import { blockRegistry } from '../../registry';
|
|
13
13
|
export function CanvasEditorView({ newsletterId, darkMode, backgroundColors: propsBackgroundColors, siteId, locale, isWelcomeEmail }) {
|
|
14
|
-
const { state, helpers, dispatch, darkMode: contextDarkMode, backgroundColors: contextBackgroundColors, canUndo, canRedo } = useEditor();
|
|
14
|
+
const { state, helpers, dispatch, darkMode: contextDarkMode, backgroundColors: contextBackgroundColors, emailConfig: contextEmailConfig, canUndo, canRedo } = useEditor();
|
|
15
15
|
const effectiveDarkMode = darkMode !== undefined ? darkMode : contextDarkMode;
|
|
16
16
|
const effectiveBackgroundColors = propsBackgroundColors || contextBackgroundColors;
|
|
17
17
|
const [isSidebarOpen, setSidebarOpen] = useState(true);
|
|
@@ -23,6 +23,12 @@ export function CanvasEditorView({ newsletterId, darkMode, backgroundColors: pro
|
|
|
23
23
|
const [isLoadingLanguage, setIsLoadingLanguage] = useState(true);
|
|
24
24
|
const [availableLanguages, setAvailableLanguages] = useState([locale || 'en']);
|
|
25
25
|
const [currentLanguage, setCurrentLanguage] = useState(locale || 'en');
|
|
26
|
+
// Global branding settings from SMTP
|
|
27
|
+
const [globalUnsubscribeTranslations, setGlobalUnsubscribeTranslations] = useState({
|
|
28
|
+
en: '',
|
|
29
|
+
nl: '',
|
|
30
|
+
sv: '',
|
|
31
|
+
});
|
|
26
32
|
// Get registered blocks
|
|
27
33
|
const registeredBlocks = useRegisteredBlocks();
|
|
28
34
|
// Newsletter loading - wait for language settings to be loaded first
|
|
@@ -65,6 +71,24 @@ export function CanvasEditorView({ newsletterId, darkMode, backgroundColors: pro
|
|
|
65
71
|
setPrimaryLanguage(primary);
|
|
66
72
|
setAvailableLanguages(available);
|
|
67
73
|
setCurrentLanguage(primary);
|
|
74
|
+
// Load global unsubscribe translations
|
|
75
|
+
if (smtpData.unsubscribeTranslations) {
|
|
76
|
+
setGlobalUnsubscribeTranslations(smtpData.unsubscribeTranslations);
|
|
77
|
+
}
|
|
78
|
+
// Update emailConfig with logo from SMTP settings if available
|
|
79
|
+
if (smtpData.logoUrl) {
|
|
80
|
+
if (typeof window !== 'undefined') {
|
|
81
|
+
if (!window.__JHITS_PLUGIN_PROPS__)
|
|
82
|
+
window.__JHITS_PLUGIN_PROPS__ = {};
|
|
83
|
+
if (!window.__JHITS_PLUGIN_PROPS__['plugin-newsletter'])
|
|
84
|
+
window.__JHITS_PLUGIN_PROPS__['plugin-newsletter'] = {};
|
|
85
|
+
const currentConfig = window.__JHITS_PLUGIN_PROPS__['plugin-newsletter'].emailConfig || {};
|
|
86
|
+
window.__JHITS_PLUGIN_PROPS__['plugin-newsletter'].emailConfig = {
|
|
87
|
+
...currentConfig,
|
|
88
|
+
logoUrl: smtpData.logoUrl
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
68
92
|
}
|
|
69
93
|
catch (error) {
|
|
70
94
|
console.error('Failed to fetch language settings:', error);
|
|
@@ -75,6 +99,39 @@ export function CanvasEditorView({ newsletterId, darkMode, backgroundColors: pro
|
|
|
75
99
|
};
|
|
76
100
|
fetchLanguageSettings();
|
|
77
101
|
}, []);
|
|
102
|
+
// Handle global unsubscribe text update
|
|
103
|
+
const handleGlobalUnsubscribeUpdate = async (text) => {
|
|
104
|
+
const newTranslations = {
|
|
105
|
+
...globalUnsubscribeTranslations,
|
|
106
|
+
[currentLanguage]: text
|
|
107
|
+
};
|
|
108
|
+
// Optimistic update
|
|
109
|
+
setGlobalUnsubscribeTranslations(newTranslations);
|
|
110
|
+
// Update window props for immediate preview reflection
|
|
111
|
+
if (typeof window !== 'undefined') {
|
|
112
|
+
if (!window.__JHITS_PLUGIN_PROPS__)
|
|
113
|
+
window.__JHITS_PLUGIN_PROPS__ = {};
|
|
114
|
+
if (!window.__JHITS_PLUGIN_PROPS__['plugin-newsletter'])
|
|
115
|
+
window.__JHITS_PLUGIN_PROPS__['plugin-newsletter'] = {};
|
|
116
|
+
window.__JHITS_PLUGIN_PROPS__['plugin-newsletter'].unsubscribeTranslations = newTranslations;
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
// We need current SMTP settings to save along with the new translation
|
|
120
|
+
const smtpResponse = await fetch('/api/plugin-newsletter/smtp');
|
|
121
|
+
const smtpData = await smtpResponse.json();
|
|
122
|
+
await fetch('/api/plugin-newsletter/smtp', {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
headers: { 'Content-Type': 'application/json' },
|
|
125
|
+
body: JSON.stringify({
|
|
126
|
+
...smtpData,
|
|
127
|
+
unsubscribeTranslations: newTranslations
|
|
128
|
+
}),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
console.error('Failed to save global unsubscribe translation:', error);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
78
135
|
// Handle language change for welcome email
|
|
79
136
|
const handleLanguageChange = async (newLanguage) => {
|
|
80
137
|
// Save current content first if dirty
|
|
@@ -164,17 +221,14 @@ export function CanvasEditorView({ newsletterId, darkMode, backgroundColors: pro
|
|
|
164
221
|
return;
|
|
165
222
|
}
|
|
166
223
|
// Replace the block in place by updating the blocks array directly
|
|
167
|
-
// This preserves the position and ID
|
|
168
224
|
const newBlocks = state.blocks.map((block, idx) => {
|
|
169
225
|
if (idx === blockIndex) {
|
|
170
|
-
// Replace this block with the new type
|
|
171
226
|
return {
|
|
172
227
|
...block,
|
|
173
228
|
type: blockType,
|
|
174
229
|
data: { ...blockDefinition.defaultData },
|
|
175
230
|
};
|
|
176
231
|
}
|
|
177
|
-
// Keep all other blocks unchanged
|
|
178
232
|
return block;
|
|
179
233
|
});
|
|
180
234
|
dispatch({ type: 'SET_BLOCKS', payload: newBlocks });
|
|
@@ -185,12 +239,26 @@ export function CanvasEditorView({ newsletterId, darkMode, backgroundColors: pro
|
|
|
185
239
|
}, [state.blocks, dispatch]);
|
|
186
240
|
// Slash command hook
|
|
187
241
|
const slashCommand = useSlashCommand(registeredBlocks, handleSlashCommandSelect);
|
|
242
|
+
// Lock dashboard scroll when editor is active to ensure our internal scrolling works
|
|
243
|
+
useEffect(() => {
|
|
244
|
+
if (typeof window === 'undefined')
|
|
245
|
+
return;
|
|
246
|
+
const dashboardContainer = document.querySelector('.custom-scrollbar.overflow-y-auto');
|
|
247
|
+
const originalOverflow = dashboardContainer ? dashboardContainer.style.overflow : '';
|
|
248
|
+
if (dashboardContainer) {
|
|
249
|
+
dashboardContainer.style.overflow = 'hidden';
|
|
250
|
+
}
|
|
251
|
+
return () => {
|
|
252
|
+
if (dashboardContainer) {
|
|
253
|
+
dashboardContainer.style.overflow = originalOverflow;
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
}, []);
|
|
188
257
|
// Handle save
|
|
189
258
|
const handleSave = async () => {
|
|
190
259
|
setIsSaving(true);
|
|
191
260
|
setSaveError(null);
|
|
192
261
|
try {
|
|
193
|
-
// Always pass language for saving (both welcome email and regular newsletters)
|
|
194
262
|
await helpers.save({ language: currentLanguage });
|
|
195
263
|
setIsSaving(false);
|
|
196
264
|
}
|
|
@@ -208,16 +276,8 @@ export function CanvasEditorView({ newsletterId, darkMode, backgroundColors: pro
|
|
|
208
276
|
if (isLoadingNewsletter) {
|
|
209
277
|
return (_jsx("div", { className: "h-full w-full bg-dashboard-card text-dashboard-text flex items-center justify-center", children: _jsxs("div", { className: "text-center", children: [_jsx("div", { className: "w-8 h-8 border-4 border-primary/20 border-t-primary rounded-full animate-spin mx-auto mb-4" }), _jsx("p", { className: "text-sm text-neutral-500 dark:text-neutral-400", children: "Loading newsletter..." })] }) }));
|
|
210
278
|
}
|
|
211
|
-
return (_jsx("div", { className: "
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
else {
|
|
216
|
-
setSaveError(null);
|
|
217
|
-
}
|
|
218
|
-
}, isDirty: state.isDirty, isWelcomeEmail: isWelcomeEmail, languages: availableLanguages, currentLanguage: currentLanguage, onLanguageChange: handleLanguageChange, onAddLanguage: handleAddLanguage }), _jsxs("div", { className: "flex flex-1 relative overflow-hidden min-h-0 flex-nowrap", children: [_jsx(EditorCanvas, { isPreviewMode: isPreviewMode, contentBlocks: state.blocks, title: state.title, siteId: siteId, locale: locale, darkMode: effectiveDarkMode, backgroundColors: effectiveBackgroundColors, metadata: state.metadata, onTitleChange: (title) => dispatch({ type: 'SET_TITLE', payload: title }), onMetadataChange: (metadata) => dispatch({ type: 'SET_METADATA', payload: metadata }), onBlockAdd: (type, index, containerId) => helpers.addBlock(type, index, containerId), onBlockUpdate: (id, data) => helpers.updateBlock(id, data), onBlockDelete: (id) => helpers.deleteBlock(id), onBlockMove: (id, newIndex, containerId) => helpers.moveBlock(id, newIndex, containerId), slashCommand: slashCommand }), !isPreviewMode && (_jsx("aside", { className: `transition-all duration-500 ease-[cubic-bezier(0.4,0,0.2,1)] border-l border-dashboard-border bg-dashboard-sidebar overflow-y-auto overflow-x-hidden h-full ${isSidebarOpen ? 'w-80' : 'w-0 opacity-0 pointer-events-none'}`, children: _jsx(EditorSidebar, { metadata: state.metadata, status: state.status, onMetadataUpdate: (metadata) => dispatch({ type: 'SET_METADATA', payload: metadata }), defaultLanguage: primaryLanguage, isWelcomeEmail: isWelcomeEmail, languages: availableLanguages, currentLanguage: currentLanguage, onLanguageChange: handleLanguageChange }) }))] }), slashCommand.isOpen && slashCommand.position && (_jsx(SlashCommandMenu, { blocks: slashCommand.filteredBlocks, query: slashCommand.query, selectedIndex: slashCommand.selectedIndex, onSelect: (replaceBlockId) => {
|
|
219
|
-
// Use the replaceBlockId passed from the menu (which comes from state)
|
|
220
|
-
// This ensures we use the correct block ID that was set when the menu opened
|
|
221
|
-
slashCommand.selectCurrent(replaceBlockId);
|
|
222
|
-
}, position: slashCommand.position, onClose: slashCommand.closeMenu, replaceBlockId: slashCommand.replaceBlockId }))] })) }));
|
|
279
|
+
return (_jsx("div", { className: "absolute inset-0 flex flex-col font-sans transition-colors duration-300 overflow-hidden bg-white dark:bg-neutral-950", children: isLoadingLanguage ? (_jsx("div", { className: "h-full w-full flex items-center justify-center", children: _jsxs("div", { className: "text-center", children: [_jsx("div", { className: "w-8 h-8 border-2 border-primary border-t-transparent rounded-full animate-spin mx-auto mb-4" }), _jsx("p", { className: "text-sm text-dashboard-text-secondary", children: "Loading..." })] }) })) : (_jsxs("main", { className: "flex flex-1 flex-col relative min-h-0 overflow-hidden", children: [_jsx(ErrorBanner, { error: saveError, onDismiss: () => setSaveError(null) }), _jsx("div", { className: "flex-none z-30 border-b border-dashboard-border", children: _jsx(EditorHeader, { isPreviewMode: isPreviewMode, onPreviewToggle: () => setIsPreviewMode(!isPreviewMode), isSidebarOpen: isSidebarOpen, onSidebarToggle: () => setSidebarOpen(!isSidebarOpen), isSaving: isSaving, onSave: handleSave, onSaveError: (error) => setSaveError(error || null), isDirty: state.isDirty, isWelcomeEmail: isWelcomeEmail, languages: availableLanguages, currentLanguage: currentLanguage, onLanguageChange: handleLanguageChange, onAddLanguage: handleAddLanguage }) }), _jsxs("div", { className: "flex-1 flex relative overflow-hidden min-h-0 flex-nowrap", children: [_jsx("div", { className: "flex-1 overflow-hidden h-full", children: _jsx(EditorCanvas, { isPreviewMode: isPreviewMode, contentBlocks: state.blocks, title: state.title, siteId: siteId, locale: currentLanguage, darkMode: effectiveDarkMode, backgroundColors: effectiveBackgroundColors, metadata: state.metadata, onTitleChange: (title) => dispatch({ type: 'SET_TITLE', payload: title }), onMetadataChange: (metadata) => dispatch({ type: 'SET_METADATA', payload: metadata }), onBlockAdd: (type, index, containerId) => helpers.addBlock(type, index, containerId), onBlockUpdate: (id, data) => helpers.updateBlock(id, data), onBlockDelete: (id) => helpers.deleteBlock(id), onBlockMove: (id, newIndex, containerId) => helpers.moveBlock(id, newIndex, containerId), slashCommand: slashCommand }) }), !isPreviewMode && (_jsx("aside", { className: `flex-none transition-all duration-500 ease-[cubic-bezier(0.4,0,0.2,1)] border-l border-dashboard-border bg-dashboard-sidebar overflow-y-auto custom-scrollbar h-full ${isSidebarOpen ? 'w-80' : 'w-0 opacity-0 pointer-events-none border-l-0'}`, children: _jsx(EditorSidebar, { metadata: state.metadata, status: state.status, onMetadataUpdate: (metadata) => dispatch({ type: 'SET_METADATA', payload: metadata }), defaultLanguage: primaryLanguage, isWelcomeEmail: isWelcomeEmail, languages: availableLanguages, currentLanguage: currentLanguage, onLanguageChange: handleLanguageChange, globalUnsubscribeText: globalUnsubscribeTranslations[currentLanguage], onGlobalUnsubscribeUpdate: handleGlobalUnsubscribeUpdate }) }))] }), slashCommand.isOpen && slashCommand.position && (_jsx("div", { className: "fixed z-50 transition-all duration-200", style: {
|
|
280
|
+
left: slashCommand.position.left,
|
|
281
|
+
top: slashCommand.position.top
|
|
282
|
+
}, children: _jsx(SlashCommandMenu, { blocks: slashCommand.filteredBlocks, query: slashCommand.query, selectedIndex: slashCommand.selectedIndex, onSelect: (replaceBlockId) => slashCommand.selectCurrent(replaceBlockId), position: slashCommand.position, onClose: slashCommand.closeMenu, replaceBlockId: slashCommand.replaceBlockId }) }))] })) }));
|
|
223
283
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditorBody.d.ts","sourceRoot":"","sources":["../../../src/views/CanvasEditor/EditorBody.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC5B,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,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,KAAK,IAAI,CAAC;IAClE,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,gBAAgB,CAAC,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,4BAA4B;IAC5B,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;CACrD;AAED,wBAAgB,UAAU,CAAC,EACvB,MAAM,EACN,UAAU,EACV,aAAa,EACb,aAAa,EACb,WAAW,EACX,QAAe,EACf,gBAAgB,EAChB,YAAY,GACf,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"EditorBody.d.ts","sourceRoot":"","sources":["../../../src/views/CanvasEditor/EditorBody.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC5B,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,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,KAAK,IAAI,CAAC;IAClE,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,gBAAgB,CAAC,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,4BAA4B;IAC5B,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;CACrD;AAED,wBAAgB,UAAU,CAAC,EACvB,MAAM,EACN,UAAU,EACV,aAAa,EACb,aAAa,EACb,WAAW,EACX,QAAe,EACf,gBAAgB,EAChB,YAAY,GACf,EAAE,eAAe,2CA2DjB"}
|
|
@@ -17,5 +17,5 @@ export function EditorBody({ blocks, onBlockAdd, onBlockUpdate, onBlockDelete, o
|
|
|
17
17
|
}, 0);
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
|
-
return (_jsxs("div", { className: "relative", children: [blocks.map((block, index) => (_jsxs(React.Fragment, { children: [_jsx("div", { className: "relative h-
|
|
20
|
+
return (_jsxs("div", { className: "relative", children: [blocks.map((block, index) => (_jsxs(React.Fragment, { children: [_jsx("div", { className: "relative h-4 group/add-button", children: _jsxs("div", { className: "absolute inset-x-0 top-1/2 -translate-y-1/2 flex items-center justify-center", children: [_jsx("div", { className: "w-full h-[1px] bg-neutral-100 dark:bg-neutral-800 opacity-0 group-hover/add-button:opacity-100 transition-opacity" }), _jsx("button", { onClick: () => onBlockAdd('paragraph', index), className: "mx-4 flex-shrink-0 w-6 h-6 flex items-center justify-center opacity-0 group-hover/add-button:opacity-100 transition-all hover:bg-primary hover:text-white bg-white dark:bg-neutral-800 border border-neutral-200 dark:border-neutral-700 shadow-sm rounded-full z-10", title: "Add block here", children: _jsx(Plus, { size: 14 }) }), _jsx("div", { className: "w-full h-[1px] bg-neutral-100 dark:bg-neutral-800 opacity-0 group-hover/add-button:opacity-100 transition-opacity" })] }) }), _jsx("div", { className: "relative", children: _jsx(BlockWrapper, { block: block, onUpdate: (data) => onBlockUpdate(block.id, data), onDelete: () => handleDelete(block.id, index), onMoveUp: index > 0 ? () => onBlockMove(block.id, index - 1) : undefined, onMoveDown: index < blocks.length - 1 ? () => onBlockMove(block.id, index + 1) : undefined, allBlocks: blocks, slashCommand: slashCommand, blockIndex: index, onAddBlockBelow: (blockType) => onBlockAdd(blockType, index + 1) }) })] }, block.id))), _jsx("div", { className: "relative h-12 mt-4 group/add-bottom", children: _jsx("button", { onClick: () => onBlockAdd('paragraph', blocks.length), className: "absolute left-0 top-1/2 -translate-y-1/2 w-8 h-8 flex items-center justify-center opacity-20 group-hover/add-bottom:opacity-100 hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-full transition-all text-neutral-500", title: "Add block at the end", children: _jsx(Plus, { size: 18 }) }) })] }));
|
|
21
21
|
}
|
|
@@ -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":"AAQA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAsNhE,MAAM,WAAW,iBAAiB;IAC9B,aAAa,EAAE,OAAO,CAAC;IACvB,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,gBAAgB,CAAC,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,kBAAkB,CAAC,KAAK,IAAI,CAAC;IACnE,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,KAAK,IAAI,CAAC;IAClE,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;CACrD;AAED,wBAAgB,YAAY,CAAC,EACzB,aAAa,EACb,aAAa,EACb,KAAK,EACL,MAAM,EACN,MAAM,EACN,QAAQ,EACR,gBAAgB,EAChB,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,aAAa,EACb,WAAW,EACX,YAAY,GACf,EAAE,iBAAiB,2CAoQnB"}
|