astro-tractstack 2.2.2 → 2.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/package.json +1 -1
  2. package/templates/src/components/codehooks/BunnyVideoSetup.tsx +0 -1
  3. package/templates/src/components/codehooks/FeaturedArticleSetup.tsx +0 -1
  4. package/templates/src/components/codehooks/ListContentSetup.tsx +0 -1
  5. package/templates/src/components/codehooks/ProductCardSetup.tsx +0 -1
  6. package/templates/src/components/codehooks/ProductGridSetup.tsx +0 -1
  7. package/templates/src/components/compositor/Compositor.tsx +0 -1
  8. package/templates/src/components/compositor/Node.tsx +157 -134
  9. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag.tsx +2 -4
  10. package/templates/src/components/edit/Header.tsx +1 -2
  11. package/templates/src/components/edit/context/ContextPaneConfig_slug.tsx +1 -1
  12. package/templates/src/components/edit/context/ContextPaneConfig_title.tsx +0 -1
  13. package/templates/src/components/edit/pane/AddPanePanel_break.tsx +1 -0
  14. package/templates/src/components/edit/pane/AddPanePanel_new.tsx +8 -12
  15. package/templates/src/components/edit/pane/AddPanePanel_reuse.tsx +9 -6
  16. package/templates/src/components/edit/pane/ConfigPanePanel.tsx +2 -2
  17. package/templates/src/components/edit/pane/PanePanel_impression.tsx +0 -4
  18. package/templates/src/components/edit/pane/PanePanel_path.tsx +0 -1
  19. package/templates/src/components/edit/pane/PanePanel_title.tsx +1 -2
  20. package/templates/src/components/edit/pane/RestylePaneModal.tsx +1 -4
  21. package/templates/src/components/edit/pane/steps/AiCreativeDesignStep.tsx +0 -3
  22. package/templates/src/components/edit/pane/steps/AiRefineDesignStep.tsx +2 -2
  23. package/templates/src/components/edit/pane/steps/AiStandardDesignStep.tsx +173 -80
  24. package/templates/src/components/edit/pane/steps/CreativeInjectStep.tsx +0 -5
  25. package/templates/src/components/edit/pane/steps/DesignLibraryStep.tsx +2 -1
  26. package/templates/src/components/edit/panels/StyleBreakPanel.tsx +1 -4
  27. package/templates/src/components/edit/panels/StyleCodeHookPanel.tsx +0 -1
  28. package/templates/src/components/edit/panels/StyleElementPanel.tsx +1 -1
  29. package/templates/src/components/edit/panels/StyleElementPanel_remove.tsx +1 -4
  30. package/templates/src/components/edit/panels/StyleElementPanel_update.tsx +3 -3
  31. package/templates/src/components/edit/panels/StyleImagePanel.tsx +3 -3
  32. package/templates/src/components/edit/panels/StyleImagePanel_remove.tsx +1 -4
  33. package/templates/src/components/edit/panels/StyleImagePanel_update.tsx +3 -4
  34. package/templates/src/components/edit/panels/StyleLiElementPanel_remove.tsx +1 -4
  35. package/templates/src/components/edit/panels/StyleLiElementPanel_update.tsx +3 -3
  36. package/templates/src/components/edit/panels/StyleLinkPanel.tsx +1 -1
  37. package/templates/src/components/edit/panels/StyleLinkPanel_config.tsx +1 -1
  38. package/templates/src/components/edit/panels/StyleLinkPanel_remove.tsx +1 -1
  39. package/templates/src/components/edit/panels/StyleLinkPanel_update.tsx +1 -1
  40. package/templates/src/components/edit/panels/StyleParentPanel.tsx +0 -7
  41. package/templates/src/components/edit/panels/StyleParentPanel_deleteLayer.tsx +0 -2
  42. package/templates/src/components/edit/panels/StyleParentPanel_remove.tsx +0 -2
  43. package/templates/src/components/edit/panels/StyleParentPanel_update.tsx +0 -2
  44. package/templates/src/components/edit/panels/StyleWidgetPanel_config.tsx +0 -3
  45. package/templates/src/components/edit/panels/StyleWidgetPanel_remove.tsx +1 -4
  46. package/templates/src/components/edit/panels/StyleWidgetPanel_update.tsx +3 -4
  47. package/templates/src/components/edit/panels/StyleWordCarouselPanel.tsx +0 -2
  48. package/templates/src/components/edit/state/StylesMemory.tsx +3 -9
  49. package/templates/src/components/edit/storyfragment/StoryFragmentConfigPanel.tsx +0 -1
  50. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_menu.tsx +0 -2
  51. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_og.tsx +0 -2
  52. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_slug.tsx +0 -1
  53. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_title.tsx +0 -1
  54. package/templates/src/components/fields/ArtpackImage.tsx +0 -7
  55. package/templates/src/components/fields/BackgroundImage.tsx +0 -14
  56. package/templates/src/components/fields/BackgroundImageWrapper.tsx +0 -5
  57. package/templates/src/components/fields/ImageUpload.tsx +0 -3
  58. package/templates/src/pages/[...slug]/edit.astro +0 -1
  59. package/templates/src/pages/api/auth/logout.ts +9 -20
  60. package/templates/src/pages/sandbox.astro +0 -1
  61. package/templates/src/stores/nodes.ts +278 -312
  62. package/templates/src/stores/nodesHistory.ts +59 -24
  63. package/templates/src/utils/api/setupHelpers.ts +1 -1
  64. package/templates/src/utils/compositor/aiPaneParser.ts +57 -0
  65. package/templates/src/utils/compositor/designLibraryHelper.ts +1 -3
  66. package/templates/src/utils/compositor/htmlAst.ts +109 -2
  67. package/templates/src/utils/compositor/nodesHelper.ts +1 -9
  68. package/templates/src/utils/compositor/savePipeline.ts +1 -4
