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,511 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react';
|
|
2
|
-
import { Select } from '@ark-ui/react/select';
|
|
3
|
-
import { Portal } from '@ark-ui/react/portal';
|
|
4
|
-
import { createListCollection } from '@ark-ui/react/collection';
|
|
5
|
-
import ChevronUpDownIcon from '@heroicons/react/20/solid/ChevronUpDownIcon';
|
|
6
|
-
import CheckIcon from '@heroicons/react/20/solid/CheckIcon';
|
|
7
|
-
import { NodesContext } from '@/stores/nodes';
|
|
8
|
-
import { createEmptyStorykeep } from '@/utils/compositor/nodesHelper';
|
|
9
|
-
import { brandColourStore, preferredThemeStore } from '@/stores/storykeep';
|
|
10
|
-
import { getTemplateVisualBreakPane } from '@/utils/compositor/TemplatePanes';
|
|
11
|
-
import {
|
|
12
|
-
getJustCopyDesign,
|
|
13
|
-
getIntroDesign,
|
|
14
|
-
getWithArtpackImageDesign,
|
|
15
|
-
} from '@/utils/compositor/templateMarkdownStyles';
|
|
16
|
-
import { tailwindToHex } from '@/utils/compositor/tailwindColors';
|
|
17
|
-
import { SvgBreaks } from '@/constants/shapes';
|
|
18
|
-
import {
|
|
19
|
-
parsePageMarkdown,
|
|
20
|
-
validatePageMarkdown,
|
|
21
|
-
} from '@/utils/compositor/processMarkdown';
|
|
22
|
-
import { themes, type Theme } from '@/types/tractstack';
|
|
23
|
-
import type { PageDesign, TemplatePane } from '@/types/compositorTypes';
|
|
24
|
-
import {
|
|
25
|
-
PanesPreviewGenerator,
|
|
26
|
-
type PanePreviewRequest,
|
|
27
|
-
type PaneFragmentResult,
|
|
28
|
-
} from '@/components/compositor/preview/PanesPreviewGenerator';
|
|
29
|
-
import {
|
|
30
|
-
PaneSnapshotGenerator,
|
|
31
|
-
type SnapshotData,
|
|
32
|
-
} from '@/components/compositor/preview/PaneSnapshotGenerator';
|
|
33
|
-
|
|
34
|
-
function getPageDesigns(brand: string, theme: Theme): PageDesign[] {
|
|
35
|
-
return [
|
|
36
|
-
{
|
|
37
|
-
id: 'bg-default-pretty',
|
|
38
|
-
title: 'Pretty with Hero Background',
|
|
39
|
-
introDesign: () =>
|
|
40
|
-
getWithArtpackImageDesign(
|
|
41
|
-
getIntroDesign,
|
|
42
|
-
theme,
|
|
43
|
-
brand,
|
|
44
|
-
false,
|
|
45
|
-
'kCz',
|
|
46
|
-
'wavedrips',
|
|
47
|
-
'cover',
|
|
48
|
-
true,
|
|
49
|
-
'default'
|
|
50
|
-
),
|
|
51
|
-
contentDesign: (useOdd: boolean) =>
|
|
52
|
-
getJustCopyDesign(theme, brand, useOdd, false, `default`),
|
|
53
|
-
visualBreaks: {
|
|
54
|
-
odd: () => getTemplateVisualBreakPane('cutwide2'),
|
|
55
|
-
even: () => getTemplateVisualBreakPane('cutwide1'),
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
id: 'min-default',
|
|
60
|
-
title: 'Default, Minimal',
|
|
61
|
-
introDesign: () => getIntroDesign(theme, brand, false, true, `default`),
|
|
62
|
-
contentDesign: (useOdd: boolean) =>
|
|
63
|
-
getJustCopyDesign(theme, brand, useOdd, false, `default`),
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
id: 'min-default-pretty',
|
|
67
|
-
title: 'Default, Pretty',
|
|
68
|
-
introDesign: () => getIntroDesign(theme, brand, false, true, `default`),
|
|
69
|
-
contentDesign: (useOdd: boolean) =>
|
|
70
|
-
getJustCopyDesign(theme, brand, useOdd, false, `default`),
|
|
71
|
-
visualBreaks: {
|
|
72
|
-
odd: () => getTemplateVisualBreakPane('cutwide2'),
|
|
73
|
-
even: () => getTemplateVisualBreakPane('cutwide1'),
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
id: 'bg-onecol-pretty',
|
|
78
|
-
title: 'One-Column, Pretty with Hero Background',
|
|
79
|
-
introDesign: () =>
|
|
80
|
-
getWithArtpackImageDesign(
|
|
81
|
-
getIntroDesign,
|
|
82
|
-
theme,
|
|
83
|
-
brand,
|
|
84
|
-
false,
|
|
85
|
-
'kCz',
|
|
86
|
-
'wavedrips',
|
|
87
|
-
'cover',
|
|
88
|
-
true,
|
|
89
|
-
'onecol'
|
|
90
|
-
),
|
|
91
|
-
contentDesign: (useOdd: boolean) =>
|
|
92
|
-
getJustCopyDesign(theme, brand, useOdd, false, `onecol`),
|
|
93
|
-
visualBreaks: {
|
|
94
|
-
odd: () => getTemplateVisualBreakPane('cutwide2'),
|
|
95
|
-
even: () => getTemplateVisualBreakPane('cutwide1'),
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
id: 'min-onecol',
|
|
100
|
-
title: 'One-Column, Minimal',
|
|
101
|
-
introDesign: () => getIntroDesign(theme, brand, false, true, `onecol`),
|
|
102
|
-
contentDesign: (useOdd: boolean) =>
|
|
103
|
-
getJustCopyDesign(theme, brand, useOdd, false, `onecol`),
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
id: 'min-onecol-pretty',
|
|
107
|
-
title: 'One-Column, Pretty',
|
|
108
|
-
introDesign: () => getIntroDesign(theme, brand, false, true, `onecol`),
|
|
109
|
-
contentDesign: (useOdd: boolean) =>
|
|
110
|
-
getJustCopyDesign(theme, brand, useOdd, false, `onecol`),
|
|
111
|
-
visualBreaks: {
|
|
112
|
-
odd: () => getTemplateVisualBreakPane('cutwide2'),
|
|
113
|
-
even: () => getTemplateVisualBreakPane('cutwide1'),
|
|
114
|
-
},
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
id: 'bg-center-pretty',
|
|
118
|
-
title: 'Centered, Pretty with Hero Background',
|
|
119
|
-
introDesign: () =>
|
|
120
|
-
getWithArtpackImageDesign(
|
|
121
|
-
getIntroDesign,
|
|
122
|
-
theme,
|
|
123
|
-
brand,
|
|
124
|
-
false,
|
|
125
|
-
'kCz',
|
|
126
|
-
'wavedrips',
|
|
127
|
-
'cover',
|
|
128
|
-
true,
|
|
129
|
-
'center'
|
|
130
|
-
),
|
|
131
|
-
contentDesign: (useOdd: boolean) =>
|
|
132
|
-
getJustCopyDesign(theme, brand, useOdd, false, `center`),
|
|
133
|
-
visualBreaks: {
|
|
134
|
-
odd: () => getTemplateVisualBreakPane('cutwide2'),
|
|
135
|
-
even: () => getTemplateVisualBreakPane('cutwide1'),
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
id: 'min-centered',
|
|
140
|
-
title: 'Centered, Minimal',
|
|
141
|
-
introDesign: () => getIntroDesign(theme, brand, false, true, `center`),
|
|
142
|
-
contentDesign: (useOdd: boolean) =>
|
|
143
|
-
getJustCopyDesign(theme, brand, useOdd, false, `center`),
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
id: 'min-centered-pretty',
|
|
147
|
-
title: 'Centered, Pretty',
|
|
148
|
-
introDesign: () => getIntroDesign(theme, brand, false, true, `center`),
|
|
149
|
-
contentDesign: (useOdd: boolean) =>
|
|
150
|
-
getJustCopyDesign(theme, brand, useOdd, false, `center`),
|
|
151
|
-
visualBreaks: {
|
|
152
|
-
odd: () => getTemplateVisualBreakPane('cutwide2'),
|
|
153
|
-
even: () => getTemplateVisualBreakPane('cutwide1'),
|
|
154
|
-
},
|
|
155
|
-
},
|
|
156
|
-
];
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
interface PageCreationPreviewProps {
|
|
160
|
-
markdownContent: string;
|
|
161
|
-
onComplete: (markdownContent: string, design: PageDesign) => void;
|
|
162
|
-
onBack: () => void;
|
|
163
|
-
isApplying?: boolean;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export const PageCreationPreview = ({
|
|
167
|
-
markdownContent,
|
|
168
|
-
onComplete,
|
|
169
|
-
onBack,
|
|
170
|
-
isApplying,
|
|
171
|
-
}: PageCreationPreviewProps) => {
|
|
172
|
-
const [selectedTheme, setSelectedTheme] = useState<Theme>(
|
|
173
|
-
preferredThemeStore.get()
|
|
174
|
-
);
|
|
175
|
-
const [selectedDesignIndex, setSelectedDesignIndex] = useState(0);
|
|
176
|
-
const [error, setError] = useState<string | null>(null);
|
|
177
|
-
|
|
178
|
-
const [paneRequests, setPaneRequests] = useState<PanePreviewRequest[]>([]);
|
|
179
|
-
const [paneFragments, setPaneFragments] = useState<PaneFragmentResult[]>([]);
|
|
180
|
-
const [snapshots, setSnapshots] = useState<Map<string, SnapshotData>>(
|
|
181
|
-
new Map()
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
const brand = brandColourStore.get();
|
|
185
|
-
const pageDesigns = getPageDesigns(brand, selectedTheme);
|
|
186
|
-
|
|
187
|
-
const themesCollection = createListCollection({
|
|
188
|
-
items: themes,
|
|
189
|
-
itemToValue: (item) => item,
|
|
190
|
-
itemToString: (item) => item.replace(/-/g, ' '),
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
const designsCollection = createListCollection({
|
|
194
|
-
items: pageDesigns.map((design, index) => ({ design, index })),
|
|
195
|
-
itemToValue: (item) => item.index.toString(),
|
|
196
|
-
itemToString: (item) => item.design.title,
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
useEffect(() => {
|
|
200
|
-
if (!markdownContent) return;
|
|
201
|
-
|
|
202
|
-
setPaneRequests([]);
|
|
203
|
-
setPaneFragments([]);
|
|
204
|
-
setSnapshots(new Map());
|
|
205
|
-
|
|
206
|
-
const createIsolatedPaneRequests = () => {
|
|
207
|
-
try {
|
|
208
|
-
if (!validatePageMarkdown(markdownContent)) {
|
|
209
|
-
setError('Invalid page structure');
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const processedPage = parsePageMarkdown(markdownContent);
|
|
214
|
-
const design = pageDesigns[selectedDesignIndex];
|
|
215
|
-
const requests: PanePreviewRequest[] = [];
|
|
216
|
-
const paneTemplates: TemplatePane[] = [];
|
|
217
|
-
let isOdd = true;
|
|
218
|
-
|
|
219
|
-
const introSection = processedPage.sections.find(
|
|
220
|
-
(s) => s.type === 'intro'
|
|
221
|
-
);
|
|
222
|
-
if (introSection) {
|
|
223
|
-
const ctx = new NodesContext();
|
|
224
|
-
ctx.addNode(createEmptyStorykeep('tmp'));
|
|
225
|
-
const introTemplate = design.introDesign();
|
|
226
|
-
introTemplate.markdown.markdownBody = introSection.content;
|
|
227
|
-
paneTemplates.push(introTemplate);
|
|
228
|
-
const paneId =
|
|
229
|
-
ctx.addTemplatePane('tmp', introTemplate) ||
|
|
230
|
-
`req-${requests.length}`;
|
|
231
|
-
requests.push({ id: paneId, ctx });
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const contentSections = processedPage.sections.filter(
|
|
235
|
-
(s) => s.type === 'content'
|
|
236
|
-
);
|
|
237
|
-
contentSections.forEach((section, index) => {
|
|
238
|
-
if (design.visualBreaks && index > 0) {
|
|
239
|
-
const aboveTemplate = paneTemplates[paneTemplates.length - 1];
|
|
240
|
-
const aboveColor = aboveTemplate?.bgColour || 'white';
|
|
241
|
-
|
|
242
|
-
const nextContentTemplate = design.contentDesign(isOdd);
|
|
243
|
-
const belowColor = nextContentTemplate.bgColour;
|
|
244
|
-
|
|
245
|
-
const breakTemplate = isOdd
|
|
246
|
-
? design.visualBreaks.odd()
|
|
247
|
-
: design.visualBreaks.even();
|
|
248
|
-
|
|
249
|
-
const breakData = breakTemplate.bgPane?.breakDesktop;
|
|
250
|
-
const shapeName = breakData
|
|
251
|
-
? `${breakData.collection}${breakData.image}`
|
|
252
|
-
: '';
|
|
253
|
-
const isFlipped =
|
|
254
|
-
(shapeName && SvgBreaks[shapeName]?.flipped) || false;
|
|
255
|
-
|
|
256
|
-
breakTemplate.bgColour = tailwindToHex(
|
|
257
|
-
isFlipped ? belowColor : aboveColor,
|
|
258
|
-
null
|
|
259
|
-
);
|
|
260
|
-
const svgFill = tailwindToHex(
|
|
261
|
-
isFlipped ? aboveColor : belowColor,
|
|
262
|
-
null
|
|
263
|
-
);
|
|
264
|
-
if (breakTemplate.bgPane) {
|
|
265
|
-
if (breakTemplate.bgPane.breakDesktop) {
|
|
266
|
-
breakTemplate.bgPane.breakDesktop.svgFill = svgFill;
|
|
267
|
-
}
|
|
268
|
-
if (breakTemplate.bgPane.breakTablet) {
|
|
269
|
-
breakTemplate.bgPane.breakTablet.svgFill = svgFill;
|
|
270
|
-
}
|
|
271
|
-
if (breakTemplate.bgPane.breakMobile) {
|
|
272
|
-
breakTemplate.bgPane.breakMobile.svgFill = svgFill;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
paneTemplates.push(breakTemplate);
|
|
277
|
-
|
|
278
|
-
const breakCtx = new NodesContext();
|
|
279
|
-
breakCtx.addNode(createEmptyStorykeep('tmp'));
|
|
280
|
-
const breakPaneId =
|
|
281
|
-
breakCtx.addTemplatePane('tmp', breakTemplate) ||
|
|
282
|
-
`req-${requests.length}`;
|
|
283
|
-
requests.push({ id: breakPaneId, ctx: breakCtx });
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
const contentCtx = new NodesContext();
|
|
287
|
-
contentCtx.addNode(createEmptyStorykeep('tmp'));
|
|
288
|
-
const contentTemplate = design.contentDesign(isOdd);
|
|
289
|
-
contentTemplate.markdown.markdownBody = section.content;
|
|
290
|
-
paneTemplates.push(contentTemplate);
|
|
291
|
-
const contentPaneId =
|
|
292
|
-
contentCtx.addTemplatePane('tmp', contentTemplate) ||
|
|
293
|
-
`req-${requests.length}`;
|
|
294
|
-
requests.push({ id: contentPaneId, ctx: contentCtx });
|
|
295
|
-
|
|
296
|
-
isOdd = !isOdd;
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
setPaneRequests(requests);
|
|
300
|
-
setError(null);
|
|
301
|
-
} catch (err) {
|
|
302
|
-
setError(
|
|
303
|
-
err instanceof Error ? err.message : 'Failed to generate preview'
|
|
304
|
-
);
|
|
305
|
-
}
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
createIsolatedPaneRequests();
|
|
309
|
-
}, [markdownContent, selectedTheme, selectedDesignIndex]);
|
|
310
|
-
|
|
311
|
-
const handleThemeChange = (details: { value: string[] }) => {
|
|
312
|
-
const newTheme = details.value[0] as Theme;
|
|
313
|
-
if (newTheme) setSelectedTheme(newTheme);
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
const handleDesignChange = (details: { value: string[] }) => {
|
|
317
|
-
const newDesignIndex = parseInt(details.value[0], 10);
|
|
318
|
-
if (!isNaN(newDesignIndex)) setSelectedDesignIndex(newDesignIndex);
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
const handleSnapshotComplete = (id: string, data: SnapshotData) => {
|
|
322
|
-
setSnapshots((prev) => new Map(prev).set(id, data));
|
|
323
|
-
};
|
|
324
|
-
|
|
325
|
-
const customStyles = `
|
|
326
|
-
.theme-item[data-highlighted] { background-color: #0891b2; color: white; }
|
|
327
|
-
.theme-item[data-highlighted] .theme-indicator { color: white; }
|
|
328
|
-
.theme-item[data-state="checked"] .theme-indicator { display: flex; }
|
|
329
|
-
.theme-item .theme-indicator { display: none; }
|
|
330
|
-
.theme-item[data-state="checked"] { font-weight: bold; }
|
|
331
|
-
.design-item[data-highlighted] { background-color: #0891b2; color: white; }
|
|
332
|
-
.design-item[data-highlighted] .design-indicator { color: white; }
|
|
333
|
-
.design-item[data-state="checked"] .design-indicator { display: flex; }
|
|
334
|
-
.design-item .indicator { display: none; }
|
|
335
|
-
.design-item[data-state="checked"] { font-weight: bold; }
|
|
336
|
-
`;
|
|
337
|
-
|
|
338
|
-
return (
|
|
339
|
-
<div className="rounded-md bg-white p-6">
|
|
340
|
-
<style>{customStyles}</style>
|
|
341
|
-
<div className="mb-6 space-y-4">
|
|
342
|
-
<div className="flex items-center gap-6">
|
|
343
|
-
<div className="w-48">
|
|
344
|
-
<Select.Root
|
|
345
|
-
collection={themesCollection}
|
|
346
|
-
defaultValue={[selectedTheme]}
|
|
347
|
-
onValueChange={handleThemeChange}
|
|
348
|
-
>
|
|
349
|
-
<Select.Label className="block text-sm font-bold text-gray-700">
|
|
350
|
-
Theme
|
|
351
|
-
</Select.Label>
|
|
352
|
-
<Select.Control className="relative mt-1">
|
|
353
|
-
<Select.Trigger className="relative w-full cursor-default rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-cyan-600 focus-visible:ring-2 focus-visible:ring-white/75 focus-visible:ring-offset-2 focus-visible:ring-offset-cyan-600">
|
|
354
|
-
<Select.ValueText className="block truncate capitalize">
|
|
355
|
-
{selectedTheme.replace(/-/g, ' ')}
|
|
356
|
-
</Select.ValueText>
|
|
357
|
-
<Select.Indicator className="absolute inset-y-0 right-0 flex items-center pr-2">
|
|
358
|
-
<ChevronUpDownIcon className="h-5 w-5 text-gray-400" />
|
|
359
|
-
</Select.Indicator>
|
|
360
|
-
</Select.Trigger>
|
|
361
|
-
</Select.Control>
|
|
362
|
-
<Portal>
|
|
363
|
-
<Select.Positioner>
|
|
364
|
-
<Select.Content className="z-50 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black/5 focus:outline-none sm:text-sm">
|
|
365
|
-
{themesCollection.items.map((theme) => (
|
|
366
|
-
<Select.Item
|
|
367
|
-
key={theme}
|
|
368
|
-
item={theme}
|
|
369
|
-
className="theme-item relative cursor-default select-none py-2 pl-10 pr-4 text-gray-900"
|
|
370
|
-
>
|
|
371
|
-
<Select.ItemText className="block truncate capitalize">
|
|
372
|
-
{theme.replace(/-/g, ' ')}
|
|
373
|
-
</Select.ItemText>
|
|
374
|
-
<Select.ItemIndicator className="theme-indicator absolute inset-y-0 left-0 flex items-center pl-3 text-amber-600">
|
|
375
|
-
<CheckIcon className="h-5 w-5" />
|
|
376
|
-
</Select.ItemIndicator>
|
|
377
|
-
</Select.Item>
|
|
378
|
-
))}
|
|
379
|
-
</Select.Content>
|
|
380
|
-
</Select.Positioner>
|
|
381
|
-
</Portal>
|
|
382
|
-
</Select.Root>
|
|
383
|
-
</div>
|
|
384
|
-
<div className="w-64">
|
|
385
|
-
<Select.Root
|
|
386
|
-
collection={designsCollection}
|
|
387
|
-
defaultValue={[selectedDesignIndex.toString()]}
|
|
388
|
-
onValueChange={handleDesignChange}
|
|
389
|
-
>
|
|
390
|
-
<Select.Label className="block text-sm font-bold text-gray-700">
|
|
391
|
-
Layout
|
|
392
|
-
</Select.Label>
|
|
393
|
-
<Select.Control className="relative mt-1">
|
|
394
|
-
<Select.Trigger className="relative w-full cursor-default rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-cyan-600 focus-visible:ring-2 focus-visible:ring-white/75 focus-visible:ring-offset-2 focus-visible:ring-offset-cyan-600">
|
|
395
|
-
<Select.ValueText className="block truncate">
|
|
396
|
-
{pageDesigns[selectedDesignIndex].title}
|
|
397
|
-
</Select.ValueText>
|
|
398
|
-
<Select.Indicator className="absolute inset-y-0 right-0 flex items-center pr-2">
|
|
399
|
-
<ChevronUpDownIcon className="h-5 w-5 text-gray-400" />
|
|
400
|
-
</Select.Indicator>
|
|
401
|
-
</Select.Trigger>
|
|
402
|
-
</Select.Control>
|
|
403
|
-
<Portal>
|
|
404
|
-
<Select.Positioner>
|
|
405
|
-
<Select.Content className="z-50 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black/5 focus:outline-none sm:text-sm">
|
|
406
|
-
{designsCollection.items.map((item) => (
|
|
407
|
-
<Select.Item
|
|
408
|
-
key={item.index}
|
|
409
|
-
item={item}
|
|
410
|
-
className="design-item relative cursor-default select-none py-2 pl-10 pr-4 text-gray-900"
|
|
411
|
-
>
|
|
412
|
-
<Select.ItemText className="block truncate">
|
|
413
|
-
{item.design.title}
|
|
414
|
-
</Select.ItemText>
|
|
415
|
-
<Select.ItemIndicator className="design-indicator absolute inset-y-0 left-0 flex items-center pl-3 text-amber-600">
|
|
416
|
-
<CheckIcon className="h-5 w-5" />
|
|
417
|
-
</Select.ItemIndicator>
|
|
418
|
-
</Select.Item>
|
|
419
|
-
))}
|
|
420
|
-
</Select.Content>
|
|
421
|
-
</Select.Positioner>
|
|
422
|
-
</Portal>
|
|
423
|
-
</Select.Root>
|
|
424
|
-
</div>
|
|
425
|
-
</div>
|
|
426
|
-
<div className="flex items-center justify-between">
|
|
427
|
-
<div className="text-sm text-gray-500">
|
|
428
|
-
{error ? (
|
|
429
|
-
<span className="text-red-500">{error}</span>
|
|
430
|
-
) : (
|
|
431
|
-
'Please select a theme and design template'
|
|
432
|
-
)}
|
|
433
|
-
</div>
|
|
434
|
-
<div className="flex gap-2">
|
|
435
|
-
<button
|
|
436
|
-
onClick={onBack}
|
|
437
|
-
className="rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-bold text-gray-700 hover:bg-gray-50"
|
|
438
|
-
disabled={isApplying}
|
|
439
|
-
>
|
|
440
|
-
Back
|
|
441
|
-
</button>
|
|
442
|
-
<button
|
|
443
|
-
// --- FIX APPLIED HERE ---
|
|
444
|
-
// The onClick handler now sends the correct parameters.
|
|
445
|
-
onClick={() => {
|
|
446
|
-
if (onComplete) {
|
|
447
|
-
onComplete(markdownContent, pageDesigns[selectedDesignIndex]);
|
|
448
|
-
}
|
|
449
|
-
}}
|
|
450
|
-
className="rounded-md bg-cyan-600 px-4 py-2 text-sm font-bold text-white hover:bg-cyan-700"
|
|
451
|
-
disabled={!!error || isApplying || paneRequests.length === 0}
|
|
452
|
-
>
|
|
453
|
-
{isApplying ? 'Applying...' : 'Apply Design'}
|
|
454
|
-
</button>
|
|
455
|
-
</div>
|
|
456
|
-
</div>
|
|
457
|
-
</div>
|
|
458
|
-
|
|
459
|
-
{paneRequests.length > 0 && (
|
|
460
|
-
<PanesPreviewGenerator
|
|
461
|
-
requests={paneRequests}
|
|
462
|
-
onComplete={setPaneFragments}
|
|
463
|
-
onError={(e) => setError(e)}
|
|
464
|
-
/>
|
|
465
|
-
)}
|
|
466
|
-
|
|
467
|
-
<div className="overflow-hidden rounded-lg bg-white p-4 shadow-lg">
|
|
468
|
-
{paneRequests.length > 0 && paneFragments.length === 0 && !error && (
|
|
469
|
-
<div className="flex h-48 flex-col items-center justify-center">
|
|
470
|
-
<div className="mb-4 h-8 w-8 animate-spin rounded-full border-b-2 border-cyan-600"></div>
|
|
471
|
-
<p className="text-sm text-gray-500">Generating fragments...</p>
|
|
472
|
-
</div>
|
|
473
|
-
)}
|
|
474
|
-
|
|
475
|
-
{paneFragments.map((fragment) => {
|
|
476
|
-
const snapshot = snapshots.get(fragment.id);
|
|
477
|
-
return (
|
|
478
|
-
<div key={fragment.id}>
|
|
479
|
-
{snapshot ? (
|
|
480
|
-
<img
|
|
481
|
-
src={snapshot.imageData}
|
|
482
|
-
alt={`Preview for pane ${fragment.id}`}
|
|
483
|
-
className="block w-full"
|
|
484
|
-
/>
|
|
485
|
-
) : (
|
|
486
|
-
fragment.htmlString && (
|
|
487
|
-
<div style={{ minHeight: '200px' }}>
|
|
488
|
-
<PaneSnapshotGenerator
|
|
489
|
-
id={fragment.id}
|
|
490
|
-
htmlString={fragment.htmlString}
|
|
491
|
-
onComplete={handleSnapshotComplete}
|
|
492
|
-
outputWidth={800}
|
|
493
|
-
/>
|
|
494
|
-
</div>
|
|
495
|
-
)
|
|
496
|
-
)}
|
|
497
|
-
{fragment.error && (
|
|
498
|
-
<div className="p-4 text-red-500">
|
|
499
|
-
Error generating preview for pane {fragment.id}:{' '}
|
|
500
|
-
{fragment.error}
|
|
501
|
-
</div>
|
|
502
|
-
)}
|
|
503
|
-
</div>
|
|
504
|
-
);
|
|
505
|
-
})}
|
|
506
|
-
</div>
|
|
507
|
-
</div>
|
|
508
|
-
);
|
|
509
|
-
};
|
|
510
|
-
|
|
511
|
-
export default PageCreationPreview;
|