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
@@ -11,6 +11,7 @@ import {
11
11
  import { PaneAddMode, type StoryFragmentNode } from '@/types/compositorTypes';
12
12
  import type { FullContentMapItem } from '@/types/tractstack';
13
13
  import { TractStackAPI } from '@/utils/api';
14
+ import { usePaneFragments } from '@/hooks/usePaneFragments';
14
15
 
15
16
  interface AddPaneReUsePanelProps {
16
17
  nodeId: string;
@@ -21,8 +22,6 @@ interface AddPaneReUsePanelProps {
21
22
  interface PreviewItem {
22
23
  ctx: NodesContext;
23
24
  snapshot?: SnapshotData;
24
- htmlFragment?: string;
25
- fragmentError?: string;
26
25
  pane: FullContentMapItem;
27
26
  index: number;
28
27
  }
@@ -43,9 +42,7 @@ const AddPaneReUsePanel = ({
43
42
  const [availablePanes, setAvailablePanes] = useState<FullContentMapItem[]>(
44
43
  []
45
44
  );
46
- const [fragmentsLoaded, setFragmentsLoaded] = useState(false);
47
45
  const [currentPage, setCurrentPage] = useState(0);
48
- const [renderedPages, setRenderedPages] = useState<Set<number>>(new Set([0]));
49
46
 
50
47
  useEffect(() => {
51
48
  const ctx = getCtx();
@@ -67,7 +64,6 @@ const AddPaneReUsePanel = ({
67
64
  setAvailablePanes(unusedPanes);
68
65
  }, [nodeId]);
69
66
 
70
- // Create collection for Ark UI Combobox
71
67
  const collection = useMemo(() => {
72
68
  const filteredPanes =
73
69
  query === ''
@@ -85,7 +81,6 @@ const AddPaneReUsePanel = ({
85
81
  });
86
82
  }, [availablePanes, query]);
87
83
 
88
- // Create previews from filtered panes
89
84
  useEffect(() => {
90
85
  const filteredPanes =
91
86
  query === ''
@@ -100,14 +95,10 @@ const AddPaneReUsePanel = ({
100
95
  ctx: new NodesContext(),
101
96
  pane,
102
97
  index,
103
- htmlFragment: undefined,
104
- fragmentError: undefined,
105
98
  }));
106
99
 
107
100
  setPreviews(newPreviews);
108
101
  setCurrentPage(0);
109
- setRenderedPages(new Set([0]));
110
- setFragmentsLoaded(false);
111
102
  }, [availablePanes, query]);
112
103
 
113
104
  const totalPages = Math.ceil(previews.length / ITEMS_PER_PAGE);
@@ -115,8 +106,6 @@ const AddPaneReUsePanel = ({
115
106
  const handlePageChange = (newPage: number) => {
116
107
  if (newPage >= 0 && newPage < totalPages) {
117
108
  setCurrentPage(newPage);
118
- setRenderedPages((prev) => new Set([...prev, newPage]));
119
- setFragmentsLoaded(false);
120
109
  }
121
110
  };
122
111
 
@@ -125,66 +114,15 @@ const AddPaneReUsePanel = ({
125
114
  return previews.slice(startIndex, startIndex + ITEMS_PER_PAGE);
126
115
  }, [previews, currentPage]);
127
116
 
128
- // Fetch fragments for visible panes
129
- useEffect(() => {
130
- if (visiblePreviews.length === 0 || fragmentsLoaded) return;
131
-
132
- const fetchFragments = async () => {
133
- try {
134
- const paneIds = visiblePreviews.map((preview) => preview.pane.id);
135
- const api = new TractStackAPI(tenantId);
136
-
137
- const response = await api.post('/api/v1/fragments/panes', { paneIds });
138
-
139
- if (!response.success) {
140
- throw new Error(response.error || `Fragment API failed`);
141
- }
142
-
143
- const data = response.data;
144
-
145
- setPreviews((prevPreviews) => {
146
- const updated = [...prevPreviews];
147
- visiblePreviews.forEach((visiblePreview) => {
148
- const globalIndex = prevPreviews.findIndex(
149
- (p) => p.pane.id === visiblePreview.pane.id
150
- );
151
- if (globalIndex !== -1) {
152
- updated[globalIndex] = {
153
- ...updated[globalIndex],
154
- htmlFragment: data.fragments?.[visiblePreview.pane.id] || '',
155
- fragmentError:
156
- data.errors?.[visiblePreview.pane.id] || undefined,
157
- };
158
- }
159
- });
160
- return updated;
161
- });
162
-
163
- setFragmentsLoaded(true);
164
- } catch (error) {
165
- console.error('Failed to fetch fragments:', error);
166
- setPreviews((prevPreviews) => {
167
- const updated = [...prevPreviews];
168
- visiblePreviews.forEach((visiblePreview) => {
169
- const globalIndex = prevPreviews.findIndex(
170
- (p) => p.pane.id === visiblePreview.pane.id
171
- );
172
- if (globalIndex !== -1) {
173
- updated[globalIndex] = {
174
- ...updated[globalIndex],
175
- fragmentError:
176
- error instanceof Error ? error.message : 'Unknown error',
177
- };
178
- }
179
- });
180
- return updated;
181
- });
182
- setFragmentsLoaded(true);
183
- }
184
- };
185
-
186
- fetchFragments();
187
- }, [visiblePreviews, fragmentsLoaded]);
117
+ const visiblePaneIds = useMemo(
118
+ () => visiblePreviews.map((p) => p.pane.id),
119
+ [visiblePreviews]
120
+ );
121
+ const {
122
+ fragments,
123
+ errors,
124
+ isLoading: fragmentsLoading,
125
+ } = usePaneFragments(visiblePaneIds);
188
126
 
189
127
  const handleSnapshotComplete = (id: string, snapshot: SnapshotData) => {
190
128
  const paneId = id.replace('reuse-', '');
@@ -215,7 +153,6 @@ const AddPaneReUsePanel = ({
215
153
  const templateData = response.data;
216
154
  const ctx = getCtx();
217
155
 
218
- // Find storyfragment
219
156
  const storyfragmentId = ctx.getClosestNodeTypeFromId(
220
157
  nodeId,
221
158
  'StoryFragment'
@@ -231,7 +168,6 @@ const AddPaneReUsePanel = ({
231
168
  throw new Error('No storyfragment found');
232
169
  }
233
170
 
234
- // Set pane parentId
235
171
  templateData.paneNode.parentId = storyfragmentId;
236
172
 
237
173
  let specificIdx = -1;
@@ -260,7 +196,6 @@ const AddPaneReUsePanel = ({
260
196
  }
261
197
  storyFragmentNode.isChanged = true;
262
198
 
263
- // Add nodes using exact same pattern as addTemplatePane
264
199
  ctx.addNode(templateData.paneNode);
265
200
  ctx.linkChildToParent(
266
201
  templateData.paneNode.id,
@@ -276,7 +211,6 @@ const AddPaneReUsePanel = ({
276
211
  }
277
212
  };
278
213
 
279
- // CSS to properly style the combobox items with hover and selection
280
214
  const comboboxItemStyles = `
281
215
  .pane-item[data-highlighted] {
282
216
  background-color: #0891b2; /* bg-cyan-600 */
@@ -354,25 +288,24 @@ const AddPaneReUsePanel = ({
354
288
  ...(!preview.snapshot ? { minHeight: '75px' } : {}),
355
289
  }}
356
290
  >
357
- {renderedPages.has(currentPage) && !fragmentsLoaded && (
291
+ {fragmentsLoading && !fragments[preview.pane.id] && (
358
292
  <div className="flex h-24 items-center justify-center">
359
293
  <div className="text-gray-500">Loading...</div>
360
294
  </div>
361
295
  )}
362
296
 
363
- {fragmentsLoaded && preview.fragmentError && (
297
+ {errors[preview.pane.id] && (
364
298
  <div className="flex h-24 items-center justify-center">
365
299
  <div className="text-red-500">Preview error</div>
366
300
  </div>
367
301
  )}
368
302
 
369
- {fragmentsLoaded &&
370
- preview.htmlFragment &&
303
+ {fragments[preview.pane.id] &&
371
304
  !preview.snapshot &&
372
- !preview.fragmentError && (
305
+ !errors[preview.pane.id] && (
373
306
  <PaneSnapshotGenerator
374
307
  id={`reuse-${preview.pane.id}`}
375
- htmlString={preview.htmlFragment}
308
+ htmlString={fragments[preview.pane.id]}
376
309
  onComplete={handleSnapshotComplete}
377
310
  onError={(id, error) =>
378
311
  console.error(`Snapshot error for ${id}:`, error)
@@ -6,11 +6,14 @@ import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon';
6
6
  import SparklesIcon from '@heroicons/react/24/outline/SparklesIcon';
7
7
  import { getCtx } from '@/stores/nodes';
8
8
  import { selectionStore } from '@/stores/selection';
9
+ import { renderedPreviews } from '@/stores/previews';
9
10
  import { sandboxTokenStore } from '@/stores/storykeep';
10
11
  import { AiDesignStep, type AiDesignConfig } from './steps/AiDesignStep';
12
+ import { AiRefineDesignStep } from './steps/AiRefineDesignStep';
11
13
  import prompts from '@/constants/prompts.json';
12
14
  import { TractStackAPI } from '@/utils/api';
13
15
  import { parseAiPane } from '@/utils/compositor/aiPaneParser';
16
+ import type { PaneNode, TemplatePane } from '@/types/compositorTypes';
14
17
 
15
18
  const callAskLemurAPI = async (
16
19
  prompt: string,
@@ -29,7 +32,7 @@ const callAskLemurAPI = async (
29
32
  input_text: context,
30
33
  final_model: '',
31
34
  temperature: 0.5,
32
- max_tokens: 2000,
35
+ max_tokens: 10000,
33
36
  };
34
37
 
35
38
  let resultData: any;
@@ -82,22 +85,34 @@ export const AiRestylePaneModal = ({
82
85
  }: AiRestylePaneModalProps) => {
83
86
  const ctx = getCtx();
84
87
  const { isAiRestyleModalOpen, paneToRestyleId } = useStore(selectionStore);
88
+ const previews = useStore(renderedPreviews);
85
89
 
86
90
  const [loading, setLoading] = useState(false);
87
91
  const [error, setError] = useState<string | null>(null);
92
+ const [additionalNotes, setAdditionalNotes] = useState('');
88
93
  const [aiDesignConfig, setAiDesignConfig] = useState<AiDesignConfig>({
89
94
  harmony: 'Analogous',
90
95
  baseColor: '',
91
96
  accentColor: '',
92
97
  theme: 'Light',
93
- additionalNotes: '',
94
98
  });
95
99
 
100
+ const node = paneToRestyleId
101
+ ? (ctx.allNodes.get().get(paneToRestyleId) as PaneNode)
102
+ : null;
103
+ const isCreative = !!node?.htmlAst;
104
+
96
105
  const handleClose = () => {
97
106
  if (loading) return;
98
107
  selectionStore.setKey('isAiRestyleModalOpen', false);
99
108
  selectionStore.setKey('paneToRestyleId', null);
100
109
  setError(null);
110
+ setAdditionalNotes('');
111
+ };
112
+
113
+ const handleCreativeUpdate = (template: TemplatePane) => {
114
+ if (!paneToRestyleId) return;
115
+ ctx.applyShellToPane(paneToRestyleId, template);
101
116
  };
102
117
 
103
118
  const handleGenerate = async () => {
@@ -124,8 +139,7 @@ export const AiRestylePaneModal = ({
124
139
  designInput += ` Base around **${aiDesignConfig.baseColor}**.`;
125
140
  if (aiDesignConfig.accentColor)
126
141
  designInput += ` Accent with **${aiDesignConfig.accentColor}**.`;
127
- if (aiDesignConfig.additionalNotes)
128
- designInput += ` Notes: "${aiDesignConfig.additionalNotes}"`;
142
+ if (additionalNotes) designInput += ` Notes: "${additionalNotes}"`;
129
143
 
130
144
  const shellPromptKey = promptConfig.prompts.shell as keyof typeof prompts;
131
145
  const shellPromptDetails = prompts[shellPromptKey] as any;
@@ -168,11 +182,11 @@ export const AiRestylePaneModal = ({
168
182
  >
169
183
  <Dialog.Backdrop className="fixed inset-0 z-103 bg-black bg-opacity-75" />
170
184
  <Dialog.Positioner className="fixed inset-0 z-104 flex items-center justify-center p-4">
171
- <Dialog.Content className="flex max-w-2xl flex-col rounded-lg bg-white shadow-2xl">
185
+ <Dialog.Content className="flex w-full max-w-7xl flex-col rounded-lg bg-white shadow-2xl">
172
186
  <div className="flex items-center justify-between border-b p-4">
173
187
  <h3 className="flex items-center gap-2 text-lg font-bold">
174
188
  <SparklesIcon className="h-5 w-5 text-purple-600" />
175
- Re-Color Pane
189
+ {isCreative ? 'Refine Creative Pane' : 'Re-Color Pane'}
176
190
  </h3>
177
191
  <button
178
192
  onClick={handleClose}
@@ -183,49 +197,85 @@ export const AiRestylePaneModal = ({
183
197
  </button>
184
198
  </div>
185
199
 
186
- <form className="p-6" onSubmit={(e) => e.preventDefault()}>
187
- <div className={loading ? 'pointer-events-none opacity-50' : ''}>
188
- <AiDesignStep
189
- designConfig={aiDesignConfig}
190
- onDesignConfigChange={setAiDesignConfig}
200
+ {isCreative ? (
201
+ <div className="overflow-y-auto" style={{ maxHeight: `80vh` }}>
202
+ <AiRefineDesignStep
203
+ onBack={handleClose}
204
+ onSuccess={handleClose}
205
+ onUpdatePane={handleCreativeUpdate}
206
+ isSandboxMode={isSandboxMode}
207
+ initialHtml={
208
+ paneToRestyleId ? previews[paneToRestyleId] || '' : ''
209
+ }
210
+ initialCss={node?.htmlAst?.css || ''}
191
211
  />
192
212
  </div>
213
+ ) : (
214
+ <form className="p-6" onSubmit={(e) => e.preventDefault()}>
215
+ <div className={loading ? 'pointer-events-none opacity-50' : ''}>
216
+ <AiDesignStep
217
+ designConfig={aiDesignConfig}
218
+ onDesignConfigChange={setAiDesignConfig}
219
+ />
193
220
 
194
- {error && (
195
- <div className="mt-4 rounded border border-red-200 bg-red-50 p-3 text-sm text-red-700">
196
- {error}
221
+ <div className="mt-6">
222
+ <label
223
+ htmlFor="restyle-notes"
224
+ className="block text-base font-bold text-gray-800"
225
+ >
226
+ Additional Design Notes (Optional)
227
+ </label>
228
+ <p className="mb-2 mt-1 text-sm text-gray-500">
229
+ Add specific requests like "use rounded corners", "add
230
+ subtle texture".
231
+ </p>
232
+ <textarea
233
+ id="restyle-notes"
234
+ value={additionalNotes}
235
+ onChange={(e) => setAdditionalNotes(e.target.value)}
236
+ placeholder="Enter additional notes..."
237
+ rows={3}
238
+ className="block w-full rounded-md border-gray-300 p-2 text-sm shadow-sm focus:border-cyan-500 focus:ring-cyan-500"
239
+ />
240
+ </div>
197
241
  </div>
198
- )}
199
-
200
- <div className="mt-8 flex justify-end gap-3">
201
- <button
202
- type="button"
203
- onClick={handleClose}
204
- disabled={loading}
205
- className="rounded-lg px-4 py-2 font-bold text-gray-600 hover:bg-gray-100 disabled:opacity-50"
206
- >
207
- Cancel
208
- </button>
209
- <button
210
- type="button"
211
- onClick={handleGenerate}
212
- disabled={loading}
213
- className="flex items-center gap-2 rounded-lg bg-gradient-to-r from-purple-600 to-indigo-600 px-6 py-2 font-bold text-white shadow transition-all hover:from-purple-500 hover:to-indigo-500 hover:shadow-lg disabled:cursor-not-allowed disabled:opacity-75"
214
- >
215
- {loading ? (
216
- <>
217
- <div className="h-5 w-5 animate-spin rounded-full border-2 border-white/30 border-t-white" />
218
- Generating...
219
- </>
220
- ) : (
221
- <>
222
- <SparklesIcon className="h-5 w-5" />
223
- Apply Re-Color
224
- </>
225
- )}
226
- </button>
227
- </div>
228
- </form>
242
+
243
+ {error && (
244
+ <div className="mt-4 rounded border border-red-200 bg-red-50 p-3 text-sm text-red-700">
245
+ {error}
246
+ </div>
247
+ )}
248
+
249
+ <div className="mt-8 flex justify-end gap-3">
250
+ <button
251
+ type="button"
252
+ onClick={handleClose}
253
+ disabled={loading}
254
+ className="rounded-lg px-4 py-2 font-bold text-gray-600 hover:bg-gray-100 disabled:opacity-50"
255
+ >
256
+ Cancel
257
+ </button>
258
+ <button
259
+ type="button"
260
+ onClick={handleGenerate}
261
+ disabled={loading}
262
+ className="flex items-center gap-2 rounded-lg bg-gradient-to-r from-purple-600 to-indigo-600 px-6 py-2 font-bold text-white shadow transition-all hover:from-purple-500 hover:to-indigo-500 hover:shadow-lg disabled:cursor-not-allowed disabled:opacity-75"
263
+ >
264
+ {loading ? (
265
+ <>
266
+ <div className="h-5 w-5 animate-spin rounded-full border-2 border-white/30 border-t-white" />
267
+ Generating...
268
+ </>
269
+ ) : (
270
+ <>
271
+ <SparklesIcon className="h-5 w-5" />
272
+ Apply Re-Color
273
+ </>
274
+ )}
275
+ </button>
276
+ </div>
277
+ </form>
278
+ )}
229
279
  </Dialog.Content>
230
280
  </Dialog.Positioner>
231
281
  </Dialog.Root>