@@ -4,7 +4,7 @@ import CheckIcon from '@heroicons/react/24/outline/CheckIcon';
4
4
  import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon';
5
5
  import ArrowPathRoundedSquareIcon from '@heroicons/react/24/outline/ArrowPathRoundedSquareIcon';
6
6
  import prompts from '@/constants/prompts.json';
7
- import { htmlToHtmlAst } from '@/utils/compositor/htmlAst';
7
+ import { htmlToHtmlAst, cleanHtml } from '@/utils/compositor/htmlAst';
8
8
  import { callAskLemurAPI } from '@/utils/compositor/aiGeneration';
9
9
  import type { TemplatePane } from '@/types/compositorTypes';
10
10
 
@@ -51,7 +51,7 @@ export const AiRefineDesignStep = ({
51
51
 
52
52
  userPrompt = userPrompt.replace('{{DESIGN_NOTES}}', prompt);
53
53
  userPrompt = userPrompt.replace('{{CSS_INPUT}}', initialCss);
54
- userPrompt = userPrompt.replace('{{HTML_INPUT}}', initialHtml);
54
+ userPrompt = userPrompt.replace('{{HTML_INPUT}}', cleanHtml(initialHtml));
55
55
 
56
56
  // 1. Get RAW output from AI
57
57
  const resultHtml = await callAskLemurAPI({
@@ -1,7 +1,11 @@
1
1
  import { useState, useCallback, useMemo, useEffect } from 'react';
2
2
  import prompts from '@/constants/prompts.json';
3
- import { parseAiPane } from '@/utils/compositor/aiPaneParser';
3
+ import {
4
+ parseAiPane,
5
+ createDefaultShell,
6
+ } from '@/utils/compositor/aiPaneParser';
4
7
  import { callAskLemurAPI } from '@/utils/compositor/aiGeneration';
8
+ import { markdownToHtml } from '@/utils/compositor/htmlAst';
5
9
  import { CopyInputStep, type CopyMode } from './CopyInputStep';
6
10
  import { AiDesignStep, type AiDesignConfig } from './AiDesignStep';
7
11
  import BooleanToggle from '@/components/form/BooleanToggle';
@@ -43,10 +47,13 @@ export const AiStandardDesignStep = ({
43
47
  const [col1Copy, setCol1Copy] = useState('');
44
48
  const [col2Copy, setCol2Copy] = useState('');
45
49
 
50
+ // Prompts State
46
51
  const [masterShellSystem, setMasterShellSystem] = useState('');
47
52
  const [masterShellUser, setMasterShellUser] = useState('');
48
53
  const [masterCopySystem, setMasterCopySystem] = useState('');
49
54
  const [masterCopyUser, setMasterCopyUser] = useState('');
55
+ const [masterStyleSystem, setMasterStyleSystem] = useState('');
56
+ const [masterStyleUser, setMasterStyleUser] = useState('');
50
57
 
51
58
  const [aiDesignConfig, setAiDesignConfig] = useState<AiDesignConfig>({
52
59
  harmony: 'Analogous',
@@ -75,6 +82,7 @@ export const AiStandardDesignStep = ({
75
82
  }
76
83
  }, [promptOptions, selectedPromptId]);
77
84
 
85
+ // Load Prompt Templates
78
86
  useEffect(() => {
79
87
  if (!selectedPromptId) return;
80
88
 
@@ -85,8 +93,11 @@ export const AiStandardDesignStep = ({
85
93
 
86
94
  const promptKey = activeConfig.prompts.copy;
87
95
  const shellKey = activeConfig.prompts.shell;
96
+ const styleKey = activeConfig.prompts.style; // New: Load style prompt key
97
+
88
98
  const copyPromptGroup = (prompts as any)[promptKey];
89
99
  const shellPromptGroup = (prompts as any)[shellKey];
100
+ const stylePromptGroup = (prompts as any)[styleKey];
90
101
 
91
102
  if (shellPromptGroup) {
92
103
  setMasterShellSystem(shellPromptGroup.system || '');
@@ -96,6 +107,10 @@ export const AiStandardDesignStep = ({
96
107
  setMasterCopySystem(copyPromptGroup.system || '');
97
108
  setMasterCopyUser(copyPromptGroup.user_template || '');
98
109
  }
110
+ if (stylePromptGroup) {
111
+ setMasterStyleSystem(stylePromptGroup.system || '');
112
+ setMasterStyleUser(stylePromptGroup.user_template || '');
113
+ }
99
114
 
100
115
  if (!copyPromptGroup) return;
101
116
 
@@ -126,65 +141,128 @@ export const AiStandardDesignStep = ({
126
141
  );
127
142
  if (!activeConfig) throw new Error('Selected prompt type not found.');
128
143
 
129
- let designInput = `Generate a design using a **${aiDesignConfig.harmony.toLowerCase()}** color scheme with a **${aiDesignConfig.theme.toLowerCase()}** theme.`;
130
- if (aiDesignConfig.baseColor)
131
- designInput += ` Base the colors around **${aiDesignConfig.baseColor}**.`;
132
- if (aiDesignConfig.accentColor)
133
- designInput += ` Use **${aiDesignConfig.accentColor}** as an accent color.`;
134
- if (additionalNotes)
135
- designInput += ` Refine with these notes: "${additionalNotes}"`;
136
-
137
144
  const layoutType = 'Text Only';
138
145
  const promptMap = prompts as any;
139
146
 
140
- const injectTopic = (text: string) => {
141
- return text.replace('{{TOPIC}}', topic.trim());
142
- };
143
-
144
- let formattedShellPrompt = masterShellUser
145
- .replace('{{DESIGN_INPUT}}', designInput)
146
- .replace('{{LAYOUT_TYPE}}', layoutType);
147
+ // --- 1. Shell Generation ---
148
+ let shellResult = '';
147
149
 
148
- if (layoutChoice === 'grid') {
149
- const finalOverallPrompt = injectTopic(overallPrompt);
150
- formattedShellPrompt = formattedShellPrompt.replace(
151
- '{{COPY_INPUT}}',
152
- finalOverallPrompt
153
- );
154
- }
155
-
156
- const shellResult = await callAskLemurAPI({
157
- prompt: formattedShellPrompt,
158
- context: masterShellSystem,
159
- expectJson: true,
160
- isSandboxMode,
161
- });
150
+ if (isAiStyling) {
151
+ // AI Path: Generate Shell via AskLemur
152
+ let designInput = `Generate a design using a **${aiDesignConfig.harmony.toLowerCase()}** color scheme with a **${aiDesignConfig.theme.toLowerCase()}** theme.`;
153
+ if (aiDesignConfig.baseColor)
154
+ designInput += ` Base the colors around **${aiDesignConfig.baseColor}**.`;
155
+ if (aiDesignConfig.accentColor)
156
+ designInput += ` Use **${aiDesignConfig.accentColor}** as an accent color.`;
157
+ if (additionalNotes)
158
+ designInput += ` Refine with these notes: "${additionalNotes}"`;
162
159
 
163
- if (layoutChoice === 'standard') {
164
- const copyInputContent =
165
- copyMode === 'prompt' ? injectTopic(promptValue) : copyValue;
160
+ const injectTopic = (text: string) => {
161
+ return text.replace('{{TOPIC}}', topic.trim());
162
+ };
166
163
 
167
- const formattedCopyPrompt = masterCopyUser
168
- .replace('{{COPY_INPUT}}', copyInputContent)
164
+ let formattedShellPrompt = masterShellUser
169
165
  .replace('{{DESIGN_INPUT}}', designInput)
170
- .replace('{{LAYOUT_TYPE}}', layoutType)
171
- .replace('{{SHELL_JSON}}', shellResult);
166
+ .replace('{{LAYOUT_TYPE}}', layoutType);
167
+
168
+ if (layoutChoice === 'grid') {
169
+ const finalOverallPrompt = injectTopic(overallPrompt);
170
+ formattedShellPrompt = formattedShellPrompt.replace(
171
+ '{{COPY_INPUT}}',
172
+ finalOverallPrompt
173
+ );
174
+ }
172
175
 
173
- const copyResult = await callAskLemurAPI({
174
- prompt: formattedCopyPrompt,
175
- context: masterCopySystem,
176
- expectJson: false,
176
+ shellResult = await callAskLemurAPI({
177
+ prompt: formattedShellPrompt,
178
+ context: masterShellSystem,
179
+ expectJson: true,
177
180
  isSandboxMode,
178
181
  });
182
+ } else {
183
+ // No AI Path: Use Default Shell
184
+ shellResult = JSON.stringify(createDefaultShell(layoutChoice));
185
+ }
186
+
187
+ const designInputForCopy = isAiStyling
188
+ ? `Using a **${aiDesignConfig.harmony.toLowerCase()}** color scheme.`
189
+ : 'Use the provided default classes.';
190
+
191
+ // --- 2. Content Generation ---
192
+ if (layoutChoice === 'standard') {
193
+ let finalHtml = '';
194
+
195
+ if (copyMode === 'prompt') {
196
+ // A. Prompt Mode: AI writes copy
197
+ const injectTopic = (text: string) =>
198
+ text.replace('{{TOPIC}}', topic.trim());
199
+ const copyInputContent = injectTopic(promptValue);
200
+
201
+ const formattedCopyPrompt = masterCopyUser
202
+ .replace('{{COPY_INPUT}}', copyInputContent)
203
+ .replace('{{DESIGN_INPUT}}', designInputForCopy)
204
+ .replace('{{LAYOUT_TYPE}}', layoutType)
205
+ .replace('{{SHELL_JSON}}', shellResult);
206
+
207
+ finalHtml = await callAskLemurAPI({
208
+ prompt: formattedCopyPrompt,
209
+ context: masterCopySystem,
210
+ expectJson: false,
211
+ isSandboxMode,
212
+ });
213
+ } else {
214
+ // B. Raw Mode: User provided markdown
215
+ if (isAiStyling) {
216
+ // Style with AI: Use the 'style' prompt to format markdown
217
+ const formattedStylePrompt = masterStyleUser
218
+ .replace('{{SHELL_JSON}}', shellResult)
219
+ .replace('{{COPY_INPUT}}', copyValue);
220
+
221
+ finalHtml = await callAskLemurAPI({
222
+ prompt: formattedStylePrompt,
223
+ context: masterStyleSystem,
224
+ expectJson: false,
225
+ isSandboxMode,
226
+ });
227
+ } else {
228
+ // No AI: Local conversion
229
+ finalHtml = markdownToHtml(copyValue);
230
+ }
231
+ }
179
232
 
180
- const finalPane = parseAiPane(shellResult, copyResult, layoutType);
233
+ const finalPane = parseAiPane(shellResult, finalHtml, layoutType);
181
234
  onCreatePane(finalPane);
182
235
  } else if (layoutChoice === 'grid') {
236
+ // --- Grid Layout Path ---
183
237
  if (copyMode === 'raw') {
238
+ // B. Raw Mode (Grid)
184
239
  const rawContents = [col1Copy, col2Copy];
185
- const finalPane = parseAiPane(shellResult, rawContents, layoutType);
240
+ let finalContents: string[] = [];
241
+
242
+ if (isAiStyling) {
243
+ // Style with AI: Loop through columns and style each
244
+ for (const content of rawContents) {
245
+ const formattedStylePrompt = masterStyleUser
246
+ .replace('{{SHELL_JSON}}', shellResult)
247
+ .replace('{{COPY_INPUT}}', content);
248
+
249
+ const styledHtml = await callAskLemurAPI({
250
+ prompt: formattedStylePrompt,
251
+ context: masterStyleSystem,
252
+ expectJson: false,
253
+ isSandboxMode,
254
+ });
255
+ finalContents.push(styledHtml);
256
+ }
257
+ } else {
258
+ // No AI: Local conversion
259
+ finalContents = rawContents.map(markdownToHtml);
260
+ }
261
+
262
+ const finalPane = parseAiPane(shellResult, finalContents, layoutType);
186
263
  onCreatePane(finalPane);
187
264
  } else {
265
+ // A. Prompt Mode (Grid): AI writes copy
188
266
  const copyPromptKey = activeConfig.prompts.copy;
189
267
  const copyPromptDetails = promptMap[copyPromptKey];
190
268
  const preset =
@@ -192,6 +270,9 @@ export const AiStandardDesignStep = ({
192
270
  copyPromptDetails.presets?.heroDefault;
193
271
  const copyResults: string[] = [];
194
272
 
273
+ const injectTopic = (text: string) =>
274
+ text.replace('{{TOPIC}}', topic.trim());
275
+
195
276
  const promptsToRun = [
196
277
  { prompt: promptValueCol1, presetKey: 'left' as ColumnPresetKey },
197
278
  { prompt: promptValueCol2, presetKey: 'right' as ColumnPresetKey },
@@ -204,7 +285,7 @@ export const AiStandardDesignStep = ({
204
285
  .replace('{{SHELL_JSON}}', shellResult)
205
286
  .replace('{{COPY_INPUT}}', injectTopic(overallPrompt))
206
287
  .replace('{{COLUMN_PROMPT}}', item.prompt)
207
- .replace('{{DESIGN_INPUT}}', designInput)
288
+ .replace('{{DESIGN_INPUT}}', designInputForCopy)
208
289
  .replace('{{LAYOUT_TYPE}}', layoutType)
209
290
  .replace('{{COLUMN_EXAMPLE}}', columnPreset.example);
210
291
 
@@ -245,16 +326,25 @@ export const AiStandardDesignStep = ({
245
326
  masterShellSystem,
246
327
  masterCopyUser,
247
328
  masterCopySystem,
329
+ masterStyleUser,
330
+ masterStyleSystem,
248
331
  topic,
332
+ isAiStyling, // Added dependency
249
333
  ]);
250
334
 
251
335
  if (isGenerating) {
252
336
  return (
253
337
  <div className="flex min-h-96 flex-col items-center justify-center space-y-4 p-6">
254
338
  <div className="h-8 w-8 animate-spin rounded-full border-b-2 border-cyan-600"></div>
255
- <p className="text-sm text-gray-600">Generating Design & Content...</p>
339
+ <p className="text-sm text-gray-600">
340
+ {isAiStyling
341
+ ? 'Generating Design & Content...'
342
+ : 'Processing Content...'}
343
+ </p>
256
344
  <p className="text-xs text-gray-500">
257
- Creating a unique layout from scratch.
345
+ {isAiStyling
346
+ ? 'Creating a unique layout from scratch.'
347
+ : 'Applying standard formatting.'}
258
348
  </p>
259
349
  </div>
260
350
  );
@@ -301,42 +391,45 @@ export const AiStandardDesignStep = ({
301
391
  masterCopyUser={masterCopyUser}
302
392
  setMasterCopyUser={setMasterCopyUser}
303
393
  >
304
- <div className="border-t pt-4">
305
- <div>
306
- <label
307
- htmlFor="dashboard-notes"
308
- className="block text-sm font-bold text-gray-700"
309
- >
310
- Design Notes
311
- </label>
312
- <textarea
313
- id="dashboard-notes"
314
- rows={2}
315
- className="mt-1 block w-full rounded-md border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
316
- placeholder="e.g. Clean, minimal, high contrast..."
317
- value={additionalNotes}
318
- onChange={(e) => setAdditionalNotes(e.target.value)}
319
- />
320
- </div>
321
-
322
- <div className="my-4 flex items-center">
323
- <BooleanToggle
324
- label="Customize Colors"
325
- value={showColors}
326
- onChange={setShowColors}
327
- size="sm"
328
- />
329
- </div>
394
+ {/* Style config is only relevant if AI Styling is ON */}
395
+ {isAiStyling && (
396
+ <div className="border-t pt-4">
397
+ <div>
398
+ <label
399
+ htmlFor="dashboard-notes"
400
+ className="block text-sm font-bold text-gray-700"
401
+ >
402
+ Design Notes
403
+ </label>
404
+ <textarea
405
+ id="dashboard-notes"
406
+ rows={2}
407
+ className="mt-1 block w-full rounded-md border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
408
+ placeholder="e.g. Clean, minimal, high contrast..."
409
+ value={additionalNotes}
410
+ onChange={(e) => setAdditionalNotes(e.target.value)}
411
+ />
412
+ </div>
330
413
 
331
- {showColors && (
332
- <div className="rounded-lg border border-gray-100 bg-gray-50 p-4">
333
- <AiDesignStep
334
- designConfig={aiDesignConfig}
335
- onDesignConfigChange={setAiDesignConfig}
414
+ <div className="my-4 flex items-center">
415
+ <BooleanToggle
416
+ label="Customize Colors"
417
+ value={showColors}
418
+ onChange={setShowColors}
419
+ size="sm"
336
420
  />
337
421
  </div>
338
- )}
339
- </div>
422
+
423
+ {showColors && (
424
+ <div className="rounded-lg border border-gray-100 bg-gray-50 p-4">
425
+ <AiDesignStep
426
+ designConfig={aiDesignConfig}
427
+ onDesignConfigChange={setAiDesignConfig}
428
+ />
429
+ </div>
430
+ )}
431
+ </div>
432
+ )}
340
433
  </CopyInputStep>
341
434
 
342
435
  {error && (
@@ -363,7 +456,7 @@ export const AiStandardDesignStep = ({
363
456
  }
364
457
  className="rounded-md bg-cyan-600 px-6 py-2 text-sm font-bold text-white shadow-sm hover:bg-cyan-700 disabled:cursor-not-allowed disabled:bg-gray-400"
365
458
  >
366
- ✨ Generate Pane
459
+ {isAiStyling ? '✨ Generate Pane' : 'Create Pane'}
367
460
  </button>
368
461
  </div>
369
462
  </div>
@@ -1,5 +1,4 @@
1
1
  import { useState } from 'react';
2
- import { getCtx } from '@/stores/nodes';
3
2
  import { htmlToHtmlAst } from '@/utils/compositor/htmlAst';
4
3
  import type { TemplatePane } from '@/types/compositorTypes';
5
4
 
@@ -28,7 +27,6 @@ export const CreativeInjectStep = ({
28
27
 
29
28
  try {
30
29
  const htmlAst = await htmlToHtmlAst(html, css);
31
-
32
30
  const template: TemplatePane = {
33
31
  id: '',
34
32
  nodeType: 'Pane',
@@ -48,10 +46,7 @@ export const CreativeInjectStep = ({
48
46
  nodes: [],
49
47
  },
50
48
  };
51
-
52
49
  onCreatePane(template);
53
- const ctx = getCtx();
54
- ctx.showSaveBypass.set(true);
55
50
  } catch (err: any) {
56
51
  console.error('Compiler Error:', err);
57
52
  setError(`Compilation failed: ${err.message}`);
@@ -56,8 +56,9 @@ const TemplatePreviewItem = ({
56
56
  );
57
57
 
58
58
  const fragmentRequest = useMemo((): PanePreviewRequest[] => {
59
- // This preview logic is correct: it creates a *temporary* context.
59
+ // This preview logic creates a *temporary* context.
60
60
  const ctx = new NodesContext();
61
+ ctx.isTemplate.set(true);
61
62
  ctx.addNode(createEmptyStorykeep('tmp'));
62
63
  ctx.addTemplatePane('tmp', liveTemplate);
63
64
  return [{ id: liveTemplate.id, ctx }];
@@ -104,10 +104,7 @@ const StyleBreakPanel = ({ node, parentNode }: BasePanelProps) => {
104
104
  }
105
105
  });
106
106
 
107
- const updatedNodes = [
108
- { ...breakNode, isChanged: true },
109
- { ...paneNode, isChanged: true },
110
- ];
107
+ const updatedNodes = [{ ...breakNode }, { ...paneNode }];
111
108
  ctx.modifyNodes(updatedNodes);
112
109
  }, [settings, node, parentNode, ctx, allNodes]);
113
110
 
@@ -64,7 +64,6 @@ const StyleCodeHookPanel = ({
64
64
  codeHookPayload: {
65
65
  options: JSON.stringify(options),
66
66
  },
67
- isChanged: true,
68
67
  };
69
68
  ctx.modifyNodes([updatedNode]);
70
69
  },
@@ -215,7 +215,7 @@ const StyleElementPanel = ({
215
215
  ...preset,
216
216
  };
217
217
 
218
- ctx.modifyNodes([{ ...targetNode, isChanged: true }]);
218
+ ctx.modifyNodes([{ ...targetNode }]);
219
219
 
220
220
  setShowPresets(false);
221
221
  };
@@ -100,10 +100,7 @@ const StyleElementRemovePanel = ({
100
100
  }
101
101
  }
102
102
 
103
- ctx.modifyNodes([
104
- { ...elementNode, isChanged: true },
105
- { ...markdownNode, isChanged: true },
106
- ]);
103
+ ctx.modifyNodes([{ ...elementNode }, { ...markdownNode }]);
107
104
  resetStore();
108
105
  };
109
106
 
@@ -131,7 +131,7 @@ const StyleElementUpdatePanel = ({
131
131
  break;
132
132
  }
133
133
 
134
- ctx.modifyNodes([{ ...elementNode, isChanged: true }]);
134
+ ctx.modifyNodes([{ ...elementNode }]);
135
135
  } else {
136
136
  // Update default classes
137
137
  const markdownNode = cloneDeep(
@@ -170,7 +170,7 @@ const StyleElementUpdatePanel = ({
170
170
  break;
171
171
  }
172
172
 
173
- ctx.modifyNodes([{ ...markdownNode, isChanged: true }]);
173
+ ctx.modifyNodes([{ ...markdownNode }]);
174
174
  }
175
175
 
176
176
  setPendingUpdate(null);
@@ -251,7 +251,7 @@ const StyleElementUpdatePanel = ({
251
251
  }
252
252
  }
253
253
 
254
- ctx.modifyNodes([{ ...elementNode, isChanged: true }]);
254
+ ctx.modifyNodes([{ ...elementNode }]);
255
255
  setIsOverridden(checked);
256
256
  },
257
257
  [node, className, parentNode]
@@ -269,7 +269,7 @@ const StyleImagePanel = ({
269
269
  const imgNode = cloneDeep(allNodes.get(node.id)) as FlatNode;
270
270
  if (!imgNode) return;
271
271
  imgNode.alt = newAlt;
272
- ctx.modifyNodes([{ ...imgNode, isChanged: true }]);
272
+ ctx.modifyNodes([{ ...imgNode }]);
273
273
  };
274
274
 
275
275
  const handleImageUpdate = (params: ImageParams) => {
@@ -285,7 +285,7 @@ const StyleImagePanel = ({
285
285
  params.altDescription || '!!This is requires a description!!'
286
286
  );
287
287
  if (params.srcSet) imgNode.srcSet = params.srcSet;
288
- ctx.modifyNodes([{ ...imgNode, isChanged: true }]);
288
+ ctx.modifyNodes([{ ...imgNode }]);
289
289
  };
290
290
 
291
291
  const handleImageRemove = () => {
@@ -297,7 +297,7 @@ const StyleImagePanel = ({
297
297
  imgNode.src = `/static.jpg`;
298
298
  if (typeof imgNode.srcSet === `string`) delete imgNode.srcSet;
299
299
  imgNode.alt = `This is a placeholder for an image that hasn't yet been uploaded`;
300
- ctx.modifyNodes([{ ...imgNode, isChanged: true }]);
300
+ ctx.modifyNodes([{ ...imgNode }]);
301
301
  };
302
302
 
303
303
  if (
@@ -109,10 +109,7 @@ const StyleImageRemovePanel = ({
109
109
  }
110
110
  }
111
111
 
112
- ctx.modifyNodes([
113
- { ...targetNode, isChanged: true },
114
- { ...parentNodeClone, isChanged: true },
115
- ]);
112
+ ctx.modifyNodes([{ ...targetNode }, { ...parentNodeClone }]);
116
113
  resetStore();
117
114
  };
118
115
 
@@ -18,7 +18,6 @@ const StyleImageUpdatePanel = ({
18
18
  node,
19
19
  parentNode,
20
20
  className,
21
- config,
22
21
  childId,
23
22
  }: BasePanelProps) => {
24
23
  if (
@@ -119,7 +118,7 @@ const StyleImageUpdatePanel = ({
119
118
  break;
120
119
  }
121
120
 
122
- ctx.modifyNodes([{ ...targetNode, isChanged: true }]);
121
+ ctx.modifyNodes([{ ...targetNode }]);
123
122
  } else {
124
123
  const markdownNode = cloneDeep(
125
124
  allNodes.get(parentNode.id)
@@ -158,7 +157,7 @@ const StyleImageUpdatePanel = ({
158
157
  break;
159
158
  }
160
159
 
161
- ctx.modifyNodes([{ ...markdownNode, isChanged: true }]);
160
+ ctx.modifyNodes([{ ...markdownNode }]);
162
161
  }
163
162
 
164
163
  setPendingUpdate(null);
@@ -240,7 +239,7 @@ const StyleImageUpdatePanel = ({
240
239
  }
241
240
  }
242
241
 
243
- ctx.modifyNodes([{ ...targetNode, isChanged: true }]);
242
+ ctx.modifyNodes([{ ...targetNode }]);
244
243
  setIsOverridden(checked);
245
244
  },
246
245
  [node, className, parentNode, childId, isImage]
@@ -88,10 +88,7 @@ const StyleLiElementRemovePanel = ({
88
88
  }
89
89
  }
90
90
 
91
- ctx.modifyNodes([
92
- { ...elementNode, isChanged: true },
93
- { ...markdownNode, isChanged: true },
94
- ]);
91
+ ctx.modifyNodes([{ ...elementNode }, { ...markdownNode }]);
95
92
  resetStore();
96
93
  };
97
94
 
@@ -115,7 +115,7 @@ const StyleLiElementUpdatePanel = ({
115
115
  break;
116
116
  }
117
117
 
118
- ctx.modifyNodes([{ ...targetNode, isChanged: true }]);
118
+ ctx.modifyNodes([{ ...targetNode }]);
119
119
  } else {
120
120
  const markdownNode = cloneDeep(
121
121
  allNodes.get(parentNode.id)
@@ -150,7 +150,7 @@ const StyleLiElementUpdatePanel = ({
150
150
  break;
151
151
  }
152
152
 
153
- ctx.modifyNodes([{ ...markdownNode, isChanged: true }]);
153
+ ctx.modifyNodes([{ ...markdownNode }]);
154
154
  }
155
155
 
156
156
  setPendingUpdate(null);
@@ -240,7 +240,7 @@ const StyleLiElementUpdatePanel = ({
240
240
  }
241
241
  }
242
242
 
243
- ctx.modifyNodes([{ ...targetNode, isChanged: true }]);
243
+ ctx.modifyNodes([{ ...targetNode }]);
244
244
  setIsOverridden(checked);
245
245
  },
246
246
  [node, className, parentNode, childId, isContainer]
@@ -256,7 +256,7 @@ const StyleLinkPanel = ({ node }: BasePanelProps) => {
256
256
  callbackPayload: linkNode.buttonPayload?.callbackPayload || '',
257
257
  };
258
258
 
259
- ctx.modifyNodes([{ ...linkNode, isChanged: true }]);
259
+ ctx.modifyNodes([{ ...linkNode }]);
260
260
 
261
261
  settingsPanelStore.set({
262
262
  action: 'style-link',
@@ -109,7 +109,7 @@ const StyleLinkConfigPanel = ({ node }: StyleLinkConfigPanelProps) => {
109
109
  });
110
110
  }
111
111
 
112
- ctx.modifyNodes([{ ...linkNode, isChanged: true }]);
112
+ ctx.modifyNodes([{ ...linkNode }]);
113
113
  } catch (error) {
114
114
  console.error('Error in updateNode:', error);
115
115
  }
@@ -48,7 +48,7 @@ const StyleLinkRemovePanel = ({ node, className }: BasePanelProps) => {
48
48
  delete linkNode.buttonPayload.buttonClasses[className];
49
49
  }
50
50
  }
51
- ctx.modifyNodes([{ ...linkNode, isChanged: true }]);
51
+ ctx.modifyNodes([{ ...linkNode }]);
52
52
  resetStore();
53
53
  };
54
54
 
@@ -73,7 +73,7 @@ const StyleLinkUpdatePanel = ({ node, className }: BasePanelProps) => {
73
73
  };
74
74
  }
75
75
  setValue(newValue);
76
- ctx.modifyNodes([{ ...linkNode, isChanged: true }]);
76
+ ctx.modifyNodes([{ ...linkNode }]);
77
77
  },
78
78
  [node, className, isHoverMode]
79
79
  );