astro-tractstack 2.1.3 → 2.2.0

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 (128) hide show
  1. package/README.md +54 -266
  2. package/bin/create-tractstack.js +9 -6
  3. package/dist/index.js +109 -71
  4. package/package.json +4 -2
  5. package/templates/css/custom.css +5 -0
  6. package/templates/icons/code.svg +18 -0
  7. package/templates/icons/li.svg +4 -0
  8. package/templates/icons/link.svg +22 -0
  9. package/templates/icons/p.svg +3 -0
  10. package/templates/src/client/app.js +80 -1
  11. package/templates/src/components/Footer.astro +1 -1
  12. package/templates/src/components/codehooks/BunnyVideoSetup.tsx +6 -6
  13. package/templates/src/components/codehooks/EpinetDurationSelector.tsx +3 -3
  14. package/templates/src/components/codehooks/FeaturedArticleSetup.tsx +1 -1
  15. package/templates/src/components/codehooks/ListContentSetup.tsx +2 -2
  16. package/templates/src/components/codehooks/ProductCardSetup.tsx +1 -1
  17. package/templates/src/components/codehooks/ProductGridSetup.tsx +2 -2
  18. package/templates/src/components/codehooks/SandboxRegisterForm.tsx +3 -3
  19. package/templates/src/components/compositor/Compositor.tsx +25 -9
  20. package/templates/src/components/compositor/Node.tsx +168 -496
  21. package/templates/src/components/compositor/PanelVisibilityWrapper.tsx +1 -0
  22. package/templates/src/components/compositor/elements/SignUp.tsx +1 -1
  23. package/templates/src/components/compositor/elements/YouTubeWrapper.tsx +2 -0
  24. package/templates/src/components/compositor/nodes/CreativePane.tsx +262 -0
  25. package/templates/src/components/compositor/nodes/GhostInsertBlock.tsx +4 -6
  26. package/templates/src/components/compositor/nodes/GridLayout.tsx +4 -2
  27. package/templates/src/components/compositor/nodes/Markdown.tsx +18 -3
  28. package/templates/src/components/compositor/nodes/Pane.tsx +11 -5
  29. package/templates/src/components/compositor/nodes/RenderChildren.tsx +1 -1
  30. package/templates/src/components/compositor/nodes/tagElements/NodeAnchorComponent.tsx +5 -5
  31. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag.tsx +90 -42
  32. package/templates/src/components/compositor/nodes/tagElements/NodeImg.tsx +2 -0
  33. package/templates/src/components/compositor/nodes/tagElements/NodeText.tsx +27 -1
  34. package/templates/src/components/compositor/preview/PaneSnapshotGenerator.tsx +10 -8
  35. package/templates/src/components/compositor/tools/NodeOverlay.tsx +224 -0
  36. package/templates/src/components/compositor/tools/PaneOverlay.tsx +122 -0
  37. package/templates/src/components/edit/Header.tsx +68 -9
  38. package/templates/src/components/edit/PanelSwitch.tsx +42 -4
  39. package/templates/src/components/edit/SettingsPanel.tsx +2 -3
  40. package/templates/src/components/edit/ToolMode.tsx +1 -31
  41. package/templates/src/components/edit/pane/AddPanePanel_break.tsx +2 -2
  42. package/templates/src/components/edit/pane/AddPanePanel_codehook.tsx +1 -1
  43. package/templates/src/components/edit/pane/AddPanePanel_new.tsx +193 -659
  44. package/templates/src/components/edit/pane/AddPanePanel_reuse.tsx +15 -82
  45. package/templates/src/components/edit/pane/AiRestylePaneModal.tsx +95 -45
  46. package/templates/src/components/edit/pane/ConfigPanePanel.tsx +137 -49
  47. package/templates/src/components/edit/pane/RestylePaneModal.tsx +1 -1
  48. package/templates/src/components/edit/pane/steps/AiCreativeDesignStep.tsx +375 -0
  49. package/templates/src/components/edit/pane/steps/AiDesignStep.tsx +1 -23
  50. package/templates/src/components/edit/pane/steps/AiLibraryCopyStep.tsx +327 -0
  51. package/templates/src/components/edit/pane/steps/AiRefineDesignStep.tsx +267 -0
  52. package/templates/src/components/edit/pane/steps/AiStandardDesignStep.tsx +371 -0
  53. package/templates/src/components/edit/pane/steps/CopyInputStep.tsx +201 -76
  54. package/templates/src/components/edit/pane/steps/CreativeInjectStep.tsx +141 -0
  55. package/templates/src/components/edit/panels/CreativeImagePanel.tsx +435 -0
  56. package/templates/src/components/edit/panels/CreativeLinkPanel.tsx +110 -0
  57. package/templates/src/components/edit/panels/StyleCodeHookPanel.tsx +1 -1
  58. package/templates/src/components/edit/panels/StyleParentPanel.tsx +118 -126
  59. package/templates/src/components/edit/panels/StyleParentPanel_add.tsx +3 -2
  60. package/templates/src/components/edit/panels/StyleParentPanel_deleteLayer.tsx +1 -0
  61. package/templates/src/components/edit/panels/StyleParentPanel_remove.tsx +3 -1
  62. package/templates/src/components/edit/panels/StyleParentPanel_update.tsx +3 -1
  63. package/templates/src/components/edit/panels/StyleWidgetPanel.tsx +1 -1
  64. package/templates/src/components/edit/state/SaveModal.tsx +19 -787
  65. package/templates/src/components/edit/state/SaveToLibraryModal.tsx +2 -2
  66. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_menu.tsx +1 -1
  67. package/templates/src/components/edit/widgets/BunnyWidget.tsx +5 -5
  68. package/templates/src/components/edit/widgets/InteractiveDisclosureWidget.tsx +1 -1
  69. package/templates/src/components/edit/widgets/SignupWidget.tsx +1 -1
  70. package/templates/src/components/fields/ActionBuilderTimeSelector.tsx +1 -1
  71. package/templates/src/components/fields/ArtpackImage.tsx +11 -3
  72. package/templates/src/components/fields/BackgroundImage.tsx +8 -0
  73. package/templates/src/components/fields/BackgroundImageWrapper.tsx +15 -9
  74. package/templates/src/components/fields/ImageUpload.tsx +6 -0
  75. package/templates/src/components/form/ActionBuilderField.tsx +15 -5
  76. package/templates/src/components/form/ActionBuilderSlugSelector.tsx +1 -1
  77. package/templates/src/components/form/ColorPicker.tsx +1 -1
  78. package/templates/src/components/form/EnumSelect.tsx +1 -1
  79. package/templates/src/components/form/NumberInput.tsx +1 -1
  80. package/templates/src/components/form/StringArrayInput.tsx +1 -1
  81. package/templates/src/components/form/StringInput.tsx +1 -1
  82. package/templates/src/components/form/UnsavedChangesBar.tsx +1 -1
  83. package/templates/src/components/form/advanced/APIConfigSection.tsx +2 -2
  84. package/templates/src/components/form/advanced/AuthConfigSection.tsx +2 -2
  85. package/templates/src/components/profile/ProfileCreate.tsx +1 -1
  86. package/templates/src/components/profile/ProfileEdit.tsx +1 -1
  87. package/templates/src/components/storykeep/Dashboard_Advanced.tsx +2 -2
  88. package/templates/src/components/storykeep/controls/content/BeliefForm.tsx +1 -1
  89. package/templates/src/components/storykeep/controls/content/ContentSummary.tsx +2 -2
  90. package/templates/src/components/storykeep/controls/content/KnownResourceTable.tsx +1 -1
  91. package/templates/src/components/storykeep/controls/content/ManageContent.tsx +6 -6
  92. package/templates/src/components/storykeep/controls/content/MenuForm.tsx +1 -1
  93. package/templates/src/components/storykeep/controls/content/PaneTable.tsx +358 -0
  94. package/templates/src/components/storykeep/controls/content/ResourceTable.tsx +1 -1
  95. package/templates/src/constants/prompts.json +18 -10
  96. package/templates/src/constants.ts +3 -0
  97. package/templates/src/hooks/usePaneFragments.ts +60 -0
  98. package/templates/src/lib/session.ts +71 -16
  99. package/templates/src/pages/[...slug].astro +4 -46
  100. package/templates/src/pages/api/css.ts +149 -0
  101. package/templates/src/pages/maint.astro +1 -1
  102. package/templates/src/pages/storykeep/login.astro +2 -2
  103. package/templates/src/stores/nodes.ts +162 -49
  104. package/templates/src/stores/orphanAnalysis.ts +6 -30
  105. package/templates/src/stores/previews.ts +7 -0
  106. package/templates/src/stores/storykeep.ts +0 -8
  107. package/templates/src/types/compositorTypes.ts +53 -10
  108. package/templates/src/utils/compositor/aiGeneration.ts +93 -0
  109. package/templates/src/utils/compositor/allowInsert.ts +2 -0
  110. package/templates/src/utils/compositor/htmlAst.ts +704 -0
  111. package/templates/src/utils/compositor/nodesHelper.ts +281 -102
  112. package/templates/src/utils/compositor/savePipeline.ts +893 -0
  113. package/templates/src/utils/etl/index.ts +3 -0
  114. package/templates/src/utils/etl/transformer.ts +10 -0
  115. package/templates/src/utils/helpers.ts +101 -0
  116. package/utils/inject-files.ts +100 -62
  117. package/templates/icons/text.svg +0 -6
  118. package/templates/src/components/compositor/NodeWithGuid.tsx +0 -69
  119. package/templates/src/components/compositor/nodes/GridLayout_eraser.tsx +0 -33
  120. package/templates/src/components/compositor/nodes/Markdown_eraser.tsx +0 -56
  121. package/templates/src/components/compositor/nodes/Pane_DesignLibrary.tsx +0 -269
  122. package/templates/src/components/compositor/nodes/Pane_eraser.tsx +0 -186
  123. package/templates/src/components/compositor/nodes/Pane_layout.tsx +0 -79
  124. package/templates/src/components/compositor/nodes/tagElements/NodeA_eraser.tsx +0 -26
  125. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_eraser.tsx +0 -61
  126. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_insert.tsx +0 -120
  127. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_settings.tsx +0 -62
  128. package/templates/src/components/compositor/nodes/tagElements/NodeButton_eraser.tsx +0 -26
