astro-tractstack 2.0.19 → 2.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +6 -32
- package/package.json +1 -1
- package/templates/src/components/codehooks/BunnyVideoSetup.tsx +1 -4
- package/templates/src/components/codehooks/FeaturedArticleSetup.tsx +0 -4
- package/templates/src/components/codehooks/ListContentSetup.tsx +1 -8
- package/templates/src/components/codehooks/ProductCardSetup.tsx +0 -2
- package/templates/src/components/codehooks/ProductGridSetup.tsx +0 -2
- package/templates/src/components/compositor/Compositor.tsx +3 -6
- package/templates/src/components/compositor/Node.tsx +13 -32
- package/templates/src/components/compositor/NodeWithGuid.tsx +49 -5
- package/templates/src/components/compositor/nodes/Pane.tsx +4 -21
- package/templates/src/components/compositor/nodes/Pane_DesignLibrary.tsx +27 -7
- package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag.tsx +3 -1
- package/templates/src/components/compositor/preview/OgImagePreview.tsx +0 -5
- package/templates/src/components/compositor/preview/PaneSnapshotGenerator.tsx +5 -6
- package/templates/src/components/compositor/preview/PanesPreviewGenerator.tsx +1 -0
- package/templates/src/components/edit/PanelSwitch.tsx +3 -24
- package/templates/src/components/edit/SettingsPanel.tsx +0 -1
- package/templates/src/components/edit/ToolMode.tsx +6 -14
- package/templates/src/components/edit/pane/AddPanePanel.tsx +45 -25
- package/templates/src/components/edit/pane/AddPanePanel_new.tsx +2 -8
- package/templates/src/components/edit/pane/AddPanePanel_paste.tsx +111 -0
- package/templates/src/components/edit/pane/RestylePaneModal.tsx +6 -13
- package/templates/src/components/edit/pane/steps/AiDesignStep.tsx +0 -5
- package/templates/src/components/edit/pane/steps/DesignLibraryStep.tsx +4 -11
- package/templates/src/components/edit/panels/StyleBreakPanel.tsx +1 -3
- package/templates/src/components/edit/panels/StyleElementPanel_update.tsx +0 -6
- package/templates/src/components/edit/panels/StyleImagePanel_update.tsx +0 -3
- package/templates/src/components/edit/panels/StyleLiElementPanel_update.tsx +0 -4
- package/templates/src/components/edit/panels/StyleLinkPanel_config.tsx +8 -5
- package/templates/src/components/edit/panels/StyleLinkPanel_update.tsx +1 -2
- package/templates/src/components/edit/panels/StyleParentPanel.tsx +1 -3
- package/templates/src/components/edit/panels/StyleParentPanel_update.tsx +2 -5
- package/templates/src/components/edit/panels/StyleWidgetPanel_config.tsx +2 -8
- package/templates/src/components/edit/panels/StyleWidgetPanel_update.tsx +0 -4
- package/templates/src/components/edit/state/SaveToLibraryModal.tsx +27 -16
- package/templates/src/components/edit/storyfragment/StoryFragmentConfigPanel.tsx +9 -26
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_og.tsx +7 -16
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_slug.tsx +5 -6
- package/templates/src/components/edit/widgets/InteractiveDisclosureWidget.tsx +0 -5
- package/templates/src/components/fields/BackgroundImageWrapper.tsx +1 -7
- package/templates/src/components/fields/ColorPickerCombo.tsx +8 -12
- package/templates/src/components/fields/ViewportComboBox.tsx +4 -6
- package/templates/src/stores/nodes.ts +14 -6
- package/templates/src/stores/storykeep.ts +3 -3
- package/templates/src/types/compositorTypes.ts +2 -0
- package/templates/src/utils/compositor/TemplatePanes.ts +0 -76
- package/templates/src/utils/compositor/aiPaneParser.ts +3 -1
- package/templates/src/utils/compositor/designLibraryHelper.ts +240 -17
- package/templates/src/utils/helpers.ts +5 -4
- package/utils/inject-files.ts +6 -32
- package/templates/src/components/compositor/preview/VisualBreakPreview.tsx +0 -154
- package/templates/src/components/edit/pane/PageGen_preview.tsx +0 -511
- package/templates/src/utils/compositor/processMarkdown.ts +0 -445
- 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
|
|
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 =
|
|
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
|
-
|
|
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,
|
|
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
|
|
|
@@ -5,9 +5,9 @@ import AddPaneNewPanel from './AddPanePanel_new';
|
|
|
5
5
|
import AddPaneBreakPanel from './AddPanePanel_break';
|
|
6
6
|
import AddPaneReUsePanel from './AddPanePanel_reuse';
|
|
7
7
|
import AddPaneCodeHookPanel from './AddPanePanel_codehook';
|
|
8
|
+
import AddPanePanel_paste from './AddPanePanel_paste';
|
|
8
9
|
import { NodesContext, ROOT_NODE_NAME, getCtx } from '@/stores/nodes';
|
|
9
10
|
import { PaneAddMode } from '@/types/compositorTypes';
|
|
10
|
-
import type { BrandConfig } from '@/types/tractstack';
|
|
11
11
|
|
|
12
12
|
interface AddPanePanelProps {
|
|
13
13
|
nodeId: string;
|
|
@@ -15,7 +15,6 @@ interface AddPanePanelProps {
|
|
|
15
15
|
ctx?: NodesContext;
|
|
16
16
|
isStoryFragment?: boolean;
|
|
17
17
|
isContextPane?: boolean;
|
|
18
|
-
config?: BrandConfig;
|
|
19
18
|
isSandboxMode?: boolean;
|
|
20
19
|
}
|
|
21
20
|
|
|
@@ -25,16 +24,14 @@ const AddPanePanel = ({
|
|
|
25
24
|
ctx,
|
|
26
25
|
isStoryFragment = false,
|
|
27
26
|
isContextPane = false,
|
|
28
|
-
config,
|
|
29
27
|
isSandboxMode = false,
|
|
30
28
|
}: AddPanePanelProps) => {
|
|
31
29
|
const [reset, setReset] = useState(false);
|
|
32
|
-
const
|
|
30
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
33
31
|
|
|
34
|
-
|
|
32
|
+
const lookup = first ? `${nodeId}-0` : nodeId;
|
|
35
33
|
const nodesCtx = ctx || getCtx();
|
|
36
34
|
|
|
37
|
-
// Use the guaranteed context to subscribe to stores
|
|
38
35
|
const activePaneMode = useStore(nodesCtx.activePaneMode);
|
|
39
36
|
const hasPanes = useStore(nodesCtx.hasPanes);
|
|
40
37
|
const isTemplate = useStore(nodesCtx.isTemplate);
|
|
@@ -51,12 +48,14 @@ const AddPanePanel = ({
|
|
|
51
48
|
|
|
52
49
|
const setMode = (newMode: PaneAddMode, reset?: boolean) => {
|
|
53
50
|
setReset(true);
|
|
54
|
-
nodesCtx.setPanelMode(lookup, 'add', newMode);
|
|
51
|
+
nodesCtx.setPanelMode(lookup, 'add', newMode);
|
|
52
|
+
if (newMode === PaneAddMode.DEFAULT) {
|
|
53
|
+
setIsExpanded(false);
|
|
54
|
+
}
|
|
55
55
|
if (reset) nodesCtx.notifyNode(ROOT_NODE_NAME);
|
|
56
56
|
settingsPanelStore.set(null);
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
-
// Always render a stable container div for the intersection observer
|
|
60
59
|
return (
|
|
61
60
|
<div className="add-pane-panel-wrapper border-mydarkgrey border-b-2 border-t-2 border-dotted">
|
|
62
61
|
{mode === PaneAddMode.NEW || (!hasPanes && first && !reset) ? (
|
|
@@ -67,7 +66,6 @@ const AddPanePanel = ({
|
|
|
67
66
|
ctx={nodesCtx}
|
|
68
67
|
isStoryFragment={isStoryFragment}
|
|
69
68
|
isContextPane={isContextPane}
|
|
70
|
-
config={config!}
|
|
71
69
|
isSandboxMode={isSandboxMode}
|
|
72
70
|
/>
|
|
73
71
|
) : mode === PaneAddMode.BREAK && !isContextPane ? (
|
|
@@ -79,47 +77,60 @@ const AddPanePanel = ({
|
|
|
79
77
|
isStoryFragment={isStoryFragment}
|
|
80
78
|
/>
|
|
81
79
|
) : mode === PaneAddMode.REUSE && !isContextPane ? (
|
|
82
|
-
<AddPaneReUsePanel
|
|
80
|
+
<AddPaneReUsePanel nodeId={nodeId} first={first} setMode={setMode} />
|
|
81
|
+
) : mode === PaneAddMode.CODEHOOK ? (
|
|
82
|
+
<AddPaneCodeHookPanel
|
|
83
83
|
nodeId={nodeId}
|
|
84
84
|
first={first}
|
|
85
85
|
setMode={setMode}
|
|
86
|
-
|
|
86
|
+
isStoryFragment={isStoryFragment}
|
|
87
|
+
isContextPane={isContextPane}
|
|
87
88
|
/>
|
|
88
|
-
) : mode === PaneAddMode.
|
|
89
|
-
<
|
|
89
|
+
) : mode === PaneAddMode.PASTE ? (
|
|
90
|
+
<AddPanePanel_paste
|
|
90
91
|
nodeId={nodeId}
|
|
91
92
|
first={first}
|
|
92
93
|
setMode={setMode}
|
|
94
|
+
ctx={nodesCtx}
|
|
93
95
|
isStoryFragment={isStoryFragment}
|
|
94
96
|
isContextPane={isContextPane}
|
|
95
97
|
/>
|
|
96
|
-
) : (
|
|
98
|
+
) : isExpanded ? (
|
|
97
99
|
<div className="border-mylightgrey border-t border-dotted">
|
|
98
|
-
<div className="group flex w-full gap-
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
<div className="group flex w-full flex-wrap items-center gap-2 px-1.5 pb-0.5 pt-1.5">
|
|
101
|
+
<button
|
|
102
|
+
onClick={() => setIsExpanded(false)}
|
|
103
|
+
className="rounded-md bg-gray-200 px-2 py-1 text-sm font-bold text-gray-800"
|
|
104
|
+
>
|
|
105
|
+
< Cancel
|
|
106
|
+
</button>
|
|
107
|
+
<div className={`flex flex-wrap gap-1 transition-opacity`}>
|
|
103
108
|
<button
|
|
104
109
|
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
|
|
110
|
+
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
111
|
>
|
|
107
112
|
+ Design New
|
|
108
113
|
</button>
|
|
114
|
+
<button
|
|
115
|
+
onClick={() => setMode(PaneAddMode.PASTE)}
|
|
116
|
+
className="rounded bg-white px-2 py-1 text-sm text-cyan-700 shadow-sm transition-colors hover:bg-cyan-700 hover:text-white"
|
|
117
|
+
>
|
|
118
|
+
+ Paste Pane
|
|
119
|
+
</button>
|
|
109
120
|
{!isContextPane && (
|
|
110
121
|
<>
|
|
111
122
|
<button
|
|
112
123
|
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
|
|
124
|
+
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
125
|
>
|
|
115
126
|
+ Visual Break
|
|
116
127
|
</button>
|
|
117
128
|
{!isTemplate && (
|
|
118
129
|
<button
|
|
119
130
|
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
|
|
131
|
+
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
132
|
>
|
|
122
|
-
+ Re-use
|
|
133
|
+
+ Re-use Pane
|
|
123
134
|
</button>
|
|
124
135
|
)}
|
|
125
136
|
</>
|
|
@@ -127,14 +138,23 @@ const AddPanePanel = ({
|
|
|
127
138
|
{!isTemplate && (
|
|
128
139
|
<button
|
|
129
140
|
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
|
|
141
|
+
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
142
|
>
|
|
132
|
-
+
|
|
143
|
+
+ Code Hook
|
|
133
144
|
</button>
|
|
134
145
|
)}
|
|
135
146
|
</div>
|
|
136
147
|
</div>
|
|
137
148
|
</div>
|
|
149
|
+
) : (
|
|
150
|
+
<div className="border-mylightgrey border-t border-dotted p-2">
|
|
151
|
+
<button
|
|
152
|
+
onClick={() => setIsExpanded(true)}
|
|
153
|
+
className="text-sm text-gray-500 underline decoration-dotted underline-offset-4 transition-colors hover:text-cyan-700"
|
|
154
|
+
>
|
|
155
|
+
Insert Pane Here
|
|
156
|
+
</button>
|
|
157
|
+
</div>
|
|
138
158
|
)}
|
|
139
159
|
</div>
|
|
140
160
|
);
|
|
@@ -9,7 +9,7 @@ import { NodesContext, getCtx } from '@/stores/nodes';
|
|
|
9
9
|
import { cloneDeep } from '@/utils/helpers';
|
|
10
10
|
import { hasAssemblyAIStore } from '@/stores/storykeep';
|
|
11
11
|
import prompts from '@/constants/prompts.json';
|
|
12
|
-
import type {
|
|
12
|
+
import type { DesignLibraryEntry } from '@/types/tractstack';
|
|
13
13
|
import { PaneAddMode, type TemplatePane } from '@/types/compositorTypes';
|
|
14
14
|
import { useStore } from '@nanostores/react';
|
|
15
15
|
import { CopyInputStep } from './steps/CopyInputStep';
|
|
@@ -120,7 +120,6 @@ interface AddPaneNewPanelProps {
|
|
|
120
120
|
ctx?: NodesContext;
|
|
121
121
|
isStoryFragment?: boolean;
|
|
122
122
|
isContextPane?: boolean;
|
|
123
|
-
config?: BrandConfig;
|
|
124
123
|
isSandboxMode?: boolean;
|
|
125
124
|
}
|
|
126
125
|
|
|
@@ -131,7 +130,6 @@ const AddPaneNewPanel = ({
|
|
|
131
130
|
ctx: providedCtx,
|
|
132
131
|
isStoryFragment = false,
|
|
133
132
|
isContextPane = false,
|
|
134
|
-
config,
|
|
135
133
|
isSandboxMode = false,
|
|
136
134
|
}: AddPaneNewPanelProps) => {
|
|
137
135
|
const ctx = providedCtx || getCtx();
|
|
@@ -672,17 +670,13 @@ const AddPaneNewPanel = ({
|
|
|
672
670
|
← Back to Choice
|
|
673
671
|
</button>
|
|
674
672
|
</div>
|
|
675
|
-
<DesignLibraryStep
|
|
676
|
-
config={config!}
|
|
677
|
-
onSelect={handleDesignLibrarySelect}
|
|
678
|
-
/>
|
|
673
|
+
<DesignLibraryStep onSelect={handleDesignLibrarySelect} />
|
|
679
674
|
</div>
|
|
680
675
|
);
|
|
681
676
|
|
|
682
677
|
const renderAiDesignStep = () => (
|
|
683
678
|
<div className="space-y-4 p-4">
|
|
684
679
|
<AiDesignStep
|
|
685
|
-
config={config!}
|
|
686
680
|
designConfig={aiDesignConfig}
|
|
687
681
|
onDesignConfigChange={setAiDesignConfig}
|
|
688
682
|
/>
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { getCtx, type NodesContext } from '@/stores/nodes';
|
|
3
|
+
import { PaneAddMode, type StoragePane } from '@/types/compositorTypes';
|
|
4
|
+
import {
|
|
5
|
+
remapPaneIds,
|
|
6
|
+
convertStorageToLiveTemplate,
|
|
7
|
+
} from '@/utils/compositor/designLibraryHelper';
|
|
8
|
+
|
|
9
|
+
interface AddPanePanelPasteProps {
|
|
10
|
+
nodeId: string;
|
|
11
|
+
first: boolean;
|
|
12
|
+
setMode: (mode: PaneAddMode, reset?: boolean) => void;
|
|
13
|
+
ctx?: NodesContext;
|
|
14
|
+
isStoryFragment?: boolean;
|
|
15
|
+
isContextPane?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const AddPanePanel_paste = ({
|
|
19
|
+
nodeId,
|
|
20
|
+
first,
|
|
21
|
+
setMode,
|
|
22
|
+
ctx: providedCtx,
|
|
23
|
+
isStoryFragment,
|
|
24
|
+
isContextPane,
|
|
25
|
+
}: AddPanePanelPasteProps) => {
|
|
26
|
+
const [jsonInput, setJsonInput] = useState('');
|
|
27
|
+
const [error, setError] = useState<string | null>(null);
|
|
28
|
+
const ctx = providedCtx || getCtx();
|
|
29
|
+
|
|
30
|
+
const handleCreate = () => {
|
|
31
|
+
setError(null);
|
|
32
|
+
if (!jsonInput.trim()) {
|
|
33
|
+
setError('Paste content cannot be empty.');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const parsedPane = JSON.parse(jsonInput) as StoragePane;
|
|
39
|
+
if (parsedPane.nodeType !== 'Pane') {
|
|
40
|
+
throw new Error('Pasted content is not a valid Pane object.');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const remappedPane = remapPaneIds(parsedPane);
|
|
44
|
+
const liveTemplate = convertStorageToLiveTemplate(remappedPane);
|
|
45
|
+
|
|
46
|
+
const ownerId =
|
|
47
|
+
isStoryFragment || isContextPane
|
|
48
|
+
? nodeId
|
|
49
|
+
: ctx.getClosestNodeTypeFromId(nodeId, 'StoryFragment');
|
|
50
|
+
|
|
51
|
+
ctx.addTemplatePane(
|
|
52
|
+
ownerId,
|
|
53
|
+
liveTemplate,
|
|
54
|
+
nodeId,
|
|
55
|
+
first ? 'before' : 'after'
|
|
56
|
+
);
|
|
57
|
+
ctx.notifyNode('root');
|
|
58
|
+
setMode(PaneAddMode.DEFAULT, true);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
const message =
|
|
61
|
+
err instanceof Error
|
|
62
|
+
? err.message
|
|
63
|
+
: 'An unknown error occurred during parsing.';
|
|
64
|
+
setError(`Invalid Pane JSON: ${message}`);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<div className="p-2 shadow-inner">
|
|
70
|
+
<div className="rounded-md border bg-gray-50 p-4">
|
|
71
|
+
<div className="flex items-center justify-between pb-4">
|
|
72
|
+
<div className="flex items-center gap-2">
|
|
73
|
+
<button
|
|
74
|
+
onClick={() => setMode(PaneAddMode.DEFAULT)}
|
|
75
|
+
className="w-fit rounded bg-gray-200 px-3 py-1 text-sm text-gray-800 transition-colors hover:bg-gray-300"
|
|
76
|
+
>
|
|
77
|
+
← Go Back
|
|
78
|
+
</button>
|
|
79
|
+
<h3 className="font-action text-sm font-bold text-cyan-700">
|
|
80
|
+
Paste Pane
|
|
81
|
+
</h3>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
<div className="space-y-4">
|
|
85
|
+
<p className="text-sm text-gray-600">
|
|
86
|
+
Paste the JSON content of a copied pane into the text area below.
|
|
87
|
+
</p>
|
|
88
|
+
<textarea
|
|
89
|
+
value={jsonInput}
|
|
90
|
+
onChange={(e) => setJsonInput(e.target.value)}
|
|
91
|
+
placeholder="Paste pane JSON here..."
|
|
92
|
+
className="h-48 w-full rounded-md border border-gray-300 bg-white p-2 font-mono text-xs focus:border-cyan-500 focus:ring-cyan-500"
|
|
93
|
+
spellCheck={false}
|
|
94
|
+
/>
|
|
95
|
+
{error && <p className="text-sm text-red-600">{error}</p>}
|
|
96
|
+
<div className="flex justify-end">
|
|
97
|
+
<button
|
|
98
|
+
onClick={handleCreate}
|
|
99
|
+
disabled={!jsonInput.trim()}
|
|
100
|
+
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"
|
|
101
|
+
>
|
|
102
|
+
Create Pane from Paste
|
|
103
|
+
</button>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export default AddPanePanel_paste;
|
|
@@ -15,6 +15,7 @@ import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon';
|
|
|
15
15
|
import { selectionStore } from '@/stores/selection';
|
|
16
16
|
import { getCtx, NodesContext } from '@/stores/nodes';
|
|
17
17
|
import { createEmptyStorykeep } from '@/utils/compositor/nodesHelper';
|
|
18
|
+
import { brandConfigStore } from '@/stores/storykeep';
|
|
18
19
|
import {
|
|
19
20
|
extractPaneCopy,
|
|
20
21
|
mergeCopyIntoTemplate,
|
|
@@ -24,10 +25,10 @@ import type {
|
|
|
24
25
|
PaneNode,
|
|
25
26
|
StoragePane,
|
|
26
27
|
TemplatePane,
|
|
27
|
-
TemplateMarkdown,
|
|
28
|
-
BaseNode,
|
|
28
|
+
TemplateMarkdown,
|
|
29
|
+
BaseNode,
|
|
29
30
|
} from '@/types/compositorTypes';
|
|
30
|
-
import type {
|
|
31
|
+
import type { DesignLibraryEntry } from '@/types/tractstack';
|
|
31
32
|
import {
|
|
32
33
|
PaneSnapshotGenerator,
|
|
33
34
|
type SnapshotData,
|
|
@@ -44,13 +45,11 @@ const VERBOSE = false;
|
|
|
44
45
|
|
|
45
46
|
interface TemplatePreviewItemProps {
|
|
46
47
|
template: TemplatePane;
|
|
47
|
-
config: BrandConfig;
|
|
48
48
|
onClick: () => void;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
const TemplatePreviewItem = ({
|
|
52
52
|
template,
|
|
53
|
-
config,
|
|
54
53
|
onClick,
|
|
55
54
|
}: TemplatePreviewItemProps) => {
|
|
56
55
|
const [previewState, setPreviewState] = useState<{
|
|
@@ -111,7 +110,6 @@ const TemplatePreviewItem = ({
|
|
|
111
110
|
id={template.id}
|
|
112
111
|
htmlString={previewState.htmlFragment}
|
|
113
112
|
outputWidth={800}
|
|
114
|
-
config={config}
|
|
115
113
|
onComplete={(_id, data) => handleSnapshotComplete(data)}
|
|
116
114
|
onError={(_id, err) =>
|
|
117
115
|
setPreviewState((prev) =>
|
|
@@ -141,16 +139,12 @@ const TemplatePreviewItem = ({
|
|
|
141
139
|
);
|
|
142
140
|
};
|
|
143
141
|
|
|
144
|
-
|
|
145
|
-
config: BrandConfig;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export const RestylePaneModal = ({ config }: RestylePaneModalProps) => {
|
|
142
|
+
export const RestylePaneModal = () => {
|
|
149
143
|
const ctx = getCtx();
|
|
150
144
|
const { isRestyleModalOpen, paneToRestyleId } = useStore(selectionStore, {
|
|
151
145
|
keys: ['isRestyleModalOpen', 'paneToRestyleId'],
|
|
152
146
|
});
|
|
153
|
-
const designLibrary =
|
|
147
|
+
const designLibrary = brandConfigStore.get()?.DESIGN_LIBRARY || [];
|
|
154
148
|
|
|
155
149
|
const [selectedCategory, setSelectedCategory] = useState<string>('all');
|
|
156
150
|
const [searchTerm, setSearchTerm] = useState('');
|
|
@@ -502,7 +496,6 @@ export const RestylePaneModal = ({ config }: RestylePaneModalProps) => {
|
|
|
502
496
|
<TemplatePreviewItem
|
|
503
497
|
key={template.id}
|
|
504
498
|
template={template}
|
|
505
|
-
config={config}
|
|
506
499
|
onClick={() => handleSelectTemplate(template)}
|
|
507
500
|
/>
|
|
508
501
|
))}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import ColorPickerCombo from '@/components/fields/ColorPickerCombo';
|
|
2
|
-
import type { BrandConfig } from '@/types/tractstack';
|
|
3
2
|
|
|
4
3
|
export interface AiDesignConfig {
|
|
5
4
|
harmony: string;
|
|
@@ -10,7 +9,6 @@ export interface AiDesignConfig {
|
|
|
10
9
|
}
|
|
11
10
|
|
|
12
11
|
interface AiDesignStepProps {
|
|
13
|
-
config: BrandConfig;
|
|
14
12
|
designConfig: AiDesignConfig;
|
|
15
13
|
onDesignConfigChange: (newConfig: AiDesignConfig) => void;
|
|
16
14
|
}
|
|
@@ -24,7 +22,6 @@ const harmonyOptions = [
|
|
|
24
22
|
const themeOptions = ['Light', 'Dark', 'Bright', 'Muted', 'Pastel', 'Earthy'];
|
|
25
23
|
|
|
26
24
|
export const AiDesignStep = ({
|
|
27
|
-
config,
|
|
28
25
|
designConfig,
|
|
29
26
|
onDesignConfigChange,
|
|
30
27
|
}: AiDesignStepProps) => {
|
|
@@ -71,7 +68,6 @@ export const AiDesignStep = ({
|
|
|
71
68
|
<div>
|
|
72
69
|
<ColorPickerCombo
|
|
73
70
|
title="Base Color (Optional)"
|
|
74
|
-
config={config}
|
|
75
71
|
defaultColor={designConfig.baseColor}
|
|
76
72
|
onColorChange={(color) => updateField('baseColor', color)}
|
|
77
73
|
allowNull={true}
|
|
@@ -80,7 +76,6 @@ export const AiDesignStep = ({
|
|
|
80
76
|
<div>
|
|
81
77
|
<ColorPickerCombo
|
|
82
78
|
title="Accent Color (Optional)"
|
|
83
|
-
config={config}
|
|
84
79
|
defaultColor={designConfig.accentColor}
|
|
85
80
|
onColorChange={(color) => updateField('accentColor', color)}
|
|
86
81
|
allowNull={true}
|