@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
@@ -1,21 +1,222 @@
1
1
  import { useState } from "react";
2
2
  import { Wizard, WizardData, WizardPageModel } from "./PageWizard";
3
- import { Button } from "primereact/button";
4
- import { ItemDescriptor, Language } from "../editor/pageModel";
5
- import { PageWizardLogo } from "../editor/ui/Icons";
3
+
4
+ import { ItemDescriptor } from "../editor/pageModel";
5
+ import { Logo } from "../editor/ui/Icons";
6
6
 
7
7
  import { flushSync } from "react-dom";
8
8
  import { useEditContext } from "../editor/client/editContext";
9
9
  import { classNames } from "primereact/utils";
10
- import { Allotment } from "allotment";
10
+ import { ChevronLeft, ChevronRight } from "lucide-react";
11
11
 
12
- export function WizardSteps({
13
- wizard,
14
- parentItem,
15
- }: {
12
+ import { Button } from "../components/ui/button";
13
+ import { cn } from "../lib/utils";
14
+
15
+ interface WizardStepsProps {
16
16
  wizard: Wizard;
17
17
  parentItem: ItemDescriptor;
18
- }) {
18
+ }
19
+
20
+ interface NavigationStepsProps {
21
+ wizard: Wizard;
22
+ currentStepIndex: number;
23
+ onStepClick: (index: number) => void;
24
+ }
25
+
26
+ interface PreviousButtonProps {
27
+ currentStepIndex: number;
28
+ wizard: Wizard;
29
+ onPrevious: () => void;
30
+ }
31
+
32
+ interface NextButtonProps {
33
+ currentStepIndex: number;
34
+ wizard: Wizard;
35
+ stepCompleted: number;
36
+ onNext: () => void;
37
+ onFinish: () => void;
38
+ }
39
+
40
+ interface WizardHeaderProps {
41
+ wizard: Wizard;
42
+ currentStepIndex: number;
43
+ onStepClick: (index: number) => void;
44
+ onPrevious: () => void;
45
+ onNext: () => void;
46
+ onFinish: () => void;
47
+ stepCompleted: number;
48
+ }
49
+
50
+ interface WizardContentProps {
51
+ currentStep: any;
52
+ children: React.ReactNode;
53
+ }
54
+
55
+ function PreviousButton({
56
+ currentStepIndex,
57
+ wizard,
58
+ onPrevious,
59
+ }: PreviousButtonProps) {
60
+ if (currentStepIndex === 0) return null;
61
+
62
+ return (
63
+ <Button onClick={onPrevious} variant="outline">
64
+ <ChevronLeft /> {wizard.steps[currentStepIndex - 1]?.name}
65
+ </Button>
66
+ );
67
+ }
68
+
69
+ function NextButton({
70
+ currentStepIndex,
71
+ wizard,
72
+ stepCompleted,
73
+ onNext,
74
+ onFinish,
75
+ }: NextButtonProps) {
76
+ const isLastStep = currentStepIndex === wizard.steps.length - 1;
77
+ const isDisabled = stepCompleted < currentStepIndex;
78
+
79
+ if (isLastStep) {
80
+ return (
81
+ <Button disabled={isDisabled} onClick={onFinish}>
82
+ Finish <ChevronRight />
83
+ </Button>
84
+ );
85
+ }
86
+
87
+ return (
88
+ <Button disabled={isDisabled} onClick={onNext}>
89
+ {wizard.steps[currentStepIndex + 1]?.name}
90
+ <ChevronRight />
91
+ </Button>
92
+ );
93
+ }
94
+
95
+ function NavigationSteps({
96
+ wizard,
97
+ currentStepIndex,
98
+ onStepClick,
99
+ }: NavigationStepsProps) {
100
+ return (
101
+ <div className="flex-1 overflow-hidden">
102
+ <div className="scrollbar-hide flex flex-1 justify-center overflow-x-auto p-2.5 text-xs md:gap-3">
103
+ <div className="flex min-w-max items-center gap-3 md:gap-3">
104
+ {wizard.steps.map((step, index) => (
105
+ <>
106
+ <div
107
+ key={step.id}
108
+ className={classNames(
109
+ "flex min-w-max flex-col items-center gap-1",
110
+ currentStepIndex > index && "cursor-pointer",
111
+ )}
112
+ onClick={() =>
113
+ index < currentStepIndex ? onStepClick(index) : undefined
114
+ }
115
+ >
116
+ <span
117
+ className={cn(
118
+ "relative flex h-6 w-6 items-center justify-center rounded-full border-1 p-2 text-xs font-medium",
119
+ currentStepIndex === index &&
120
+ "border-theme-secondary text-theme-secondary bg-theme-secondary-light",
121
+ currentStepIndex < index && "border-gray-400 text-gray-400",
122
+ currentStepIndex > index &&
123
+ "bg-theme-secondary text-gray-200",
124
+ )}
125
+ >
126
+ {currentStepIndex > index ? "✓" : index + 1}
127
+ </span>
128
+ <div
129
+ className={classNames(
130
+ "w-auto text-center whitespace-nowrap opacity-100",
131
+ currentStepIndex === index
132
+ ? "text-theme-secondary font-semibold"
133
+ : currentStepIndex >= index
134
+ ? "text-gray-600"
135
+ : "text-gray-400",
136
+ )}
137
+ >
138
+ {step.name}
139
+ </div>
140
+ </div>
141
+
142
+ {index < wizard.steps.length - 1 && (
143
+ <div className="mt-[-20px] h-0 w-8 border-t border-gray-300 bg-gray-300 md:w-10" />
144
+ )}
145
+ </>
146
+ ))}
147
+ </div>
148
+ </div>
149
+ </div>
150
+ );
151
+ }
152
+
153
+ function WizardHeader({
154
+ wizard,
155
+ currentStepIndex,
156
+ onStepClick,
157
+ onPrevious,
158
+ onNext,
159
+ onFinish,
160
+ stepCompleted,
161
+ }: WizardHeaderProps) {
162
+ return (
163
+ <div className="flex items-center gap-3 border-b border-gray-300 bg-white md:pr-8">
164
+ <div className="text-md flex items-center justify-center self-stretch border-r border-gray-300 p-2 px-10 text-sm font-semibold text-neutral-800">
165
+ {wizard.name}
166
+ </div>
167
+
168
+ <PreviousButton
169
+ currentStepIndex={currentStepIndex}
170
+ wizard={wizard}
171
+ onPrevious={onPrevious}
172
+ />
173
+
174
+ <NavigationSteps
175
+ wizard={wizard}
176
+ currentStepIndex={currentStepIndex}
177
+ onStepClick={onStepClick}
178
+ />
179
+
180
+ <div>
181
+ <NextButton
182
+ currentStepIndex={currentStepIndex}
183
+ wizard={wizard}
184
+ stepCompleted={stepCompleted}
185
+ onNext={onNext}
186
+ onFinish={onFinish}
187
+ />
188
+ </div>
189
+ </div>
190
+ );
191
+ }
192
+
193
+ function WizardContent({ currentStep, children }: WizardContentProps) {
194
+ return (
195
+ <div className="relative flex-1 bg-neutral-100">
196
+ <div className="h-full p-8">
197
+ <div className="relative z-10 h-full">
198
+ <div className="flex h-full flex-col">
199
+ <div className="mb-10 flex gap-4">
200
+ <Logo className="h-8 w-8" />
201
+ <div className="flex-1 text-neutral-800">
202
+ <div className="text-xl font-semibold">{currentStep?.name}</div>
203
+ {currentStep?.description && (
204
+ <div className="mt-1 font-light">
205
+ {currentStep.description}
206
+ </div>
207
+ )}
208
+ </div>
209
+ </div>
210
+ <div className="relative flex-1">{children}</div>
211
+ </div>
212
+ </div>
213
+ <div className="bg-wizard absolute inset-0" />
214
+ </div>
215
+ </div>
216
+ );
217
+ }
218
+
219
+ export function WizardSteps({ wizard, parentItem }: WizardStepsProps) {
19
220
  const [currentStepIndex, setCurrentStepIndex] = useState(0);
20
221
  const [data, setData] = useState<WizardData>({});
21
222
  const [pageModel, setPageModel] = useState<WizardPageModel>({
@@ -81,118 +282,37 @@ export function WizardSteps({
81
282
  });
82
283
  };
83
284
 
285
+ const handlePrevious = () => {
286
+ switchStep(currentStepIndex - 1);
287
+ };
288
+
289
+ const handleNext = () => {
290
+ switchStep(currentStepIndex + 1);
291
+ };
292
+
293
+ const handleFinish = () => {
294
+ editContext?.switchView("editor", { skipConfirmation: true });
295
+ };
296
+
84
297
  const currentStep = wizard.steps[currentStepIndex];
85
298
 
86
299
  if (!currentStep) return null;
87
300
 
88
- const panels = [
89
- <Allotment.Pane key="left" minSize={200}>
90
- <div className="absolute inset-0 overflow-y-auto">
91
- <div className="flex h-full flex-col bg-gray-50 text-sm text-gray-700">
92
- <div className="flex gap-3 border-b border-gray-200 bg-gray-100 p-2">
93
- <PageWizardLogo />
94
- <div className="gap-1p-2 flex flex-col justify-center">
95
- <div className="text-md font-semibold">{wizard.name}</div>
96
- <div className="text-sm font-light">{wizard.description}</div>
97
- </div>
98
- </div>
99
- <div className="flex flex-1 flex-col gap-3 p-4">
100
- {wizard.steps.map((step, index) => (
101
- <div
102
- key={step.id}
103
- className={classNames(
104
- "flex items-center gap-4",
105
- currentStepIndex > index && "cursor-pointer",
106
- )}
107
- onClick={() =>
108
- index < currentStepIndex ? switchStep(index) : undefined
109
- }
110
- >
111
- <span
112
- className={classNames(
113
- "text-activeStepColor flex h-7 w-7 items-center justify-center rounded-full border-2 p-2 text-xs font-medium",
114
- currentStepIndex === index
115
- ? "border-canvas-red text-canvas-red"
116
- : "border-gray-400",
117
- )}
118
- >
119
- {index + 1}
120
- </span>
121
- <div
122
- className={classNames(
123
- "w-auto opacity-100",
124
- currentStepIndex === index
125
- ? "text-canvas-red font-semibold"
126
- : currentStepIndex >= index
127
- ? "text-sm text-gray-600"
128
- : "text-sm text-gray-400",
129
- )}
130
- >
131
- {step.name}
132
- </div>
133
- </div>
134
- ))}
135
- </div>
136
- </div>
137
- </div>
138
- </Allotment.Pane>,
139
- <Allotment.Pane key="right">
140
- <div className="absolute inset-0 overflow-y-auto">
141
- <div className="bg-secondary animate-fadeIn flex h-full flex-col px-4 pt-4 transition-all duration-500 lg:pr-20 xl:pr-32">
142
- <div className="border-b border-gray-200 pb-4">
143
- <div className="text-xl font-semibold">{currentStep?.name}</div>
144
- {currentStep?.description && (
145
- <div className="mt-2 text-base font-light">
146
- {currentStep.description}
147
- </div>
148
- )}
149
- </div>
150
- <div className="flex-1 pt-4 pb-4">{getCurrentStep()}</div>
151
- </div>
152
- </div>
153
- </Allotment.Pane>,
154
- ];
155
-
156
301
  return (
157
- <div className="flex h-full flex-col justify-stretch">
158
- <div className="relative flex-1 border-b border-gray-200 bg-gray-100">
159
- <Allotment defaultSizes={[20, 80]}>{panels}</Allotment>
160
- </div>
161
- <div className="flex justify-between border-t border-gray-200 p-3">
162
- <div>
163
- {currentStepIndex > 0 && (
164
- <Button
165
- icon="pi pi-arrow-left mr-2"
166
- onClick={() => switchStep(currentStepIndex - 1)}
167
- disabled={currentStepIndex === 0}
168
- >
169
- {wizard.steps[currentStepIndex - 1]?.name}
170
- </Button>
171
- )}
172
- </div>
173
- <div>
174
- {currentStepIndex < wizard.steps.length - 1 && (
175
- <Button
176
- icon="pi pi-arrow-right mr-2"
177
- disabled={stepCompleted < currentStepIndex}
178
- onClick={() => switchStep(currentStepIndex + 1)}
179
- >
180
- {wizard.steps[currentStepIndex + 1]?.name}
181
- </Button>
182
- )}
183
- {currentStepIndex === wizard.steps.length - 1 && (
184
- <Button
185
- icon="pi pi-check"
186
- disabled={stepCompleted < currentStepIndex}
187
- onClick={() => {
188
- editContext?.switchView("editor", { skipConfirmation: true });
189
- }}
190
- label="Finish"
191
- className="ml-2"
192
- />
193
- )}
194
- </div>
195
- </div>
302
+ <div className="flex h-full flex-col">
303
+ <WizardHeader
304
+ wizard={wizard}
305
+ currentStepIndex={currentStepIndex}
306
+ onStepClick={switchStep}
307
+ onPrevious={handlePrevious}
308
+ onNext={handleNext}
309
+ onFinish={handleFinish}
310
+ stepCompleted={stepCompleted}
311
+ />
312
+
313
+ <WizardContent currentStep={currentStep}>
314
+ {getCurrentStep()}
315
+ </WizardContent>
196
316
  </div>
197
317
  );
198
318
  }
@@ -5,8 +5,11 @@ import { Splitter, SplitterPanel } from "../../editor/ui/Splitter";
5
5
  import MDEditor from "@uiw/react-md-editor";
6
6
  import { StepComponentProps } from "../../config/types";
7
7
  import { ActionButton } from "../../components/ActionButton";
8
- import { UploadCloudIcon } from "../../editor/ui/Icons";
8
+ import { UploadIcon, DocumentIcon } from "../../editor/ui/Icons";
9
9
  import { Spinner } from "../../editor/ui/Spinner";
10
+ import { WizardBox } from "../WizardBox";
11
+ import { LinkIcon } from "lucide-react";
12
+ import { InputTextarea } from "primereact/inputtextarea";
10
13
 
11
14
  export function CollectStep({
12
15
  data,
@@ -129,45 +132,6 @@ export function CollectStep({
129
132
  <div className="text-sm font-semibold text-gray-700">
130
133
  Upload a file
131
134
  </div>
132
-
133
- <div
134
- className={`flex h-40 w-40 flex-col items-center justify-center border border-dashed border-gray-300 p-5 ${
135
- isUploading ? "bg-gray-200" : "bg-white"
136
- }`}
137
- onDrop={handleDrop}
138
- onDragOver={(e) => e.preventDefault()}
139
- >
140
- <div className="flex flex-col items-center justify-center gap-1 text-center text-sm font-medium">
141
- {!isUploading && <UploadCloudIcon />}
142
- {isUploading && <Spinner />}
143
- <input
144
- ref={fileInputRef}
145
- type="file"
146
- multiple
147
- accept=".pdf,.doc,.docx"
148
- style={{ display: "none" }}
149
- onChange={(e) => {
150
- const file = e.target.files?.[0];
151
- if (file) {
152
- uploadFile(file);
153
- }
154
- }}
155
- onDrop={handleDrop}
156
- disabled={isUploading}
157
- />
158
- Drag & Drop to upload or
159
- <span
160
- className={`text-sm font-medium ${
161
- isUploading
162
- ? "text-gray-500"
163
- : "text-canvas-pink cursor-pointer underline"
164
- } `}
165
- onClick={triggerFileInput}
166
- >
167
- browse
168
- </span>
169
- </div>
170
- </div>
171
135
  </div>
172
136
 
173
137
  {error && <div className="mt-2 text-sm text-red-500">{error}</div>}
@@ -204,33 +168,131 @@ export function CollectStep({
204
168
  ),
205
169
  };
206
170
 
207
- const resultPanel: SplitterPanel = {
208
- name: "result",
209
- defaultSize: "auto",
210
- collapsible: false,
211
- content: (
212
- <div className="absolute inset-0 h-full w-full px-4 pb-4">
213
- <MDEditor
214
- height="100%"
215
- className="max-h-full"
216
- value={data.htmlContent}
217
- preview="edit"
218
- enableScroll={true}
219
- onChange={(val) =>
220
- setData((prev: WizardData) => ({
221
- ...prev,
222
- htmlContent: val || "",
223
- }))
224
- }
225
- />
226
- </div>
227
- ),
228
- };
229
-
230
171
  return (
231
- <Splitter
232
- localStorageKey="editor.page-wizard.panels"
233
- panels={[uploadPanel, resultPanel]}
234
- />
172
+ <div className="absolute inset-0 overflow-auto">
173
+ <div className="grid grid-cols-2 gap-4">
174
+ <WizardBox
175
+ icon={<UploadIcon className="text-theme-secondary" />}
176
+ title="Upload a file (optional)"
177
+ description="Upload a file to the page"
178
+ className="flex-1"
179
+ >
180
+ <div
181
+ className={`flex flex-col items-center justify-center border border-dashed border-gray-300 p-8 ${
182
+ isUploading ? "bg-gray-200" : "bg-white"
183
+ }`}
184
+ onDrop={handleDrop}
185
+ onDragOver={(e) => e.preventDefault()}
186
+ >
187
+ <div className="flex flex-col items-center justify-center gap-1 text-center text-sm">
188
+ {!isUploading && (
189
+ <svg
190
+ width="49"
191
+ height="48"
192
+ viewBox="0 0 49 48"
193
+ fill="none"
194
+ xmlns="http://www.w3.org/2000/svg"
195
+ >
196
+ <rect
197
+ x="0.666992"
198
+ width="48"
199
+ height="48"
200
+ rx="24"
201
+ fill="#F6EEFF"
202
+ />
203
+ <path
204
+ d="M32.604 20.68C32.594 20.648 32.583 20.6167 32.571 20.586C32.5235 20.4775 32.4572 20.3783 32.375 20.293L26.375 14.293C26.2897 14.2108 26.1905 14.1445 26.082 14.097C26.052 14.083 26.02 14.075 25.988 14.064C25.9043 14.0356 25.8172 14.0185 25.729 14.013C25.707 14.011 25.688 14 25.667 14H18.667C17.564 14 16.667 14.897 16.667 16V32C16.667 33.103 17.564 34 18.667 34H30.667C31.77 34 32.667 33.103 32.667 32V21C32.667 20.979 32.656 20.96 32.654 20.938C32.6487 20.8502 32.6319 20.7634 32.604 20.68ZM29.253 20H26.667V17.414L29.253 20ZM18.667 32V16H24.667V21C24.667 21.2652 24.7723 21.5196 24.9599 21.7071C25.1474 21.8946 25.4018 22 25.667 22H30.667L30.669 32H18.667Z"
205
+ fill="#9650FB"
206
+ />
207
+ </svg>
208
+ )}
209
+ {isUploading && <Spinner />}
210
+ <input
211
+ ref={fileInputRef}
212
+ type="file"
213
+ multiple
214
+ accept=".pdf,.doc,.docx"
215
+ style={{ display: "none" }}
216
+ onChange={(e) => {
217
+ const file = e.target.files?.[0];
218
+ if (file) {
219
+ uploadFile(file);
220
+ }
221
+ }}
222
+ onDrop={handleDrop}
223
+ disabled={isUploading}
224
+ />
225
+ <div className="flex items-center gap-1">
226
+ <span
227
+ className={`text-sm font-medium ${
228
+ isUploading
229
+ ? "text-gray-500"
230
+ : "text-theme-secondary cursor-pointer underline"
231
+ } `}
232
+ onClick={triggerFileInput}
233
+ >
234
+ Click
235
+ </span>
236
+ or drag & drop to upload
237
+ </div>
238
+ </div>
239
+ </div>
240
+ </WizardBox>
241
+ <WizardBox
242
+ icon={<LinkIcon className="text-theme-secondary" />}
243
+ title="Scrape page from URL (optional)"
244
+ description="Upload a file to the page"
245
+ className="flex-1"
246
+ >
247
+ {error && <div className="mt-2 text-sm text-red-500">{error}</div>}
248
+
249
+ <div className="flex flex-col gap-2">
250
+ <div className="text-sm font-semibold text-gray-700">
251
+ <div className="text-xs font-normal text-gray-500">
252
+ Only scrape websites you have permission to access. You are
253
+ responsible for complying with the website's terms of service
254
+ and all applicable laws.
255
+ </div>
256
+ </div>
257
+ <InputText
258
+ type="text"
259
+ className="rounded-md border border-gray-300 px-3 py-2"
260
+ onChange={(e) => setScrapeUrl(e.target.value)}
261
+ />
262
+ {scrapeError && (
263
+ <div className="mt-2 text-sm text-red-500">{scrapeError}</div>
264
+ )}
265
+ <div className="flex gap-2">
266
+ <ActionButton
267
+ type="submit"
268
+ isLoading={isScraping}
269
+ onClick={handleScrape}
270
+ loadingText="Scraping..."
271
+ >
272
+ Scrape
273
+ </ActionButton>
274
+ </div>
275
+ </div>
276
+ </WizardBox>
277
+ <WizardBox
278
+ icon={<DocumentIcon className="text-theme-secondary" />}
279
+ title="Text"
280
+ description="Provide the text you want to use for the page"
281
+ className="col-span-2"
282
+ >
283
+ <InputTextarea
284
+ className="max-h-full w-full"
285
+ value={data.htmlContent}
286
+ rows={20}
287
+ onChange={(e) =>
288
+ setData((prev: WizardData) => ({
289
+ ...prev,
290
+ htmlContent: e.target.value || "",
291
+ }))
292
+ }
293
+ />
294
+ </WizardBox>
295
+ </div>
296
+ </div>
235
297
  );
236
298
  }
@@ -1,4 +1,4 @@
1
- import { Dispatch, SetStateAction, useEffect, useState } from "react";
1
+ import { Dispatch, SetStateAction, useEffect, useState, useRef } from "react";
2
2
  import { WizardStep } from "../PageWizard";
3
3
  import {
4
4
  PageSchema,
@@ -30,6 +30,7 @@ export function ComponentTypeSelector({
30
30
  useState(true);
31
31
  const [preselectedTypes, setPreselectedTypes] = useState<string[]>([]);
32
32
  const [searchFilter, setSearchFilter] = useState<string>("");
33
+ const contentRef = useRef<HTMLDivElement>(null);
33
34
 
34
35
  // Ensure selectedComponentTypes is always an array
35
36
  useEffect(() => {
@@ -270,22 +271,42 @@ export function ComponentTypeSelector({
270
271
  </div>
271
272
  <button
272
273
  onClick={() => setIsSettingsPanelCollapsed(!isSettingsPanelCollapsed)}
273
- className="flex h-6 w-6 items-center justify-center rounded bg-gray-200 p-1 text-gray-700 hover:bg-gray-300"
274
+ className="flex h-6 w-6 items-center justify-center rounded bg-gray-200 p-1 text-gray-700 transition-colors duration-200 hover:bg-gray-300"
274
275
  title={
275
276
  isSettingsPanelCollapsed ? "Expand settings" : "Collapse settings"
276
277
  }
277
278
  aria-expanded={!isSettingsPanelCollapsed}
278
279
  >
279
- {isSettingsPanelCollapsed ? (
280
- <span className="text-lg">↓</span>
281
- ) : (
282
- <span className="text-lg">↑</span>
283
- )}
280
+ <svg
281
+ className={`h-4 w-4 transition-transform duration-300 ease-in-out ${
282
+ isSettingsPanelCollapsed ? "rotate-0" : "rotate-180"
283
+ }`}
284
+ fill="none"
285
+ stroke="currentColor"
286
+ viewBox="0 0 24 24"
287
+ >
288
+ <path
289
+ strokeLinecap="round"
290
+ strokeLinejoin="round"
291
+ strokeWidth={2}
292
+ d="M19 9l-7 7-7-7"
293
+ />
294
+ </svg>
284
295
  </button>
285
296
  </div>
286
297
 
287
- {!isSettingsPanelCollapsed && (
288
- <>
298
+ <div
299
+ ref={contentRef}
300
+ className={`overflow-hidden transition-all duration-300 ease-in-out ${
301
+ isSettingsPanelCollapsed
302
+ ? "max-h-0 opacity-0"
303
+ : "max-h-[1000px] opacity-100"
304
+ }`}
305
+ style={{
306
+ transitionProperty: "max-height, opacity",
307
+ }}
308
+ >
309
+ <div className="pt-2">
289
310
  <div className="mb-2">
290
311
  <input
291
312
  type="text"
@@ -467,8 +488,8 @@ export function ComponentTypeSelector({
467
488
  </div>
468
489
  </div>
469
490
  </div>
470
- </>
471
- )}
491
+ </div>
492
+ </div>
472
493
  </div>
473
494
  );
474
495
  }