astro-tractstack 2.0.19 → 2.0.21

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.
Files changed (54) hide show
  1. package/dist/index.js +6 -32
  2. package/package.json +1 -1
  3. package/templates/src/components/codehooks/BunnyVideoSetup.tsx +1 -4
  4. package/templates/src/components/codehooks/FeaturedArticleSetup.tsx +0 -4
  5. package/templates/src/components/codehooks/ListContentSetup.tsx +1 -8
  6. package/templates/src/components/codehooks/ProductCardSetup.tsx +0 -2
  7. package/templates/src/components/codehooks/ProductGridSetup.tsx +0 -2
  8. package/templates/src/components/compositor/Compositor.tsx +3 -6
  9. package/templates/src/components/compositor/Node.tsx +13 -32
  10. package/templates/src/components/compositor/NodeWithGuid.tsx +49 -5
  11. package/templates/src/components/compositor/nodes/Pane.tsx +4 -21
  12. package/templates/src/components/compositor/nodes/Pane_DesignLibrary.tsx +27 -7
  13. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag.tsx +3 -1
  14. package/templates/src/components/compositor/preview/OgImagePreview.tsx +0 -5
  15. package/templates/src/components/compositor/preview/PaneSnapshotGenerator.tsx +5 -6
  16. package/templates/src/components/edit/PanelSwitch.tsx +3 -24
  17. package/templates/src/components/edit/SettingsPanel.tsx +0 -1
  18. package/templates/src/components/edit/ToolMode.tsx +6 -14
  19. package/templates/src/components/edit/pane/AddPanePanel.tsx +58 -25
  20. package/templates/src/components/edit/pane/AddPanePanel_new.tsx +140 -133
  21. package/templates/src/components/edit/pane/AddPanePanel_paste.tsx +111 -0
  22. package/templates/src/components/edit/pane/RestylePaneModal.tsx +231 -282
  23. package/templates/src/components/edit/pane/steps/AiDesignStep.tsx +0 -5
  24. package/templates/src/components/edit/pane/steps/DesignLibraryStep.tsx +4 -13
  25. package/templates/src/components/edit/panels/StyleBreakPanel.tsx +1 -3
  26. package/templates/src/components/edit/panels/StyleElementPanel_update.tsx +0 -6
  27. package/templates/src/components/edit/panels/StyleImagePanel_update.tsx +0 -3
  28. package/templates/src/components/edit/panels/StyleLiElementPanel_update.tsx +0 -4
  29. package/templates/src/components/edit/panels/StyleLinkPanel_config.tsx +8 -5
  30. package/templates/src/components/edit/panels/StyleLinkPanel_update.tsx +1 -2
  31. package/templates/src/components/edit/panels/StyleParentPanel.tsx +1 -3
  32. package/templates/src/components/edit/panels/StyleParentPanel_update.tsx +2 -5
  33. package/templates/src/components/edit/panels/StyleWidgetPanel_config.tsx +2 -8
  34. package/templates/src/components/edit/panels/StyleWidgetPanel_update.tsx +0 -4
  35. package/templates/src/components/edit/state/SaveToLibraryModal.tsx +29 -16
  36. package/templates/src/components/edit/storyfragment/StoryFragmentConfigPanel.tsx +9 -26
  37. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_og.tsx +7 -16
  38. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_slug.tsx +5 -6
  39. package/templates/src/components/edit/widgets/InteractiveDisclosureWidget.tsx +0 -5
  40. package/templates/src/components/fields/BackgroundImageWrapper.tsx +1 -7
  41. package/templates/src/components/fields/ColorPickerCombo.tsx +8 -12
  42. package/templates/src/components/fields/ViewportComboBox.tsx +4 -6
  43. package/templates/src/stores/nodes.ts +14 -6
  44. package/templates/src/stores/storykeep.ts +3 -3
  45. package/templates/src/types/compositorTypes.ts +2 -0
  46. package/templates/src/utils/compositor/TemplatePanes.ts +0 -76
  47. package/templates/src/utils/compositor/aiPaneParser.ts +3 -1
  48. package/templates/src/utils/compositor/designLibraryHelper.ts +523 -203
  49. package/templates/src/utils/helpers.ts +5 -4
  50. package/utils/inject-files.ts +6 -32
  51. package/templates/src/components/compositor/preview/VisualBreakPreview.tsx +0 -154
  52. package/templates/src/components/edit/pane/PageGen_preview.tsx +0 -511
  53. package/templates/src/utils/compositor/processMarkdown.ts +0 -445
  54. 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;