@alpaca-editor/core 1.0.3906 → 1.0.3908

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 (80) hide show
  1. package/dist/components/ActionButton.d.ts +1 -1
  2. package/dist/components/ui/card.js +2 -2
  3. package/dist/components/ui/card.js.map +1 -1
  4. package/dist/config/config.js +34 -2
  5. package/dist/config/config.js.map +1 -1
  6. package/dist/editor/ConfirmationDialog.js +1 -1
  7. package/dist/editor/ConfirmationDialog.js.map +1 -1
  8. package/dist/editor/Titlebar.js +2 -2
  9. package/dist/editor/Titlebar.js.map +1 -1
  10. package/dist/editor/client/EditorClient.js +4 -2
  11. package/dist/editor/client/EditorClient.js.map +1 -1
  12. package/dist/editor/menubar/ActionsMenu.js +1 -0
  13. package/dist/editor/menubar/ActionsMenu.js.map +1 -1
  14. package/dist/editor/sidebar/ViewSelector.js +3 -3
  15. package/dist/editor/sidebar/ViewSelector.js.map +1 -1
  16. package/dist/editor/ui/Icons.d.ts +1 -0
  17. package/dist/editor/ui/Icons.js +4 -1
  18. package/dist/editor/ui/Icons.js.map +1 -1
  19. package/dist/editor/ui/Spinner.js +1 -1
  20. package/dist/editor/ui/Spinner.js.map +1 -1
  21. package/dist/editor/ui/Splitter.js +2 -2
  22. package/dist/editor/ui/Splitter.js.map +1 -1
  23. package/dist/page-wizard/WizardSteps.js +1 -1
  24. package/dist/page-wizard/WizardSteps.js.map +1 -1
  25. package/dist/page-wizard/steps/CollectStep.d.ts +1 -1
  26. package/dist/page-wizard/steps/CollectStep.js +22 -11
  27. package/dist/page-wizard/steps/CollectStep.js.map +1 -1
  28. package/dist/page-wizard/steps/ComponentTypesSelector.js +3 -5
  29. package/dist/page-wizard/steps/ComponentTypesSelector.js.map +1 -1
  30. package/dist/page-wizard/steps/ContentStep.js +111 -10
  31. package/dist/page-wizard/steps/ContentStep.js.map +1 -1
  32. package/dist/page-wizard/steps/ImagesStep.js +12 -2
  33. package/dist/page-wizard/steps/ImagesStep.js.map +1 -1
  34. package/dist/page-wizard/steps/LayoutStep.js +1 -1
  35. package/dist/page-wizard/steps/LayoutStep.js.map +1 -1
  36. package/dist/page-wizard/steps/MetaDataStep.d.ts +2 -0
  37. package/dist/page-wizard/steps/MetaDataStep.js +90 -0
  38. package/dist/page-wizard/steps/MetaDataStep.js.map +1 -0
  39. package/dist/page-wizard/steps/SelectStep.js +1 -1
  40. package/dist/page-wizard/steps/SelectStep.js.map +1 -1
  41. package/dist/revision.d.ts +2 -2
  42. package/dist/revision.js +2 -2
  43. package/dist/splash-screen/NewPage.js +15 -13
  44. package/dist/splash-screen/NewPage.js.map +1 -1
  45. package/dist/splash-screen/OpenPage.d.ts +1 -0
  46. package/dist/splash-screen/OpenPage.js +58 -0
  47. package/dist/splash-screen/OpenPage.js.map +1 -0
  48. package/dist/splash-screen/SplashScreen.d.ts +1 -1
  49. package/dist/splash-screen/SplashScreen.js +51 -76
  50. package/dist/splash-screen/SplashScreen.js.map +1 -1
  51. package/dist/styles.css +36 -36
  52. package/package.json +1 -1
  53. package/src/components/ActionButton.tsx +1 -1
  54. package/src/components/ui/card.tsx +52 -47
  55. package/src/config/config.tsx +35 -4
  56. package/src/editor/ConfirmationDialog.tsx +1 -1
  57. package/src/editor/Titlebar.tsx +2 -2
  58. package/src/editor/client/EditorClient.tsx +5 -2
  59. package/src/editor/menubar/ActionsMenu.tsx +1 -0
  60. package/src/editor/menubar/SecondaryControls.tsx +1 -1
  61. package/src/editor/sidebar/ViewSelector.tsx +3 -3
  62. package/src/editor/ui/Icons.tsx +22 -1
  63. package/src/editor/ui/Spinner.tsx +3 -1
  64. package/src/editor/ui/Splitter.tsx +2 -2
  65. package/src/page-wizard/WizardSteps.tsx +1 -1
  66. package/src/page-wizard/steps/CollectStep.tsx +137 -115
  67. package/src/page-wizard/steps/ComponentTypesSelector.tsx +4 -25
  68. package/src/page-wizard/steps/ContentStep.tsx +232 -23
  69. package/src/page-wizard/steps/ImagesStep.tsx +43 -3
  70. package/src/page-wizard/steps/LayoutStep.tsx +1 -1
  71. package/src/page-wizard/steps/MetaDataStep.tsx +173 -0
  72. package/src/page-wizard/steps/SelectStep.tsx +1 -1
  73. package/src/revision.ts +2 -2
  74. package/src/splash-screen/NewPage.tsx +133 -104
  75. package/src/splash-screen/OpenPage.tsx +146 -0
  76. package/src/splash-screen/SplashScreen.tsx +93 -164
  77. package/dist/page-wizard/steps/SetupPageStep.d.ts +0 -2
  78. package/dist/page-wizard/steps/SetupPageStep.js +0 -152
  79. package/dist/page-wizard/steps/SetupPageStep.js.map +0 -1
  80. package/src/page-wizard/steps/SetupPageStep.tsx +0 -329
