astro-tractstack 2.1.3 → 2.2.1

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 (128) hide show
  1. package/README.md +54 -266
  2. package/bin/create-tractstack.js +9 -6
  3. package/dist/index.js +109 -71
  4. package/package.json +4 -2
  5. package/templates/css/custom.css +5 -0
  6. package/templates/icons/code.svg +18 -0
  7. package/templates/icons/li.svg +4 -0
  8. package/templates/icons/link.svg +22 -0
  9. package/templates/icons/p.svg +3 -0
  10. package/templates/src/client/app.js +80 -1
  11. package/templates/src/components/Footer.astro +1 -1
  12. package/templates/src/components/codehooks/BunnyVideoSetup.tsx +6 -6
  13. package/templates/src/components/codehooks/EpinetDurationSelector.tsx +3 -3
  14. package/templates/src/components/codehooks/FeaturedArticleSetup.tsx +1 -1
  15. package/templates/src/components/codehooks/ListContentSetup.tsx +2 -2
  16. package/templates/src/components/codehooks/ProductCardSetup.tsx +1 -1
  17. package/templates/src/components/codehooks/ProductGridSetup.tsx +2 -2
  18. package/templates/src/components/codehooks/SandboxRegisterForm.tsx +3 -3
  19. package/templates/src/components/compositor/Compositor.tsx +25 -9
  20. package/templates/src/components/compositor/Node.tsx +168 -496
  21. package/templates/src/components/compositor/PanelVisibilityWrapper.tsx +1 -0
  22. package/templates/src/components/compositor/elements/SignUp.tsx +1 -1
  23. package/templates/src/components/compositor/elements/YouTubeWrapper.tsx +2 -0
  24. package/templates/src/components/compositor/nodes/CreativePane.tsx +262 -0
  25. package/templates/src/components/compositor/nodes/GhostInsertBlock.tsx +4 -6
  26. package/templates/src/components/compositor/nodes/GridLayout.tsx +4 -2
  27. package/templates/src/components/compositor/nodes/Markdown.tsx +18 -3
  28. package/templates/src/components/compositor/nodes/Pane.tsx +11 -5
  29. package/templates/src/components/compositor/nodes/RenderChildren.tsx +1 -1
  30. package/templates/src/components/compositor/nodes/tagElements/NodeAnchorComponent.tsx +5 -5
  31. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag.tsx +90 -42
  32. package/templates/src/components/compositor/nodes/tagElements/NodeImg.tsx +2 -0
  33. package/templates/src/components/compositor/nodes/tagElements/NodeText.tsx +27 -1
  34. package/templates/src/components/compositor/preview/PaneSnapshotGenerator.tsx +10 -8
  35. package/templates/src/components/compositor/tools/NodeOverlay.tsx +224 -0
  36. package/templates/src/components/compositor/tools/PaneOverlay.tsx +122 -0
  37. package/templates/src/components/edit/Header.tsx +68 -9
  38. package/templates/src/components/edit/PanelSwitch.tsx +42 -4
  39. package/templates/src/components/edit/SettingsPanel.tsx +2 -3
  40. package/templates/src/components/edit/ToolMode.tsx +1 -31
  41. package/templates/src/components/edit/pane/AddPanePanel_break.tsx +2 -2
  42. package/templates/src/components/edit/pane/AddPanePanel_codehook.tsx +1 -1
  43. package/templates/src/components/edit/pane/AddPanePanel_new.tsx +193 -659
  44. package/templates/src/components/edit/pane/AddPanePanel_reuse.tsx +15 -82
  45. package/templates/src/components/edit/pane/AiRestylePaneModal.tsx +95 -45
  46. package/templates/src/components/edit/pane/ConfigPanePanel.tsx +137 -49
  47. package/templates/src/components/edit/pane/RestylePaneModal.tsx +1 -1
  48. package/templates/src/components/edit/pane/steps/AiCreativeDesignStep.tsx +375 -0
  49. package/templates/src/components/edit/pane/steps/AiDesignStep.tsx +1 -23
  50. package/templates/src/components/edit/pane/steps/AiLibraryCopyStep.tsx +327 -0
  51. package/templates/src/components/edit/pane/steps/AiRefineDesignStep.tsx +267 -0
  52. package/templates/src/components/edit/pane/steps/AiStandardDesignStep.tsx +371 -0
  53. package/templates/src/components/edit/pane/steps/CopyInputStep.tsx +201 -76
  54. package/templates/src/components/edit/pane/steps/CreativeInjectStep.tsx +141 -0
  55. package/templates/src/components/edit/panels/CreativeImagePanel.tsx +435 -0
  56. package/templates/src/components/edit/panels/CreativeLinkPanel.tsx +110 -0
  57. package/templates/src/components/edit/panels/StyleCodeHookPanel.tsx +1 -1
  58. package/templates/src/components/edit/panels/StyleParentPanel.tsx +118 -126
  59. package/templates/src/components/edit/panels/StyleParentPanel_add.tsx +3 -2
  60. package/templates/src/components/edit/panels/StyleParentPanel_deleteLayer.tsx +1 -0
  61. package/templates/src/components/edit/panels/StyleParentPanel_remove.tsx +3 -1
  62. package/templates/src/components/edit/panels/StyleParentPanel_update.tsx +3 -1
  63. package/templates/src/components/edit/panels/StyleWidgetPanel.tsx +1 -1
  64. package/templates/src/components/edit/state/SaveModal.tsx +19 -787
  65. package/templates/src/components/edit/state/SaveToLibraryModal.tsx +2 -2
  66. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_menu.tsx +1 -1
  67. package/templates/src/components/edit/widgets/BunnyWidget.tsx +5 -5
  68. package/templates/src/components/edit/widgets/InteractiveDisclosureWidget.tsx +1 -1
  69. package/templates/src/components/edit/widgets/SignupWidget.tsx +1 -1
  70. package/templates/src/components/fields/ActionBuilderTimeSelector.tsx +1 -1
  71. package/templates/src/components/fields/ArtpackImage.tsx +11 -3
  72. package/templates/src/components/fields/BackgroundImage.tsx +8 -0
  73. package/templates/src/components/fields/BackgroundImageWrapper.tsx +15 -9
  74. package/templates/src/components/fields/ImageUpload.tsx +6 -0
  75. package/templates/src/components/form/ActionBuilderField.tsx +15 -5
  76. package/templates/src/components/form/ActionBuilderSlugSelector.tsx +1 -1
  77. package/templates/src/components/form/ColorPicker.tsx +1 -1
  78. package/templates/src/components/form/EnumSelect.tsx +1 -1
  79. package/templates/src/components/form/NumberInput.tsx +1 -1
  80. package/templates/src/components/form/StringArrayInput.tsx +1 -1
  81. package/templates/src/components/form/StringInput.tsx +1 -1
  82. package/templates/src/components/form/UnsavedChangesBar.tsx +1 -1
  83. package/templates/src/components/form/advanced/APIConfigSection.tsx +2 -2
  84. package/templates/src/components/form/advanced/AuthConfigSection.tsx +2 -2
  85. package/templates/src/components/profile/ProfileCreate.tsx +1 -1
  86. package/templates/src/components/profile/ProfileEdit.tsx +1 -1
  87. package/templates/src/components/storykeep/Dashboard_Advanced.tsx +2 -2
  88. package/templates/src/components/storykeep/controls/content/BeliefForm.tsx +1 -1
  89. package/templates/src/components/storykeep/controls/content/ContentSummary.tsx +2 -2
  90. package/templates/src/components/storykeep/controls/content/KnownResourceTable.tsx +1 -1
  91. package/templates/src/components/storykeep/controls/content/ManageContent.tsx +6 -6
  92. package/templates/src/components/storykeep/controls/content/MenuForm.tsx +1 -1
  93. package/templates/src/components/storykeep/controls/content/PaneTable.tsx +358 -0
  94. package/templates/src/components/storykeep/controls/content/ResourceTable.tsx +1 -1
  95. package/templates/src/constants/prompts.json +18 -10
  96. package/templates/src/constants.ts +3 -0
  97. package/templates/src/hooks/usePaneFragments.ts +60 -0
  98. package/templates/src/lib/session.ts +71 -16
  99. package/templates/src/pages/[...slug].astro +4 -46
  100. package/templates/src/pages/api/css.ts +149 -0
  101. package/templates/src/pages/maint.astro +1 -1
  102. package/templates/src/pages/storykeep/login.astro +2 -2
  103. package/templates/src/stores/nodes.ts +162 -49
  104. package/templates/src/stores/orphanAnalysis.ts +6 -30
  105. package/templates/src/stores/previews.ts +7 -0
  106. package/templates/src/stores/storykeep.ts +0 -8
  107. package/templates/src/types/compositorTypes.ts +53 -10
  108. package/templates/src/utils/compositor/aiGeneration.ts +93 -0
  109. package/templates/src/utils/compositor/allowInsert.ts +2 -0
  110. package/templates/src/utils/compositor/htmlAst.ts +704 -0
  111. package/templates/src/utils/compositor/nodesHelper.ts +281 -102
  112. package/templates/src/utils/compositor/savePipeline.ts +893 -0
  113. package/templates/src/utils/etl/index.ts +3 -0
  114. package/templates/src/utils/etl/transformer.ts +10 -0
  115. package/templates/src/utils/helpers.ts +101 -0
  116. package/utils/inject-files.ts +100 -62
  117. package/templates/icons/text.svg +0 -6
  118. package/templates/src/components/compositor/NodeWithGuid.tsx +0 -69
  119. package/templates/src/components/compositor/nodes/GridLayout_eraser.tsx +0 -33
  120. package/templates/src/components/compositor/nodes/Markdown_eraser.tsx +0 -56
  121. package/templates/src/components/compositor/nodes/Pane_DesignLibrary.tsx +0 -269
  122. package/templates/src/components/compositor/nodes/Pane_eraser.tsx +0 -186
  123. package/templates/src/components/compositor/nodes/Pane_layout.tsx +0 -79
  124. package/templates/src/components/compositor/nodes/tagElements/NodeA_eraser.tsx +0 -26
  125. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_eraser.tsx +0 -61
  126. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_insert.tsx +0 -120
  127. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_settings.tsx +0 -62
  128. package/templates/src/components/compositor/nodes/tagElements/NodeButton_eraser.tsx +0 -26
