astro-tractstack 2.0.27 → 2.0.29
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
CHANGED
|
@@ -5,22 +5,48 @@ import XMarkIcon from '@heroicons/react/24/solid/XMarkIcon';
|
|
|
5
5
|
import { ProfileStorage } from '@/utils/profileStorage';
|
|
6
6
|
import SandboxRegisterForm from '@/components/codehooks/SandboxRegisterForm';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
interface SandboxAuthWrapperProps {
|
|
9
|
+
isServerSideAuthenticated: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default function SandboxAuthWrapper({
|
|
13
|
+
isServerSideAuthenticated,
|
|
14
|
+
}: SandboxAuthWrapperProps) {
|
|
9
15
|
const [profileExists, setProfileExists] = useState<boolean | null>(null);
|
|
10
16
|
|
|
11
17
|
useEffect(() => {
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
const hasLocalProfile = ProfileStorage.hasProfile();
|
|
19
|
+
|
|
20
|
+
if (hasLocalProfile && !isServerSideAuthenticated) {
|
|
21
|
+
const token = localStorage.getItem('tractstack_profile_token');
|
|
22
|
+
|
|
23
|
+
if (token) {
|
|
24
|
+
ProfileStorage.storeProfileToken(token);
|
|
25
|
+
window.location.reload();
|
|
26
|
+
return;
|
|
27
|
+
} else {
|
|
28
|
+
ProfileStorage.clearProfile();
|
|
29
|
+
setProfileExists(false);
|
|
30
|
+
}
|
|
31
|
+
} else {
|
|
32
|
+
setProfileExists(hasLocalProfile);
|
|
33
|
+
}
|
|
34
|
+
}, [isServerSideAuthenticated]);
|
|
14
35
|
|
|
15
36
|
const handleRegistrationSuccess = () => {
|
|
16
37
|
setProfileExists(true);
|
|
38
|
+
window.location.reload();
|
|
17
39
|
};
|
|
18
40
|
|
|
19
41
|
const handleClose = () => {
|
|
20
42
|
window.location.href = '/';
|
|
21
43
|
};
|
|
22
44
|
|
|
23
|
-
if (profileExists ===
|
|
45
|
+
if (profileExists === true && isServerSideAuthenticated) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (profileExists === null) {
|
|
24
50
|
return null;
|
|
25
51
|
}
|
|
26
52
|
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import { useMemo, useEffect } from 'react';
|
|
1
|
+
import { useMemo, useEffect, useState } from 'react';
|
|
2
2
|
import Cog6ToothIcon from '@heroicons/react/24/outline/Cog6ToothIcon';
|
|
3
3
|
import {
|
|
4
4
|
styleElementInfoStore,
|
|
5
5
|
resetStyleElementInfo,
|
|
6
6
|
settingsPanelStore,
|
|
7
7
|
} from '@/stores/storykeep';
|
|
8
|
+
import { getCtx } from '@/stores/nodes';
|
|
8
9
|
import { StylesMemory } from '@/components/edit/state/StylesMemory';
|
|
9
10
|
import {
|
|
10
11
|
isMarkdownPaneFragmentNode,
|
|
11
12
|
isGridLayoutNode,
|
|
12
13
|
} from '@/utils/compositor/typeGuards';
|
|
14
|
+
import { getNodeText } from '@/utils/compositor/nodesHelper';
|
|
15
|
+
import { cloneDeep } from '@/utils/helpers';
|
|
16
|
+
import { processClassesForViewports } from '@/utils/compositor/reduceNodesClassNames';
|
|
13
17
|
import SelectedTailwindClass from '@/components/fields/SelectedTailwindClass';
|
|
14
18
|
import { tagTitles } from '@/types/compositorTypes';
|
|
15
19
|
import type {
|
|
@@ -19,6 +23,78 @@ import type {
|
|
|
19
23
|
GridLayoutNode,
|
|
20
24
|
} from '@/types/compositorTypes';
|
|
21
25
|
|
|
26
|
+
type SpanOverride = {
|
|
27
|
+
mobile?: Record<string, string>;
|
|
28
|
+
tablet?: Record<string, string>;
|
|
29
|
+
desktop?: Record<string, string>;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const spanStyleClasses: SpanOverride[] = [
|
|
33
|
+
{
|
|
34
|
+
mobile: {
|
|
35
|
+
bgCLIP: 'text',
|
|
36
|
+
bgGradientDIRECTION: 'r',
|
|
37
|
+
gradientFrom: 'blue-600',
|
|
38
|
+
gradientTo: 'teal-500',
|
|
39
|
+
textCOLOR: 'transparent',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
mobile: {
|
|
44
|
+
textCOLOR: 'blue-600',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
mobile: {
|
|
49
|
+
bgCOLOR: 'yellow-300',
|
|
50
|
+
textCOLOR: 'slate-900',
|
|
51
|
+
px: '1',
|
|
52
|
+
rounded: 'sm',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
mobile: {
|
|
57
|
+
display: 'inline-block',
|
|
58
|
+
bgCOLOR: 'indigo-100',
|
|
59
|
+
textCOLOR: 'indigo-700',
|
|
60
|
+
textSIZE: 'xs',
|
|
61
|
+
fontWEIGHT: 'bold',
|
|
62
|
+
px: '2.5',
|
|
63
|
+
py: '0.5',
|
|
64
|
+
rounded: 'full',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
mobile: {
|
|
69
|
+
bgCLIP: 'text',
|
|
70
|
+
textCOLOR: 'transparent',
|
|
71
|
+
bgGradientDIRECTION: 'r',
|
|
72
|
+
gradientFrom: 'orange-400',
|
|
73
|
+
gradientVia: 'pink-500',
|
|
74
|
+
gradientTo: 'purple-600',
|
|
75
|
+
fontWEIGHT: 'bold',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
mobile: {
|
|
80
|
+
textDECORATION: 'underline',
|
|
81
|
+
textDECORATIONSTYLE: 'wavy',
|
|
82
|
+
textDECORATIONCOLOR: 'teal-400',
|
|
83
|
+
textDECORATIONTHICKNESS: '4',
|
|
84
|
+
textUNDERLINEOFFSET: '4',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
mobile: {
|
|
89
|
+
display: 'inline-block',
|
|
90
|
+
bgCOLOR: 'rose-500',
|
|
91
|
+
textCOLOR: 'white',
|
|
92
|
+
px: '2',
|
|
93
|
+
skew: '-3',
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
|
|
22
98
|
export interface StyleElementPanelProps {
|
|
23
99
|
node: FlatNode;
|
|
24
100
|
parentNode: MarkdownPaneFragmentNode | GridLayoutNode;
|
|
@@ -30,6 +106,8 @@ const StyleElementPanel = ({
|
|
|
30
106
|
parentNode,
|
|
31
107
|
onTitleChange,
|
|
32
108
|
}: StyleElementPanelProps) => {
|
|
109
|
+
const [showPresets, setShowPresets] = useState(true);
|
|
110
|
+
|
|
33
111
|
if (
|
|
34
112
|
!node?.tagName ||
|
|
35
113
|
(!isMarkdownPaneFragmentNode(parentNode) && !isGridLayoutNode(parentNode))
|
|
@@ -40,6 +118,18 @@ const StyleElementPanel = ({
|
|
|
40
118
|
const defaultClasses = parentNode.defaultClasses?.[node.tagName];
|
|
41
119
|
const overrideClasses = node.overrideClasses;
|
|
42
120
|
|
|
121
|
+
const hasOverrides = useMemo(() => {
|
|
122
|
+
return (
|
|
123
|
+
overrideClasses &&
|
|
124
|
+
((overrideClasses.mobile &&
|
|
125
|
+
Object.keys(overrideClasses.mobile).length > 0) ||
|
|
126
|
+
(overrideClasses.tablet &&
|
|
127
|
+
Object.keys(overrideClasses.tablet).length > 0) ||
|
|
128
|
+
(overrideClasses.desktop &&
|
|
129
|
+
Object.keys(overrideClasses.desktop).length > 0))
|
|
130
|
+
);
|
|
131
|
+
}, [overrideClasses]);
|
|
132
|
+
|
|
43
133
|
const mergedClasses = useMemo(() => {
|
|
44
134
|
const result: {
|
|
45
135
|
[key: string]: {
|
|
@@ -49,7 +139,6 @@ const StyleElementPanel = ({
|
|
|
49
139
|
};
|
|
50
140
|
} = {};
|
|
51
141
|
|
|
52
|
-
// First add all default classes
|
|
53
142
|
if (defaultClasses) {
|
|
54
143
|
Object.keys(defaultClasses.mobile).forEach((className) => {
|
|
55
144
|
result[className] = {
|
|
@@ -64,7 +153,6 @@ const StyleElementPanel = ({
|
|
|
64
153
|
});
|
|
65
154
|
}
|
|
66
155
|
|
|
67
|
-
// Then overlay any override classes
|
|
68
156
|
if (overrideClasses) {
|
|
69
157
|
['mobile', 'tablet', 'desktop'].forEach((viewport) => {
|
|
70
158
|
const viewportOverrides =
|
|
@@ -114,6 +202,24 @@ const StyleElementPanel = ({
|
|
|
114
202
|
});
|
|
115
203
|
};
|
|
116
204
|
|
|
205
|
+
const applySpanPreset = (styleIndex: number) => {
|
|
206
|
+
const ctx = getCtx();
|
|
207
|
+
const allNodes = ctx.allNodes.get();
|
|
208
|
+
const targetNode = cloneDeep(allNodes.get(node.id)) as FlatNode;
|
|
209
|
+
if (!targetNode) return;
|
|
210
|
+
|
|
211
|
+
const preset = spanStyleClasses[styleIndex];
|
|
212
|
+
|
|
213
|
+
targetNode.overrideClasses = {
|
|
214
|
+
...targetNode.overrideClasses,
|
|
215
|
+
...preset,
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
ctx.modifyNodes([{ ...targetNode, isChanged: true }]);
|
|
219
|
+
|
|
220
|
+
setShowPresets(false);
|
|
221
|
+
};
|
|
222
|
+
|
|
117
223
|
useEffect(() => {
|
|
118
224
|
if (
|
|
119
225
|
styleElementInfoStore.get().markdownParentId !== parentNode.id ||
|
|
@@ -140,6 +246,10 @@ const StyleElementPanel = ({
|
|
|
140
246
|
}
|
|
141
247
|
}, [node?.tagName, onTitleChange]);
|
|
142
248
|
|
|
249
|
+
const shouldShowQuickStyles =
|
|
250
|
+
node.tagName === 'span' && !hasOverrides && showPresets;
|
|
251
|
+
const nodeText = shouldShowQuickStyles ? getNodeText(node) : '';
|
|
252
|
+
|
|
143
253
|
return (
|
|
144
254
|
<div className="space-y-4">
|
|
145
255
|
{node.wordCarouselPayload && (
|
|
@@ -165,42 +275,90 @@ const StyleElementPanel = ({
|
|
|
165
275
|
</div>
|
|
166
276
|
</div>
|
|
167
277
|
)}
|
|
168
|
-
{Object.keys(mergedClasses).length > 0 ? (
|
|
169
|
-
<div className="flex flex-wrap gap-2">
|
|
170
|
-
{Object.entries(mergedClasses).map(([className, values]) => (
|
|
171
|
-
<SelectedTailwindClass
|
|
172
|
-
key={className}
|
|
173
|
-
name={className}
|
|
174
|
-
values={values}
|
|
175
|
-
onRemove={handleRemove}
|
|
176
|
-
onUpdate={handleUpdate}
|
|
177
|
-
/>
|
|
178
|
-
))}
|
|
179
|
-
</div>
|
|
180
|
-
) : (
|
|
181
|
-
<div className="space-y-4">
|
|
182
|
-
<em>No styles.</em>
|
|
183
|
-
</div>
|
|
184
|
-
)}
|
|
185
278
|
|
|
186
|
-
|
|
187
|
-
<
|
|
188
|
-
<
|
|
189
|
-
<
|
|
190
|
-
|
|
191
|
-
|
|
279
|
+
{shouldShowQuickStyles ? (
|
|
280
|
+
<div className="space-y-6">
|
|
281
|
+
<div className="space-y-2">
|
|
282
|
+
<h3 className="text-mydarkgrey text-sm font-bold">
|
|
283
|
+
Quick Style Selection
|
|
284
|
+
</h3>
|
|
285
|
+
<p className="text-xs text-gray-500">
|
|
286
|
+
Select a preset style for your text selection.
|
|
287
|
+
</p>
|
|
288
|
+
</div>
|
|
289
|
+
|
|
290
|
+
<div className="flex flex-col gap-4">
|
|
291
|
+
{spanStyleClasses.map((style, index) => {
|
|
292
|
+
const [classesPayload] = processClassesForViewports(
|
|
293
|
+
style as any,
|
|
294
|
+
{},
|
|
295
|
+
1
|
|
296
|
+
);
|
|
297
|
+
const combinedClasses = classesPayload[0] || '';
|
|
298
|
+
|
|
299
|
+
return (
|
|
300
|
+
<button
|
|
301
|
+
key={index}
|
|
302
|
+
onClick={() => applySpanPreset(index)}
|
|
303
|
+
className="group w-full text-left text-xl transition-colors hover:outline-dotted hover:outline-2 hover:outline-black"
|
|
304
|
+
>
|
|
305
|
+
<span className={combinedClasses}>
|
|
306
|
+
{nodeText || 'Sample Text'}
|
|
307
|
+
</span>
|
|
308
|
+
</button>
|
|
309
|
+
);
|
|
310
|
+
})}
|
|
311
|
+
</div>
|
|
312
|
+
|
|
313
|
+
<div className="border-t border-gray-100 pt-4">
|
|
192
314
|
<button
|
|
193
|
-
onClick={() =>
|
|
194
|
-
className="text-myblue
|
|
315
|
+
onClick={() => setShowPresets(false)}
|
|
316
|
+
className="text-myblue w-full text-center text-sm underline hover:text-black"
|
|
195
317
|
>
|
|
196
|
-
|
|
318
|
+
Apply your own styles manually
|
|
197
319
|
</button>
|
|
198
|
-
</
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
320
|
+
</div>
|
|
321
|
+
</div>
|
|
322
|
+
) : (
|
|
323
|
+
<>
|
|
324
|
+
{Object.keys(mergedClasses).length > 0 ? (
|
|
325
|
+
<div className="flex flex-wrap gap-2">
|
|
326
|
+
{Object.entries(mergedClasses).map(([className, values]) => (
|
|
327
|
+
<SelectedTailwindClass
|
|
328
|
+
key={className}
|
|
329
|
+
name={className}
|
|
330
|
+
values={values}
|
|
331
|
+
onRemove={handleRemove}
|
|
332
|
+
onUpdate={handleUpdate}
|
|
333
|
+
/>
|
|
334
|
+
))}
|
|
335
|
+
</div>
|
|
336
|
+
) : (
|
|
337
|
+
<div className="space-y-4">
|
|
338
|
+
<em>No styles.</em>
|
|
339
|
+
</div>
|
|
340
|
+
)}
|
|
341
|
+
|
|
342
|
+
<div className="space-y-4">
|
|
343
|
+
<ul className="text-mydarkgrey flex flex-wrap gap-x-4 gap-y-1">
|
|
344
|
+
<li>
|
|
345
|
+
<em>Actions:</em>
|
|
346
|
+
</li>
|
|
347
|
+
<li>
|
|
348
|
+
<button
|
|
349
|
+
onClick={() => handleClickAdd()}
|
|
350
|
+
className="text-myblue font-bold underline hover:text-black"
|
|
351
|
+
>
|
|
352
|
+
Add Style
|
|
353
|
+
</button>
|
|
354
|
+
</li>
|
|
355
|
+
<li>
|
|
356
|
+
<StylesMemory node={node} parentNode={parentNode} />
|
|
357
|
+
</li>
|
|
358
|
+
</ul>
|
|
359
|
+
</div>
|
|
360
|
+
</>
|
|
361
|
+
)}
|
|
204
362
|
</div>
|
|
205
363
|
);
|
|
206
364
|
};
|
|
@@ -32,10 +32,13 @@ type ButtonStylePair = [ButtonStyle, ButtonStyle];
|
|
|
32
32
|
|
|
33
33
|
const buttonStyleOptions = [
|
|
34
34
|
'Plain text inline',
|
|
35
|
-
'
|
|
36
|
-
'
|
|
35
|
+
'Primary',
|
|
36
|
+
'Primary inverse',
|
|
37
|
+
'Dark',
|
|
38
|
+
'Dark inverse',
|
|
37
39
|
];
|
|
38
40
|
const buttonStyleClasses: ButtonStylePair[] = [
|
|
41
|
+
// Plain text inline
|
|
39
42
|
[
|
|
40
43
|
{
|
|
41
44
|
fontWEIGHT: ['bold'],
|
|
@@ -48,32 +51,93 @@ const buttonStyleClasses: ButtonStylePair[] = [
|
|
|
48
51
|
textCOLOR: ['brand-1'],
|
|
49
52
|
},
|
|
50
53
|
],
|
|
54
|
+
// Primary Solid Button
|
|
51
55
|
[
|
|
52
56
|
{
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
alignITEMS: ['center'],
|
|
58
|
+
bgCOLOR: ['blue-600'],
|
|
59
|
+
borderCOLOR: ['transparent'],
|
|
60
|
+
display: ['inline-flex'],
|
|
61
|
+
justifyCONTENT: ['center'],
|
|
62
|
+
px: ['6'],
|
|
63
|
+
py: ['3'],
|
|
64
|
+
rounded: ['md'],
|
|
65
|
+
textCOLOR: ['white'],
|
|
66
|
+
textSIZE: ['base'],
|
|
67
|
+
transition: ['colors'],
|
|
68
|
+
transitionDURATION: ['200'],
|
|
69
|
+
w: ['full'],
|
|
59
70
|
},
|
|
60
71
|
{
|
|
61
|
-
bgCOLOR: ['
|
|
72
|
+
bgCOLOR: ['blue-700'],
|
|
62
73
|
},
|
|
63
74
|
],
|
|
75
|
+
// Secondary Outline Button
|
|
64
76
|
[
|
|
65
77
|
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
78
|
+
alignITEMS: ['center'],
|
|
79
|
+
bgCOLOR: ['transparent'],
|
|
80
|
+
borderCOLOR: ['blue-600'],
|
|
81
|
+
borderWIDTH: ['2'],
|
|
82
|
+
display: ['inline-flex'],
|
|
83
|
+
justifyCONTENT: ['center'],
|
|
84
|
+
px: ['6'],
|
|
85
|
+
py: ['3'],
|
|
71
86
|
rounded: ['md'],
|
|
72
|
-
textCOLOR: ['
|
|
87
|
+
textCOLOR: ['blue-600'],
|
|
88
|
+
textSIZE: ['base'],
|
|
89
|
+
transition: ['colors'],
|
|
90
|
+
transitionDURATION: ['200'],
|
|
91
|
+
w: ['full'],
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
bgCOLOR: ['blue-50'],
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
[
|
|
98
|
+
{
|
|
99
|
+
alignITEMS: ['center'],
|
|
100
|
+
bgCOLOR: ['black'],
|
|
101
|
+
borderCOLOR: ['transparent'],
|
|
102
|
+
borderWIDTH: ['2'],
|
|
103
|
+
display: ['inline-flex'],
|
|
104
|
+
justifyCONTENT: ['center'],
|
|
105
|
+
px: ['6'],
|
|
106
|
+
py: ['3'],
|
|
107
|
+
rounded: ['md'],
|
|
108
|
+
textCOLOR: ['white'],
|
|
109
|
+
textSIZE: ['base'],
|
|
110
|
+
transition: ['colors'],
|
|
111
|
+
transitionDURATION: ['200'],
|
|
112
|
+
w: ['full'],
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
bgCOLOR: ['white'],
|
|
116
|
+
textCOLOR: ['black'],
|
|
117
|
+
borderCOLOR: ['black'],
|
|
118
|
+
borderWIDTH: ['2'],
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
[
|
|
122
|
+
{
|
|
123
|
+
alignITEMS: ['center'],
|
|
124
|
+
bgCOLOR: ['transparent'],
|
|
125
|
+
borderCOLOR: ['black'],
|
|
126
|
+
borderWIDTH: ['2'],
|
|
127
|
+
display: ['inline-flex'],
|
|
128
|
+
justifyCONTENT: ['center'],
|
|
129
|
+
px: ['6'],
|
|
130
|
+
py: ['3'],
|
|
131
|
+
rounded: ['md'],
|
|
132
|
+
textCOLOR: ['black'],
|
|
133
|
+
textSIZE: ['base'],
|
|
134
|
+
transition: ['colors'],
|
|
135
|
+
transitionDURATION: ['200'],
|
|
136
|
+
w: ['full'],
|
|
73
137
|
},
|
|
74
138
|
{
|
|
75
|
-
|
|
76
|
-
|
|
139
|
+
textCOLOR: ['myblack'],
|
|
140
|
+
bgCOLOR: ['slate-100'],
|
|
77
141
|
},
|
|
78
142
|
],
|
|
79
143
|
];
|
|
@@ -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>
|