@@ -18,6 +18,7 @@ type Thumbnail = {
18
18
  id: string;
19
19
  name: string;
20
20
  thumbUrl?: string;
21
+ previewUrl?: string;
21
22
  description?: string;
22
23
  selected?: boolean;
23
24
  };
@@ -28,6 +29,43 @@ type Image = {
28
29
  options?: Thumbnail[];
29
30
  };
30
31
 
32
+ // Responsive image component that chooses the best image size
33
+ const ResponsiveImage = ({
34
+ thumbUrl,
35
+ previewUrl,
36
+ alt,
37
+ className,
38
+ }: {
39
+ thumbUrl?: string;
40
+ previewUrl?: string;
41
+ alt: string;
42
+ className?: string;
43
+ }) => {
44
+ // If we have both URLs, use srcset to let browser choose
45
+ if (thumbUrl && previewUrl) {
46
+ return (
47
+ <img
48
+ src={thumbUrl} // fallback for older browsers
49
+ srcSet={`${thumbUrl} 96w, ${previewUrl} 400w`}
50
+ sizes="(max-width: 640px) calc(50vw - 1rem), (max-width: 768px) calc(33vw - 1rem), calc(16.666vw - 1rem)"
51
+ alt={alt}
52
+ className={className}
53
+ loading="lazy"
54
+ />
55
+ );
56
+ }
57
+
58
+ // Fallback to available URL
59
+ return (
60
+ <img
61
+ src={previewUrl || thumbUrl}
62
+ alt={alt}
63
+ className={className}
64
+ loading="lazy"
65
+ />
66
+ );
67
+ };
68
+
31
69
  export const ImagesStep = (props: StepComponentProps) => {
32
70
  const mediaRootId = "3D6658D8-A0BF-4E75-B3E2-D050FABCF4E1";
33
71
  const [selectedFolderId, setSelectedFolderId] = useState<string>(mediaRootId);
@@ -78,7 +116,7 @@ export const ImagesStep = (props: StepComponentProps) => {
78
116
  createWizardAiContext,
79
117
  {},
80
118
  undefined,
81
- "o3-mini-low",
119
+ "gpt-4.1",
82
120
  );
83
121
  const images = JSON.parse(aiPromptResult.content).images;
84
122
 
@@ -99,6 +137,7 @@ export const ImagesStep = (props: StepComponentProps) => {
99
137
  name: thumbnail.name,
100
138
  id: thumbnail.id,
101
139
  thumbUrl: thumbnail.thumbUrl,
140
+ previewUrl: thumbnail.previewUrl,
102
141
  description: thumbnail.description,
103
142
  }),
104
143
  );
@@ -314,8 +353,9 @@ export const ImagesStep = (props: StepComponentProps) => {
314
353
  }));
315
354
  }}
316
355
  >
