@alpaca-editor/core 1.0.3896 → 1.0.3898

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 (124) hide show
  1. package/dist/components/ActionButton.js +2 -2
  2. package/dist/components/ActionButton.js.map +1 -1
  3. package/dist/components/ui/button.js +3 -3
  4. package/dist/components/ui/button.js.map +1 -1
  5. package/dist/config/config.js +44 -22
  6. package/dist/config/config.js.map +1 -1
  7. package/dist/editor/FieldListField.js +1 -1
  8. package/dist/editor/FieldListField.js.map +1 -1
  9. package/dist/editor/Titlebar.js +2 -1
  10. package/dist/editor/Titlebar.js.map +1 -1
  11. package/dist/editor/client/EditorClient.d.ts +27 -2
  12. package/dist/editor/client/EditorClient.js +140 -1
  13. package/dist/editor/client/EditorClient.js.map +1 -1
  14. package/dist/editor/client/editContext.d.ts +6 -1
  15. package/dist/editor/client/editContext.js.map +1 -1
  16. package/dist/editor/client/itemsRepository.js +1 -1
  17. package/dist/editor/client/itemsRepository.js.map +1 -1
  18. package/dist/editor/client/operations.js +1 -1
  19. package/dist/editor/client/operations.js.map +1 -1
  20. package/dist/editor/control-center/About.d.ts +1 -0
  21. package/dist/editor/control-center/About.js +8 -0
  22. package/dist/editor/control-center/About.js.map +1 -0
  23. package/dist/editor/control-center/ControlCenterMenu.js +3 -0
  24. package/dist/editor/control-center/ControlCenterMenu.js.map +1 -1
  25. package/dist/editor/control-center/Info.d.ts +1 -0
  26. package/dist/editor/control-center/Info.js +10 -0
  27. package/dist/editor/control-center/Info.js.map +1 -0
  28. package/dist/editor/control-center/QuotaInfo.d.ts +1 -0
  29. package/dist/editor/control-center/QuotaInfo.js +102 -0
  30. package/dist/editor/control-center/QuotaInfo.js.map +1 -0
  31. package/dist/editor/control-center/Status.js +69 -2
  32. package/dist/editor/control-center/Status.js.map +1 -1
  33. package/dist/editor/control-center/WebSocketMessages.d.ts +1 -0
  34. package/dist/editor/control-center/WebSocketMessages.js +66 -0
  35. package/dist/editor/control-center/WebSocketMessages.js.map +1 -0
  36. package/dist/editor/page-editor-chrome/FieldActionIndicator.js +7 -6
  37. package/dist/editor/page-editor-chrome/FieldActionIndicator.js.map +1 -1
  38. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  39. package/dist/editor/services/aiService.d.ts +7 -1
  40. package/dist/editor/services/aiService.js +8 -1
  41. package/dist/editor/services/aiService.js.map +1 -1
  42. package/dist/editor/sidebar/ComponentTree.js +1 -1
  43. package/dist/editor/sidebar/ComponentTree.js.map +1 -1
  44. package/dist/editor/sidebar/ViewSelector.js +9 -4
  45. package/dist/editor/sidebar/ViewSelector.js.map +1 -1
  46. package/dist/editor/ui/Icons.d.ts +19 -1
  47. package/dist/editor/ui/Icons.js +23 -5
  48. package/dist/editor/ui/Icons.js.map +1 -1
  49. package/dist/editor/ui/SimpleMenu.js +1 -1
  50. package/dist/editor/ui/SimpleMenu.js.map +1 -1
  51. package/dist/fonts/index.d.ts +4 -0
  52. package/dist/fonts/index.js +9 -0
  53. package/dist/fonts/index.js.map +1 -0
  54. package/dist/images/wizard-bg.png +0 -0
  55. package/dist/index.d.ts +2 -1
  56. package/dist/index.js +1 -0
  57. package/dist/index.js.map +1 -1
  58. package/dist/page-wizard/WizardBox.d.ts +8 -0
  59. package/dist/page-wizard/WizardBox.js +6 -0
  60. package/dist/page-wizard/WizardBox.js.map +1 -0
  61. package/dist/page-wizard/WizardBoxConnector.d.ts +3 -0
  62. package/dist/page-wizard/WizardBoxConnector.js +6 -0
  63. package/dist/page-wizard/WizardBoxConnector.js.map +1 -0
  64. package/dist/page-wizard/WizardSteps.d.ts +4 -2
  65. package/dist/page-wizard/WizardSteps.js +44 -18
  66. package/dist/page-wizard/WizardSteps.js.map +1 -1
  67. package/dist/page-wizard/steps/CollectStep.js +16 -21
  68. package/dist/page-wizard/steps/CollectStep.js.map +1 -1
  69. package/dist/page-wizard/steps/ComponentTypesSelector.js +50 -45
  70. package/dist/page-wizard/steps/ComponentTypesSelector.js.map +1 -1
  71. package/dist/page-wizard/steps/CreatePage.js +6 -3
  72. package/dist/page-wizard/steps/CreatePage.js.map +1 -1
  73. package/dist/page-wizard/steps/CreatePageAndLayoutStep.js +21 -28
  74. package/dist/page-wizard/steps/CreatePageAndLayoutStep.js.map +1 -1
  75. package/dist/page-wizard/steps/Generate.js +27 -5
  76. package/dist/page-wizard/steps/Generate.js.map +1 -1
  77. package/dist/page-wizard/steps/ImagesStep.js +46 -44
  78. package/dist/page-wizard/steps/ImagesStep.js.map +1 -1
  79. package/dist/page-wizard/steps/SelectStep.js +11 -19
  80. package/dist/page-wizard/steps/SelectStep.js.map +1 -1
  81. package/dist/page-wizard/steps/usePageCreator.js +41 -12
  82. package/dist/page-wizard/steps/usePageCreator.js.map +1 -1
  83. package/dist/revision.d.ts +2 -2
  84. package/dist/revision.js +2 -2
  85. package/dist/styles.css +236 -120
  86. package/images/wizard-bg.png +0 -0
  87. package/package.json +1 -1
  88. package/src/components/ActionButton.tsx +6 -8
  89. package/src/components/ui/button.tsx +3 -3
  90. package/src/config/config.tsx +54 -22
  91. package/src/editor/FieldListField.tsx +2 -2
  92. package/src/editor/Titlebar.tsx +2 -1
  93. package/src/editor/client/EditorClient.tsx +192 -9
  94. package/src/editor/client/editContext.ts +12 -2
  95. package/src/editor/client/itemsRepository.ts +1 -1
  96. package/src/editor/client/operations.ts +1 -1
  97. package/src/editor/control-center/About.tsx +342 -0
  98. package/src/editor/control-center/ControlCenterMenu.tsx +5 -0
  99. package/src/editor/control-center/Info.tsx +104 -0
  100. package/src/editor/control-center/QuotaInfo.tsx +301 -0
  101. package/src/editor/control-center/Status.tsx +108 -2
  102. package/src/editor/control-center/WebSocketMessages.tsx +155 -0
  103. package/src/editor/page-editor-chrome/FieldActionIndicator.tsx +20 -5
  104. package/src/editor/page-viewer/PageViewer.tsx +1 -1
  105. package/src/editor/services/aiService.ts +17 -2
  106. package/src/editor/sidebar/ComponentTree.tsx +1 -1
  107. package/src/editor/sidebar/ViewSelector.tsx +10 -11
  108. package/src/editor/ui/Icons.tsx +146 -26
  109. package/src/editor/ui/SimpleMenu.tsx +1 -1
  110. package/src/fonts/index.ts +10 -0
  111. package/src/index.ts +7 -1
  112. package/src/page-wizard/WizardBox.tsx +40 -0
  113. package/src/page-wizard/WizardBoxConnector.tsx +21 -0
  114. package/src/page-wizard/WizardSteps.tsx +236 -116
  115. package/src/page-wizard/steps/CollectStep.tsx +129 -67
  116. package/src/page-wizard/steps/ComponentTypesSelector.tsx +32 -11
  117. package/src/page-wizard/steps/CreatePage.tsx +130 -84
  118. package/src/page-wizard/steps/CreatePageAndLayoutStep.tsx +47 -30
  119. package/src/page-wizard/steps/Generate.tsx +45 -17
  120. package/src/page-wizard/steps/ImagesStep.tsx +161 -141
  121. package/src/page-wizard/steps/SelectStep.tsx +92 -76
  122. package/src/page-wizard/steps/usePageCreator.ts +40 -14
  123. package/src/revision.ts +2 -2
  124. package/styles.css +49 -8
