@alpaca-editor/core 1.0.3902 → 1.0.3904

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 (98) hide show
  1. package/dist/components/ui/CardConnector.d.ts +2 -1
  2. package/dist/components/ui/CardConnector.js +3 -3
  3. package/dist/components/ui/CardConnector.js.map +1 -1
  4. package/dist/components/ui/button.js +1 -1
  5. package/dist/components/ui/button.js.map +1 -1
  6. package/dist/components/ui/card.d.ts +7 -1
  7. package/dist/components/ui/card.js +71 -3
  8. package/dist/components/ui/card.js.map +1 -1
  9. package/dist/config/config.js +4 -2
  10. package/dist/config/config.js.map +1 -1
  11. package/dist/config/types.d.ts +1 -0
  12. package/dist/editor/MobileLayout.js +1 -1
  13. package/dist/editor/MobileLayout.js.map +1 -1
  14. package/dist/editor/PictureEditor.js +13 -5
  15. package/dist/editor/PictureEditor.js.map +1 -1
  16. package/dist/editor/client/EditorClient.js +2 -2
  17. package/dist/editor/client/EditorClient.js.map +1 -1
  18. package/dist/editor/client/editContext.d.ts +14 -1
  19. package/dist/editor/client/editContext.js.map +1 -1
  20. package/dist/editor/client/operations.js +1 -1
  21. package/dist/editor/client/operations.js.map +1 -1
  22. package/dist/editor/page-editor-chrome/CommentHighlighting.js +4 -1
  23. package/dist/editor/page-editor-chrome/CommentHighlighting.js.map +1 -1
  24. package/dist/editor/ui/Splitter.js +3 -1
  25. package/dist/editor/ui/Splitter.js.map +1 -1
  26. package/dist/page-wizard/WizardBoxConnector.d.ts +2 -1
  27. package/dist/page-wizard/WizardBoxConnector.js +3 -3
  28. package/dist/page-wizard/WizardBoxConnector.js.map +1 -1
  29. package/dist/page-wizard/WizardSteps.js +63 -17
  30. package/dist/page-wizard/WizardSteps.js.map +1 -1
  31. package/dist/page-wizard/service.d.ts +1 -1
  32. package/dist/page-wizard/service.js +1 -1
  33. package/dist/page-wizard/service.js.map +1 -1
  34. package/dist/page-wizard/steps/CollectStep.js +11 -17
  35. package/dist/page-wizard/steps/CollectStep.js.map +1 -1
  36. package/dist/page-wizard/steps/ComponentTypesSelector.d.ts +1 -0
  37. package/dist/page-wizard/steps/ComponentTypesSelector.js +53 -78
  38. package/dist/page-wizard/steps/ComponentTypesSelector.js.map +1 -1
  39. package/dist/page-wizard/steps/ContentStep.d.ts +2 -0
  40. package/dist/page-wizard/steps/ContentStep.js +403 -0
  41. package/dist/page-wizard/steps/ContentStep.js.map +1 -0
  42. package/dist/page-wizard/steps/Generate.js +1 -1
  43. package/dist/page-wizard/steps/Generate.js.map +1 -1
  44. package/dist/page-wizard/steps/ImagesStep.js +16 -13
  45. package/dist/page-wizard/steps/ImagesStep.js.map +1 -1
  46. package/dist/page-wizard/steps/SelectStep.js +1 -1
  47. package/dist/page-wizard/steps/SelectStep.js.map +1 -1
  48. package/dist/page-wizard/steps/SetupPageStep.d.ts +2 -0
  49. package/dist/page-wizard/steps/SetupPageStep.js +152 -0
  50. package/dist/page-wizard/steps/SetupPageStep.js.map +1 -0
  51. package/dist/page-wizard/steps/usePageCreator.js +4 -4
  52. package/dist/page-wizard/steps/usePageCreator.js.map +1 -1
  53. package/dist/page-wizard/usePageWizard.d.ts +17 -3
  54. package/dist/page-wizard/usePageWizard.js +62 -2
  55. package/dist/page-wizard/usePageWizard.js.map +1 -1
  56. package/dist/revision.d.ts +2 -2
  57. package/dist/revision.js +2 -2
  58. package/dist/splash-screen/NewPage.js +10 -10
  59. package/dist/splash-screen/NewPage.js.map +1 -1
  60. package/dist/splash-screen/SplashScreen.js +3 -3
  61. package/dist/splash-screen/SplashScreen.js.map +1 -1
  62. package/dist/styles.css +184 -68
  63. package/package.json +1 -1
  64. package/src/components/ui/CardConnector.tsx +50 -15
  65. package/src/components/ui/button.tsx +1 -1
  66. package/src/components/ui/card.tsx +331 -15
  67. package/src/config/config.tsx +4 -2
  68. package/src/config/types.ts +3 -0
  69. package/src/editor/MobileLayout.tsx +7 -9
  70. package/src/editor/PictureEditor.tsx +16 -10
  71. package/src/editor/client/EditorClient.tsx +3 -5
  72. package/src/editor/client/editContext.ts +23 -1
  73. package/src/editor/client/operations.ts +1 -1
  74. package/src/editor/page-editor-chrome/CommentHighlighting.tsx +6 -1
  75. package/src/editor/ui/Splitter.tsx +10 -1
  76. package/src/page-wizard/WizardBoxConnector.tsx +50 -15
  77. package/src/page-wizard/WizardSteps.tsx +163 -34
  78. package/src/page-wizard/service.ts +2 -2
  79. package/src/page-wizard/steps/CollectStep.tsx +95 -141
  80. package/src/page-wizard/steps/ComponentTypesSelector.tsx +225 -245
  81. package/src/page-wizard/steps/ContentStep.tsx +648 -0
  82. package/src/page-wizard/steps/Generate.tsx +3 -3
  83. package/src/page-wizard/steps/ImagesStep.tsx +20 -15
  84. package/src/page-wizard/steps/SelectStep.tsx +4 -4
  85. package/src/page-wizard/steps/SetupPageStep.tsx +329 -0
  86. package/src/page-wizard/steps/usePageCreator.ts +4 -4
  87. package/src/page-wizard/usePageWizard.ts +69 -4
  88. package/src/revision.ts +2 -2
  89. package/src/splash-screen/NewPage.tsx +22 -16
  90. package/src/splash-screen/SplashScreen.tsx +3 -1
  91. package/dist/page-wizard/steps/CreatePage.d.ts +0 -12
  92. package/dist/page-wizard/steps/CreatePage.js +0 -149
  93. package/dist/page-wizard/steps/CreatePage.js.map +0 -1
  94. package/dist/page-wizard/steps/CreatePageAndLayoutStep.d.ts +0 -2
  95. package/dist/page-wizard/steps/CreatePageAndLayoutStep.js +0 -235
  96. package/dist/page-wizard/steps/CreatePageAndLayoutStep.js.map +0 -1
  97. package/src/page-wizard/steps/CreatePage.tsx +0 -329
  98. package/src/page-wizard/steps/CreatePageAndLayoutStep.tsx +0 -430
