astro-tractstack 2.0.19 → 2.0.21

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 (54) hide show
  1. package/dist/index.js +6 -32
  2. package/package.json +1 -1
  3. package/templates/src/components/codehooks/BunnyVideoSetup.tsx +1 -4
  4. package/templates/src/components/codehooks/FeaturedArticleSetup.tsx +0 -4
  5. package/templates/src/components/codehooks/ListContentSetup.tsx +1 -8
  6. package/templates/src/components/codehooks/ProductCardSetup.tsx +0 -2
  7. package/templates/src/components/codehooks/ProductGridSetup.tsx +0 -2
  8. package/templates/src/components/compositor/Compositor.tsx +3 -6
  9. package/templates/src/components/compositor/Node.tsx +13 -32
  10. package/templates/src/components/compositor/NodeWithGuid.tsx +49 -5
  11. package/templates/src/components/compositor/nodes/Pane.tsx +4 -21
  12. package/templates/src/components/compositor/nodes/Pane_DesignLibrary.tsx +27 -7
  13. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag.tsx +3 -1
  14. package/templates/src/components/compositor/preview/OgImagePreview.tsx +0 -5
  15. package/templates/src/components/compositor/preview/PaneSnapshotGenerator.tsx +5 -6
  16. package/templates/src/components/edit/PanelSwitch.tsx +3 -24
  17. package/templates/src/components/edit/SettingsPanel.tsx +0 -1
  18. package/templates/src/components/edit/ToolMode.tsx +6 -14
  19. package/templates/src/components/edit/pane/AddPanePanel.tsx +58 -25
  20. package/templates/src/components/edit/pane/AddPanePanel_new.tsx +140 -133
  21. package/templates/src/components/edit/pane/AddPanePanel_paste.tsx +111 -0
  22. package/templates/src/components/edit/pane/RestylePaneModal.tsx +231 -282
  23. package/templates/src/components/edit/pane/steps/AiDesignStep.tsx +0 -5
  24. package/templates/src/components/edit/pane/steps/DesignLibraryStep.tsx +4 -13
  25. package/templates/src/components/edit/panels/StyleBreakPanel.tsx +1 -3
  26. package/templates/src/components/edit/panels/StyleElementPanel_update.tsx +0 -6
  27. package/templates/src/components/edit/panels/StyleImagePanel_update.tsx +0 -3
  28. package/templates/src/components/edit/panels/StyleLiElementPanel_update.tsx +0 -4
  29. package/templates/src/components/edit/panels/StyleLinkPanel_config.tsx +8 -5
  30. package/templates/src/components/edit/panels/StyleLinkPanel_update.tsx +1 -2
  31. package/templates/src/components/edit/panels/StyleParentPanel.tsx +1 -3
  32. package/templates/src/components/edit/panels/StyleParentPanel_update.tsx +2 -5
  33. package/templates/src/components/edit/panels/StyleWidgetPanel_config.tsx +2 -8
  34. package/templates/src/components/edit/panels/StyleWidgetPanel_update.tsx +0 -4
  35. package/templates/src/components/edit/state/SaveToLibraryModal.tsx +29 -16
  36. package/templates/src/components/edit/storyfragment/StoryFragmentConfigPanel.tsx +9 -26
  37. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_og.tsx +7 -16
  38. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_slug.tsx +5 -6
  39. package/templates/src/components/edit/widgets/InteractiveDisclosureWidget.tsx +0 -5
  40. package/templates/src/components/fields/BackgroundImageWrapper.tsx +1 -7
  41. package/templates/src/components/fields/ColorPickerCombo.tsx +8 -12
  42. package/templates/src/components/fields/ViewportComboBox.tsx +4 -6
  43. package/templates/src/stores/nodes.ts +14 -6
  44. package/templates/src/stores/storykeep.ts +3 -3
  45. package/templates/src/types/compositorTypes.ts +2 -0
  46. package/templates/src/utils/compositor/TemplatePanes.ts +0 -76
  47. package/templates/src/utils/compositor/aiPaneParser.ts +3 -1
  48. package/templates/src/utils/compositor/designLibraryHelper.ts +523 -203
  49. package/templates/src/utils/helpers.ts +5 -4
  50. package/utils/inject-files.ts +6 -32
  51. package/templates/src/components/compositor/preview/VisualBreakPreview.tsx +0 -154
  52. package/templates/src/components/edit/pane/PageGen_preview.tsx +0 -511
  53. package/templates/src/utils/compositor/processMarkdown.ts +0 -445
  54. package/templates/src/utils/compositor/templateMarkdownStyles.ts +0 -1273