@@ -2,7 +2,6 @@ import { StepComponentProps } from "../../config/types";
2
2
  import { useEffect, useState } from "react";
3
3
  import { ScrollingContentTree } from "../../editor/ScrollingContentTree";
4
4
  import { ItemTreeNodeData } from "../../editor/services/contentService";
5
- import { Splitter, SplitterPanel } from "../../editor/ui/Splitter";
6
5
  import { useEditContext } from "../../editor/client/editContext";
7
6
  import { executePrompt, executeSearch } from "../../editor/services/aiService";
8
7
  import { createWizardAiContext } from "../service";
@@ -11,6 +10,10 @@ import { classNames } from "primereact/utils";
11
10
  import { Button } from "primereact/button";
12
11
  import { Dialog } from "primereact/dialog";
13
12
  import { FullItem } from "../../editor/pageModel";
13
+ import { WizardBox } from "../WizardBox";
14
+ import { WizardBoxConnector } from "../WizardBoxConnector";
15
+ import { Settings, Images, ChevronDown, Check } from "lucide-react";
16
+
14
17
  type Thumbnail = {
15
18
  id: string;
16
19
  name: string;
@@ -36,6 +39,9 @@ export const ImagesStep = (props: StepComponentProps) => {
36
39
  const propName = props.step.propertyName || "images";
37
40
 
38
41
  const [showFolderDialog, setShowFolderDialog] = useState<boolean>(false);
42
+ const [collapsedSections, setCollapsedSections] = useState<Set<number>>(
43
+ new Set(),
44
+ );
39
45
 
40
46
  const [selectedFolder, setSelectedFolder] = useState<FullItem>();
41
47
 
@@ -158,160 +164,174 @@ export const ImagesStep = (props: StepComponentProps) => {
158
164
  loadFolder();
159
165
  }, [selectedFolderId]);
160
166
 
161
- const panels: SplitterPanel[] = [
162
- {
163
- name: "Settings",
164
- defaultSize: 400,
165
- content: (
166
- <div className="flex h-full flex-col gap-2 pr-6 pb-4">
167
- <div className="relative mb-2 rounded-md border border-gray-400 bg-white p-4">
168
- <div className="mb-2 text-sm font-bold text-gray-800">
169
- Image library folder
170
- </div>
171
- {selectedFolder && (
172
- <div className="mb-2 text-sm text-gray-500">
173
- {selectedFolder.path}
167
+ return (
168
+ <div className="flex h-full">
169
+ <WizardBox
170
+ title="Settings"
171
+ icon={<Settings />}
172
+ description="Configure image search settings and find matching images"
173
+ className="w-96"
174
+ >
175
+ <div className="flex h-full flex-col gap-4">
176
+ <div className="flex-1 overflow-y-auto">
177
+ <div className="relative mb-4 rounded-md border border-gray-400 bg-white p-4">
178
+ <div className="mb-2 text-sm font-bold text-gray-800">
179
+ Image library folder
174
180
  </div>
175
- )}
176
- <Button
177
- label="Change Folder"
178
- onClick={() => {
179
- setShowFolderDialog(true);
180
- }}
181
- />
182
- <Dialog
183
- header="Select Folder"
184
- visible={showFolderDialog}
185
- onHide={() => {
186
- setShowFolderDialog(false);
187
- }}
188
- style={{ width: "50vw", height: "50vh" }}
189
- >
190
- <div className="flex h-full flex-col p-1">
191
- <div className="relative flex-1">
192
- <ScrollingContentTree
193
- rootItemId={mediaRootId}
194
- onSelectionChange={(selection) => {
195
- const selectedNode = selection[0] as ItemTreeNodeData;
196
- if (selectedNode) setSelectedFolderId(selectedNode.id);
197
- else setSelectedFolderId(mediaRootId);
198
- setShowFolderDialog(false);
199
- }}
200
- />
181
+ {selectedFolder && (
182
+ <div className="mb-2 text-sm text-gray-500">
183
+ {selectedFolder.path}
201
184
  </div>
202
- </div>
203
- </Dialog>
185
+ )}
186
+ <Button
187
+ label="Change Folder"
188
+ onClick={() => {
189
+ setShowFolderDialog(true);
190
+ }}
191
+ />
192
+ <Dialog
193
+ header="Select Folder"
194
+ visible={showFolderDialog}
195
+ onHide={() => {
196
+ setShowFolderDialog(false);
197
+ }}
198
+ style={{ width: "50vw", height: "50vh" }}
199
+ >
200
+ <div className="flex h-full flex-col p-1">
201
+ <div className="relative flex-1">
202
+ <ScrollingContentTree
203
+ rootItemId={mediaRootId}
204
+ onSelectionChange={(selection) => {
205
+ const selectedNode = selection[0] as ItemTreeNodeData;
206
+ if (selectedNode) setSelectedFolderId(selectedNode.id);
207
+ else setSelectedFolderId(mediaRootId);
208
+ setShowFolderDialog(false);
209
+ }}
210
+ />
211
+ </div>
212
+ </div>
213
+ </Dialog>
214
+ </div>
215
+ </div>
216
+ <div className="flex-shrink-0">
217
+ <ActionButton
218
+ onClick={findMatchingImages}
219
+ isLoading={isLoading}
220
+ disabled={isLoading}
221
+ loadingText="Searching..."
222
+ className="w-full"
223
+ >
224
+ Find Matching Images
225
+ </ActionButton>
204
226
  </div>
205
- <ActionButton
206
- onClick={findMatchingImages}
207
- isLoading={isLoading}
208
- disabled={isLoading}
209
- loadingText="Searching..."
210
- >
211
- Find Matching Images
212
- </ActionButton>
213
227
  </div>
214
- ),
215
- },
216
- {
217
- name: "Images",
218
- defaultSize: "auto",
219
- content: (
228
+ </WizardBox>
229
+ <WizardBoxConnector className="mt-6" />
230
+ <WizardBox
231
+ title="Images"
232
+ icon={<Images />}
233
+ description="Select images from the search results"
234
+ noPadding={true}
235
+ className="relative flex-1"
236
+ >
220
237
  <div className="absolute inset-0 overflow-auto">
221
- <div className="flex flex-col gap-4 p-4 pt-0">
222
- <div className="flex items-center gap-4">
223
- {error && <div className="text-red-500">{error}</div>}
238
+ <div className="p-6">
239
+ {error && <div className="mb-4 text-red-500">{error}</div>}
224
240
 
225
- {props.data[propName]?.length > 0 && (
226
- <div className="flex flex-col gap-4">
227
- {props.data[propName]?.map((image: Image, index: number) => (
228
- <span
229
- key={index}
230
- className={classNames(
231
- "rounded border border-gray-400 bg-white p-4 text-sm",
232
- index % 2 === 0
233
- ? "animate-fadeRight"
234
- : "animate-fadeLeft",
235
- )}
236
- >
237
- <div className="mb-3 text-lg">{image.title}</div>
238
- <div className="flex flex-wrap gap-5">
239
- {image.options?.map(
240
- (option: Thumbnail, thumbnailIndex: number) => (
241
- <div
242
- key={thumbnailIndex}
243
- className="relative flex h-28 w-28 cursor-pointer items-center justify-center border border-gray-400"
244
- onClick={() => {
245
- props.setData((prevData) => ({
246
- ...prevData,
247
- [propName]: prevData[propName].map(
248
- (img: Image, imgIndex: number) =>
249
- ({
250
- ...img,
251
- options:
252
- imgIndex !== index
253
- ? img.options
254
- : img.options?.map(
255
- (
256
- option,
257
- optionIndex: number,
258
- ) =>
259
- optionIndex === thumbnailIndex
260
- ? {
261
- ...option,
262
- selected:
263
- !option.selected,
264
- }
265
- : option,
266
- ),
267
- }) as Image,
268
- ),
269
- }));
270
- }}
271
- >
272
- <img
273
- key={thumbnailIndex}
274
- src={option.thumbUrl}
275
- alt={option.name}
276
- />
241
+ {props.data[propName]?.length > 0 && (
242
+ <div className="space-y-6">
243
+ {props.data[propName]?.map((image: Image, index: number) => {
244
+ const isCollapsed = collapsedSections.has(index);
245
+
246
+ return (
247
+ <div key={index} className="space-y-4">
248
+ <button
249
+ onClick={() => {
250
+ const newCollapsed = new Set(collapsedSections);
251
+ if (isCollapsed) {
252
+ newCollapsed.delete(index);
253
+ } else {
254
+ newCollapsed.add(index);
255
+ }
256
+ setCollapsedSections(newCollapsed);
257
+ }}
258
+ className="flex w-full items-center justify-between text-left"
259
+ >
260
+ <h3 className="text-lg font-medium text-gray-900">
261
+ {image.title}
262
+ </h3>
263
+ <ChevronDown
264
+ className={classNames(
265
+ "h-5 w-5 text-gray-500 transition-transform",
266
+ isCollapsed ? "-rotate-90" : "rotate-0",
267
+ )}
268
+ />
269
+ </button>
270
+
271
+ {!isCollapsed && (
272
+ <div className="grid grid-cols-6 gap-4">
273
+ {image.options?.map(
274
+ (option: Thumbnail, thumbnailIndex: number) => (
277
275
  <div
276
+ key={thumbnailIndex}
278
277
  className={classNames(
279
- "peer ring-offset-background focus-visible:ring-ring pointer-events-none absolute right-1 bottom-1 flex h-5 w-5 shrink-0 items-center justify-center rounded-full border-2 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
278
+ "relative aspect-square cursor-pointer overflow-hidden rounded-lg border-2 transition-all",
280
279
  option.selected
281
- ? "text-canvas-pink border-canvas-pink bg-white"
282
- : "",
280
+ ? "border-purple-500 ring-2 ring-purple-200"
281
+ : "border-gray-200 hover:border-gray-300",
283
282
  )}
283
+ onClick={() => {
284
+ props.setData((prevData) => ({
285
+ ...prevData,
286
+ [propName]: prevData[propName].map(
287
+ (img: Image, imgIndex: number) =>
288
+ ({
289
+ ...img,
290
+ options:
291
+ imgIndex !== index
292
+ ? img.options
293
+ : img.options?.map(
294
+ (
295
+ option,
296
+ optionIndex: number,
297
+ ) =>
298
+ optionIndex ===
299
+ thumbnailIndex
300
+ ? {
301
+ ...option,
302
+ selected:
303
+ !option.selected,
304
+ }
305
+ : option,
306
+ ),
307
+ }) as Image,
308
+ ),
309
+ }));
310
+ }}
284
311
  >
312
+ <img
313
+ src={option.thumbUrl}
314
+ alt={option.name}
315
+ className="h-full w-full object-cover"
316
+ />
285
317
  {option.selected && (
286
- <svg
287
- xmlns="http://www.w3.org/2000/svg"
288
- width="24"
289
- height="24"
290
- viewBox="0 0 24 24"
291
- fill="none"
292
- stroke="currentColor"
293
- strokeWidth="2"
294
- strokeLinecap="round"
295
- strokeLinejoin="round"
296
- >
297
- <path d="M20 6 9 17l-5-5"></path>
298
- </svg>
318
+ <div className="absolute top-2 right-2 flex h-6 w-6 items-center justify-center rounded-full bg-purple-500 text-white">
319
+ <Check className="h-4 w-4" />
320
+ </div>
299
321
  )}
300
322
  </div>
301
- </div>
302
- ),
303
- )}
304
- </div>
305
- </span>
306
- ))}
307
- </div>
308
- )}
309
- </div>
323
+ ),
324
+ )}
325
+ </div>
326
+ )}
327
+ </div>
328
+ );
329
+ })}
330
+ </div>
331
+ )}
310
332
  </div>
311
333
  </div>
312
- ),
313
- },
314
- ];
315
-
316
- return <Splitter panels={panels} />;
334
+ </WizardBox>
335
+ </div>
336
+ );
317
337
  };
