astro-tractstack 2.0.43 → 2.0.45
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 -0
- package/package.json +1 -1
- package/templates/src/components/compositor/nodes/Pane_DesignLibrary.tsx +24 -3
- package/templates/src/components/edit/pane/AddPanePanel_new.tsx +156 -343
- package/templates/src/components/edit/pane/AiRestylePaneModal.tsx +230 -0
- package/templates/src/components/edit/pane/RestylePaneModal.tsx +7 -5
- package/templates/src/components/edit/pane/steps/AiDesignStep.tsx +28 -14
- package/templates/src/components/edit/pane/steps/CopyInputStep.tsx +238 -96
- package/templates/src/components/edit/panels/StyleParentPanel.tsx +29 -1
- package/templates/src/stores/nodes.ts +65 -0
- package/templates/src/stores/selection.ts +2 -0
- package/utils/inject-files.ts +6 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
2
1
|
import BooleanToggle from '@/components/form/BooleanToggle';
|
|
3
2
|
import EnumSelect from '@/components/form/EnumSelect';
|
|
4
3
|
|
|
@@ -10,13 +9,32 @@ interface PromptOption {
|
|
|
10
9
|
}
|
|
11
10
|
|
|
12
11
|
interface CopyInputStepProps {
|
|
12
|
+
layoutChoice: 'standard' | 'grid';
|
|
13
13
|
copyMode: CopyMode;
|
|
14
14
|
onCopyModeChange: (mode: CopyMode) => void;
|
|
15
|
+
|
|
16
|
+
topic: string;
|
|
17
|
+
onTopicChange: (value: string) => void;
|
|
18
|
+
|
|
19
|
+
showAdvancedPrompts: boolean;
|
|
20
|
+
onShowAdvancedPromptsChange: (value: boolean) => void;
|
|
21
|
+
|
|
15
22
|
promptValue: string;
|
|
16
23
|
onPromptValueChange: (value: string) => void;
|
|
17
24
|
copyValue: string;
|
|
18
25
|
onCopyValueChange: (value: string) => void;
|
|
19
|
-
|
|
26
|
+
|
|
27
|
+
overallPrompt: string;
|
|
28
|
+
onOverallPromptChange: (value: string) => void;
|
|
29
|
+
promptValueCol1: string;
|
|
30
|
+
onPromptValueCol1Change: (value: string) => void;
|
|
31
|
+
promptValueCol2: string;
|
|
32
|
+
onPromptValueCol2Change: (value: string) => void;
|
|
33
|
+
col1Copy: string;
|
|
34
|
+
onCol1CopyChange: (value: string) => void;
|
|
35
|
+
col2Copy: string;
|
|
36
|
+
onCol2CopyChange: (value: string) => void;
|
|
37
|
+
|
|
20
38
|
hasRetainedContent?: boolean;
|
|
21
39
|
promptOptions: PromptOption[];
|
|
22
40
|
selectedPromptId: string;
|
|
@@ -27,13 +45,27 @@ interface CopyInputStepProps {
|
|
|
27
45
|
}
|
|
28
46
|
|
|
29
47
|
export const CopyInputStep = ({
|
|
48
|
+
layoutChoice,
|
|
30
49
|
copyMode,
|
|
31
50
|
onCopyModeChange,
|
|
51
|
+
topic,
|
|
52
|
+
onTopicChange,
|
|
53
|
+
showAdvancedPrompts,
|
|
54
|
+
onShowAdvancedPromptsChange,
|
|
32
55
|
promptValue,
|
|
33
56
|
onPromptValueChange,
|
|
34
57
|
copyValue,
|
|
35
58
|
onCopyValueChange,
|
|
36
|
-
|
|
59
|
+
overallPrompt,
|
|
60
|
+
onOverallPromptChange,
|
|
61
|
+
promptValueCol1,
|
|
62
|
+
onPromptValueCol1Change,
|
|
63
|
+
promptValueCol2,
|
|
64
|
+
onPromptValueCol2Change,
|
|
65
|
+
col1Copy,
|
|
66
|
+
onCol1CopyChange,
|
|
67
|
+
col2Copy,
|
|
68
|
+
onCol2CopyChange,
|
|
37
69
|
hasRetainedContent = false,
|
|
38
70
|
promptOptions,
|
|
39
71
|
selectedPromptId,
|
|
@@ -42,77 +74,182 @@ export const CopyInputStep = ({
|
|
|
42
74
|
onIsAiStylingChange,
|
|
43
75
|
showStyleToggle = true,
|
|
44
76
|
}: CopyInputStepProps) => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
77
|
+
const renderModeSelection = () => (
|
|
78
|
+
<div className="my-2 flex flex-wrap gap-4">
|
|
79
|
+
<div className="flex items-center space-x-2">
|
|
80
|
+
<input
|
|
81
|
+
type="radio"
|
|
82
|
+
id="copy-prompt-mode"
|
|
83
|
+
name="copyModeOptions"
|
|
84
|
+
value="prompt"
|
|
85
|
+
checked={copyMode === 'prompt'}
|
|
86
|
+
onChange={(e) => onCopyModeChange(e.target.value as CopyMode)}
|
|
87
|
+
className="h-4 w-4 border-gray-300 text-cyan-600 focus:ring-cyan-500"
|
|
88
|
+
/>
|
|
89
|
+
<label
|
|
90
|
+
htmlFor="copy-prompt-mode"
|
|
91
|
+
className="text-sm font-bold text-gray-700"
|
|
92
|
+
>
|
|
93
|
+
Write a prompt
|
|
94
|
+
</label>
|
|
95
|
+
</div>
|
|
96
|
+
<div className="flex items-center space-x-2">
|
|
97
|
+
<input
|
|
98
|
+
type="radio"
|
|
99
|
+
id="copy-raw-mode"
|
|
100
|
+
name="copyModeOptions"
|
|
101
|
+
value="raw"
|
|
102
|
+
checked={copyMode === 'raw'}
|
|
103
|
+
onChange={(e) => onCopyModeChange(e.target.value as CopyMode)}
|
|
104
|
+
className="h-4 w-4 border-gray-300 text-cyan-600 focus:ring-cyan-500"
|
|
105
|
+
/>
|
|
106
|
+
<label
|
|
107
|
+
htmlFor="copy-raw-mode"
|
|
108
|
+
className="text-sm font-bold text-gray-700"
|
|
109
|
+
>
|
|
110
|
+
Provide Copy (Markdown)
|
|
111
|
+
</label>
|
|
112
|
+
</div>
|
|
113
|
+
{hasRetainedContent && (
|
|
57
114
|
<div className="flex items-center space-x-2">
|
|
58
115
|
<input
|
|
59
116
|
type="radio"
|
|
60
|
-
id="copy-
|
|
117
|
+
id="copy-original-mode"
|
|
61
118
|
name="copyModeOptions"
|
|
62
|
-
value="
|
|
63
|
-
checked={copyMode === '
|
|
119
|
+
value="original"
|
|
120
|
+
checked={copyMode === 'original'}
|
|
64
121
|
onChange={(e) => onCopyModeChange(e.target.value as CopyMode)}
|
|
65
122
|
className="h-4 w-4 border-gray-300 text-cyan-600 focus:ring-cyan-500"
|
|
66
123
|
/>
|
|
67
124
|
<label
|
|
68
|
-
htmlFor="copy-
|
|
125
|
+
htmlFor="copy-original-mode"
|
|
69
126
|
className="text-sm font-bold text-gray-700"
|
|
70
127
|
>
|
|
71
|
-
|
|
128
|
+
Use Original
|
|
72
129
|
</label>
|
|
73
130
|
</div>
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
131
|
+
)}
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
const renderPromptMode = () => (
|
|
136
|
+
<>
|
|
137
|
+
<div className="mb-4">
|
|
138
|
+
<EnumSelect
|
|
139
|
+
label="Section Type"
|
|
140
|
+
value={selectedPromptId}
|
|
141
|
+
onChange={onSelectedPromptIdChange}
|
|
142
|
+
options={promptOptions}
|
|
143
|
+
placeholder="Select a type..."
|
|
144
|
+
className="w-full"
|
|
145
|
+
/>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
<div className="mb-4">
|
|
149
|
+
<label className="mb-2 block text-sm font-bold text-gray-700">
|
|
150
|
+
Topic / Context
|
|
151
|
+
</label>
|
|
152
|
+
<textarea
|
|
153
|
+
value={topic}
|
|
154
|
+
onChange={(e) => onTopicChange(e.target.value)}
|
|
155
|
+
placeholder="e.g. a SaaS product for team collaboration"
|
|
156
|
+
rows={2}
|
|
157
|
+
className="block w-full rounded-md border-gray-300 p-2 shadow-sm focus:border-cyan-500 focus:ring-cyan-500 sm:text-sm"
|
|
158
|
+
/>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
<div className="mb-4 flex items-center">
|
|
162
|
+
<BooleanToggle
|
|
163
|
+
label="Advanced: Edit Full Prompts"
|
|
164
|
+
value={showAdvancedPrompts}
|
|
165
|
+
onChange={onShowAdvancedPromptsChange}
|
|
166
|
+
size="sm"
|
|
167
|
+
/>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
{showAdvancedPrompts && (
|
|
171
|
+
<div className="mt-4 space-y-4 rounded-md border border-gray-200 bg-white p-4">
|
|
172
|
+
{layoutChoice === 'standard' ? (
|
|
173
|
+
<div>
|
|
174
|
+
<label className="mb-2 block text-sm font-bold text-gray-700">
|
|
175
|
+
Full Prompt
|
|
176
|
+
</label>
|
|
177
|
+
<textarea
|
|
178
|
+
value={promptValue}
|
|
179
|
+
onChange={(e) => onPromptValueChange(e.target.value)}
|
|
180
|
+
rows={4}
|
|
181
|
+
className="block w-full rounded-md border-gray-300 p-2 shadow-sm focus:border-cyan-500 focus:ring-cyan-500 sm:text-sm"
|
|
182
|
+
/>
|
|
183
|
+
<p className="mt-1 text-xs text-gray-500">
|
|
184
|
+
Leave [topic] as it will be replaced with your prompt.
|
|
185
|
+
</p>
|
|
186
|
+
</div>
|
|
187
|
+
) : (
|
|
188
|
+
<>
|
|
189
|
+
<div>
|
|
190
|
+
<label className="mb-2 block text-sm font-bold text-gray-700">
|
|
191
|
+
Overall Component Brief
|
|
192
|
+
</label>
|
|
193
|
+
<textarea
|
|
194
|
+
value={overallPrompt}
|
|
195
|
+
onChange={(e) => onOverallPromptChange(e.target.value)}
|
|
196
|
+
rows={3}
|
|
197
|
+
className="block w-full rounded-md border-gray-300 p-2 shadow-sm focus:border-cyan-500 focus:ring-cyan-500 sm:text-sm"
|
|
198
|
+
/>
|
|
199
|
+
</div>
|
|
200
|
+
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
|
|
201
|
+
<div>
|
|
202
|
+
<label className="mb-2 block text-sm font-bold text-gray-700">
|
|
203
|
+
Left Column Prompt
|
|
204
|
+
</label>
|
|
205
|
+
<textarea
|
|
206
|
+
value={promptValueCol1}
|
|
207
|
+
onChange={(e) => onPromptValueCol1Change(e.target.value)}
|
|
208
|
+
rows={4}
|
|
209
|
+
className="block w-full rounded-md border-gray-300 p-2 shadow-sm focus:border-cyan-500 focus:ring-cyan-500 sm:text-sm"
|
|
210
|
+
/>
|
|
211
|
+
</div>
|
|
212
|
+
<div>
|
|
213
|
+
<label className="mb-2 block text-sm font-bold text-gray-700">
|
|
214
|
+
Right Column Prompt
|
|
215
|
+
</label>
|
|
216
|
+
<textarea
|
|
217
|
+
value={promptValueCol2}
|
|
218
|
+
onChange={(e) => onPromptValueCol2Change(e.target.value)}
|
|
219
|
+
rows={4}
|
|
220
|
+
className="block w-full rounded-md border-gray-300 p-2 shadow-sm focus:border-cyan-500 focus:ring-cyan-500 sm:text-sm"
|
|
221
|
+
/>
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
</>
|
|
225
|
+
)}
|
|
90
226
|
</div>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
227
|
+
)}
|
|
228
|
+
</>
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
const renderRawMode = () => (
|
|
232
|
+
<>
|
|
233
|
+
<div className="mb-2 flex items-center justify-between">
|
|
234
|
+
<p className="text-sm text-gray-500">
|
|
235
|
+
Provide your raw copy here. Use Markdown.
|
|
236
|
+
</p>
|
|
237
|
+
{showStyleToggle && (
|
|
238
|
+
<div className="flex items-center">
|
|
239
|
+
<BooleanToggle
|
|
240
|
+
label="Style with AI"
|
|
241
|
+
value={isAiStyling}
|
|
242
|
+
onChange={onIsAiStylingChange}
|
|
243
|
+
size="sm"
|
|
101
244
|
/>
|
|
102
|
-
<label
|
|
103
|
-
htmlFor="copy-original-mode"
|
|
104
|
-
className="text-sm font-bold text-gray-700"
|
|
105
|
-
>
|
|
106
|
-
Use Original
|
|
107
|
-
</label>
|
|
108
245
|
</div>
|
|
109
246
|
)}
|
|
110
247
|
</div>
|
|
111
248
|
|
|
112
|
-
{
|
|
249
|
+
{isAiStyling && (
|
|
113
250
|
<div className="mb-4">
|
|
114
251
|
<EnumSelect
|
|
115
|
-
label="Section Type"
|
|
252
|
+
label="Section Type (for Styling)"
|
|
116
253
|
value={selectedPromptId}
|
|
117
254
|
onChange={onSelectedPromptIdChange}
|
|
118
255
|
options={promptOptions}
|
|
@@ -122,49 +259,54 @@ export const CopyInputStep = ({
|
|
|
122
259
|
</div>
|
|
123
260
|
)}
|
|
124
261
|
|
|
125
|
-
{
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
</p>
|
|
147
|
-
{showStyleToggle && (
|
|
148
|
-
<div className="flex items-center">
|
|
149
|
-
<BooleanToggle
|
|
150
|
-
label="Style with AI"
|
|
151
|
-
value={isAiStyling}
|
|
152
|
-
onChange={onIsAiStylingChange}
|
|
153
|
-
size="sm"
|
|
154
|
-
/>
|
|
155
|
-
</div>
|
|
156
|
-
)}
|
|
262
|
+
{layoutChoice === 'standard' ? (
|
|
263
|
+
<textarea
|
|
264
|
+
id="raw-copy"
|
|
265
|
+
value={copyValue}
|
|
266
|
+
onChange={(e) => onCopyValueChange(e.target.value)}
|
|
267
|
+
placeholder="## My Awesome Headline..."
|
|
268
|
+
rows={6}
|
|
269
|
+
className="block w-full rounded-md border-gray-300 p-2 font-mono text-sm shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
|
|
270
|
+
/>
|
|
271
|
+
) : (
|
|
272
|
+
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
|
|
273
|
+
<div>
|
|
274
|
+
<label className="mb-2 block text-sm font-bold text-gray-700">
|
|
275
|
+
Left Column Markdown
|
|
276
|
+
</label>
|
|
277
|
+
<textarea
|
|
278
|
+
value={col1Copy}
|
|
279
|
+
onChange={(e) => onCol1CopyChange(e.target.value)}
|
|
280
|
+
rows={8}
|
|
281
|
+
className="block w-full rounded-md border-gray-300 p-2 font-mono text-sm shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
|
|
282
|
+
/>
|
|
157
283
|
</div>
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
284
|
+
<div>
|
|
285
|
+
<label className="mb-2 block text-sm font-bold text-gray-700">
|
|
286
|
+
Right Column Markdown
|
|
287
|
+
</label>
|
|
288
|
+
<textarea
|
|
289
|
+
value={col2Copy}
|
|
290
|
+
onChange={(e) => onCol2CopyChange(e.target.value)}
|
|
291
|
+
rows={8}
|
|
292
|
+
className="block w-full rounded-md border-gray-300 p-2 font-mono text-sm shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
|
|
293
|
+
/>
|
|
294
|
+
</div>
|
|
295
|
+
</div>
|
|
167
296
|
)}
|
|
297
|
+
</>
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
return (
|
|
301
|
+
<>
|
|
302
|
+
<label className="block text-lg font-bold text-gray-800">
|
|
303
|
+
Content Configuration
|
|
304
|
+
</label>
|
|
305
|
+
|
|
306
|
+
{renderModeSelection()}
|
|
307
|
+
|
|
308
|
+
{copyMode === 'prompt' && renderPromptMode()}
|
|
309
|
+
{copyMode === 'raw' && renderRawMode()}
|
|
168
310
|
|
|
169
311
|
{copyMode === 'original' && (
|
|
170
312
|
<div className="rounded-md border border-blue-200 bg-blue-50 p-4 text-blue-700">
|
|
@@ -173,6 +315,6 @@ export const CopyInputStep = ({
|
|
|
173
315
|
</p>
|
|
174
316
|
</div>
|
|
175
317
|
)}
|
|
176
|
-
|
|
318
|
+
</>
|
|
177
319
|
);
|
|
178
320
|
};
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { useState, useEffect } from 'react';
|
|
2
|
+
import { useStore } from '@nanostores/react';
|
|
3
|
+
import { Portal } from '@ark-ui/react';
|
|
4
|
+
import SparklesIcon from '@heroicons/react/24/outline/SparklesIcon';
|
|
2
5
|
import PlusIcon from '@heroicons/react/24/outline/PlusIcon';
|
|
3
6
|
import ArrowUturnLeftIcon from '@heroicons/react/24/outline/ArrowUturnLeftIcon';
|
|
4
7
|
import ChevronLeftIcon from '@heroicons/react/24/outline/ChevronLeftIcon';
|
|
5
8
|
import ChevronRightIcon from '@heroicons/react/24/outline/ChevronRightIcon';
|
|
9
|
+
import { selectionStore } from '@/stores/selection';
|
|
6
10
|
import {
|
|
7
11
|
settingsPanelStore,
|
|
8
12
|
stylePanelTargetMemoryStore,
|
|
@@ -18,6 +22,7 @@ import {
|
|
|
18
22
|
import SelectedTailwindClass from '@/components/fields/SelectedTailwindClass';
|
|
19
23
|
import BackgroundImageWrapper from '@/components/fields/BackgroundImageWrapper';
|
|
20
24
|
import ColorPickerCombo from '@/components/fields/ColorPickerCombo';
|
|
25
|
+
import { AiRestylePaneModal } from '@/components/edit/pane/AiRestylePaneModal';
|
|
21
26
|
import { cloneDeep } from '@/utils/helpers';
|
|
22
27
|
import {
|
|
23
28
|
convertToGrid,
|
|
@@ -60,6 +65,7 @@ const StyleParentPanel = ({
|
|
|
60
65
|
const [selectedTargetIndex, setSelectedTargetIndex] = useState(0);
|
|
61
66
|
|
|
62
67
|
const ctx = getCtx();
|
|
68
|
+
const { isAiRestyleModalOpen } = useStore(selectionStore);
|
|
63
69
|
|
|
64
70
|
useEffect(() => {
|
|
65
71
|
if (
|
|
@@ -518,6 +524,19 @@ const StyleParentPanel = ({
|
|
|
518
524
|
})}
|
|
519
525
|
</div>
|
|
520
526
|
</div>
|
|
527
|
+
<div className="space-y-3 border-t border-gray-200 pt-4">
|
|
528
|
+
<button
|
|
529
|
+
onClick={() => {
|
|
530
|
+
ctx.toolModeValStore.set({ value: 'styles' });
|
|
531
|
+
selectionStore.setKey('paneToRestyleId', paneNode.id);
|
|
532
|
+
selectionStore.setKey('isAiRestyleModalOpen', true);
|
|
533
|
+
}}
|
|
534
|
+
className="flex w-full items-center justify-center gap-2 rounded bg-purple-600 px-4 py-2 text-sm font-bold text-white hover:bg-purple-700"
|
|
535
|
+
>
|
|
536
|
+
<SparklesIcon className="h-5 w-5" />
|
|
537
|
+
Re-Color this Pane
|
|
538
|
+
</button>
|
|
539
|
+
</div>
|
|
521
540
|
</div>
|
|
522
541
|
);
|
|
523
542
|
};
|
|
@@ -645,7 +664,16 @@ const StyleParentPanel = ({
|
|
|
645
664
|
}
|
|
646
665
|
};
|
|
647
666
|
|
|
648
|
-
return
|
|
667
|
+
return (
|
|
668
|
+
<div className="space-y-4">
|
|
669
|
+
{renderContent()}
|
|
670
|
+
{isAiRestyleModalOpen && (
|
|
671
|
+
<Portal>
|
|
672
|
+
<AiRestylePaneModal />
|
|
673
|
+
</Portal>
|
|
674
|
+
)}
|
|
675
|
+
</div>
|
|
676
|
+
);
|
|
649
677
|
};
|
|
650
678
|
|
|
651
679
|
export default StyleParentPanel;
|
|
@@ -560,6 +560,71 @@ export class NodesContext {
|
|
|
560
560
|
);
|
|
561
561
|
}
|
|
562
562
|
|
|
563
|
+
applyShellToPane(paneId: string, template: TemplatePane) {
|
|
564
|
+
const allNodes = new Map(this.allNodes.get());
|
|
565
|
+
const paneNode = allNodes.get(paneId) as PaneNode;
|
|
566
|
+
if (!paneNode) return;
|
|
567
|
+
|
|
568
|
+
if (template.bgColour) {
|
|
569
|
+
paneNode.bgColour = template.bgColour;
|
|
570
|
+
paneNode.isChanged = true;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
const childrenIds = this.getChildNodeIDs(paneId);
|
|
574
|
+
|
|
575
|
+
const gridLayoutNode = childrenIds
|
|
576
|
+
.map((id) => allNodes.get(id))
|
|
577
|
+
.find((n) => n?.nodeType === 'GridLayoutNode') as
|
|
578
|
+
| GridLayoutNode
|
|
579
|
+
| undefined;
|
|
580
|
+
|
|
581
|
+
const markdownNodes = childrenIds
|
|
582
|
+
.map((id) => allNodes.get(id))
|
|
583
|
+
.filter((n) => n?.nodeType === 'Markdown') as MarkdownPaneFragmentNode[];
|
|
584
|
+
|
|
585
|
+
if (gridLayoutNode && template.gridLayout) {
|
|
586
|
+
if (template.gridLayout.parentClasses) {
|
|
587
|
+
gridLayoutNode.parentClasses = template.gridLayout.parentClasses;
|
|
588
|
+
}
|
|
589
|
+
if (template.gridLayout.defaultClasses) {
|
|
590
|
+
gridLayoutNode.defaultClasses = template.gridLayout.defaultClasses;
|
|
591
|
+
}
|
|
592
|
+
gridLayoutNode.isChanged = true;
|
|
593
|
+
|
|
594
|
+
if (
|
|
595
|
+
template.gridLayout.nodes &&
|
|
596
|
+
Array.isArray(template.gridLayout.nodes)
|
|
597
|
+
) {
|
|
598
|
+
const columnIds = this.getChildNodeIDs(gridLayoutNode.id);
|
|
599
|
+
|
|
600
|
+
columnIds.forEach((colId, index) => {
|
|
601
|
+
const templateCol = template.gridLayout!.nodes![index];
|
|
602
|
+
if (templateCol && templateCol.gridClasses) {
|
|
603
|
+
const liveColNode = allNodes.get(colId) as MarkdownPaneFragmentNode;
|
|
604
|
+
if (liveColNode) {
|
|
605
|
+
liveColNode.gridClasses = templateCol.gridClasses;
|
|
606
|
+
liveColNode.isChanged = true;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
} else if (markdownNodes.length > 0 && template.markdown) {
|
|
612
|
+
const primaryMarkdown = markdownNodes[0];
|
|
613
|
+
|
|
614
|
+
if (template.markdown.parentClasses) {
|
|
615
|
+
primaryMarkdown.parentClasses = template.markdown.parentClasses;
|
|
616
|
+
}
|
|
617
|
+
if (template.markdown.defaultClasses) {
|
|
618
|
+
primaryMarkdown.defaultClasses = template.markdown.defaultClasses;
|
|
619
|
+
}
|
|
620
|
+
primaryMarkdown.isChanged = true;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
this.allNodes.set(allNodes);
|
|
624
|
+
this.notifyNode(paneId);
|
|
625
|
+
this.notifyNode('root');
|
|
626
|
+
}
|
|
627
|
+
|
|
563
628
|
/**
|
|
564
629
|
* Splits a text node at a given character offset.
|
|
565
630
|
* This is a robust function that correctly handles splits at offset 0
|
|
@@ -20,6 +20,7 @@ export interface SelectionStoreState extends SelectionRange {
|
|
|
20
20
|
selectionBox: SelectionBox | null;
|
|
21
21
|
pendingAction: 'style' | 'link' | 'carousel' | null;
|
|
22
22
|
isRestyleModalOpen: boolean;
|
|
23
|
+
isAiRestyleModalOpen: boolean;
|
|
23
24
|
paneToRestyleId: string | null;
|
|
24
25
|
}
|
|
25
26
|
|
|
@@ -35,6 +36,7 @@ const DEFAULT_SELECTION_STATE: SelectionStoreState = {
|
|
|
35
36
|
selectionBox: null,
|
|
36
37
|
pendingAction: null,
|
|
37
38
|
isRestyleModalOpen: false,
|
|
39
|
+
isAiRestyleModalOpen: false,
|
|
38
40
|
paneToRestyleId: null,
|
|
39
41
|
};
|
|
40
42
|
|
package/utils/inject-files.ts
CHANGED
|
@@ -477,6 +477,12 @@ export async function injectTemplateFiles(
|
|
|
477
477
|
),
|
|
478
478
|
dest: 'src/components/edit/pane/RestylePaneModal.tsx',
|
|
479
479
|
},
|
|
480
|
+
{
|
|
481
|
+
src: resolve(
|
|
482
|
+
'../templates/src/components/edit/pane/AiRestylePaneModal.tsx'
|
|
483
|
+
),
|
|
484
|
+
dest: 'src/components/edit/pane/AiRestylePaneModal.tsx',
|
|
485
|
+
},
|
|
480
486
|
{
|
|
481
487
|
src: resolve(
|
|
482
488
|
'../templates/src/components/edit/pane/steps/CopyInputStep.tsx'
|