astro-tractstack 2.0.28 → 2.0.30
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/package.json +1 -1
- package/templates/src/components/codehooks/SandboxAuthWrapper.tsx +30 -4
- package/templates/src/components/edit/pane/AddPanePanel_new.tsx +323 -77
- package/templates/src/components/edit/pane/steps/CopyInputStep.tsx +82 -9
- package/templates/src/components/edit/pane/steps/DirectInjectStep.tsx +41 -21
- package/templates/src/components/edit/state/SaveToLibraryModal.tsx +68 -34
- package/templates/src/constants/prompts.json +65 -36
- package/templates/src/constants.ts +3 -3
- package/templates/src/pages/sandbox.astro +62 -54
- package/templates/src/stores/nodes.ts +17 -4
- package/templates/src/types/compositorTypes.ts +3 -0
- package/templates/src/types/tractstack.ts +2 -0
- package/templates/src/utils/compositor/designLibraryHelper.ts +8 -3
- package/templates/src/utils/compositor/typeGuards.ts +0 -18
|
@@ -26,7 +26,6 @@ if (healthCheckRedirect !== undefined) {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const brandConfig = await getBrandConfig(tenantId);
|
|
29
|
-
|
|
30
29
|
const emptyStoryFragment = {
|
|
31
30
|
id: ulid(),
|
|
32
31
|
nodeType: 'StoryFragment' as const,
|
|
@@ -43,12 +42,15 @@ const loadData = {
|
|
|
43
42
|
};
|
|
44
43
|
const title = 'Sandbox - TractStack Editor';
|
|
45
44
|
const storyFragmentID = emptyStoryFragment.id;
|
|
46
|
-
|
|
47
45
|
const fullContentMap = await getFullContentMap(tenantId);
|
|
48
46
|
const urlParams: Record<string, string | boolean> = {};
|
|
49
47
|
for (const [key, value] of Astro.url.searchParams) {
|
|
50
48
|
urlParams[key] = value === '' ? true : value;
|
|
51
49
|
}
|
|
50
|
+
|
|
51
|
+
const hasProfile = Astro.request.headers
|
|
52
|
+
.get('cookie')
|
|
53
|
+
?.includes('tractstack_profile=true');
|
|
52
54
|
---
|
|
53
55
|
|
|
54
56
|
<Layout
|
|
@@ -59,7 +61,7 @@ for (const [key, value] of Astro.url.searchParams) {
|
|
|
59
61
|
isStoryKeep={true}
|
|
60
62
|
isEditor={true}
|
|
61
63
|
>
|
|
62
|
-
<SandboxAuthWrapper client:load />
|
|
64
|
+
<SandboxAuthWrapper client:load isServerSideAuthenticated={!!hasProfile} />
|
|
63
65
|
<Header
|
|
64
66
|
title={title}
|
|
65
67
|
slug="sandbox"
|
|
@@ -70,65 +72,71 @@ for (const [key, value] of Astro.url.searchParams) {
|
|
|
70
72
|
menu={null}
|
|
71
73
|
/>
|
|
72
74
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
isContext={false}
|
|
81
|
-
isSandboxMode={true}
|
|
82
|
-
client:only="react"
|
|
83
|
-
/>
|
|
84
|
-
</section>
|
|
85
|
-
|
|
86
|
-
<div class="flex min-h-screen">
|
|
87
|
-
<StoryKeepToolMode isContext={false} client:only="react" />
|
|
88
|
-
|
|
89
|
-
<main id="mainContent" class="relative flex-1 overflow-x-auto">
|
|
90
|
-
<div class="bg-myblue/20 bg-mylightgrey h-full p-1.5">
|
|
91
|
-
<div
|
|
92
|
-
class="h-fit min-h-screen pb-96"
|
|
93
|
-
style={{
|
|
94
|
-
backgroundImage:
|
|
95
|
-
'repeating-linear-gradient(135deg, transparent, transparent 10px, rgba(0,0,0,0.05) 10px, rgba(0,0,0,0.05) 20px)',
|
|
96
|
-
}}
|
|
75
|
+
{
|
|
76
|
+
hasProfile && (
|
|
77
|
+
<>
|
|
78
|
+
<section
|
|
79
|
+
id="storykeepHeader"
|
|
80
|
+
role="banner"
|
|
81
|
+
class="z-101 bg-mywhite left-0 right-0 drop-shadow transition-all duration-200"
|
|
97
82
|
>
|
|
98
|
-
<
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
config={brandConfig}
|
|
102
|
-
fullContentMap={fullContentMap}
|
|
103
|
-
fullCanonicalURL="/sandbox"
|
|
104
|
-
urlParams={urlParams}
|
|
105
|
-
availableCodeHooks={Object.keys(codeHookComponents)}
|
|
83
|
+
<StoryKeepHeader
|
|
84
|
+
slug="sandbox"
|
|
85
|
+
isContext={false}
|
|
106
86
|
isSandboxMode={true}
|
|
107
87
|
client:only="react"
|
|
108
88
|
/>
|
|
89
|
+
</section>
|
|
90
|
+
|
|
91
|
+
<div class="flex min-h-screen">
|
|
92
|
+
<StoryKeepToolMode isContext={false} client:only="react" />
|
|
93
|
+
|
|
94
|
+
<main id="mainContent" class="relative flex-1 overflow-x-auto">
|
|
95
|
+
<div class="bg-myblue/20 bg-mylightgrey h-full p-1.5">
|
|
96
|
+
<div
|
|
97
|
+
class="h-fit min-h-screen pb-96"
|
|
98
|
+
style={{
|
|
99
|
+
backgroundImage:
|
|
100
|
+
'repeating-linear-gradient(135deg, transparent, transparent 10px, rgba(0,0,0,0.05) 10px, rgba(0,0,0,0.05) 20px)',
|
|
101
|
+
}}
|
|
102
|
+
>
|
|
103
|
+
<Compositor
|
|
104
|
+
id={storyFragmentID}
|
|
105
|
+
nodes={loadData}
|
|
106
|
+
config={brandConfig}
|
|
107
|
+
fullContentMap={fullContentMap}
|
|
108
|
+
fullCanonicalURL="/sandbox"
|
|
109
|
+
urlParams={urlParams}
|
|
110
|
+
availableCodeHooks={Object.keys(codeHookComponents)}
|
|
111
|
+
isSandboxMode={true}
|
|
112
|
+
client:only="react"
|
|
113
|
+
/>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
</main>
|
|
109
117
|
</div>
|
|
110
|
-
</div>
|
|
111
|
-
</main>
|
|
112
|
-
</div>
|
|
113
118
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
<aside
|
|
120
|
+
id="settingsControls"
|
|
121
|
+
class="z-101 pointer-events-none fixed bottom-16 right-2 flex flex-col items-end gap-2 md:bottom-2"
|
|
122
|
+
>
|
|
123
|
+
<div class="pointer-events-none flex-grow" />
|
|
119
124
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
125
|
+
<div class="pointer-events-auto flex-shrink-0">
|
|
126
|
+
<StoryKeepToolBar client:only="react" />
|
|
127
|
+
</div>
|
|
123
128
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
<div class="pointer-events-auto max-h-full">
|
|
130
|
+
<SettingsPanel
|
|
131
|
+
config={brandConfig}
|
|
132
|
+
availableCodeHooks={Object.keys(codeHookComponents)}
|
|
133
|
+
client:only="react"
|
|
134
|
+
/>
|
|
135
|
+
</div>
|
|
136
|
+
</aside>
|
|
137
|
+
</>
|
|
138
|
+
)
|
|
139
|
+
}
|
|
132
140
|
</Layout>
|
|
133
141
|
|
|
134
142
|
<script>
|
|
@@ -3199,6 +3199,9 @@ export class NodesContext {
|
|
|
3199
3199
|
const allOriginalNodes: TemplateNode[] = [];
|
|
3200
3200
|
const columnNodes: TemplateMarkdown[] = [];
|
|
3201
3201
|
|
|
3202
|
+
// Instantiate generator for column markdown parsing
|
|
3203
|
+
const markdownGen = new MarkdownGenerator(this);
|
|
3204
|
+
|
|
3202
3205
|
duplicatedGrid.nodes?.forEach((originalColumn) => {
|
|
3203
3206
|
const newColumn = cloneDeep(originalColumn);
|
|
3204
3207
|
newColumn.id = ulid();
|
|
@@ -3206,12 +3209,22 @@ export class NodesContext {
|
|
|
3206
3209
|
oldToNewIdMap.set(originalColumn.id, newColumn.id);
|
|
3207
3210
|
columnNodes.push(newColumn);
|
|
3208
3211
|
|
|
3209
|
-
originalColumn.
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
+
if (originalColumn.markdownBody) {
|
|
3213
|
+
const columnContentNodes = markdownGen.markdownToFlatNodes(
|
|
3214
|
+
originalColumn.markdownBody,
|
|
3215
|
+
newColumn.id
|
|
3216
|
+
) as TemplateNode[];
|
|
3217
|
+
// Add generated nodes directly to allNodes
|
|
3218
|
+
allNodes.push(...columnContentNodes);
|
|
3219
|
+
} else {
|
|
3220
|
+
// Standard flow: collect existing nodes for remapping
|
|
3221
|
+
originalColumn.nodes?.forEach((colNode) => {
|
|
3222
|
+
allOriginalNodes.push(colNode);
|
|
3223
|
+
});
|
|
3224
|
+
}
|
|
3212
3225
|
});
|
|
3213
3226
|
|
|
3214
|
-
// Second pass: Clone all descendant nodes
|
|
3227
|
+
// Second pass: Clone all descendant nodes (only those from the standard flow)
|
|
3215
3228
|
const allClonedDescendants = allOriginalNodes.map((originalNode) => {
|
|
3216
3229
|
const newNode = cloneDeep(originalNode);
|
|
3217
3230
|
newNode.id = ulid();
|
|
@@ -281,12 +281,15 @@ export interface MarkdownPaneFragmentNode extends PaneFragmentNode {
|
|
|
281
281
|
parentClasses?: ParentClassesPayload;
|
|
282
282
|
parentCss?: string[];
|
|
283
283
|
gridClasses?: DefaultClassValue;
|
|
284
|
+
gridCss?: string;
|
|
284
285
|
}
|
|
285
286
|
|
|
286
287
|
export interface GridLayoutNode extends PaneFragmentNode {
|
|
287
288
|
nodeType: 'GridLayoutNode';
|
|
288
289
|
type: 'grid-layout';
|
|
289
290
|
parentClasses?: ParentClassesPayload;
|
|
291
|
+
parentCss?: string;
|
|
292
|
+
gridCss?: string;
|
|
290
293
|
defaultClasses?: Record<
|
|
291
294
|
string,
|
|
292
295
|
{
|
|
@@ -62,7 +62,7 @@ function convertLiveNodeToStorageNode(
|
|
|
62
62
|
fileId: copyMode === 'retain' ? node.fileId : undefined,
|
|
63
63
|
buttonPayload: copyMode === 'retain' ? node.buttonPayload : undefined,
|
|
64
64
|
codeHookParams: copyMode === 'retain' ? node.codeHookParams : undefined,
|
|
65
|
-
|
|
65
|
+
copy: copyMode === 'retain' ? node.copy : undefined,
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
const childIds = ctx.getChildNodeIDs(node.id);
|
|
@@ -500,7 +500,8 @@ function convertLivePaneToStoragePane(
|
|
|
500
500
|
: [],
|
|
501
501
|
};
|
|
502
502
|
} else if (gridLayoutNode) {
|
|
503
|
-
const { id, parentId, isChanged, ...restOfGrid } =
|
|
503
|
+
const { id, parentId, isChanged, parentCss, gridCss, ...restOfGrid } =
|
|
504
|
+
gridLayoutNode;
|
|
504
505
|
storageGridLayout = {
|
|
505
506
|
...restOfGrid,
|
|
506
507
|
nodes: ctx
|
|
@@ -517,6 +518,7 @@ function convertLivePaneToStoragePane(
|
|
|
517
518
|
isChanged,
|
|
518
519
|
markdownId,
|
|
519
520
|
parentCss,
|
|
521
|
+
gridCss,
|
|
520
522
|
...restOfColumn
|
|
521
523
|
} = columnNode;
|
|
522
524
|
|
|
@@ -584,10 +586,11 @@ export async function savePaneToLibrary(
|
|
|
584
586
|
title: string;
|
|
585
587
|
category: string;
|
|
586
588
|
copyMode: CopyMode;
|
|
589
|
+
locked?: boolean;
|
|
587
590
|
}
|
|
588
591
|
): Promise<BrandConfigState | null> {
|
|
589
592
|
const ctx = getCtx();
|
|
590
|
-
const { title, category, copyMode } = formData;
|
|
593
|
+
const { title, category, copyMode, locked } = formData;
|
|
591
594
|
|
|
592
595
|
const newStoragePane = convertLivePaneToStoragePane(paneId, ctx, {
|
|
593
596
|
title,
|
|
@@ -613,6 +616,8 @@ export async function savePaneToLibrary(
|
|
|
613
616
|
title: title,
|
|
614
617
|
markdownCount: actualMarkdownCount,
|
|
615
618
|
template: newStoragePane,
|
|
619
|
+
retain: copyMode === 'retain',
|
|
620
|
+
locked: !!locked,
|
|
616
621
|
};
|
|
617
622
|
|
|
618
623
|
const currentState: BrandConfigState = convertToLocalState(config);
|
|
@@ -93,24 +93,6 @@ export const isMarkdownPaneFragmentNode = (
|
|
|
93
93
|
);
|
|
94
94
|
};
|
|
95
95
|
|
|
96
|
-
interface WidgetNode extends FlatNode {
|
|
97
|
-
tagName: 'code';
|
|
98
|
-
codeHookParams: (string | string[])[];
|
|
99
|
-
copy: string;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export const isWidgetNode = (
|
|
103
|
-
node: BaseNode | FlatNode | null
|
|
104
|
-
): node is WidgetNode => {
|
|
105
|
-
return (
|
|
106
|
-
node !== null &&
|
|
107
|
-
'tagName' in node &&
|
|
108
|
-
node.tagName === 'code' &&
|
|
109
|
-
'codeHookParams' in node &&
|
|
110
|
-
Array.isArray(node.codeHookParams)
|
|
111
|
-
);
|
|
112
|
-
};
|
|
113
|
-
|
|
114
96
|
export function hasTagName(
|
|
115
97
|
node: BaseNode | null | undefined
|
|
116
98
|
): node is FlatNode {
|