@@ -4,11 +4,14 @@ import { useEditContext } from "../../editor/client/editContext";
4
4
  import { executePrompt } from "../../editor/services/aiService";
5
5
  import { createWizardAiContext } from "../service";
6
6
  import { classNames } from "primereact/utils";
7
- import { Splitter, SplitterPanel } from "../../editor/ui/Splitter";
8
7
  import { InputTextarea } from "primereact/inputtextarea";
9
8
  import { StepComponentProps } from "../../config/types";
10
9
  import { ActionButton } from "../../components/ActionButton";
11
10
  import Generate from "./Generate";
11
+ import { WizardBox } from "../WizardBox";
12
+ import { WizardBoxConnector } from "../WizardBoxConnector";
13
+ import { Settings, CheckSquare } from "lucide-react";
14
+
12
15
  type Option = {
13
16
  title: string;
14
17
  description: string;
@@ -174,82 +177,95 @@ export function SelectStep({
174
177
  );
175
178
  }
176
179
 
177
- const optionsPanel: SplitterPanel = {
178
- name: "options",
179
- defaultSize: "auto",
180
- content: (
181
- <div className="h-full p-4">
182
- {loading && (
183
- <div className="flex h-full items-center justify-center">
184
- <Generate title="Generating options..." />
180
+ return (
181
+ <div className="flex h-full">
182
+ <WizardBox
183
+ title="Configuration"
184
+ icon={<Settings />}
185
+ description="Configure instructions and regenerate options"
186
+ className="w-96"
187
+ >
188
+ <div className="flex h-full flex-col items-stretch">
189
+ <div className="relative flex-1">
190
+ <div className="absolute inset-0 overflow-y-auto pr-6">
191
+ <h3 className="text-sm font-bold">Instructions</h3>
192
+ <InputTextarea
193
+ className="h-48 w-full text-sm"
194
+ value={instructions}
195
+ onChange={(e) => setInstructions(e.target.value)}
196
+ placeholder="Enter instructions for the options"
197
+ />
198
+ </div>
185
199
  </div>
186
- )}
187
- {!loading && (
188
- <div>
189
- {options.length === 0 ? (
190
- <div className="p-4 text-gray-500">
191
- No options available. Try refreshing the page.
192
- </div>
193
- ) : (
194
- options.map((option, index) => {
195
- const isSelected = selectedOptions.includes(option.id);
196
-
197
- return (
198
- <div
199
- key={option.id}
200
- className={classNames(
201
- "mb-3 flex items-center rounded border-2 bg-white p-3",
202
- index % 2 === 0
203
- ? "animate-fadeRight"
204
- : "animate-fadeLeft",
205
- isSelected
206
- ? "text-canvas-pink border-canvas-pink"
207
- : "border-gray-300 text-gray-600",
208
- )}
209
- onClick={() => handleOptionSelect(option)}
210
- >
211
- <div className="flex flex-1 cursor-pointer flex-col">
212
- <div className="font-medium">{option.title}</div>
213
- <div className="text-xs text-gray-600">
214
- {option.description}
215
- </div>
216
- </div>
217
- {isSelected && (
218
- <div className="text-canvas-pink ml-2">✓</div>
219
- )}
220
- </div>
221
- );
222
- })
223
- )}
200
+ <div className="py-2">
201
+ <ActionButton
202
+ onClick={generateOptions}
203
+ isLoading={loading}
204
+ disabled={loading}
205
+ loadingText="Thinking..."
206
+ className="w-full"
207
+ >
208
+ Regenerate Options
209
+ </ActionButton>
224
210
  </div>
225
- )}
226
- </div>
227
- ),
228
- };
211
+ </div>
212
+ </WizardBox>
213
+ <WizardBoxConnector className="mt-6" />
214
+ <WizardBox
215
+ title="Select Options"
216
+ icon={<CheckSquare />}
217
+ description="Choose from the generated options below"
218
+ className="flex-1"
219
+ >
220
+ <div className="h-full">
221
+ {loading && (
222
+ <div className="flex h-full items-center justify-center">
223
+ <Generate title="Generating options..." />
224
+ </div>
225
+ )}
226
+ {!loading && (
227
+ <div>
228
+ {options.length === 0 ? (
229
+ <div className="p-4 text-gray-500">
230
+ No options available. Try refreshing the page.
231
+ </div>
232
+ ) : (
233
+ options.map((option, index) => {
234
+ const isSelected = selectedOptions.includes(option.id);
229
235
 
230
- const settingsPanel: SplitterPanel = {
231
- name: "settings",
232
- defaultSize: 400,
233
- content: (
234
- <div className="flex flex-col gap-2 pr-6">
235
- <h3 className="text-sm font-bold">Instructions</h3>
236
- <InputTextarea
237
- className="h-48 text-sm"
238
- value={instructions}
239
- onChange={(e) => setInstructions(e.target.value)}
240
- placeholder="Enter instructions for the options"
241
- />
242
- <ActionButton
243
- onClick={generateOptions}
244
- isLoading={loading}
245
- disabled={loading}
246
- loadingText="Thinking..."
247
- >
248
- Regenerate Options
249
- </ActionButton>
250
- </div>
251
- ),
252
- };
253
-
254
- return <Splitter panels={[settingsPanel, optionsPanel]} />;
236
+ return (
237
+ <div
238
+ key={option.id}
239
+ className={classNames(
240
+ "mb-3 flex items-center rounded border-2 bg-white p-3",
241
+ index % 2 === 0
242
+ ? "animate-fadeRight"
243
+ : "animate-fadeLeft",
244
+ isSelected
245
+ ? "text-theme-secondary border-theme-secondary"
246
+ : "border-gray-300 text-gray-600",
247
+ )}
248
+ onClick={() => handleOptionSelect(option)}
249
+ >
250
+ <div className="flex flex-1 cursor-pointer flex-col">
251
+ <div className="font-medium">{option.title}</div>
252
+ <div className="text-xs text-gray-600">
253
+ {option.description}
254
+ </div>
255
+ </div>
256
+ {isSelected && (
257
+ <div className="bg-theme-secondary ml-2 flex h-6 w-6 items-center justify-center rounded-full text-white">
258
+
259
+ </div>
260
+ )}
261
+ </div>
262
+ );
263
+ })
264
+ )}
265
+ </div>
266
+ )}
267
+ </div>
268
+ </WizardBox>
269
+ </div>
270
+ );
255
271
  }
