astro-tractstack 2.0.17 → 2.0.18

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 (60) hide show
  1. package/dist/index.js +18 -0
  2. package/package.json +1 -1
  3. package/templates/src/components/codehooks/FeaturedArticleSetup.tsx +1 -1
  4. package/templates/src/components/codehooks/ListContentSetup.tsx +1 -1
  5. package/templates/src/components/compositor/Compositor.tsx +1 -0
  6. package/templates/src/components/compositor/Node.tsx +41 -17
  7. package/templates/src/components/compositor/nodes/GhostInsertBlock.tsx +9 -6
  8. package/templates/src/components/compositor/nodes/GridLayout.tsx +124 -0
  9. package/templates/src/components/compositor/nodes/GridLayout_eraser.tsx +33 -0
  10. package/templates/src/components/compositor/nodes/Markdown.tsx +67 -37
  11. package/templates/src/components/compositor/nodes/Markdown_eraser.tsx +56 -0
  12. package/templates/src/components/compositor/preview/FeaturedArticlePreview.tsx +8 -2
  13. package/templates/src/components/edit/PanelSwitch.tsx +232 -75
  14. package/templates/src/components/edit/SettingsPanel.tsx +0 -1
  15. package/templates/src/components/edit/pane/AddPanePanel_codehook.tsx +3 -3
  16. package/templates/src/components/edit/pane/AddPanePanel_new.tsx +167 -145
  17. package/templates/src/components/edit/pane/AddPanePanel_reuse.tsx +2 -2
  18. package/templates/src/components/edit/pane/ConfigPanePanel.tsx +1 -7
  19. package/templates/src/components/edit/pane/PanePanel_impression.tsx +1 -1
  20. package/templates/src/components/edit/pane/RestylePaneModal.tsx +8 -5
  21. package/templates/src/components/edit/pane/steps/AiDesignStep.tsx +6 -6
  22. package/templates/src/components/edit/pane/steps/CopyInputStep.tsx +3 -3
  23. package/templates/src/components/edit/pane/steps/DesignLibraryStep.tsx +4 -4
  24. package/templates/src/components/edit/panels/StyleElementPanel.tsx +11 -4
  25. package/templates/src/components/edit/panels/StyleElementPanel_add.tsx +8 -8
  26. package/templates/src/components/edit/panels/StyleElementPanel_remove.tsx +14 -4
  27. package/templates/src/components/edit/panels/StyleElementPanel_update.tsx +16 -4
  28. package/templates/src/components/edit/panels/StyleImagePanel.tsx +8 -3
  29. package/templates/src/components/edit/panels/StyleImagePanel_add.tsx +9 -2
  30. package/templates/src/components/edit/panels/StyleImagePanel_remove.tsx +5 -2
  31. package/templates/src/components/edit/panels/StyleImagePanel_update.tsx +5 -2
  32. package/templates/src/components/edit/panels/StyleLiElementPanel.tsx +7 -3
  33. package/templates/src/components/edit/panels/StyleLiElementPanel_add.tsx +9 -2
  34. package/templates/src/components/edit/panels/StyleLiElementPanel_remove.tsx +5 -2
  35. package/templates/src/components/edit/panels/StyleLiElementPanel_update.tsx +5 -2
  36. package/templates/src/components/edit/panels/StyleParentPanel.tsx +530 -171
  37. package/templates/src/components/edit/panels/StyleParentPanel_add.tsx +77 -42
  38. package/templates/src/components/edit/panels/StyleParentPanel_deleteLayer.tsx +38 -22
  39. package/templates/src/components/edit/panels/StyleParentPanel_remove.tsx +171 -66
  40. package/templates/src/components/edit/panels/StyleParentPanel_update.tsx +166 -98
  41. package/templates/src/components/edit/panels/StyleWidgetPanel.tsx +7 -3
  42. package/templates/src/components/edit/panels/StyleWidgetPanel_add.tsx +9 -2
  43. package/templates/src/components/edit/panels/StyleWidgetPanel_remove.tsx +5 -2
  44. package/templates/src/components/edit/panels/StyleWidgetPanel_update.tsx +6 -2
  45. package/templates/src/components/edit/state/SaveModal.tsx +10 -2
  46. package/templates/src/components/edit/state/SaveToLibraryModal.tsx +6 -6
  47. package/templates/src/components/fields/PaneBreakShapeSelector.tsx +1 -1
  48. package/templates/src/components/widgets/ImpressionWrapper.tsx +4 -1
  49. package/templates/src/constants/prompts.json +1 -1
  50. package/templates/src/stores/nodes.ts +110 -33
  51. package/templates/src/stores/storykeep.ts +3 -1
  52. package/templates/src/types/compositorTypes.ts +37 -2
  53. package/templates/src/utils/compositor/TemplateNodes.ts +8 -0
  54. package/templates/src/utils/compositor/nodesHelper.ts +229 -0
  55. package/templates/src/utils/compositor/reduceNodesClassNames.ts +40 -1
  56. package/templates/src/utils/compositor/typeGuards.ts +7 -0
  57. package/templates/src/utils/etl/extractor.ts +1 -5
  58. package/templates/src/utils/etl/index.ts +1 -0
  59. package/templates/src/utils/etl/transformer.ts +70 -25
  60. package/utils/inject-files.ts +18 -0