@@ -1,3 +1,4 @@
1
+ import { type ReactNode } from 'react';
1
2
  import BooleanToggle from '@/components/form/BooleanToggle';
2
3
  import EnumSelect from '@/components/form/EnumSelect';
3
4
 
@@ -17,7 +18,7 @@ interface CopyInputStepProps {
17
18
  onTopicChange: (value: string) => void;
18
19
 
19
20
  showAdvancedPrompts: boolean;
20
- onShowAdvancedPromptsChange: (value: boolean) => void;
21
+ onShowAdvancedPromptsChange?: (value: boolean) => void;
21
22
 
22
23
  promptValue: string;
23
24
  onPromptValueChange: (value: string) => void;
@@ -42,6 +43,18 @@ interface CopyInputStepProps {
42
43
  isAiStyling: boolean;
43
44
  onIsAiStylingChange: (checked: boolean) => void;
44
45
  showStyleToggle?: boolean;
46
+ onDirectInject?: () => void;
47
+
48
+ masterShellSystem?: string;
49
+ setMasterShellSystem?: (val: string) => void;
50
+ masterShellUser?: string;
51
+ setMasterShellUser?: (val: string) => void;
52
+ masterCopySystem?: string;
53
+ setMasterCopySystem?: (val: string) => void;
54
+ masterCopyUser?: string;
55
+ setMasterCopyUser?: (val: string) => void;
56
+
57
+ children?: ReactNode;
45
58
  }
46
59
 
47
60
  export const CopyInputStep = ({
@@ -73,6 +86,16 @@ export const CopyInputStep = ({
73
86
  isAiStyling,
74
87
  onIsAiStylingChange,
75
88
  showStyleToggle = true,
89
+ onDirectInject,
90
+ masterShellSystem,
91
+ setMasterShellSystem,
92
+ masterShellUser,
93
+ setMasterShellUser,
94
+ masterCopySystem,
95
+ setMasterCopySystem,
96
+ masterCopyUser,
97
+ setMasterCopyUser,
98
+ children,
76
99
  }: CopyInputStepProps) => {
77
100
  const renderModeSelection = () => (
78
101
  <div className="my-2 flex flex-wrap gap-4">
@@ -132,99 +155,190 @@ export const CopyInputStep = ({
132
155
  </div>
133
156
  );
134
157
 
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>
158
+ const renderAdvancedEditors = () => {
159
+ if (
160
+ masterShellSystem !== undefined &&
161
+ masterShellUser !== undefined &&
162
+ masterCopySystem !== undefined &&
163
+ masterCopyUser !== undefined &&
164
+ setMasterShellSystem &&
165
+ setMasterShellUser &&
166
+ setMasterCopySystem &&
167
+ setMasterCopyUser
168
+ ) {
169
+ return (
170
+ <div className="mt-4 space-y-6 rounded-md border border-yellow-200 bg-yellow-50 p-4">
171
+ <div className="flex items-start gap-2">
172
+ <div className="mt-0.5 text-xl">⚡</div>
173
+ <div>
174
+ <p className="font-bold text-gray-900">Master Template Mode</p>
175
+ <p className="text-xs text-gray-600">
176
+ You are editing the raw source prompts. Variables like{' '}
177
+ <code className="bg-gray-100 px-1 font-mono font-bold">{`{{DESIGN_INPUT}}`}</code>{' '}
178
+ will be replaced by your settings unless you remove them.
179
+ </p>
180
+ </div>
181
+ </div>
147
182
 
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="sm:text-sm block w-full rounded-md border-gray-300 p-2 shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
158
- />
159
- </div>
183
+ <div>
184
+ <label className="mb-2 block text-sm font-bold text-gray-800">
185
+ Shell System Prompt
186
+ </label>
187
+ <textarea
188
+ value={masterShellSystem}
189
+ onChange={(e) => setMasterShellSystem(e.target.value)}
190
+ rows={4}
191
+ className="block w-full rounded-md border-gray-300 p-2 font-mono text-xs shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
192
+ />
193
+ </div>
160
194
 
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>
195
+ <div>
196
+ <label className="mb-2 block text-sm font-bold text-gray-800">
197
+ Shell User Template
198
+ </label>
199
+ <textarea
200
+ value={masterShellUser}
201
+ onChange={(e) => setMasterShellUser(e.target.value)}
202
+ rows={10}
203
+ className="block w-full rounded-md border-gray-300 p-2 font-mono text-xs shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
204
+ />
205
+ </div>
169
206
 
170
- {showAdvancedPrompts && (
171
- <div className="mt-4 space-y-4 rounded-md border border-gray-200 bg-white p-4">
172
- {layoutChoice === 'standard' ? (
207
+ <div>
208
+ <label className="mb-2 block text-sm font-bold text-gray-800">
209
+ Copy System Prompt
210
+ </label>
211
+ <textarea
212
+ value={masterCopySystem}
213
+ onChange={(e) => setMasterCopySystem(e.target.value)}
214
+ rows={4}
215
+ className="block w-full rounded-md border-gray-300 p-2 font-mono text-xs shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
216
+ />
217
+ </div>
218
+
219
+ <div>
220
+ <label className="mb-2 block text-sm font-bold text-gray-800">
221
+ Copy User Template
222
+ </label>
223
+ <textarea
224
+ value={masterCopyUser}
225
+ onChange={(e) => setMasterCopyUser(e.target.value)}
226
+ rows={10}
227
+ className="block w-full rounded-md border-gray-300 p-2 font-mono text-xs shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
228
+ />
229
+ </div>
230
+ </div>
231
+ );
232
+ }
233
+
234
+ return (
235
+ <div className="mt-4 space-y-4 rounded-md border border-gray-200 bg-white p-4">
236
+ <p className="mb-3 text-xs text-gray-600">
237
+ Edit the raw prompts sent to the AI. Variables like{' '}
238
+ <code className="bg-gray-100 px-1 font-mono font-bold">
239
+ {`{{TOPIC}}`}
240
+ </code>{' '}
241
+ will still be replaced.
242
+ </p>
243
+ {layoutChoice === 'standard' ? (
244
+ <div>
245
+ <label className="mb-2 block text-sm font-bold text-gray-700">
246
+ Full Prompt
247
+ </label>
248
+ <textarea
249
+ value={promptValue}
250
+ onChange={(e) => onPromptValueChange(e.target.value)}
251
+ rows={12}
252
+ className="block w-full rounded-md border-gray-300 p-2 font-mono text-xs shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
253
+ />
254
+ </div>
255
+ ) : (
256
+ <>
173
257
  <div>
174
258
  <label className="mb-2 block text-sm font-bold text-gray-700">
175
- Full Prompt
259
+ Overall Component Brief
176
260
  </label>
177
261
  <textarea
178
- value={promptValue}
179
- onChange={(e) => onPromptValueChange(e.target.value)}
180
- rows={4}
181
- className="sm:text-sm block w-full rounded-md border-gray-300 p-2 shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
262
+ value={overallPrompt}
263
+ onChange={(e) => onOverallPromptChange(e.target.value)}
264
+ rows={3}
265
+ className="block w-full rounded-md border-gray-300 p-2 shadow-sm focus:border-cyan-500 focus:ring-cyan-500 md:text-sm"
182
266
  />
183
- <p className="mt-1 text-xs text-gray-500">
184
- Leave [topic] as it will be replaced with your prompt.
185
- </p>
186
267
  </div>
187
- ) : (
188
- <>
268
+ <div className="grid grid-cols-1 gap-6 md:grid-cols-2">
189
269
  <div>
190
270
  <label className="mb-2 block text-sm font-bold text-gray-700">
191
- Overall Component Brief
271
+ Left Column Prompt
192
272
  </label>
193
273
  <textarea
194
- value={overallPrompt}
195
- onChange={(e) => onOverallPromptChange(e.target.value)}
196
- rows={3}
197
- className="sm:text-sm block w-full rounded-md border-gray-300 p-2 shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
274
+ value={promptValueCol1}
275
+ onChange={(e) => onPromptValueCol1Change(e.target.value)}
276
+ rows={8}
277
+ className="block w-full rounded-md border-gray-300 p-2 font-mono text-xs shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
198
278
  />
199
279
  </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="sm:text-sm block w-full rounded-md border-gray-300 p-2 shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
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="sm:text-sm block w-full rounded-md border-gray-300 p-2 shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
221
- />
222
- </div>
280
+ <div>
281
+ <label className="mb-2 block text-sm font-bold text-gray-700">
282
+ Right Column Prompt
283
+ </label>
284
+ <textarea
285
+ value={promptValueCol2}
286
+ onChange={(e) => onPromptValueCol2Change(e.target.value)}
287
+ rows={8}
288
+ className="block w-full rounded-md border-gray-300 p-2 font-mono text-xs shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
289
+ />
223
290
  </div>
224
- </>
225
- )}
291
+ </div>
292
+ </>
293
+ )}
294
+ </div>
295
+ );
296
+ };
297
+
298
+ const renderPromptMode = () => (
299
+ <>
300
+ {!showAdvancedPrompts && (
301
+ <>
302
+ <div className="mb-4">
303
+ <EnumSelect
304
+ label="Section Type"
305
+ value={selectedPromptId}
306
+ onChange={onSelectedPromptIdChange}
307
+ options={promptOptions}
308
+ placeholder="Select a type..."
309
+ className="w-full"
310
+ />
311
+ </div>
312
+
313
+ <div className="mb-4">
314
+ <label className="mb-2 block text-sm font-bold text-gray-700">
315
+ Topic / Context
316
+ </label>
317
+ <textarea
318
+ value={topic}
319
+ onChange={(e) => onTopicChange(e.target.value)}
320
+ placeholder="e.g. a SaaS product for team collaboration"
321
+ rows={2}
322
+ className="block w-full rounded-md border-gray-300 p-2 shadow-sm focus:border-cyan-500 focus:ring-cyan-500 md:text-sm"
323
+ />
324
+ </div>
325
+
326
+ {children}
327
+ </>
328
+ )}
329
+
330
+ {onShowAdvancedPromptsChange && (
331
+ <div className="mt-4 flex items-center border-t border-gray-100 pt-4">
332
+ <BooleanToggle
333
+ label="Advanced: Edit Full Prompts"
334
+ value={showAdvancedPrompts}
335
+ onChange={onShowAdvancedPromptsChange}
336
+ size="sm"
337
+ />
226
338
  </div>
227
339
  )}
340
+
341
+ {showAdvancedPrompts && renderAdvancedEditors()}
228
342
  </>
229
343
  );
230
344
 
@@ -315,6 +429,17 @@ export const CopyInputStep = ({
315
429
  </p>
316
430
  </div>
317
431
  )}
432
+
433
+ {onDirectInject && (
434
+ <div className="mt-4 text-center">
435
+ <button
436
+ onClick={onDirectInject}
437
+ className="text-xs text-gray-400 underline hover:text-gray-600"
438
+ >
439
+ Direct Inject HTML+CSS
440
+ </button>
441
+ </div>
442
+ )}
318
443
  </>
319
444
  );
320
445
  };
@@ -0,0 +1,141 @@
1
+ import { useState } from 'react';
2
+ import { getCtx } from '@/stores/nodes';
3
+ import { htmlToHtmlAst } from '@/utils/compositor/htmlAst';
4
+ import type { TemplatePane } from '@/types/compositorTypes';
5
+
6
+ interface CreativeInjectStepProps {
7
+ onBack: () => void;
8
+ onCreatePane: (template: TemplatePane) => void;
9
+ }
10
+
11
+ export const CreativeInjectStep = ({
12
+ onBack,
13
+ onCreatePane,
14
+ }: CreativeInjectStepProps) => {
15
+ const [html, setHtml] = useState('');
16
+ const [css, setCss] = useState('');
17
+ const [isCompiling, setIsCompiling] = useState(false);
18
+ const [error, setError] = useState<string | null>(null);
19
+
20
+ const handleCreate = async () => {
21
+ setError(null);
22
+ if (!html.trim()) {
23
+ setError('HTML content is required.');
24
+ return;
25
+ }
26
+
27
+ setIsCompiling(true);
28
+
29
+ try {
30
+ const htmlAst = await htmlToHtmlAst(html, css);
31
+
32
+ const template: TemplatePane = {
33
+ id: '',
34
+ nodeType: 'Pane',
35
+ parentId: '',
36
+ title: 'Creative Pane',
37
+ slug: '',
38
+ isDecorative: false,
39
+ htmlAst,
40
+ markdown: {
41
+ id: '',
42
+ nodeType: 'Markdown',
43
+ parentId: '',
44
+ type: 'markdown',
45
+ markdownId: '',
46
+ defaultClasses: {},
47
+ parentClasses: [],
48
+ nodes: [],
49
+ },
50
+ };
51
+
52
+ onCreatePane(template);
53
+ const ctx = getCtx();
54
+ ctx.showSaveBypass.set(true);
55
+ } catch (err: any) {
56
+ console.error('Compiler Error:', err);
57
+ setError(`Compilation failed: ${err.message}`);
58
+ } finally {
59
+ setIsCompiling(false);
60
+ }
61
+ };
62
+
63
+ return (
64
+ <div className="space-y-6 p-4">
65
+ <div className="rounded-md bg-blue-50 p-4">
66
+ <p className="text-sm text-blue-800">
67
+ <strong>Creative Mode:</strong> Input raw HTML and CSS. Tailwind
68
+ classes will be compiled and bucketed into an optimized structure.
69
+ </p>
70
+ </div>
71
+
72
+ <div className="grid gap-6 md:grid-cols-2">
73
+ <div className="space-y-2">
74
+ <label
75
+ htmlFor="htmlInput"
76
+ className="block text-sm font-bold text-gray-700"
77
+ >
78
+ HTML Structure
79
+ </label>
80
+ <textarea
81
+ id="htmlInput"
82
+ rows={15}
83
+ value={html}
84
+ onChange={(e) => setHtml(e.target.value)}
85
+ disabled={isCompiling}
86
+ className="block w-full rounded-md border-gray-300 p-2 font-mono text-xs shadow-sm focus:border-cyan-500 focus:ring-cyan-500 disabled:bg-gray-100"
87
+ placeholder={`<div class="p-8 bg-blue-500 hover:bg-blue-600">\n <h1 class="text-white text-4xl">Hello</h1>\n</div>`}
88
+ />
89
+ </div>
90
+
91
+ <div className="space-y-2">
92
+ <label
93
+ htmlFor="cssInput"
94
+ className="block text-sm font-bold text-gray-700"
95
+ >
96
+ Custom CSS Styles
97
+ </label>
98
+ <textarea
99
+ id="cssInput"
100
+ rows={15}
101
+ value={css}
102
+ onChange={(e) => setCss(e.target.value)}
103
+ disabled={isCompiling}
104
+ className="block w-full rounded-md border-gray-300 p-2 font-mono text-xs shadow-sm focus:border-cyan-500 focus:ring-cyan-500 disabled:bg-gray-100"
105
+ placeholder={`.my-class {\n border: 1px solid red;\n}`}
106
+ />
107
+ </div>
108
+ </div>
109
+
110
+ {error && (
111
+ <div className="rounded-md bg-red-50 p-4">
112
+ <p className="text-sm font-bold text-red-800">{error}</p>
113
+ </div>
114
+ )}
115
+
116
+ <div className="flex justify-between border-t pt-4">
117
+ <button
118
+ onClick={onBack}
119
+ disabled={isCompiling}
120
+ className="rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-bold text-gray-700 shadow-sm hover:bg-gray-50 disabled:opacity-50"
121
+ >
122
+ ← Back
123
+ </button>
124
+ <button
125
+ onClick={handleCreate}
126
+ disabled={isCompiling}
127
+ className="flex items-center gap-2 rounded-md bg-cyan-600 px-6 py-2 text-sm font-bold text-white shadow-sm hover:bg-cyan-700 disabled:opacity-50"
128
+ >
129
+ {isCompiling ? (
130
+ <>
131
+ <span className="h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent"></span>
132
+ Compiling...
133
+ </>
134
+ ) : (
135
+ 'Compile & Create'
136
+ )}
137
+ </button>
138
+ </div>
139
+ </div>
140
+ );
141
+ };