@@ -1,4 +1,4 @@
1
- import { useState, useEffect } from 'react';
1
+ import { useMemo } from 'react';
2
2
  import { useStore } from '@nanostores/react';
3
3
  import { Portal } from '@ark-ui/react';
4
4
  import SparklesIcon from '@heroicons/react/24/outline/SparklesIcon';
@@ -7,10 +7,7 @@ import ArrowUturnLeftIcon from '@heroicons/react/24/outline/ArrowUturnLeftIcon';
7
7
  import ChevronLeftIcon from '@heroicons/react/24/outline/ChevronLeftIcon';
8
8
  import ChevronRightIcon from '@heroicons/react/24/outline/ChevronRightIcon';
9
9
  import { selectionStore } from '@/stores/selection';
10
- import {
11
- settingsPanelStore,
12
- stylePanelTargetMemoryStore,
13
- } from '@/stores/storykeep';
10
+ import { settingsPanelStore } from '@/stores/storykeep';
14
11
  import { getCtx } from '@/stores/nodes';
15
12
  import {
16
13
  isMarkdownPaneFragmentNode,
@@ -58,28 +55,20 @@ const StyleParentPanel = ({
58
55
  node: initialNode,
59
56
  parentNode: paneNode,
60
57
  layer,
58
+ view,
61
59
  }: ParentBasePanelProps) => {
62
- const [currentView, setCurrentView] = useState<PanelView>('summary');
63
- const [currentLayer, setCurrentLayer] = useState<number>(layer || 1);
64
- const [styleTargets, setStyleTargets] = useState<StyleableTarget[]>([]);
65
- const [selectedTargetIndex, setSelectedTargetIndex] = useState(0);
66
-
60
+ const signal = useStore(settingsPanelStore);
61
+ const currentView = (view as PanelView) || 'summary';
62
+ const activeLayer = layer || 1;
67
63
  const ctx = getCtx();
68
64
  const { isAiRestyleModalOpen } = useStore(selectionStore);
69
65
 
70
- useEffect(() => {
71
- if (
72
- !initialNode ||
73
- !(
74
- isMarkdownPaneFragmentNode(initialNode) || isGridLayoutNode(initialNode)
75
- ) ||
76
- !paneNode ||
77
- !isPaneNode(paneNode)
78
- ) {
79
- return;
80
- }
66
+ // 1. Build the list of available targets (Outer Container + Columns)
67
+ const styleTargets = useMemo(() => {
68
+ if (!initialNode || !paneNode) return [];
81
69
 
82
70
  let effectiveNode = initialNode;
71
+ // Find the parent grid if we are currently looking at a column
83
72
  if (isMarkdownPaneFragmentNode(initialNode) && initialNode.parentId) {
84
73
  const parent = ctx.allNodes.get().get(initialNode.parentId);
85
74
  if (parent && isGridLayoutNode(parent)) {
@@ -112,38 +101,17 @@ const StyleParentPanel = ({
112
101
  });
113
102
  });
114
103
  }
104
+ return targets;
105
+ }, [initialNode, paneNode, ctx]);
115
106
 
116
- setStyleTargets(targets);
117
-
118
- const rememberedIndex = stylePanelTargetMemoryStore.get().get(paneNode.id);
119
-
120
- if (rememberedIndex != null && rememberedIndex < targets.length) {
121
- setSelectedTargetIndex(rememberedIndex);
122
- } else if (initialNode.id !== effectiveNode.id) {
123
- // If opened on a child column, find and select it in the list
124
- const index = targets.findIndex((t) => t.id === initialNode.id);
125
- if (index !== -1) setSelectedTargetIndex(index);
126
- else setSelectedTargetIndex(0);
127
- } else {
128
- setSelectedTargetIndex(0);
129
- }
130
-
131
- setCurrentView('summary');
132
- }, [initialNode, ctx, paneNode]);
133
-
134
- useEffect(() => {
135
- setCurrentLayer(layer || 1);
136
- }, [layer]);
137
-
138
- useEffect(() => {
139
- if (paneNode?.id) {
140
- const newMemory = new Map(stylePanelTargetMemoryStore.get());
141
- newMemory.set(paneNode.id, selectedTargetIndex);
142
- stylePanelTargetMemoryStore.set(newMemory);
143
- }
144
- }, [selectedTargetIndex, paneNode?.id]);
107
+ // 2. Identify active index based on global signal nodeId (Source of Truth)
108
+ const selectedTargetIndex = useMemo(() => {
109
+ const idx = styleTargets.findIndex((t) => t.id === signal?.nodeId);
110
+ return idx === -1 ? 0 : idx;
111
+ }, [styleTargets, signal?.nodeId]);
145
112
 
146
113
  const selectedTarget = styleTargets[selectedTargetIndex];
114
+
147
115
  if (!selectedTarget || !paneNode || !isPaneNode(paneNode)) {
148
116
  return null;
149
117
  }
@@ -155,6 +123,7 @@ const StyleParentPanel = ({
155
123
  targetProperty,
156
124
  } = selectedTarget;
157
125
 
126
+ // 3. Navigation updates the global store directly
158
127
  const handleNavigation = (direction: 'prev' | 'next') => {
159
128
  const len = styleTargets.length;
160
129
  if (len < 2) return;
@@ -164,24 +133,20 @@ const StyleParentPanel = ({
164
133
  ? (selectedTargetIndex + 1) % len
165
134
  : (selectedTargetIndex - 1 + len) % len;
166
135
 
167
- setSelectedTargetIndex(newIndex);
168
-
169
- // Dispatch Signal to move the Orange Outline
170
136
  const newTarget = styleTargets[newIndex];
171
- const currentSettings = settingsPanelStore.get();
172
137
 
173
- if (currentSettings && newTarget) {
174
- settingsPanelStore.set({
175
- ...currentSettings,
176
- nodeId: newTarget.id,
177
- action: 'style-parent',
178
- });
179
- }
138
+ settingsPanelStore.set({
139
+ ...signal!,
140
+ nodeId: newTarget.id,
141
+ action: 'style-parent',
142
+ view: 'summary', // Reset view to summary when switching physical nodes
143
+ targetProperty: newTarget.targetProperty,
144
+ expanded: true,
145
+ });
180
146
  };
181
147
 
182
148
  const handleLayerAdd = (position: 'before' | 'after', layerNum: number) => {
183
149
  const targetNode = cloneDeep(selectedTargetNode);
184
-
185
150
  const emptyLayer = { mobile: {}, tablet: {}, desktop: {} };
186
151
  let newParentClasses = [...(targetNode.parentClasses || [])];
187
152
  const insertIndex = position === 'before' ? layerNum - 1 : layerNum;
@@ -201,7 +166,9 @@ const StyleParentPanel = ({
201
166
  ]);
202
167
 
203
168
  const newLayer = position === 'before' ? layerNum : layerNum + 1;
204
- setCurrentLayer(newLayer);
169
+ if (signal) {
170
+ settingsPanelStore.set({ ...signal, layer: newLayer });
171
+ }
205
172
  };
206
173
 
207
174
  const dispatchToSubPanel = (
@@ -209,10 +176,12 @@ const StyleParentPanel = ({
209
176
  extraProps: Record<string, any> = {}
210
177
  ) => {
211
178
  settingsPanelStore.set({
179
+ ...signal!,
212
180
  nodeId: selectedTargetId,
213
181
  action,
214
182
  ...extraProps,
215
183
  targetProperty: targetProperty,
184
+ view,
216
185
  expanded: true,
217
186
  });
218
187
  };
@@ -232,22 +201,22 @@ const StyleParentPanel = ({
232
201
  };
233
202
 
234
203
  const handleClickDeleteLayer = () => {
235
- dispatchToSubPanel('style-parent-delete-layer', { layer: currentLayer });
204
+ dispatchToSubPanel('style-parent-delete-layer', { layer: activeLayer });
236
205
  };
237
206
  const handleClickRemove = (name: string) => {
238
207
  dispatchToSubPanel('style-parent-remove', {
239
- layer: currentLayer,
208
+ layer: activeLayer,
240
209
  className: name,
241
210
  });
242
211
  };
243
212
  const handleClickUpdate = (name: string) => {
244
213
  dispatchToSubPanel('style-parent-update', {
245
- layer: currentLayer,
214
+ layer: activeLayer,
246
215
  className: name,
247
216
  });
248
217
  };
249
218
  const handleClickAdd = () => {
250
- dispatchToSubPanel('style-parent-add', { layer: currentLayer });
219
+ dispatchToSubPanel('style-parent-add', { layer: activeLayer });
251
220
  };
252
221
 
253
222
  const handleColorChange = (color: string) => {
@@ -275,9 +244,18 @@ const StyleParentPanel = ({
275
244
  ctx.notifyNode('root');
276
245
  };
277
246
 
247
+ const setView = (newView: PanelView) => {
248
+ if (signal) {
249
+ settingsPanelStore.set({
250
+ ...signal,
251
+ view: newView,
252
+ });
253
+ }
254
+ };
255
+
278
256
  const BackButton = () => (
279
257
  <button
280
- onClick={() => setCurrentView('summary')}
258
+ onClick={() => setView('summary')}
281
259
  className="mb-4 flex items-center gap-2 text-sm font-bold text-gray-600 hover:text-black"
282
260
  >
283
261
  <ArrowUturnLeftIcon className="h-4 w-4" />
@@ -308,8 +286,7 @@ const StyleParentPanel = ({
308
286
  );
309
287
 
310
288
  const renderSummaryView = () => {
311
- if (!initialNode) return null;
312
- const isGrid = isGridLayoutNode(initialNode);
289
+ const isGrid = isGridLayoutNode(selectedTargetNode);
313
290
  const childNodeIds = ctx.getChildNodeIDs(paneNode.id);
314
291
  const bgNode = childNodeIds
315
292
  .map((id) => ctx.allNodes.get().get(id))
@@ -319,6 +296,13 @@ const StyleParentPanel = ({
319
296
  'type' in n &&
320
297
  (n.type === 'background-image' || n.type === 'artpack-image')
321
298
  ) as (BgImageNode | ArtpackImageNode) | undefined;
299
+
300
+ const preventGrid =
301
+ !!bgNode &&
302
+ ['left', 'right', 'leftBleed', 'rightBleed'].includes(
303
+ bgNode.position || ''
304
+ );
305
+
322
306
  let bgSummary = 'None';
323
307
  if (bgNode) {
324
308
  if (isArtpackImageNode(bgNode)) bgSummary = `Artpack: ${bgNode.image}`;
@@ -365,7 +349,7 @@ const StyleParentPanel = ({
365
349
  <div className="flex items-center gap-2">
366
350
  <span className="text-sm text-gray-600">{wrapperSummary}</span>
367
351
  <button
368
- onClick={() => setCurrentView('wrapperStyles')}
352
+ onClick={() => setView('wrapperStyles')}
369
353
  className="rounded bg-gray-100 px-3 py-1 text-sm font-bold text-gray-700 hover:bg-gray-200"
370
354
  >
371
355
  Edit
@@ -379,7 +363,7 @@ const StyleParentPanel = ({
379
363
  {bgSummary}
380
364
  </span>
381
365
  <button
382
- onClick={() => setCurrentView('backgroundImage')}
366
+ onClick={() => setView('backgroundImage')}
383
367
  className="rounded bg-gray-100 px-3 py-1 text-sm font-bold text-gray-700 hover:bg-gray-200"
384
368
  >
385
369
  Edit
@@ -436,14 +420,14 @@ const StyleParentPanel = ({
436
420
  </div>
437
421
  )}
438
422
 
439
- {selectedTargetIndex === 0 && (
423
+ {!preventGrid && selectedTargetIndex === 0 && (
440
424
  <div className="space-y-3 border-t border-gray-200 pt-4">
441
425
  <h3 className="text-sm font-bold uppercase text-gray-500">
442
426
  Layout
443
427
  </h3>
444
428
  {!isGrid ? (
445
429
  <button
446
- onClick={() => convertToGrid(initialNode.id)}
430
+ onClick={() => initialNode && convertToGrid(initialNode.id)}
447
431
  className="w-full rounded bg-cyan-600 px-4 py-2 text-sm font-bold text-white hover:bg-cyan-700"
448
432
  >
449
433
  Convert to Grid Layout
@@ -484,13 +468,13 @@ const StyleParentPanel = ({
484
468
  </div>
485
469
  )}
486
470
  <button
487
- onClick={() => revertFromGrid(initialNode.id)}
471
+ onClick={() => initialNode && revertFromGrid(initialNode.id)}
488
472
  className="w-full rounded bg-gray-200 px-4 py-2 text-sm font-bold text-gray-700 hover:bg-gray-300"
489
473
  >
490
474
  Revert to Standard Pane
491
475
  </button>
492
476
  <button
493
- onClick={() => addColumn(initialNode.id)}
477
+ onClick={() => initialNode && addColumn(initialNode.id)}
494
478
  className="w-full rounded border border-dashed border-gray-400 bg-transparent px-4 py-2 text-sm font-bold text-gray-700 hover:border-gray-600 hover:bg-gray-50"
495
479
  >
496
480
  Add Column
@@ -527,7 +511,7 @@ const StyleParentPanel = ({
527
511
  <div className="space-y-3 border-t border-gray-200 pt-4">
528
512
  <button
529
513
  onClick={() => {
530
- ctx.toolModeValStore.set({ value: 'styles' });
514
+ ctx.toolModeValStore.set({ value: 'text' });
531
515
  selectionStore.setKey('paneToRestyleId', paneNode.id);
532
516
  selectionStore.setKey('isAiRestyleModalOpen', true);
533
517
  }}
@@ -544,7 +528,7 @@ const StyleParentPanel = ({
544
528
  const renderWrapperStylesView = () => {
545
529
  const layerCount = selectedTargetNode.parentClasses?.length || 0;
546
530
  const currentClasses = selectedTargetNode.parentClasses?.[
547
- currentLayer - 1
531
+ activeLayer - 1
548
532
  ] || { mobile: {}, tablet: {}, desktop: {} };
549
533
  const hasNoClasses = !Object.values(currentClasses).some(
550
534
  (breakpoint) => Object.keys(breakpoint).length > 0
@@ -572,16 +556,19 @@ const StyleParentPanel = ({
572
556
  >
573
557
  <button
574
558
  className={`min-w-8 rounded-md px-3 py-1.5 text-sm font-bold transition-colors ${
575
- currentLayer === num
559
+ activeLayer === num
576
560
  ? 'bg-myblue text-white shadow-sm'
577
- : 'bg-white text-mydarkgrey hover:bg-mydarkgrey/10 hover:text-black'
561
+ : 'bg-white text-mydarkgrey hover:bg-mydarkgrey hover:bg-opacity-10 hover:text-black'
578
562
  }`}
579
- onClick={() => setCurrentLayer(num)}
563
+ onClick={() => {
564
+ if (signal)
565
+ settingsPanelStore.set({ ...signal, layer: num });
566
+ }}
580
567
  >
581
568
  {num}
582
569
  </button>
583
570
  <button
584
- className="rounded border border-dashed border-mydarkgrey/30 p-1 text-xs text-mydarkgrey transition-colors hover:bg-white/50 hover:text-black"
571
+ className="rounded border border-dashed border-mydarkgrey border-opacity-30 p-1 text-xs text-mydarkgrey transition-colors hover:bg-white/50 hover:text-black"
585
572
  title="Add Layer Here"
586
573
  onClick={() =>
587
574
  handleLayerAdd(
@@ -596,58 +583,63 @@ const StyleParentPanel = ({
596
583
  ))}
597
584
  </div>
598
585
  </div>
599
- {hasNoClasses ? (
600
- <div>
601
- <em>No styles for this layer.</em>
602
- </div>
603
- ) : (
604
- <div className="flex flex-wrap gap-2">
605
- {Object.entries(currentClasses.mobile).map(([className]) => (
606
- <SelectedTailwindClass
607
- key={className}
608
- name={className}
609
- values={{
610
- mobile: currentClasses.mobile[className],
611
- tablet: currentClasses.tablet?.[className],
612
- desktop: currentClasses.desktop?.[className],
613
- }}
614
- onRemove={handleClickRemove}
615
- onUpdate={handleClickUpdate}
616
- />
617
- ))}
618
- </div>
586
+ {layerCount > 0 && activeLayer <= layerCount && (
587
+ <>
588
+ {hasNoClasses ? (
589
+ <div>
590
+ <em>No styles for this layer.</em>
591
+ </div>
592
+ ) : (
593
+ <div className="flex flex-wrap gap-2">
594
+ {Object.entries(currentClasses.mobile).map(([className]) => (
595
+ <SelectedTailwindClass
596
+ key={className}
597
+ name={className}
598
+ values={{
599
+ mobile: currentClasses.mobile[className],
600
+ tablet: currentClasses.tablet?.[className],
601
+ desktop: currentClasses.desktop?.[className],
602
+ }}
603
+ onRemove={handleClickRemove}
604
+ onUpdate={handleClickUpdate}
605
+ />
606
+ ))}
607
+ </div>
608
+ )}
609
+ <div>
610
+ <ul className="flex flex-wrap gap-x-4 gap-y-1 text-mydarkgrey">
611
+ <li>
612
+ <em>Actions:</em>
613
+ </li>
614
+ <li>
615
+ <button
616
+ onClick={handleClickAdd}
617
+ className="font-bold text-myblue underline hover:text-black"
618
+ >
619
+ Add Style
620
+ </button>
621
+ </li>
622
+ <li>
623
+ <button
624
+ onClick={handleClickDeleteLayer}
625
+ className="font-bold text-myblue underline hover:text-black"
626
+ >
627
+ Delete Layer
628
+ </button>
629
+ </li>
630
+ </ul>
631
+ </div>
632
+ </>
619
633
  )}
620
- <div>
621
- <ul className="flex flex-wrap gap-x-4 gap-y-1 text-mydarkgrey">
622
- <li>
623
- <em>Actions:</em>
624
- </li>
625
- <li>
626
- <button
627
- onClick={handleClickAdd}
628
- className="font-bold text-myblue underline hover:text-black"
629
- >
630
- Add Style
631
- </button>
632
- </li>
633
- <li>
634
- <button
635
- onClick={handleClickDeleteLayer}
636
- className="font-bold text-myblue underline hover:text-black"
637
- >
638
- Delete Layer
639
- </button>
640
- </li>
641
- </ul>
642
- </div>
643
634
  </div>
644
635
  );
645
636
  };
646
637
 
638
+ const isGrid = isGridLayoutNode(selectedTargetNode);
647
639
  const renderBackgroundImageVIew = () => (
648
640
  <div className="space-y-4">
649
641
  <BackButton />
650
- <BackgroundImageWrapper paneId={paneNode.id} />
642
+ <BackgroundImageWrapper paneId={paneNode.id} isGrid={isGrid} />
651
643
  </div>
652
644
  );
653
645
 
@@ -64,9 +64,8 @@ interface StyleOption {
64
64
 
65
65
  type StyleableNode = MarkdownPaneFragmentNode | GridLayoutNode;
66
66
 
67
- // This custom prop is passed via the settingsPanelStore signal.
68
67
  type CustomPanelProps = ParentBasePanelProps & {
69
- targetProperty: 'parentClasses' | 'gridClasses';
68
+ targetProperty: 'parentClasses' | 'gridClasses' | undefined;
70
69
  };
71
70
 
72
71
  const StyleParentPanelAdd = ({
@@ -83,6 +82,7 @@ const StyleParentPanelAdd = ({
83
82
  const styleableNode = node as StyleableNode | null;
84
83
 
85
84
  if (
85
+ !targetProperty ||
86
86
  !styleableNode ||
87
87
  (!isMarkdownPaneFragmentNode(styleableNode) &&
88
88
  !isGridLayoutNode(styleableNode))
@@ -187,6 +187,7 @@ const StyleParentPanelAdd = ({
187
187
  settingsPanelStore.set({
188
188
  nodeId: styleableNode.id,
189
189
  layer: layer,
190
+ view: settingsPanelStore.get()?.view,
190
191
  action: 'style-parent',
191
192
  expanded: true,
192
193
  });
@@ -43,6 +43,7 @@ const StyleParentDeleteLayerPanel = ({ node, layer }: ParentBasePanelProps) => {
43
43
  settingsPanelStore.set({
44
44
  nodeId: styleableNode.id,
45
45
  action: 'style-parent',
46
+ view: settingsPanelStore.get()?.view,
46
47
  expanded: true,
47
48
  });
48
49
  };
@@ -17,7 +17,7 @@ type StyleableNode = MarkdownPaneFragmentNode | GridLayoutNode;
17
17
 
18
18
  // This custom prop is passed via the settingsPanelStore signal.
19
19
  type CustomPanelProps = ParentBasePanelProps & {
20
- targetProperty: 'parentClasses' | 'gridClasses';
20
+ targetProperty: 'parentClasses' | 'gridClasses' | undefined;
21
21
  };
22
22
 
23
23
  const StyleParentPanelRemove = ({
@@ -32,6 +32,7 @@ const StyleParentPanelRemove = ({
32
32
  const styleableNode = node as StyleableNode | null;
33
33
 
34
34
  if (
35
+ !targetProperty ||
35
36
  !styleableNode ||
36
37
  (!isMarkdownPaneFragmentNode(styleableNode) &&
37
38
  !isGridLayoutNode(styleableNode))
@@ -71,6 +72,7 @@ const StyleParentPanelRemove = ({
71
72
  settingsPanelStore.set({
72
73
  nodeId: styleableNode.id,
73
74
  layer: layer,
75
+ view: settingsPanelStore.get()?.view,
74
76
  action: 'style-parent',
75
77
  expanded: true,
76
78
  });
@@ -24,7 +24,7 @@ type ViewportValues = {
24
24
  };
25
25
 
26
26
  type CustomPanelProps = ParentBasePanelProps & {
27
- targetProperty: 'parentClasses' | 'gridClasses';
27
+ targetProperty: 'parentClasses' | 'gridClasses' | undefined;
28
28
  };
29
29
 
30
30
  const StyleParentPanelUpdate = ({
@@ -38,6 +38,7 @@ const StyleParentPanelUpdate = ({
38
38
  const config = brandConfigStore.get();
39
39
 
40
40
  if (
41
+ !targetProperty ||
41
42
  !styleableNode ||
42
43
  (!isMarkdownPaneFragmentNode(styleableNode) &&
43
44
  !isGridLayoutNode(styleableNode)) ||
@@ -100,6 +101,7 @@ const StyleParentPanelUpdate = ({
100
101
  settingsPanelStore.set({
101
102
  nodeId: styleableNode.id,
102
103
  layer: layer,
104
+ view: settingsPanelStore.get()?.view,
103
105
  action: 'style-parent',
104
106
  expanded: true,
105
107
  });
@@ -274,7 +274,7 @@ const StyleWidgetPanel = ({
274
274
  };
275
275
 
276
276
  const handleWidgetConfig = () => {
277
- getCtx().toolModeValStore.set({ value: 'styles' });
277
+ getCtx().toolModeValStore.set({ value: 'text' });
278
278
  settingsPanelStore.set({
279
279
  action: `style-code-config`,
280
280
  nodeId: node.id,