@@ -1,430 +0,0 @@
1
- import { StepComponentProps } from "../../config/types";
2
-
3
- import { CreatePage } from "./CreatePage";
4
- import { useEffect, useState } from "react";
5
- import { PageViewer } from "../../editor/page-viewer/PageViewer";
6
- import {
7
- useEditContext,
8
- useModifiedFieldsContext,
9
- } from "../../editor/client/editContext";
10
-
11
- import { ComponentTypeSelector } from "./ComponentTypesSelector";
12
- import { ActionButton } from "../../components/ActionButton";
13
- import { convertPageSchemaToWizardComponents } from "./schema";
14
- import { WizardPageModel } from "../PageWizard";
15
- import { createWizardAiContext, wipeComponents } from "../service";
16
-
17
- import { executePrompt } from "../../editor/services/aiService";
18
- import { usePageCreator } from "./usePageCreator";
19
- import { useThrottledCallback } from "use-debounce";
20
- import { InputTextarea } from "primereact/inputtextarea";
21
-
22
- import { convertToAiPageModel } from "../../editor/ai/aiPageModel";
23
- import { WizardBox } from "../WizardBox";
24
- import { Layers, PanelsTopLeft } from "lucide-react";
25
- import { cn } from "../../lib/utils";
26
- import { WizardBoxConnector } from "../WizardBoxConnector";
27
-
28
- export function CreatePageAndLayoutStep({
29
- wizard,
30
- step,
31
- parentItem,
32
- pageModel,
33
- setPageModel,
34
- data,
35
- setData,
36
- internalState,
37
- setInternalState,
38
- setStepCompleted,
39
- }: StepComponentProps) {
40
- const [pageLoaded, setPageLoaded] = useState(false);
41
- const [isLoading, setIsLoading] = useState(false);
42
-
43
- const editContext = useEditContext();
44
- const [abortController, setAbortController] = useState<AbortController>();
45
- const [message, setMessage] = useState<string>();
46
- const [isCreatingComponents, setIsCreatingComponents] = useState(false);
47
- const pageItem = internalState.pageItem;
48
- const modifiedFieldsContext = useModifiedFieldsContext();
49
-
50
- const pageCreator = usePageCreator(pageItem, wizard, setPageModel);
51
-
52
- if (!parentItem) return "No parent item";
53
-
54
- useEffect(() => {
55
- editContext?.setMode("edit");
56
- if (!internalState.layoutInstructions) {
57
- setInternalState({
58
- ...internalState,
59
- layoutInstructions: step.instructions,
60
- });
61
- }
62
- }, []);
63
-
64
- const createComponents = async () => {
65
- if (!pageLoaded) return;
66
- if (pageModel?.components && !isCreatingComponents) {
67
- try {
68
- setIsCreatingComponents(true);
69
-
70
- await pageCreator.createComponentsRecursively(
71
- pageModel.components,
72
- "root",
73
- );
74
- setInternalState((prev: any) => ({
75
- ...prev,
76
- componentsCreated: true,
77
- }));
78
- } finally {
79
- setIsCreatingComponents(false);
80
- }
81
- }
82
- };
83
-
84
- useEffect(() => {
85
- if (
86
- internalState.componentsCreated &&
87
- !isCreatingComponents &&
88
- !isLoading
89
- ) {
90
- editContext?.requestRefresh("immediate");
91
- }
92
- }, [isCreatingComponents, isLoading]);
93
-
94
- const createComponentsThrottled = useThrottledCallback(createComponents, 300);
95
-
96
- useEffect(() => {
97
- createComponentsThrottled();
98
- }, [pageModel]);
99
-
100
- useEffect(() => {
101
- if (
102
- editContext &&
103
- editContext.page &&
104
- editContext.page.item &&
105
- pageItem &&
106
- pageItem.id === editContext.page.item.descriptor.id
107
- )
108
- setPageLoaded(true);
109
- }, [editContext?.page, pageItem]);
110
-
111
- if (!pageItem) {
112
- return (
113
- <CreatePage
114
- wizard={wizard}
115
- parentItem={parentItem}
116
- setPageItem={(pageItem) =>
117
- setInternalState((prev: any) => ({ ...prev, pageItem }))
118
- }
119
- pageItem={pageItem}
120
- pageModel={pageModel}
121
- setPageModel={setPageModel}
122
- step={step}
123
- data={data}
124
- />
125
- );
126
- }
127
-
128
- const createLayout = async () => {
129
- try {
130
- if (!editContext) return;
131
-
132
- setIsLoading(true);
133
- setStepCompleted(false);
134
-
135
- if (internalState.componentsCreated) {
136
- editContext?.itemsRepository.clear();
137
- modifiedFieldsContext?.clear();
138
- await wipeComponents(pageItem.descriptor);
139
-
140
- setPageModel((prev) => ({
141
- ...prev,
142
- components: [],
143
- message: "",
144
- }));
145
-
146
- editContext?.requestRefresh("immediate");
147
- }
148
-
149
- // Parse schema if it's a string
150
- const schema =
151
- typeof wizard.schema === "string"
152
- ? JSON.parse(wizard.schema)
153
- : wizard.schema;
154
-
155
- // Filter the schema based on selected component types and placeholders
156
- const filteredSchema = convertPageSchemaToWizardComponents(
157
- schema,
158
- data.selectedComponentTypes,
159
- );
160
-
161
- const localAbortController = new AbortController();
162
- setAbortController(localAbortController);
163
-
164
- // Get the existing page model
165
- const existingPageModel = await convertToAiPageModel(
166
- editContext.page!,
167
- editContext,
168
- );
169
-
170
- const result = await executePrompt(
171
- [
172
- {
173
- content: `${internalState.layoutInstructions?.trim()} Reply with a json object of type PageModel = { components: Component[]; message: string; };
174
- Component = { id: string | undefined, name: string, type: string; fields: Field[]; placeholder?: string; children?: Component[]; };
175
- Field = { name: string; value: string; type: string; };
176
- Generate a descriptive name for each component including the topic.
177
- Only use component types that are in the page schema.
178
- Keep existing components with their ids. Leave id field empty for new components.
179
- Existing page model: ${JSON.stringify(existingPageModel)}
180
- Fill empty fields of existing components before you insert new components.
181
- Component types: ${JSON.stringify(
182
- filteredSchema,
183
- )} Root level component types ${filteredSchema
184
- .filter((c) => c.allowedOnRoot)
185
- .map((c) => c.type)
186
- .join(", ")}
187
- Tell the user your reasoning in the message field.
188
- If the user provided image ids, fill them into picture / image fields with an "id:" prefix. The image id needs to be guid.
189
- If you dont have a matching image id, provide a description of a picture that you would like to use with a "generate:" prefix instead.
190
- The language of the page is ${pageItem.descriptor.language}.
191
- Input data: ${JSON.stringify(data)}`,
192
-
193
- name: "system",
194
- role: "system",
195
- },
196
- ], //Fill image ids into picture / image fields.
197
- editContext,
198
- createWizardAiContext,
199
- { allowedFunctions: [] },
200
- { signal: localAbortController.signal },
201
- step.aiModel || "o3-mini-low",
202
- (response) => {
203
- try {
204
- const newLayout = JSON.parse(response.content) as WizardPageModel;
205
-
206
- if (newLayout) {
207
- setPageModel((prev) => mergeLayout(prev, newLayout));
208
- }
209
-
210
- setMessage(newLayout.message);
211
- } catch (parseError: unknown) {}
212
- },
213
- );
214
-
215
- const pageModel = result;
216
-
217
- console.log("RESULT MODEL: ", pageModel);
218
-
219
- setPageModel((prev) => mergeLayout(prev, pageModel));
220
- setMessage(pageModel.message);
221
- setStepCompleted(true);
222
- } catch (error) {
223
- console.error(error);
224
- } finally {
225
- setIsLoading(false);
226
- }
227
- };
228
-
229
- // Custom instructions panel
230
- const customInstructionsPanel = () => {
231
- return (
232
- <div className="mb-4">
233
- <h3 className="text-sm font-semibold">Instructions</h3>
234
- <div className="mb-3 text-xs text-gray-500">
235
- Provide guidance for the AI when generating your layout
236
- </div>
237
- <InputTextarea
238
- value={internalState.layoutInstructions}
239
- onChange={(e) =>
240
- setInternalState({
241
- ...internalState,
242
- layoutInstructions: e.target.value,
243
- })
244
- }
245
- placeholder="Example: Make it modern and minimalist. Focus on images. Include a hero section at the top."
246
- className="h-48 w-full rounded border border-gray-300 px-3 py-2 text-sm focus:ring-1 focus:ring-blue-500 focus:outline-none"
247
- />
248
- </div>
249
- );
250
- };
251
-
252
- return (
253
- <div className="flex h-full">
254
- <WizardBox
255
- title="Generate content"
256
- icon={<Layers />}
257
- description="Generate content for the page"
258
- className="w-96"
259
- >
260
- <div className="flex h-full flex-col items-stretch">
261
- <div className="relative flex-1">
262
- <div className="absolute inset-0 overflow-y-auto pr-6">
263
- <div className="text-sm font-medium">Page item</div>
264
- <div className="text-xs text-gray-500">{pageItem.path}</div>
265
- <ComponentTypeSelector
266
- selectedComponentTypes={data.selectedComponentTypes}
267
- setSelectedComponentTypes={(selectedTypes) => {
268
- setData({
269
- ...data,
270
- selectedComponentTypes: selectedTypes,
271
- });
272
- }}
273
- schema={wizard.schema}
274
- data={data}
275
- setData={setData}
276
- step={step}
277
- />
278
- {customInstructionsPanel()}
279
- </div>
280
- </div>
281
- <div className="py-2">
282
- <div className="flex w-full gap-2">
283
- <ActionButton
284
- onClick={createLayout}
285
- disabled={
286
- isLoading ||
287
- isCreatingComponents ||
288
- !data.selectedComponentTypes ||
289
- data.selectedComponentTypes.length === 0
290
- }
291
- isLoading={
292
- isLoading ||
293
- isCreatingComponents ||
294
- !!editContext?.activeFieldActions.find(
295
- (action) => action.state === "running",
296
- )
297
- }
298
- loadingText="Working"
299
- className="w-full flex-1"
300
- >
301
- {internalState.componentsCreated
302
- ? "Reset and regenerate content"
303
- : "Generate content"}
304
- </ActionButton>
305
-
306
- {isLoading && (
307
- <ActionButton
308
- isLoading={false}
309
- onClick={() => abortController?.abort("User aborted")}
310
- >
311
- Abort
312
- </ActionButton>
313
- )}
314
- </div>
315
- {message && <div className="mt-2 text-xs">{message}</div>}
316
- </div>
317
- </div>
318
- </WizardBox>
319
- <WizardBoxConnector className="mt-6" />
320
- <WizardBox
321
- title="Page preview"
322
- icon={<PanelsTopLeft />}
323
- description="After finalizing the page, you can edit, further enhance the content and share the page with your team for collaboration."
324
- noPadding={true}
325
- className="flex-1"
326
- >
327
- <div
328
- className={cn(
329
- "border-t border-gray-200",
330
- pageLoaded ? "h-full" : "h-0",
331
- )}
332
- >
333
- <PageViewer
334
- name="single"
335
- compareView={false}
336
- showFormEditor={false}
337
- followEditsDefault={true}
338
- pageViewContext={editContext!.pageView}
339
- />
340
- </div>
341
- </WizardBox>
342
- </div>
343
- );
344
- }
345
-
346
- /**
347
- * Merges a new layout with the previous layout
348
- * - Keeps all previous components
349
- * - Adds new components
350
- * - Updates existing fields with new values
351
- * - Adds new fields
352
- */
353
- const mergeLayout = (
354
- prev: WizardPageModel | null,
355
- newLayout: WizardPageModel,
356
- ): WizardPageModel => {
357
- if (!prev) return newLayout;
358
-
359
- // Merge top-level properties
360
- const result: WizardPageModel = {
361
- name: newLayout.name || prev.name,
362
- message: newLayout.message,
363
- metaDescription: prev.metaDescription,
364
- metaKeywords: prev.metaKeywords,
365
- components: [...(prev.components || [])],
366
- };
367
-
368
- // Function to merge components recursively
369
- const mergeComponents = (
370
- existingComponents: any[],
371
- newComponents: any[],
372
- ): any[] => {
373
- if (!newComponents?.length) return existingComponents;
374
-
375
- const result = [...existingComponents];
376
-
377
- for (const newComp of newComponents) {
378
- // Try to find a matching component by type and name
379
- const existingIndex = result.findIndex(
380
- (comp) => comp.type === newComp.type && comp.name === newComp.name,
381
- );
382
-
383
- if (existingIndex >= 0) {
384
- // Update existing component
385
- const existing = result[existingIndex];
386
-
387
- // Merge fields - update existing fields and add new ones
388
- const mergedFields = [...(existing.fields || [])];
389
- for (const newField of newComp.fields || []) {
390
- const fieldIndex = mergedFields.findIndex(
391
- (f) => f.name === newField.name,
392
- );
393
- if (fieldIndex >= 0) {
394
- mergedFields[fieldIndex].value = newField.value; // Update existing field
395
- mergedFields[fieldIndex].type = newField.type;
396
- } else {
397
- mergedFields.push(newField); // Add new field
398
- }
399
- }
400
-
401
- // Recursive merge of children components
402
- const mergedChildren = mergeComponents(
403
- existing.children || [],
404
- newComp.children || [],
405
- );
406
-
407
- // Create updated component
408
- result[existingIndex] = {
409
- ...existing,
410
- fields: mergedFields,
411
- children: mergedChildren,
412
- placeholder: newComp.placeholder || existing.placeholder,
413
- };
414
- } else {
415
- // Add new component
416
- result.push(newComp);
417
- }
418
- }
419
-
420
- return result;
421
- };
422
-
423
- // Merge components recursively
424
- result.components = mergeComponents(
425
- result.components,
426
- newLayout.components || [],
427
- );
428
-
429
- return result;
430
- };