317
- <img
318
- src={option.thumbUrl}
356
+ <ResponsiveImage
357
+ thumbUrl={option.thumbUrl}
358
+ previewUrl={option.previewUrl}
319
359
  alt={option.name}
320
360
  className="h-full w-full object-cover"
321
361
  />
@@ -89,7 +89,7 @@ export function LayoutStep({
89
89
  createWizardAiContext,
90
90
  {},
91
91
  { signal: localAbortController.signal },
92
- "o3-mini-low",
92
+ "gpt-4.1",
93
93
  (response) => {
94
94
  try {
95
95
  const newLayout = JSON.parse(response.content) as WizardPageModel;
@@ -0,0 +1,173 @@
1
+ import { useEffect, useState } from "react";
2
+ import { FullItem } from "../../editor/pageModel";
3
+ import { WizardPageModel } from "../PageWizard";
4
+ import { executePrompt } from "../../editor/services/aiService";
5
+ import { createWizardAiContext } from "../service";
6
+ import { useEditContext } from "../../editor/client/editContext";
7
+ import { InputTextarea } from "primereact/inputtextarea";
8
+ import { WizardBox } from "../WizardBox";
9
+ import { FileText } from "lucide-react";
10
+ import { StepComponentProps } from "../../config/types";
11
+ import Generate from "./Generate";
12
+
13
+ export function MetaDataStep({
14
+ parentItem,
15
+ pageModel,
16
+ setPageModel,
17
+ step,
18
+ data,
19
+ setStepCompleted,
20
+ }: StepComponentProps) {
21
+ const [isGenerating, setIsGenerating] = useState(false);
22
+ const [fullParentItem, setFullParentItem] = useState<FullItem>();
23
+ const editContext = useEditContext();
24
+
25
+ useEffect(() => {
26
+ if (!editContext) return;
27
+
28
+ if (editContext.mode !== "edit") {
29
+ editContext.setMode("edit");
30
+ }
31
+ }, [editContext]);
32
+
33
+ useEffect(() => {
34
+ const loadParentItem = async () => {
35
+ if (!parentItem) return;
36
+ const item = await editContext?.itemsRepository.getItem(parentItem);
37
+ setFullParentItem(item);
38
+ };
39
+ loadParentItem();
40
+ }, [parentItem]);
41
+
42
+ // Mark step as completed immediately since this is now just informational
43
+ useEffect(() => {
44
+ setStepCompleted(true);
45
+ }, [setStepCompleted]);
46
+
47
+ // Auto-generate meta description and keywords if not set
48
+ useEffect(() => {
49
+ if (!editContext) return;
50
+
51
+ const generateMetaFields = async () => {
52
+ const metaInstructions =
53
+ step["Instructions for generating item name and meta fields"];
54
+
55
+ setIsGenerating(true);
56
+
57
+ try {
58
+ const abortController = new AbortController();
59
+
60
+ const result = await executePrompt(
61
+ [
62
+ {
63
+ content: `${metaInstructions?.trim()} Reply with a json object of type PageModel = { metaDescription: string; metaKeywords: string; };
64
+ Generate SEO-optimized meta description and keywords.
65
+ The language of the page is ${parentItem?.language || "en"}.
66
+ Input data: ${JSON.stringify(data)}`,
67
+ name: "system",
68
+ role: "system",
69
+ },
70
+ ],
71
+ editContext,
72
+ createWizardAiContext,
73
+ {},
74
+ { signal: abortController.signal },
75
+ "gpt-4.1",
76
+ (response) => {
77
+ try {
78
+ const newLayout = JSON.parse(response.content) as WizardPageModel;
79
+
80
+ setPageModel({
81
+ ...pageModel,
82
+ metaDescription: newLayout.metaDescription,
83
+ metaKeywords: newLayout.metaKeywords,
84
+ });
85
+ } catch (parseError: unknown) {}
86
+ },
87
+ );
88
+
89
+ const pageModelResult = JSON.parse(result.content) as WizardPageModel;
90
+ setPageModel({
91
+ ...pageModel,
92
+ metaDescription: pageModelResult.metaDescription,
93
+ metaKeywords: pageModelResult.metaKeywords,
94
+ });
95
+ } catch (error) {
96
+ console.error("Error generating meta fields", error);
97
+ } finally {
98
+ setIsGenerating(false);
99
+ }
100
+ };
101
+
102
+ if (!pageModel.metaDescription && !pageModel.metaKeywords) {
103
+ generateMetaFields();
104
+ }
105
+ }, []);
106
+
107
+ const handleInputChange = (field: keyof typeof pageModel, value: string) => {
108
+ const updatedPageModel = {
109
+ ...pageModel,
110
+ [field]: value,
111
+ };
112
+
113
+ setPageModel(updatedPageModel);
114
+ };
115
+
116
+ return (
117
+ <div className="flex h-full flex-col md:flex-row">
118
+ <WizardBox
119
+ title="SEO Settings"
120
+ icon={<FileText />}
121
+ description="Configure meta information for SEO optimization"
122
+ className="flex-1"
123
+ >
124
+ <div className="flex h-full flex-col items-stretch">
125
+ <div className="relative flex-1">
126
+ {isGenerating ? (
127
+ <div className="flex h-full items-center justify-center">
128
+ <Generate title="Generating SEO fields..." />
129
+ </div>
130
+ ) : (
131
+ <>
132
+ <div className="mb-4">
133
+ <label
134
+ htmlFor="metaDescription"
135
+ className="mb-1 block text-sm font-medium"
136
+ >
137
+ Meta Description
138
+ </label>
139
+ <InputTextarea
140
+ id="metaDescription"
141
+ className="min-h-[100px] w-full rounded border p-2 text-sm"
142
+ value={pageModel.metaDescription}
143
+ onChange={(e) =>
144
+ handleInputChange("metaDescription", e.target.value)
145
+ }
146
+ placeholder="Enter meta description"
147
+ />
148
+ </div>
149
+ <div className="mb-4">
150
+ <label
151
+ htmlFor="metaKeywords"
152
+ className="mb-1 block text-sm font-medium"
153
+ >
154
+ Meta Keywords
155
+ </label>
156
+ <InputTextarea
157
+ id="metaKeywords"
158
+ className="min-h-[100px] w-full rounded border p-2 text-sm"
159
+ value={pageModel.metaKeywords}
160
+ onChange={(e) =>
161
+ handleInputChange("metaKeywords", e.target.value)
162
+ }
163
+ placeholder="Enter meta keywords"
164
+ />
165
+ </div>
166
+ </>
167
+ )}
168
+ </div>
169
+ </div>
170
+ </WizardBox>
171
+ </div>
172
+ );
173
+ }
@@ -91,7 +91,7 @@ export function SelectStep({
91
91
  createWizardAiContext,
92
92
  { allowedFunctions: [] },
93
93
  undefined,
94
- step.aiModel || "o3-mini-low",
94
+ step.aiModel || "gpt-4.1",
95
95
  );
96
96
 
97
97
  // Parse the result and set options
package/src/revision.ts CHANGED
@@ -1,2 +1,2 @@
1
- export const version = "1.0.3906";
2
- export const buildDate = "2025-05-28 01:46:33";
1
+ export const version = "1.0.3908";
2
+ export const buildDate = "2025-05-29 01:53:46";
@@ -10,7 +10,6 @@ import {
10
10
  loadInsertOptions,
11
11
  } from "../editor/services/editService";
12
12
  import { InputText } from "primereact/inputtext";
13
- import { Button } from "primereact/button";
14
13
  import { getAbsoluteIconUrl, getItemDescriptor } from "../editor/utils";
15
14
  import { classNames } from "primereact/utils";
16
15
  import { useEditContext } from "../client-components";
@@ -22,6 +21,10 @@ import { getWizards } from "../page-wizard/service";
22
21
  import { Wizard } from "../page-wizard/PageWizard";
23
22
  import { Card } from "../components/ui/card";
24
23
  import { CardConnector } from "../components/ui/CardConnector";
24
+ import { Logo } from "../editor/ui/Icons";
25
+ import { ActionButton } from "../components/ActionButton";
26
+ import { FilePenLine, Palette } from "lucide-react";
27
+
25
28
  export function NewPage({ selectedItemId }: { selectedItemId?: string }) {
26
29
  const [selectedItem, setSelectedItem] = useState<ItemDescriptor | null>(null);
27
30
  const [isValid, setIsValid] = useState<boolean>(false);
@@ -145,121 +148,147 @@ export function NewPage({ selectedItemId }: { selectedItemId?: string }) {
145
148
  };
146
149
 
147
150
  return (
148
- <div className="flex h-full flex-col bg-gray-50 p-4 md:flex-row">
149
- <div className="tour-pick-location flex-1">
150
- <Card
151
- icon={<i className="pi pi-map-marker text-sm"></i>}
152
- title="Pick Location"
153
- description="Select where to create your new page"
154
- noPadding
155
- className="h-full"
156
- >
157
- <div className="relative h-full">
158
- <div className="absolute inset-0 overflow-auto">
159
- <ScrollingContentTree
160
- selectedItemId={selectedItem?.id || selectedItemId}
161
- onSelectionChange={(selection) => {
162
- const selected = selection[0] as ItemTreeNodeData;
163
- if (selected) setSelectedItem(selected);
164
- }}
165
- />
166
- </div>
151
+ <div className="flex h-full flex-col gap-6 bg-gray-100 p-4 md:p-8">
152
+ {/* Header with icon, title, description, and back button */}
153
+ <div className="flex gap-4">
154
+ <Logo className="h-8 w-8" />
155
+ <div className="flex-1 text-neutral-800">
156
+ <div className="text-lg font-semibold md:text-xl">
157
+ Create New Page
167
158
  </div>
168
- </Card>
169
- </div>
159
+ <div className="mt-1 text-xs font-light md:text-sm">
160
+ Select a location, choose a template or wizard, and name your new
161
+ page
162
+ </div>
163
+ </div>
170
164
 
171
- {/* Card Connector - only visible when location is selected */}
172
- {selectedItem && <CardConnector />}
165
+ <div className="flex items-start">
166
+ <ActionButton onClick={() => editContext?.switchView("open-page")}>
167
+ Open Existing
168
+ </ActionButton>
169
+ </div>
170
+ </div>
173
171
 
174
- {/* Second card - only visible when location is selected */}
175
- {selectedItem && (
176
- <div className="flex flex-1 flex-col">
172
+ {/* Content */}
173
+ <div className="flex flex-1 flex-col md:flex-row">
174
+ <div className="tour-pick-location flex-1">
177
175
  <Card
178
- icon={<i className="pi pi-palette text-sm"></i>}
179
- title="Choose Template or Wizard"
180
- description="Select a template or wizard to create your page"
176
+ icon={<i className="pi pi-map-marker text-sm"></i>}
177
+ title="Pick Location"
178
+ description="Select where to create your new page"
179
+ noPadding
180
+ className="h-full"
181
181
  >
182
- <div className="tour-choose-template">
183
- <div className="flex min-h-12 flex-wrap gap-3">
184
- {!insertOptions?.length && (
185
- <div>No page templates available here.</div>
186
- )}
187
- {insertOptionsAndWizards?.map((option) => (
188
- <div
189
- key={option.id}
190
- onClick={() => setSelectedTemplate(option.id)}
191
- className={classNames(
192
- "mb-2 flex cursor-pointer flex-col items-center rounded bg-gray-100 p-2 text-sm",
193
- selectedTemplate === option.id
194
- ? "tour-selected-template bg-gray-200 outline-2 outline-offset-2 outline-gray-200"
195
- : "bg-gray-100",
196
- )}
197
- >
198
- {
199
- <img
200
- src={getAbsoluteIconUrl(option.icon)}
201
- width="32"
202
- height="32"
203
- ></img>
204
- }
205
- {option.name}
206
- </div>
207
- ))}
182
+ <div className="h-full px-4 pb-4 md:px-6">
183
+ <div className="relative h-full">
184
+ <div className="absolute inset-0 overflow-auto">
185
+ <ScrollingContentTree
186
+ selectedItemId={selectedItem?.id || selectedItemId}
187
+ onSelectionChange={(selection) => {
188
+ const selected = selection[0] as ItemTreeNodeData;
189
+ if (selected) setSelectedItem(selected);
190
+ }}
191
+ />
192
+ </div>
208
193
  </div>
209
- {selectedTemplate &&
210
- wizards?.find((x) => x.id === selectedTemplate) && (
211
- <div className="mt-4">
212
- <Button
213
- onClick={launchWizard}
214
- label="Start Wizard"
215
- id="launch-wizard-button"
216
- />
217
- </div>
218
- )}
219
194
  </div>
220
195
  </Card>
196
+ </div>
221
197
 
222
- {/* Name Your Page card - only visible when template is selected */}
223
- {selectedTemplate &&
224
- insertOptions?.find((x) => x.id === selectedTemplate) && (
225
- <>
226
- <CardConnector direction="vertical" />
227
- <Card
228
- icon={<i className="pi pi-file-edit text-sm"></i>}
229
- title="Name Your Page"
230
- description="Enter a name for your new page"
231
- >
232
- <div>
233
- <InputText
234
- className="w-full"
235
- value={name}
236
- id="new-page-name"
237
- onChange={(e) => setName(e.target.value)}
238
- onKeyDown={(ev) => {
239
- if (ev.key === "Enter" && isValid) handleOk();
240
- }}
241
- data-testid="new-page-name"
242
- placeholder="Enter page name..."
243
- />
244
- {validationMessage && (
245
- <div className="mt-2 text-red-500">
246
- {validationMessage}
247
- </div>
248
- )}
198
+ {/* Card Connector - only visible when location is selected */}
199
+ {selectedItem && <CardConnector />}
200
+
201
+ {/* Second card - only visible when location is selected */}
202
+ {selectedItem && (
203
+ <div className="flex flex-1 flex-col">
204
+ <Card
205
+ icon={<Palette className="h-4 w-4" />}
206
+ title="Choose Template or Wizard"
207
+ description="Select a template or wizard to create your page"
208
+ >
209
+ <div className="tour-choose-template">
210
+ <div className="flex min-h-8 flex-wrap gap-3">
211
+ {!insertOptions?.length && (
212
+ <div className="text-sm text-gray-500">
213
+ You cannot insert content at the selected location.
214
+ </div>
215
+ )}
216
+ {insertOptionsAndWizards?.map((option) => (
217
+ <div
218
+ key={option.id}
219
+ onClick={() => setSelectedTemplate(option.id)}
220
+ className={classNames(
221
+ "hover:border-theme-secondary flex h-23 min-w-34 cursor-pointer flex-col items-center justify-center gap-2 rounded border border-gray-200 text-xs",
222
+ selectedTemplate === option.id
223
+ ? "bg-theme-secondary-light border-theme-secondary"
224
+ : "bg-white",
225
+ )}
226
+ >
227
+ {
228
+ <img
229
+ src={getAbsoluteIconUrl(option.icon)}
230
+ width="32"
231
+ height="32"
232
+ ></img>
233
+ }
234
+ {option.name}
235
+ </div>
236
+ ))}
237
+ </div>
238
+ {selectedTemplate &&
239
+ wizards?.find((x) => x.id === selectedTemplate) && (
249
240
  <div className="mt-4">
250
- <Button
251
- onClick={handleOk}
252
- label="Create"
253
- disabled={!isValid}
254
- id="create-new-page-button"
241
+ <ActionButton onClick={launchWizard} isLoading={false}>
242
+ Start wizard
243
+ </ActionButton>
244
+ </div>
245
+ )}
246
+ </div>
247
+ </Card>
248
+
249
+ {/* Name Your Page card - only visible when template is selected */}
250
+ {selectedTemplate &&
251
+ insertOptions?.find((x) => x.id === selectedTemplate) && (
252
+ <>
253
+ <CardConnector direction="vertical" />
254
+ <Card
255
+ icon={<FilePenLine />}
256
+ title="Name Your Page"
257
+ description="Enter a name for your new page"
258
+ >
259
+ <div>
260
+ <InputText
261
+ className="w-full rounded p-1.5 text-xs"
262
+ value={name}
263
+ id="new-page-name"
264
+ onChange={(e) => setName(e.target.value)}
265
+ onKeyDown={(ev) => {
266
+ if (ev.key === "Enter" && isValid) handleOk();
267
+ }}
268
+ data-testid="new-page-name"
269
+ placeholder="Enter page name..."
255
270
  />
271
+ {validationMessage && (
272
+ <div className="mt-2 text-red-500">
273
+ {validationMessage}
274
+ </div>
275
+ )}
276
+ <div className="mt-4">
277
+ <ActionButton
278
+ onClick={handleOk}
279
+ disabled={!isValid}
280
+ isLoading={false}
281
+ >
282
+ Create page
283
+ </ActionButton>
284
+ </div>
256
285
  </div>
257
- </div>
258
- </Card>
259
- </>
260
- )}
261
- </div>
262
- )}
286
+ </Card>
287
+ </>
288
+ )}
289
+ </div>
290
+ )}
291
+ </div>
263
292
  </div>
264
293
  );
265
294
  }