@@ -10,8 +10,9 @@ import { useEditContextRef } from "../../editor/client/editContext";
10
10
  import { useEditContext } from "../../editor/client/editContext";
11
11
  import { getComponentById } from "../../editor/componentTreeHelper";
12
12
  import { getPlaceholder } from "./schema";
13
- import { normalizeGuid } from "../../editor/utils";
13
+ import { getItemDescriptor, normalizeGuid } from "../../editor/utils";
14
14
  import { ItemDescriptor } from "../../editor/pageModel";
15
+ import { generateImage } from "../../editor/services/aiService";
15
16
 
16
17
  export function usePageCreator(
17
18
  pageItem: ItemDescriptor | undefined,
@@ -169,8 +170,6 @@ export function usePageCreator(
169
170
 
170
171
  const { fieldIdsMap, componentMap } = mappings;
171
172
 
172
- console.log("Creating components recursively", components);
173
-
174
173
  // Process each component in the array
175
174
  for (let i = 0; i < components.length; i++) {
176
175
  //console.log("Processing component", i);
@@ -238,18 +237,45 @@ export function usePageCreator(
238
237
  let value = field.value as any;
239
238
 
240
239
  if (field.type === "Picture") {
241
- value = {
242
- Variants: [{ Name: "Landscape", MediaId: field.value }],
243
- };
244
- rawValue = JSON.stringify(value);
245
- }
240
+ console.log("#### Editing picture field", field);
241
+ if (rawValue.startsWith("generate:")) {
242
+ rawValue = rawValue.slice(9);
243
+ const image = await generateImage({
244
+ ...fieldDescriptor,
245
+ prompt: rawValue,
246
+ sessionId: editContext.sessionId,
247
+ pageItem: getItemDescriptor(pageItem),
248
+ });
249
+ } else {
250
+ if (rawValue.startsWith("id:")) {
251
+ rawValue = rawValue.slice(3);
252
+ const imageId = rawValue.split(":")[1];
253
+ if (imageId) {
254
+ value = {
255
+ Variants: [{ Name: "Landscape", MediaId: imageId }],
256
+ };
257
+ }
258
+ await editContext.operations.editField({
259
+ field: fieldDescriptor,
260
+ value: value,
261
+ rawValue: value,
262
+ refresh: "none",
263
+ });
264
+ }
265
+ }
246
266
 
247
- await editContext.operations.editField({
248
- field: fieldDescriptor,
249
- value: value,
250
- rawValue: rawValue,
251
- refresh: "none",
252
- });
267
+ // value = {
268
+ // Variants: [{ Name: "Landscape", MediaId: field.value }],
269
+ // };
270
+ // rawValue = JSON.stringify(value);
271
+ } else {
272
+ await editContext.operations.editField({
273
+ field: fieldDescriptor,
274
+ value: value,
275
+ rawValue: rawValue,
276
+ refresh: "none",
277
+ });
278
+ }
253
279
 
254
280
  setPageModel((prev) => {
255
281
  const component = findComponent(prev.components, componentPath);
package/src/revision.ts CHANGED
@@ -1,2 +1,2 @@
1
- export const version = "1.0.3896";
2
- export const buildDate = "2025-05-23 09:37:52";
1
+ export const version = "1.0.3898";
2
+ export const buildDate = "2025-05-25 15:23:00";