@@ -1,6 +1,6 @@
1
1
  import { useEffect, useState } from 'react';
2
2
  import * as htmlToImage from 'html-to-image';
3
- import type { BrandConfig } from '@/types/tractstack';
3
+ import { brandConfigStore } from '@/stores/storykeep';
4
4
 
5
5
  export type SnapshotData = {
6
6
  imageData: string;
@@ -12,7 +12,6 @@ export interface PaneSnapshotGeneratorProps {
12
12
  htmlString: string;
13
13
  onComplete: (id: string, data: SnapshotData) => void;
14
14
  onError?: (id: string, error: string) => void;
15
- config?: BrandConfig;
16
15
  outputWidth?: number;
17
16
  }
18
17
 
@@ -33,7 +32,6 @@ export const PaneSnapshotGenerator = ({
33
32
  htmlString,
34
33
  onComplete,
35
34
  onError,
36
- config,
37
35
  outputWidth = 800,
38
36
  }: PaneSnapshotGeneratorProps) => {
39
37
  const [isGenerating, setIsGenerating] = useState(false);
@@ -80,7 +78,8 @@ export const PaneSnapshotGenerator = ({
80
78
  const customCssUrl = `${cssBasePath}/custom.css`;
81
79
  const storykeepCssUrl = `${cssBasePath}/storykeep.css`;
82
80
 
83
- const brandColors = config?.BRAND_COLOURS?.split(',') || [];
81
+ const brandColors =
82
+ brandConfigStore.get()?.BRAND_COLOURS?.split(',') || [];
84
83
 
85
84
  // Get all existing CSS links from current document
86
85
  const existingCssLinks = Array.from(
@@ -100,7 +99,7 @@ export const PaneSnapshotGenerator = ({
100
99
  <link rel="stylesheet" href="${storykeepCssUrl}">
101
100
  ${existingCssLinks.map((href) => `<link rel="stylesheet" href="${href}">`).join('\n')}
102
101
  ${
103
- config
102
+ brandColors
104
103
  ? `
105
104
  <style>
106
105
  :root {
@@ -203,7 +202,7 @@ export const PaneSnapshotGenerator = ({
203
202
  };
204
203
 
205
204
  generateSnapshot();
206
- }, [id, htmlString, isGenerating, onComplete, onError, config, outputWidth]);
205
+ }, [id, htmlString, isGenerating, onComplete, onError, outputWidth]);
207
206
 
208
207
  // Show spinner while generating
209
208
  if (isGenerating) {
@@ -36,7 +36,6 @@ import StyleLiElementUpdatePanel from './panels/StyleLiElementPanel_update';
36
36
  import StyleLiElementRemovePanel from './panels/StyleLiElementPanel_remove';
37
37
  import StyleCodeHookPanel from './panels/StyleCodeHookPanel';
38
38
  import { getSettingsPanelTitle } from '@/utils/helpers';
39
- import type { BrandConfig } from '@/types/tractstack';
40
39
  import type {
41
40
  FlatNode,
42
41
  GridLayoutNode,
@@ -44,13 +43,11 @@ import type {
44
43
  } from '@/types/compositorTypes';
45
44
 
46
45
  interface SettingsPanelProps {
47
- config: BrandConfig;
48
46
  availableCodeHooks: string[];
49
47
  onTitleChange?: (title: string) => void;
50
48
  }
51
49
 
52
50
  const PanelSwitch = ({
53
- config,
54
51
  availableCodeHooks,
55
52
  onTitleChange,
56
53
  }: SettingsPanelProps) => {
@@ -101,13 +98,7 @@ const PanelSwitch = ({
101
98
  switch (signal.action) {
102
99
  case 'style-break':
103
100
  if (clickedNode && paneNode)
104
- return (
105
- <StyleBreakPanel
106
- config={config}
107
- node={clickedNode}
108
- parentNode={paneNode}
109
- />
110
- );
101
+ return <StyleBreakPanel node={clickedNode} parentNode={paneNode} />;
111
102
  break;
112
103
 
113
104
  case 'style-parent':
@@ -117,7 +108,6 @@ const PanelSwitch = ({
117
108
  node={markdownNode}
118
109
  parentNode={paneNode}
119
110
  layer={signal.layer || 0}
120
- config={config}
121
111
  />
122
112
  );
123
113
  else if (gridLayoutNode && paneNode)
@@ -126,7 +116,6 @@ const PanelSwitch = ({
126
116
  node={gridLayoutNode}
127
117
  parentNode={paneNode}
128
118
  layer={signal.layer || 0}
129
- config={config}
130
119
  />
131
120
  );
132
121
  break;
@@ -181,7 +170,6 @@ const PanelSwitch = ({
181
170
  node={clickedNode}
182
171
  layer={signal.layer || 0}
183
172
  className={signal.className}
184
- config={config}
185
173
  targetProperty={(signal as any).targetProperty}
186
174
  />
187
175
  );
@@ -215,7 +203,6 @@ const PanelSwitch = ({
215
203
  <StyleLinkUpdatePanel
216
204
  node={clickedNode}
217
205
  className={signal.className}
218
- config={config}
219
206
  />
220
207
  );
221
208
  break;
@@ -232,8 +219,7 @@ const PanelSwitch = ({
232
219
  break;
233
220
 
234
221
  case 'style-link-config':
235
- if (clickedNode)
236
- return <StyleLinkConfigPanel node={clickedNode} config={config} />;
222
+ if (clickedNode) return <StyleLinkConfigPanel node={clickedNode} />;
237
223
  break;
238
224
 
239
225
  case 'style-element':
@@ -280,7 +266,6 @@ const PanelSwitch = ({
280
266
  parentNode={styleContextNode}
281
267
  className={signal.className}
282
268
  onTitleChange={onTitleChange}
283
- config={config}
284
269
  />
285
270
  );
286
271
  break;
@@ -353,7 +338,6 @@ const PanelSwitch = ({
353
338
  parentNode={styleContextNode}
354
339
  className={signal.className}
355
340
  childId={signal.childId}
356
- config={config}
357
341
  />
358
342
  );
359
343
  break;
@@ -429,8 +413,7 @@ const PanelSwitch = ({
429
413
  }
430
414
 
431
415
  case 'style-code-config':
432
- if (clickedNode)
433
- return <StyleWidgetConfigPanel node={clickedNode} config={config} />;
416
+ if (clickedNode) return <StyleWidgetConfigPanel node={clickedNode} />;
434
417
  break;
435
418
 
436
419
  case 'style-code-add':
@@ -453,7 +436,6 @@ const PanelSwitch = ({
453
436
  node={clickedNode}
454
437
  parentNode={styleContextNode}
455
438
  className={signal.className}
456
- config={config}
457
439
  />
458
440
  );
459
441
  break;
@@ -467,7 +449,6 @@ const PanelSwitch = ({
467
449
  parentNode={styleContextNode}
468
450
  className={signal.className}
469
451
  childId={signal.childId}
470
- config={config}
471
452
  />
472
453
  );
473
454
  break;
@@ -541,7 +522,6 @@ const PanelSwitch = ({
541
522
  node={clickedNode}
542
523
  parentNode={styleContextNode}
543
524
  className={signal.className}
544
- config={config}
545
525
  />
546
526
  );
547
527
  break;
@@ -554,7 +534,6 @@ const PanelSwitch = ({
554
534
  parentNode={styleContextNode}
555
535
  className={signal.className}
556
536
  childId={signal.childId}
557
- config={config}
558
537
  />
559
538
  );
560
539
  break;
@@ -66,7 +66,6 @@ const SettingsPanel = ({ config, availableCodeHooks }: SettingsPanelProps) => {
66
66
  <div className="min-h-0 flex-1 space-y-4 overflow-y-auto p-1.5 pt-0 md:p-2.5 md:pt-0">
67
67
  <div className="rounded bg-gray-50 p-1.5 md:p-2.5">
68
68
  <PanelSwitch
69
- config={config}
70
69
  availableCodeHooks={availableCodeHooks}
71
70
  onTitleChange={setPanelTitle}
72
71
  />
@@ -52,6 +52,12 @@ const storykeepToolModes = [
52
52
  title: 'Design Library',
53
53
  description: 'Save pane to design library',
54
54
  },
55
+ {
56
+ key: 'debug' as const,
57
+ Icon: BugAntIcon,
58
+ title: 'Debug Mode',
59
+ description: 'Toggle node tree id reveal',
60
+ },
55
61
  ] as const;
56
62
 
57
63
  interface StoryKeepToolModeProps {
@@ -62,7 +68,6 @@ const StoryKeepToolMode = ({ isContext }: StoryKeepToolModeProps) => {
62
68
  const ctx = getCtx();
63
69
  const { value: toolModeVal } = useStore(ctx.toolModeValStore);
64
70
  const $selection = useStore(selectionStore);
65
- const showGuids = useStore(ctx.showGuids);
66
71
  const navRef = useRef<HTMLElement>(null);
67
72
 
68
73
  const hasTitle = useStore(ctx.hasTitle);
@@ -73,8 +78,6 @@ const StoryKeepToolMode = ({ isContext }: StoryKeepToolModeProps) => {
73
78
  const className =
74
79
  'w-8 h-8 py-1 rounded-xl bg-white text-myblue hover:bg-mygreen/20 hover:text-black hover:rotate-3 cursor-pointer transition-all';
75
80
  const classNameActive = 'w-8 h-8 py-1.5 rounded-md bg-myblue text-white';
76
- const classNameDebugActive =
77
- 'w-8 h-8 py-1.5 rounded-md bg-orange-500 text-white';
78
81
 
79
82
  const currentToolMode =
80
83
  storykeepToolModes.find((mode) => mode.key === toolModeVal) ??
@@ -86,11 +89,6 @@ const StoryKeepToolMode = ({ isContext }: StoryKeepToolModeProps) => {
86
89
  ctx.notifyNode('root');
87
90
  };
88
91
 
89
- const handleDebugToggle = () => {
90
- ctx.showGuids.set(!showGuids);
91
- ctx.notifyNode('root');
92
- };
93
-
94
92
  const handleStyleClick = () => {
95
93
  selectionStore.setKey('pendingAction', 'style');
96
94
  };
@@ -156,12 +154,6 @@ const StoryKeepToolMode = ({ isContext }: StoryKeepToolModeProps) => {
156
154
  )}
157
155
  </div>
158
156
  ))}
159
- <div title="Toggle debug node ids" key="debug">
160
- <BugAntIcon
161
- className={showGuids ? classNameDebugActive : className}
162
- onClick={handleDebugToggle}
163
- />
164
- </div>
165
157
  </div>
166
158
  )}
167
159
 
@@ -1,13 +1,14 @@
1
1
  import { useState } from 'react';
2
2
  import { useStore } from '@nanostores/react';
3
+ import PlusCircleIcon from '@heroicons/react/24/outline/PlusCircleIcon';
3
4
  import { settingsPanelStore } from '@/stores/storykeep';
4
5
  import AddPaneNewPanel from './AddPanePanel_new';
5
6
  import AddPaneBreakPanel from './AddPanePanel_break';
6
7
  import AddPaneReUsePanel from './AddPanePanel_reuse';
7
8
  import AddPaneCodeHookPanel from './AddPanePanel_codehook';
9
+ import AddPanePanel_paste from './AddPanePanel_paste';
8
10
  import { NodesContext, ROOT_NODE_NAME, getCtx } from '@/stores/nodes';
9
11
  import { PaneAddMode } from '@/types/compositorTypes';
10
- import type { BrandConfig } from '@/types/tractstack';
11
12
 
12
13
  interface AddPanePanelProps {
13
14
  nodeId: string;
@@ -15,7 +16,6 @@ interface AddPanePanelProps {
15
16
  ctx?: NodesContext;
16
17
  isStoryFragment?: boolean;
17
18
  isContextPane?: boolean;
18
- config?: BrandConfig;
19
19
  isSandboxMode?: boolean;
20
20
  }
21
21
 
@@ -25,16 +25,14 @@ const AddPanePanel = ({
25
25
  ctx,
26
26
  isStoryFragment = false,
27
27
  isContextPane = false,
28
- config,
29
28
  isSandboxMode = false,
30
29
  }: AddPanePanelProps) => {
31
30
  const [reset, setReset] = useState(false);
32
- const lookup = first ? `${nodeId}-0` : nodeId;
31
+ const [isExpanded, setIsExpanded] = useState(false);
33
32
 
34
- // Always get a valid context, either from props or the global getter
33
+ const lookup = first ? `${nodeId}-0` : nodeId;
35
34
  const nodesCtx = ctx || getCtx();
36
35
 
37
- // Use the guaranteed context to subscribe to stores
38
36
  const activePaneMode = useStore(nodesCtx.activePaneMode);
39
37
  const hasPanes = useStore(nodesCtx.hasPanes);
40
38
  const isTemplate = useStore(nodesCtx.isTemplate);
@@ -51,14 +49,31 @@ const AddPanePanel = ({
51
49
 
52
50
  const setMode = (newMode: PaneAddMode, reset?: boolean) => {
53
51
  setReset(true);
54
- nodesCtx.setPanelMode(lookup, 'add', newMode); // No longer needs optional chaining
52
+ nodesCtx.setPanelMode(lookup, 'add', newMode);
53
+ if (newMode === PaneAddMode.DEFAULT) {
54
+ setIsExpanded(false);
55
+ }
55
56
  if (reset) nodesCtx.notifyNode(ROOT_NODE_NAME);
56
57
  settingsPanelStore.set(null);
57
58
  };
58
59
 
59
- // Always render a stable container div for the intersection observer
60
60
  return (
61
61
  <div className="add-pane-panel-wrapper border-mydarkgrey border-b-2 border-t-2 border-dotted">
62
+ {isExpanded && (
63
+ <div className="border-mylightgrey border-t border-dotted">
64
+ <div className="group flex w-full flex-wrap items-center gap-2 px-1.5 pb-0.5 pt-1.5">
65
+ <button
66
+ onClick={() => {
67
+ setMode(PaneAddMode.DEFAULT);
68
+ setIsExpanded(false);
69
+ }}
70
+ className="rounded-md bg-gray-200 px-2 py-1 text-sm font-bold text-gray-800"
71
+ >
72
+ &lt; Cancel
73
+ </button>
74
+ </div>
75
+ </div>
76
+ )}
62
77
  {mode === PaneAddMode.NEW || (!hasPanes && first && !reset) ? (
63
78
  <AddPaneNewPanel
64
79
  nodeId={nodeId}
@@ -67,7 +82,6 @@ const AddPanePanel = ({
67
82
  ctx={nodesCtx}
68
83
  isStoryFragment={isStoryFragment}
69
84
  isContextPane={isContextPane}
70
- config={config!}
71
85
  isSandboxMode={isSandboxMode}
72
86
  />
73
87
  ) : mode === PaneAddMode.BREAK && !isContextPane ? (
@@ -79,30 +93,31 @@ const AddPanePanel = ({
79
93
  isStoryFragment={isStoryFragment}
80
94
  />
81
95
  ) : mode === PaneAddMode.REUSE && !isContextPane ? (
82
- <AddPaneReUsePanel
96
+ <AddPaneReUsePanel nodeId={nodeId} first={first} setMode={setMode} />
97
+ ) : mode === PaneAddMode.CODEHOOK ? (
98
+ <AddPaneCodeHookPanel
83
99
  nodeId={nodeId}
84
100
  first={first}
85
101
  setMode={setMode}
86
- //ctx={nodesCtx}
102
+ isStoryFragment={isStoryFragment}
103
+ isContextPane={isContextPane}
87
104
  />
88
- ) : mode === PaneAddMode.CODEHOOK ? (
89
- <AddPaneCodeHookPanel
105
+ ) : mode === PaneAddMode.PASTE ? (
106
+ <AddPanePanel_paste
90
107
  nodeId={nodeId}
91
108
  first={first}
92
109
  setMode={setMode}
110
+ ctx={nodesCtx}
93
111
  isStoryFragment={isStoryFragment}
94
112
  isContextPane={isContextPane}
95
113
  />
96
- ) : (
114
+ ) : isExpanded ? (
97
115
  <div className="border-mylightgrey border-t border-dotted">
98
- <div className="group flex w-full gap-1 px-1.5 pb-0.5 pt-1.5">
99
- <div className="rounded-md bg-gray-200 px-2 py-1 text-sm text-gray-800">
100
- Insert Pane Here
101
- </div>
102
- <div className={`flex gap-1 transition-opacity`}>
116
+ <div className="group flex w-full flex-wrap items-center gap-2 px-1.5 pb-0.5 pt-1.5">
117
+ <div className={`flex flex-wrap gap-1 transition-opacity`}>
103
118
  <button
104
119
  onClick={() => setMode(PaneAddMode.NEW)}
105
- className="rounded bg-white px-2 py-1 text-sm text-cyan-700 shadow-sm transition-colors hover:bg-cyan-700 hover:text-white focus:bg-cyan-700 focus:text-white"
120
+ className="rounded bg-white px-2 py-1 text-sm text-cyan-700 shadow-sm transition-colors hover:bg-cyan-700 hover:text-white"
106
121
  >
107
122
  + Design New
108
123
  </button>
@@ -110,16 +125,16 @@ const AddPanePanel = ({
110
125
  <>
111
126
  <button
112
127
  onClick={() => setMode(PaneAddMode.BREAK)}
113
- className="rounded bg-white px-2 py-1 text-sm text-cyan-700 shadow-sm transition-colors hover:bg-cyan-700 hover:text-white focus:bg-cyan-700 focus:text-white"
128
+ className="rounded bg-white px-2 py-1 text-sm text-cyan-700 shadow-sm transition-colors hover:bg-cyan-700 hover:text-white"
114
129
  >
115
130
  + Visual Break
116
131
  </button>
117
132
  {!isTemplate && (
118
133
  <button
119
134
  onClick={() => setMode(PaneAddMode.REUSE)}
120
- className="rounded bg-white px-2 py-1 text-sm text-cyan-700 shadow-sm transition-colors hover:bg-cyan-700 hover:text-white focus:bg-cyan-700 focus:text-white"
135
+ className="rounded bg-white px-2 py-1 text-sm text-cyan-700 shadow-sm transition-colors hover:bg-cyan-700 hover:text-white"
121
136
  >
122
- + Re-use existing pane
137
+ + Re-use Pane
123
138
  </button>
124
139
  )}
125
140
  </>
@@ -127,14 +142,32 @@ const AddPanePanel = ({
127
142
  {!isTemplate && (
128
143
  <button
129
144
  onClick={() => setMode(PaneAddMode.CODEHOOK)}
130
- className="rounded bg-white px-2 py-1 text-sm text-cyan-700 shadow-sm transition-colors hover:bg-cyan-700 hover:text-white focus:bg-cyan-700 focus:text-white"
145
+ className="rounded bg-white px-2 py-1 text-sm text-cyan-700 shadow-sm transition-colors hover:bg-cyan-700 hover:text-white"
131
146
  >
132
- + Custom Code Hook
147
+ + Code Hook
133
148
  </button>
134
149
  )}
150
+ <button
151
+ onClick={() => setMode(PaneAddMode.PASTE)}
152
+ className="rounded bg-white px-2 py-1 text-sm text-cyan-700 shadow-sm transition-colors hover:bg-cyan-700 hover:text-white"
153
+ >
154
+ + Paste Pane
155
+ </button>
135
156
  </div>
136
157
  </div>
137
158
  </div>
159
+ ) : (
160
+ <div className="border-mylightgrey flex border-t border-dotted p-0.5">
161
+ <button
162
+ onClick={() => setIsExpanded(true)}
163
+ title="Insert Pane here"
164
+ className="group w-full text-gray-500"
165
+ >
166
+ <div className="text-mydarkgrey hover:bg-myoffwhite rounded-md transition-colors duration-150 ease-in-out hover:bg-opacity-50 hover:mix-blend-difference">
167
+ <PlusCircleIcon className="mx-auto h-8 w-8" />
168
+ </div>
169
+ </button>
170
+ </div>
138
171
  )}
139
172
  </div>
140
173
  );