astro-tractstack 2.0.27 → 2.0.28
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
|
@@ -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
|
];
|