@@ -139,6 +139,8 @@ const AddPaneNewPanel = ({
139
139
  const [copyMode, setCopyMode] = useState<CopyMode>('prompt');
140
140
  const [promptValue, setPromptValue] = useState('');
141
141
  const [copyValue, setCopyValue] = useState('');
142
+ const [selectedLibraryEntry, setSelectedLibraryEntry] =
143
+ useState<DesignLibraryEntry | null>(null);
142
144
  const [aiDesignConfig, setAiDesignConfig] = useState<AiDesignConfig>({
143
145
  harmony: 'Analogous',
144
146
  baseColor: '',
@@ -153,27 +155,31 @@ const AddPaneNewPanel = ({
153
155
 
154
156
  if (choice === 'blank') {
155
157
  handleBlankSlate();
156
- } else {
157
- setStep('copyInput');
158
+ } else if (choice === 'library') {
159
+ setStep('designLibrary');
160
+ } else if (choice === 'ai') {
161
+ setStep('aiDesign');
158
162
  }
159
163
  };
160
164
 
161
165
  const handleBack = () => {
162
166
  setError(null);
163
167
  if (step === 'copyInput') {
164
- setStep('initial');
168
+ if (initialChoice === 'library') {
169
+ setStep('designLibrary');
170
+ } else if (initialChoice === 'ai') {
171
+ setStep('aiDesign');
172
+ } else {
173
+ setStep('initial');
174
+ }
165
175
  } else if (step === 'directInject') {
166
176
  setStep('aiDesign');
167
- } else if (step === 'designLibrary' || step === 'aiDesign' || 'error') {
168
- setStep('copyInput');
169
- }
170
- };
171
-
172
- const handleCopyContinue = () => {
173
- if (initialChoice === 'library') {
174
- setStep('designLibrary');
175
- } else if (initialChoice === 'ai') {
176
- setStep('aiDesign');
177
+ } else if (
178
+ step === 'designLibrary' ||
179
+ step === 'aiDesign' ||
180
+ step === 'error'
181
+ ) {
182
+ setStep('initial');
177
183
  }
178
184
  };
179
185
 
@@ -182,7 +188,7 @@ const AddPaneNewPanel = ({
182
188
  id: '',
183
189
  nodeType: 'Pane',
184
190
  parentId: '',
185
- title: 'New Pane',
191
+ title: '',
186
192
  slug: '',
187
193
  isDecorative: false,
188
194
  markdown: {
@@ -199,130 +205,25 @@ const AddPaneNewPanel = ({
199
205
  handleApplyTemplate(blankTemplate);
200
206
  };
201
207
 
202
- const handleDesignLibrarySelect = async (entry: DesignLibraryEntry) => {
203
- if (copyMode === 'raw') {
204
- const liveTemplate = convertStorageToLiveTemplate(
205
- mergeCopyIntoTemplate(entry.template, [])
206
- );
207
- if (liveTemplate.markdown) {
208
- liveTemplate.markdown.markdownBody = copyValue;
209
- }
210
- handleApplyTemplate(liveTemplate);
211
- return;
212
- }
213
-
214
- if (copyMode === 'prompt') {
215
- setError(null);
216
- setStep('loading');
217
- try {
218
- const liveTemplate = convertStorageToLiveTemplate(entry.template);
219
- if (!liveTemplate.markdown) {
220
- throw new Error(
221
- 'The selected design library item is not compatible with this workflow as it has no markdown section.'
222
- );
223
- }
224
-
225
- const shellJson = convertTemplateToAIShell(liveTemplate);
226
- if (!shellJson || shellJson === '{}') {
227
- throw new Error(
228
- 'Could not generate a valid AI shell from this design.'
229
- );
230
- }
231
-
232
- const copyPromptDetails = prompts.aiPaneCopyPrompt;
233
- const layout = 'Text Only';
234
- const formattedCopyPrompt = copyPromptDetails.user_template
235
- .replace('{{COPY_INPUT}}', promptValue)
236
- .replace(
237
- '{{DESIGN_INPUT}}',
238
- "N/A - Use the provided Shell JSON's design."
239
- )
240
- .replace('{{LAYOUT_TYPE}}', layout)
241
- .replace('{{SHELL_JSON}}', shellJson);
242
-
243
- const copyResult = await callAskLemurAPI(
244
- formattedCopyPrompt,
245
- copyPromptDetails.system || '',
246
- false,
247
- isSandboxMode
248
- );
249
-
250
- const newNodes = parseAiCopyHtml(copyResult, liveTemplate.markdown.id);
251
-
252
- const finalPane = cloneDeep(liveTemplate);
253
-
254
- finalPane.markdown!.nodes = newNodes;
255
-
256
- handleApplyTemplate(finalPane);
257
- } catch (err: any) {
258
- setError(err.message || 'Failed to generate AI copy for this design.');
259
- setStep('error');
260
- }
261
- }
208
+ const handleDesignLibrarySelect = (entry: DesignLibraryEntry) => {
209
+ setSelectedLibraryEntry(entry);
210
+ setStep('copyInput');
262
211
  };
263
212
 
264
- const handleAiDesignGenerate = useCallback(async () => {
265
- setError(null);
266
- setStep('loading');
267
-
268
- let designInput = `Generate a design using a **${aiDesignConfig.harmony.toLowerCase()}** color scheme with a **${aiDesignConfig.theme.toLowerCase()}** theme.`;
269
- if (aiDesignConfig.baseColor)
270
- designInput += ` Base the colors around **${aiDesignConfig.baseColor}**.`;
271
- if (aiDesignConfig.accentColor)
272
- designInput += ` Use **${aiDesignConfig.accentColor}** as an accent color.`;
273
- if (aiDesignConfig.additionalNotes)
274
- designInput += ` Refine with these notes: "${aiDesignConfig.additionalNotes}"`;
275
-
276
- try {
277
- const shellPromptDetails = prompts.aiPaneShellPrompt;
278
- const copyPromptDetails = prompts.aiPaneCopyPrompt;
279
- const layout = 'Text Only';
280
-
281
- const formattedShellPrompt = shellPromptDetails.user_template
282
- .replace('{{DESIGN_INPUT}}', designInput)
283
- .replace('{{LAYOUT_TYPE}}', layout);
284
-
285
- const shellResult = await callAskLemurAPI(
286
- formattedShellPrompt,
287
- shellPromptDetails.system || '',
288
- true,
289
- isSandboxMode
290
- );
291
-
292
- const copyInputContent = copyMode === 'prompt' ? promptValue : copyValue;
293
- const formattedCopyPrompt = copyPromptDetails.user_template
294
- .replace('{{COPY_INPUT}}', copyInputContent)
295
- .replace('{{DESIGN_INPUT}}', designInput)
296
- .replace('{{LAYOUT_TYPE}}', layout)
297
- .replace('{{SHELL_JSON}}', shellResult);
298
-
299
- const copyResult = await callAskLemurAPI(
300
- formattedCopyPrompt,
301
- copyPromptDetails.system || '',
302
- false,
303
- isSandboxMode
304
- );
305
-
306
- const finalPane = parseAiPane(shellResult, copyResult, layout);
307
- handleApplyTemplate(finalPane);
308
- } catch (err: any) {
309
- setError(err.message || 'Failed to generate AI pane.');
310
- setStep('error');
311
- }
312
- }, [aiDesignConfig, copyMode, promptValue, copyValue, isSandboxMode]);
213
+ const handleAiDesignContinue = () => {
214
+ setStep('copyInput');
215
+ };
313
216
 
314
217
  const handleApplyTemplate = async (template: TemplatePane) => {
315
- console.log(template);
316
218
  if (!ctx) return;
317
219
  try {
318
220
  const insertTemplate = cloneDeep(template);
319
- insertTemplate.title = insertTemplate.title || 'New Pane';
320
- insertTemplate.slug = insertTemplate.slug || '';
321
-
322
221
  const ownerId =
323
222
  isStoryFragment || isContextPane
324
223
  ? nodeId
325
224
  : ctx.getClosestNodeTypeFromId(nodeId, 'StoryFragment');
225
+ insertTemplate.title = '';
226
+ insertTemplate.slug = '';
326
227
 
327
228
  if (isContextPane) {
328
229
  insertTemplate.isContextPane = true;
@@ -352,6 +253,127 @@ const AddPaneNewPanel = ({
352
253
  }
353
254
  };
354
255
 
256
+ const handleFinalGenerate = useCallback(async () => {
257
+ setError(null);
258
+ setStep('loading');
259
+
260
+ try {
261
+ if (initialChoice === 'library') {
262
+ if (!selectedLibraryEntry) {
263
+ throw new Error('No design library item was selected.');
264
+ }
265
+
266
+ if (copyMode === 'raw') {
267
+ const liveTemplate = convertStorageToLiveTemplate(
268
+ mergeCopyIntoTemplate(selectedLibraryEntry.template, [])
269
+ );
270
+ if (liveTemplate.markdown) {
271
+ liveTemplate.markdown.markdownBody = copyValue;
272
+ }
273
+ handleApplyTemplate(liveTemplate);
274
+ return;
275
+ }
276
+
277
+ if (copyMode === 'prompt') {
278
+ const liveTemplate = convertStorageToLiveTemplate(
279
+ selectedLibraryEntry.template
280
+ );
281
+ if (!liveTemplate.markdown) {
282
+ throw new Error(
283
+ 'The selected design library item is not compatible with this workflow as it has no markdown section.'
284
+ );
285
+ }
286
+
287
+ const shellJson = convertTemplateToAIShell(liveTemplate);
288
+ if (!shellJson || shellJson === '{}') {
289
+ throw new Error(
290
+ 'Could not generate a valid AI shell from this design.'
291
+ );
292
+ }
293
+
294
+ const copyPromptDetails = prompts.aiPaneCopyPrompt;
295
+ const layout = 'Text Only';
296
+ const formattedCopyPrompt = copyPromptDetails.user_template
297
+ .replace('{{COPY_INPUT}}', promptValue)
298
+ .replace(
299
+ '{{DESIGN_INPUT}}',
300
+ "N/A - Use the provided Shell JSON's design."
301
+ )
302
+ .replace('{{LAYOUT_TYPE}}', layout)
303
+ .replace('{{SHELL_JSON}}', shellJson);
304
+
305
+ const copyResult = await callAskLemurAPI(
306
+ formattedCopyPrompt,
307
+ copyPromptDetails.system || '',
308
+ false,
309
+ isSandboxMode
310
+ );
311
+
312
+ const newNodes = parseAiCopyHtml(
313
+ copyResult,
314
+ liveTemplate.markdown.id
315
+ );
316
+ const finalPane = cloneDeep(liveTemplate);
317
+ finalPane.markdown!.nodes = newNodes;
318
+ handleApplyTemplate(finalPane);
319
+ }
320
+ } else if (initialChoice === 'ai') {
321
+ let designInput = `Generate a design using a **${aiDesignConfig.harmony.toLowerCase()}** color scheme with a **${aiDesignConfig.theme.toLowerCase()}** theme.`;
322
+ if (aiDesignConfig.baseColor)
323
+ designInput += ` Base the colors around **${aiDesignConfig.baseColor}**.`;
324
+ if (aiDesignConfig.accentColor)
325
+ designInput += ` Use **${aiDesignConfig.accentColor}** as an accent color.`;
326
+ if (aiDesignConfig.additionalNotes)
327
+ designInput += ` Refine with these notes: "${aiDesignConfig.additionalNotes}"`;
328
+
329
+ const shellPromptDetails = prompts.aiPaneShellPrompt;
330
+ const copyPromptDetails = prompts.aiPaneCopyPrompt;
331
+ const layout = 'Text Only';
332
+
333
+ const formattedShellPrompt = shellPromptDetails.user_template
334
+ .replace('{{DESIGN_INPUT}}', designInput)
335
+ .replace('{{LAYOUT_TYPE}}', layout);
336
+
337
+ const shellResult = await callAskLemurAPI(
338
+ formattedShellPrompt,
339
+ shellPromptDetails.system || '',
340
+ true,
341
+ isSandboxMode
342
+ );
343
+
344
+ const copyInputContent =
345
+ copyMode === 'prompt' ? promptValue : copyValue;
346
+ const formattedCopyPrompt = copyPromptDetails.user_template
347
+ .replace('{{COPY_INPUT}}', copyInputContent)
348
+ .replace('{{DESIGN_INPUT}}', designInput)
349
+ .replace('{{LAYOUT_TYPE}}', layout)
350
+ .replace('{{SHELL_JSON}}', shellResult);
351
+
352
+ const copyResult = await callAskLemurAPI(
353
+ formattedCopyPrompt,
354
+ copyPromptDetails.system || '',
355
+ false,
356
+ isSandboxMode
357
+ );
358
+
359
+ const finalPane = parseAiPane(shellResult, copyResult, layout);
360
+ handleApplyTemplate(finalPane);
361
+ }
362
+ } catch (err: any) {
363
+ setError(err.message || 'Failed to generate AI pane.');
364
+ setStep('error');
365
+ }
366
+ }, [
367
+ aiDesignConfig,
368
+ copyMode,
369
+ promptValue,
370
+ copyValue,
371
+ isSandboxMode,
372
+ initialChoice,
373
+ selectedLibraryEntry,
374
+ handleApplyTemplate,
375
+ ]);
376
+
355
377
  const renderInitialStep = () => (
356
378
  <div className="p-4">
357
379
  <h3 className="font-action mb-4 text-center text-xl font-bold text-gray-800">
@@ -417,26 +439,15 @@ const AddPaneNewPanel = ({
417
439
  ← Back
418
440
  </button>
419
441
  <button
420
- onClick={handleCopyContinue}
442
+ onClick={handleFinalGenerate}
421
443
  disabled={
422
444
  copyMode === 'prompt' ? !promptValue.trim() : !copyValue.trim()
423
445
  }
424
446
  className="rounded-md bg-cyan-600 px-4 py-2 text-sm font-bold text-white shadow-sm hover:bg-cyan-700 disabled:cursor-not-allowed disabled:bg-gray-400"
425
447
  >
426
- Continue
448
+ Generate Pane
427
449
  </button>
428
450
  </div>
429
- {initialChoice === `ai` && !isSandboxMode && (
430
- <div className="mt-6 text-center text-sm text-gray-600">
431
- ADVANCED:{' '}
432
- <button
433
- onClick={() => setStep('directInject')}
434
- className="font-bold text-cyan-700 underline hover:text-cyan-900 focus:outline-none"
435
- >
436
- Direct Inject
437
- </button>
438
- </div>
439
- )}
440
451
  </div>
441
452
  );
442
453
 
@@ -447,7 +458,7 @@ const AddPaneNewPanel = ({
447
458
  onClick={handleBack}
448
459
  className="rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-bold text-gray-700 shadow-sm hover:bg-gray-50"
449
460
  >
450
- ← Back to Content
461
+ ← Back to Choice
451
462
  </button>
452
463
  </div>
453
464
  <DesignLibraryStep
@@ -472,12 +483,23 @@ const AddPaneNewPanel = ({
472
483
  ← Back
473
484
  </button>
474
485
  <button
475
- onClick={handleAiDesignGenerate}
486
+ onClick={handleAiDesignContinue}
476
487
  className="rounded-md bg-cyan-600 px-4 py-2 text-sm font-bold text-white shadow-sm hover:bg-cyan-700"
477
488
  >
478
- Generate with AI
489
+ Continue
479
490
  </button>
480
491
  </div>
492
+ {initialChoice === `ai` && !isSandboxMode && (
493
+ <div className="mt-6 text-center text-sm text-gray-600">
494
+ ADVANCED:{' '}
495
+ <button
496
+ onClick={() => setStep('directInject')}
497
+ className="font-bold text-cyan-700 underline hover:text-cyan-900 focus:outline-none"
498
+ >
499
+ Direct Inject
500
+ </button>
501
+ </div>
502
+ )}
481
503
  </div>
482
504
  );
483
505
 
@@ -486,7 +508,7 @@ const AddPaneNewPanel = ({
486
508
  );
487
509
 
488
510
  const renderLoading = () => (
489
- <div className="flex min-h-[300px] flex-col items-center justify-center space-y-4 p-6">
511
+ <div className="flex min-h-80 flex-col items-center justify-center space-y-4 p-6">
490
512
  <div className="h-8 w-8 animate-spin rounded-full border-b-2 border-cyan-600"></div>
491
513
  <p className="text-sm text-gray-600">Generating AI Pane...</p>
492
514
  <p className="text-xs text-gray-500">This may take a moment.</p>
@@ -550,7 +572,7 @@ const AddPaneNewPanel = ({
550
572
  </>
551
573
  )}
552
574
  </div>
553
- <div className="min-h-[400px] rounded-md border bg-gray-50">
575
+ <div className="min-h-96 rounded-md border bg-gray-50">
554
576
  {renderStep()}
555
577
  </div>
556
578
  </div>
@@ -310,7 +310,7 @@ const AddPaneReUsePanel = ({
310
310
  <style>{comboboxItemStyles}</style>
311
311
  <div className="w-full rounded-md bg-white p-1.5">
312
312
  <div className="flex flex-wrap items-center gap-2">
313
- <div className="flex min-w-[200px] flex-wrap items-center gap-2">
313
+ <div className="flex min-w-48 flex-wrap items-center gap-2">
314
314
  <button
315
315
  onClick={() => setMode(PaneAddMode.DEFAULT)}
316
316
  className="w-fit flex-none rounded bg-gray-100 px-3 py-1 text-sm text-gray-700 transition-colors hover:bg-gray-200 focus:bg-gray-200"
@@ -323,7 +323,7 @@ const AddPaneReUsePanel = ({
323
323
  </div>
324
324
  </div>
325
325
 
326
- <div className="min-w-[300px] flex-1">
326
+ <div className="min-w-72 flex-1">
327
327
  <Combobox.Root
328
328
  collection={collection}
329
329
  value={[]}
@@ -9,11 +9,7 @@ import {
9
9
  isContextPaneNode,
10
10
  hasBeliefPayload,
11
11
  } from '@/utils/compositor/typeGuards';
12
- import {
13
- settingsPanelStore,
14
- viewportKeyStore,
15
- fullContentMapStore,
16
- } from '@/stores/storykeep';
12
+ import { settingsPanelStore, fullContentMapStore } from '@/stores/storykeep';
17
13
  import { getCtx } from '@/stores/nodes';
18
14
  import PaneTitlePanel from './PanePanel_title';
19
15
  import PaneMagicPathPanel from './PanePanel_path';
@@ -34,8 +30,6 @@ const ConfigPanePanel = ({ nodeId }: ConfigPanePanelProps) => {
34
30
  const isActiveMode =
35
31
  activePaneMode.panel === 'settings' && activePaneMode.paneId === nodeId;
36
32
  const $contentMap = useStore(fullContentMapStore);
37
- const $viewportKey = useStore(viewportKeyStore);
38
- const isMobile = $viewportKey.value === `mobile`;
39
33
 
40
34
  const allNodes = ctx.allNodes.get();
41
35
  const paneNode = allNodes.get(nodeId) as PaneNode;
@@ -200,7 +200,7 @@ const PaneImpressionPanel = ({ nodeId, setMode }: PaneImpressionPanelProps) => {
200
200
  onChange={(e) => handleInputChange('body', e.target.value)}
201
201
  onBlur={handleBlur}
202
202
  placeholder="Enter impression body text"
203
- className={`${commonInputClass} min-h-[100px]`}
203
+ className={`${commonInputClass} min-h-24`}
204
204
  />
205
205
  </div>
206
206
 
@@ -130,7 +130,7 @@ const TemplatePreviewItem = ({
130
130
  )}
131
131
  </div>
132
132
  <div className="p-3">
133
- <h3 className="truncate font-semibold" title={template.title}>
133
+ <h3 className="truncate font-bold" title={template.title}>
134
134
  {template.title}
135
135
  </h3>
136
136
  <p className="text-sm text-gray-600">
@@ -404,9 +404,12 @@ export const RestylePaneModal = ({ config }: RestylePaneModalProps) => {
404
404
  <Portal>
405
405
  <Dialog.Backdrop className="z-103 fixed inset-0 bg-black/70" />
406
406
  <Dialog.Positioner className="z-104 fixed inset-0 flex items-center justify-center">
407
- <Dialog.Content className="flex h-[90vh] w-[90vw] flex-col rounded-lg bg-white shadow-2xl">
407
+ <Dialog.Content
408
+ className="flex flex-col rounded-lg bg-white shadow-2xl"
409
+ style={{ height: '90vw', width: '90vw' }}
410
+ >
408
411
  <header className="flex items-center justify-between border-b p-4">
409
- <Dialog.Title className="text-xl font-semibold">
412
+ <Dialog.Title className="text-xl font-bold">
410
413
  Restyle Pane from Design Library
411
414
  </Dialog.Title>
412
415
  <Dialog.CloseTrigger
@@ -427,7 +430,7 @@ export const RestylePaneModal = ({ config }: RestylePaneModalProps) => {
427
430
  className="w-48"
428
431
  positioning={{ gutter: 4 }}
429
432
  >
430
- <Select.Label className="mb-1 text-sm font-medium">
433
+ <Select.Label className="mb-1 text-sm font-bold">
431
434
  Category
432
435
  </Select.Label>
433
436
  <Select.Control>
@@ -461,7 +464,7 @@ export const RestylePaneModal = ({ config }: RestylePaneModalProps) => {
461
464
  className="flex-1"
462
465
  positioning={{ gutter: 4 }}
463
466
  >
464
- <Combobox.Label className="mb-1 text-sm font-medium">
467
+ <Combobox.Label className="mb-1 text-sm font-bold">
465
468
  Filter by Title
466
469
  </Combobox.Label>
467
470
  <Combobox.Control>
@@ -37,11 +37,11 @@ export const AiDesignStep = ({
37
37
 
38
38
  return (
39
39
  <div className="space-y-6 rounded-lg bg-gray-50 p-4 shadow-inner">
40
- <label className="block text-lg font-semibold text-gray-800">
40
+ <label className="block text-lg font-bold text-gray-800">
41
41
  2. Configure AI Design
42
42
  </label>
43
43
  <div>
44
- <label className="block text-base font-semibold text-gray-800">
44
+ <label className="block text-base font-bold text-gray-800">
45
45
  Color Harmony
46
46
  </label>
47
47
  <div className="mt-2 flex flex-wrap gap-x-4 gap-y-2">
@@ -58,7 +58,7 @@ export const AiDesignStep = ({
58
58
  />
59
59
  <label
60
60
  htmlFor={`harmony-${option}`}
61
- className="text-sm font-medium text-gray-700"
61
+ className="text-sm font-bold text-gray-700"
62
62
  >
63
63
  {option}
64
64
  </label>
@@ -89,7 +89,7 @@ export const AiDesignStep = ({
89
89
  </div>
90
90
 
91
91
  <div>
92
- <label className="block text-base font-semibold text-gray-800">
92
+ <label className="block text-base font-bold text-gray-800">
93
93
  Theme / Mood
94
94
  </label>
95
95
  <div className="mt-2 flex flex-wrap gap-x-4 gap-y-2">
@@ -106,7 +106,7 @@ export const AiDesignStep = ({
106
106
  />
107
107
  <label
108
108
  htmlFor={`theme-${option}`}
109
- className="text-sm font-medium text-gray-700"
109
+ className="text-sm font-bold text-gray-700"
110
110
  >
111
111
  {option}
112
112
  </label>
@@ -118,7 +118,7 @@ export const AiDesignStep = ({
118
118
  <div>
119
119
  <label
120
120
  htmlFor="additional-notes"
121
- className="block text-base font-semibold text-gray-800"
121
+ className="block text-base font-bold text-gray-800"
122
122
  >
123
123
  Additional Design Notes (Optional)
124
124
  </label>
@@ -30,7 +30,7 @@ export const CopyInputStep = ({
30
30
 
31
31
  return (
32
32
  <div className="space-y-4 rounded-lg bg-gray-50 p-4 shadow-inner">
33
- <label className="block text-lg font-semibold text-gray-800">
33
+ <label className="block text-lg font-bold text-gray-800">
34
34
  1. Provide Content
35
35
  </label>
36
36
  <div className="my-2 flex space-x-4">
@@ -46,7 +46,7 @@ export const CopyInputStep = ({
46
46
  />
47
47
  <label
48
48
  htmlFor="copy-prompt-mode"
49
- className="text-sm font-medium text-gray-700"
49
+ className="text-sm font-bold text-gray-700"
50
50
  >
51
51
  Write a prompt
52
52
  </label>
@@ -63,7 +63,7 @@ export const CopyInputStep = ({
63
63
  />
64
64
  <label
65
65
  htmlFor="copy-raw-mode"
66
- className="text-sm font-medium text-gray-700"
66
+ className="text-sm font-bold text-gray-700"
67
67
  >
68
68
  Provide Copy (Markdown)
69
69
  </label>
@@ -139,7 +139,7 @@ const TemplatePreviewItem = ({
139
139
  </div>
140
140
  </div>
141
141
  <div className="flex-grow p-3">
142
- <h3 className="truncate font-semibold" title={title}>
142
+ <h3 className="truncate font-bold" title={title}>
143
143
  {title}
144
144
  </h3>
145
145
  <p className="text-sm capitalize text-gray-600">{category}</p>
@@ -226,7 +226,7 @@ export const DesignLibraryStep = ({
226
226
 
227
227
  return (
228
228
  <div className="flex h-full flex-col space-y-4 rounded-lg bg-gray-50 p-4 shadow-inner">
229
- <label className="block text-lg font-semibold text-gray-800">
229
+ <label className="block text-lg font-bold text-gray-800">
230
230
  2. Choose a Design
231
231
  </label>
232
232
 
@@ -241,7 +241,7 @@ export const DesignLibraryStep = ({
241
241
  className="w-48"
242
242
  positioning={{ gutter: 4 }}
243
243
  >
244
- <Select.Label className="mb-1 text-sm font-medium text-gray-700">
244
+ <Select.Label className="mb-1 text-sm font-bold text-gray-700">
245
245
  Category
246
246
  </Select.Label>
247
247
  <Select.Control>
@@ -280,7 +280,7 @@ export const DesignLibraryStep = ({
280
280
  className="flex-1"
281
281
  positioning={{ gutter: 4 }}
282
282
  >
283
- <Combobox.Label className="mb-1 text-sm font-medium text-gray-700">
283
+ <Combobox.Label className="mb-1 text-sm font-bold text-gray-700">
284
284
  Filter by Title
285
285
  </Combobox.Label>
286
286
  <Combobox.Control>
@@ -5,18 +5,22 @@ import {
5
5
  settingsPanelStore,
6
6
  } from '@/stores/storykeep';
7
7
  import { StylesMemory } from '@/components/edit/state/StylesMemory';
8
- import { isMarkdownPaneFragmentNode } from '@/utils/compositor/typeGuards';
8
+ import {
9
+ isMarkdownPaneFragmentNode,
10
+ isGridLayoutNode,
11
+ } from '@/utils/compositor/typeGuards';
9
12
  import SelectedTailwindClass from '@/components/fields/SelectedTailwindClass';
10
13
  import { tagTitles } from '@/types/compositorTypes';
11
14
  import type {
12
15
  Tag,
13
16
  FlatNode,
14
17
  MarkdownPaneFragmentNode,
18
+ GridLayoutNode,
15
19
  } from '@/types/compositorTypes';
16
20
 
17
- interface StyleElementPanelProps {
21
+ export interface StyleElementPanelProps {
18
22
  node: FlatNode;
19
- parentNode: MarkdownPaneFragmentNode;
23
+ parentNode: MarkdownPaneFragmentNode | GridLayoutNode;
20
24
  onTitleChange?: (title: string) => void;
21
25
  }
22
26
 
@@ -25,7 +29,10 @@ const StyleElementPanel = ({
25
29
  parentNode,
26
30
  onTitleChange,
27
31
  }: StyleElementPanelProps) => {
28
- if (!node?.tagName || !isMarkdownPaneFragmentNode(parentNode)) {
32
+ if (
33
+ !node?.tagName ||
34
+ (!isMarkdownPaneFragmentNode(parentNode) && !isGridLayoutNode(parentNode))
35
+ ) {
29
36
  return null;
30
37
  }
31
38