@alpaca-editor/core 1.0.3906 → 1.0.3907
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.
- package/dist/components/ui/card.js +1 -1
- package/dist/components/ui/card.js.map +1 -1
- package/dist/config/config.js +2 -2
- package/dist/config/config.js.map +1 -1
- package/dist/editor/sidebar/ViewSelector.js +3 -3
- package/dist/editor/sidebar/ViewSelector.js.map +1 -1
- package/dist/editor/ui/Icons.js +1 -1
- package/dist/editor/ui/Icons.js.map +1 -1
- package/dist/editor/ui/Splitter.js +2 -2
- package/dist/editor/ui/Splitter.js.map +1 -1
- package/dist/page-wizard/steps/CollectStep.d.ts +1 -1
- package/dist/page-wizard/steps/CollectStep.js +15 -4
- package/dist/page-wizard/steps/CollectStep.js.map +1 -1
- package/dist/page-wizard/steps/ContentStep.js +110 -9
- package/dist/page-wizard/steps/ContentStep.js.map +1 -1
- package/dist/page-wizard/steps/MetaDataStep.d.ts +2 -0
- package/dist/page-wizard/steps/MetaDataStep.js +90 -0
- package/dist/page-wizard/steps/MetaDataStep.js.map +1 -0
- package/dist/page-wizard/steps/SelectStep.js +1 -1
- package/dist/page-wizard/steps/SelectStep.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/styles.css +5 -6
- package/package.json +1 -1
- package/src/components/ui/card.tsx +1 -1
- package/src/config/config.tsx +2 -2
- package/src/editor/sidebar/ViewSelector.tsx +3 -3
- package/src/editor/ui/Icons.tsx +2 -1
- package/src/editor/ui/Splitter.tsx +2 -2
- package/src/page-wizard/steps/CollectStep.tsx +133 -115
- package/src/page-wizard/steps/ContentStep.tsx +231 -22
- package/src/page-wizard/steps/MetaDataStep.tsx +173 -0
- package/src/page-wizard/steps/SelectStep.tsx +1 -1
- package/src/revision.ts +2 -2
- package/dist/page-wizard/steps/SetupPageStep.d.ts +0 -2
- package/dist/page-wizard/steps/SetupPageStep.js +0 -152
- package/dist/page-wizard/steps/SetupPageStep.js.map +0 -1
- package/src/page-wizard/steps/SetupPageStep.tsx +0 -329
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState, useCallback } 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 { LanguageSelector } from "../../editor/menubar/LanguageSelector";
|
|
8
|
-
import { InputText } from "primereact/inputtext";
|
|
9
|
-
import { InputTextarea } from "primereact/inputtextarea";
|
|
10
|
-
import { WizardBox } from "../WizardBox";
|
|
11
|
-
import { WizardBoxConnector } from "../WizardBoxConnector";
|
|
12
|
-
import { Settings, FileText } from "lucide-react";
|
|
13
|
-
import { StepComponentProps } from "../../config/types";
|
|
14
|
-
import Generate from "./Generate";
|
|
15
|
-
import { getChildren } from "../../editor/services/contentService";
|
|
16
|
-
|
|
17
|
-
export function SetupPageStep({
|
|
18
|
-
wizard,
|
|
19
|
-
parentItem,
|
|
20
|
-
pageModel,
|
|
21
|
-
setPageModel,
|
|
22
|
-
step,
|
|
23
|
-
data,
|
|
24
|
-
setStepCompleted,
|
|
25
|
-
}: StepComponentProps) {
|
|
26
|
-
const [isGenerating, setIsGenerating] = useState(false);
|
|
27
|
-
const [language, setLanguage] = useState<string>(
|
|
28
|
-
parentItem?.language || "en",
|
|
29
|
-
);
|
|
30
|
-
const [previousLanguage, setPreviousLanguage] = useState<string>(language);
|
|
31
|
-
const [fullParentItem, setFullParentItem] = useState<FullItem>();
|
|
32
|
-
const [nameValidation, setNameValidation] = useState<{
|
|
33
|
-
isValid: boolean;
|
|
34
|
-
message?: string;
|
|
35
|
-
}>({ isValid: false });
|
|
36
|
-
|
|
37
|
-
const editContext = useEditContext();
|
|
38
|
-
|
|
39
|
-
const checkPageName = useCallback(async () => {
|
|
40
|
-
if (!parentItem) {
|
|
41
|
-
setNameValidation({ isValid: false, message: "No parent item" });
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Check if page name is valid
|
|
46
|
-
if (!pageModel.name || pageModel.name.trim().length < 3) {
|
|
47
|
-
setNameValidation({
|
|
48
|
-
isValid: false,
|
|
49
|
-
message: "Page name must be at least 3 characters long",
|
|
50
|
-
});
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
// Check if page with same name already exists
|
|
56
|
-
const children = await getChildren(
|
|
57
|
-
parentItem.id,
|
|
58
|
-
editContext?.sessionId ?? "",
|
|
59
|
-
[],
|
|
60
|
-
false,
|
|
61
|
-
editContext?.contentEditorItem?.language || "en",
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
if (
|
|
65
|
-
children.find(
|
|
66
|
-
(x) =>
|
|
67
|
-
x.name.toLocaleLowerCase() ===
|
|
68
|
-
pageModel.name.trim().toLocaleLowerCase(),
|
|
69
|
-
)
|
|
70
|
-
) {
|
|
71
|
-
setNameValidation({
|
|
72
|
-
isValid: false,
|
|
73
|
-
message: "A page with this name already exists",
|
|
74
|
-
});
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
setNameValidation({ isValid: true });
|
|
79
|
-
return true;
|
|
80
|
-
} catch (error) {
|
|
81
|
-
setNameValidation({
|
|
82
|
-
isValid: false,
|
|
83
|
-
message: "Error checking page name",
|
|
84
|
-
});
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
}, [
|
|
88
|
-
parentItem,
|
|
89
|
-
pageModel.name,
|
|
90
|
-
editContext?.sessionId,
|
|
91
|
-
editContext?.contentEditorItem?.language,
|
|
92
|
-
]);
|
|
93
|
-
|
|
94
|
-
// Check page name whenever it changes
|
|
95
|
-
useEffect(() => {
|
|
96
|
-
if (pageModel.name) {
|
|
97
|
-
checkPageName();
|
|
98
|
-
}
|
|
99
|
-
}, [pageModel.name, checkPageName]);
|
|
100
|
-
|
|
101
|
-
// Mark step as completed when page name is valid
|
|
102
|
-
useEffect(() => {
|
|
103
|
-
if (nameValidation.isValid) {
|
|
104
|
-
setStepCompleted(true);
|
|
105
|
-
} else {
|
|
106
|
-
setStepCompleted(false);
|
|
107
|
-
}
|
|
108
|
-
}, [nameValidation.isValid, setStepCompleted]);
|
|
109
|
-
|
|
110
|
-
useEffect(() => {
|
|
111
|
-
if (!editContext) return;
|
|
112
|
-
|
|
113
|
-
if (editContext.mode !== "edit") {
|
|
114
|
-
editContext.setMode("edit");
|
|
115
|
-
}
|
|
116
|
-
}, [editContext]);
|
|
117
|
-
|
|
118
|
-
useEffect(() => {
|
|
119
|
-
if (!editContext) return;
|
|
120
|
-
|
|
121
|
-
const generateNameAndMetaDescription = async () => {
|
|
122
|
-
const metaInstructions =
|
|
123
|
-
step["Instructions for generating item name and meta fields"];
|
|
124
|
-
|
|
125
|
-
setIsGenerating(true);
|
|
126
|
-
|
|
127
|
-
try {
|
|
128
|
-
const abortController = new AbortController();
|
|
129
|
-
|
|
130
|
-
const result = await executePrompt(
|
|
131
|
-
[
|
|
132
|
-
{
|
|
133
|
-
content: `${metaInstructions?.trim()} Reply with a json object of type PageModel = { name: string; metaDescription: string; metaKeywords: string; };
|
|
134
|
-
The item name should be a valid sitecore item name. Spaces are allowed but no special characters or Umlaute.
|
|
135
|
-
The language of the page is ${language}.
|
|
136
|
-
Input data: ${JSON.stringify(data)}`,
|
|
137
|
-
name: "system",
|
|
138
|
-
role: "system",
|
|
139
|
-
},
|
|
140
|
-
],
|
|
141
|
-
editContext,
|
|
142
|
-
createWizardAiContext,
|
|
143
|
-
{},
|
|
144
|
-
{ signal: abortController.signal },
|
|
145
|
-
"o3-mini-low",
|
|
146
|
-
(response) => {
|
|
147
|
-
try {
|
|
148
|
-
const newLayout = JSON.parse(response.content) as WizardPageModel;
|
|
149
|
-
|
|
150
|
-
setPageModel({
|
|
151
|
-
...pageModel,
|
|
152
|
-
name: newLayout.name,
|
|
153
|
-
metaDescription: newLayout.metaDescription,
|
|
154
|
-
metaKeywords: newLayout.metaKeywords,
|
|
155
|
-
});
|
|
156
|
-
} catch (parseError: unknown) {}
|
|
157
|
-
},
|
|
158
|
-
);
|
|
159
|
-
|
|
160
|
-
const pageModel = JSON.parse(result.content) as WizardPageModel;
|
|
161
|
-
setPageModel({
|
|
162
|
-
...pageModel,
|
|
163
|
-
name: pageModel.name,
|
|
164
|
-
metaDescription: pageModel.metaDescription,
|
|
165
|
-
metaKeywords: pageModel.metaKeywords,
|
|
166
|
-
});
|
|
167
|
-
} catch (error) {
|
|
168
|
-
console.error("Error generating name and meta description", error);
|
|
169
|
-
} finally {
|
|
170
|
-
setIsGenerating(false);
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
if (!pageModel.name) generateNameAndMetaDescription();
|
|
175
|
-
}, []);
|
|
176
|
-
|
|
177
|
-
useEffect(() => {
|
|
178
|
-
const loadParentItem = async () => {
|
|
179
|
-
if (!parentItem) return;
|
|
180
|
-
const item = await editContext?.itemsRepository.getItem(parentItem);
|
|
181
|
-
setFullParentItem(item);
|
|
182
|
-
};
|
|
183
|
-
loadParentItem();
|
|
184
|
-
}, [parentItem]);
|
|
185
|
-
|
|
186
|
-
const handleInputChange = (field: keyof typeof pageModel, value: string) => {
|
|
187
|
-
const updatedPageModel = {
|
|
188
|
-
...pageModel,
|
|
189
|
-
[field]: value,
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
setPageModel(updatedPageModel);
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
return (
|
|
196
|
-
<div className="flex h-full flex-col md:flex-row">
|
|
197
|
-
<WizardBox
|
|
198
|
-
title="Page Setup"
|
|
199
|
-
icon={<Settings />}
|
|
200
|
-
description="Configure the target location and language for your new page"
|
|
201
|
-
collapsible="mobileOnly"
|
|
202
|
-
defaultCollapsed="mobileOnly"
|
|
203
|
-
summary={
|
|
204
|
-
<div className="text-xs text-gray-500">
|
|
205
|
-
Folder: {fullParentItem?.path}, Language: {language}
|
|
206
|
-
</div>
|
|
207
|
-
}
|
|
208
|
-
>
|
|
209
|
-
<div className="flex flex-col items-stretch">
|
|
210
|
-
<div className="relative flex-1">
|
|
211
|
-
<div className="mb-4">
|
|
212
|
-
<div className="mb-1 text-sm font-medium">Target Parent Item</div>
|
|
213
|
-
<div className="mb-4 break-after-all text-xs">
|
|
214
|
-
{fullParentItem?.path}
|
|
215
|
-
</div>
|
|
216
|
-
</div>
|
|
217
|
-
<div className="relative mb-4">
|
|
218
|
-
<label
|
|
219
|
-
htmlFor="language"
|
|
220
|
-
className="mb-1 block text-sm font-medium"
|
|
221
|
-
>
|
|
222
|
-
Language
|
|
223
|
-
</label>
|
|
224
|
-
<div className="w-fit">
|
|
225
|
-
<LanguageSelector
|
|
226
|
-
selectedLanguage={language}
|
|
227
|
-
darkMode={true}
|
|
228
|
-
disabled={isGenerating}
|
|
229
|
-
onLanguageSelected={(language) =>
|
|
230
|
-
setLanguage(language.languageCode)
|
|
231
|
-
}
|
|
232
|
-
showAllLanguages={true}
|
|
233
|
-
/>
|
|
234
|
-
</div>
|
|
235
|
-
</div>
|
|
236
|
-
</div>
|
|
237
|
-
</div>
|
|
238
|
-
</WizardBox>
|
|
239
|
-
<WizardBoxConnector />
|
|
240
|
-
<WizardBox
|
|
241
|
-
title="Page Details"
|
|
242
|
-
icon={<FileText />}
|
|
243
|
-
description="Define the page name and meta information for SEO optimization"
|
|
244
|
-
className="flex-1"
|
|
245
|
-
>
|
|
246
|
-
<div className="flex h-full flex-col items-stretch">
|
|
247
|
-
<div className="relative flex-1">
|
|
248
|
-
{isGenerating ? (
|
|
249
|
-
<div className="flex h-full items-center justify-center">
|
|
250
|
-
<Generate title="Generating page details..." />
|
|
251
|
-
</div>
|
|
252
|
-
) : (
|
|
253
|
-
<>
|
|
254
|
-
<div className="mb-4">
|
|
255
|
-
<label
|
|
256
|
-
htmlFor="pageName"
|
|
257
|
-
className="mb-1 block text-sm font-medium"
|
|
258
|
-
>
|
|
259
|
-
Page Name
|
|
260
|
-
</label>
|
|
261
|
-
<InputText
|
|
262
|
-
id="pageName"
|
|
263
|
-
type="text"
|
|
264
|
-
disabled={false}
|
|
265
|
-
className={`w-full rounded border p-2 text-sm ${
|
|
266
|
-
!nameValidation.isValid
|
|
267
|
-
? "border-red-500"
|
|
268
|
-
: nameValidation.isValid && pageModel.name
|
|
269
|
-
? "border-green-500"
|
|
270
|
-
: ""
|
|
271
|
-
}`}
|
|
272
|
-
value={pageModel.name}
|
|
273
|
-
onChange={(e) => handleInputChange("name", e.target.value)}
|
|
274
|
-
placeholder="Enter page name"
|
|
275
|
-
/>
|
|
276
|
-
{nameValidation.message && !nameValidation.isValid && (
|
|
277
|
-
<div className="mt-1 text-xs text-red-600">
|
|
278
|
-
{nameValidation.message}
|
|
279
|
-
</div>
|
|
280
|
-
)}
|
|
281
|
-
{nameValidation.isValid && pageModel.name && (
|
|
282
|
-
<div className="mt-1 text-xs text-green-600">
|
|
283
|
-
✓ Page name is available
|
|
284
|
-
</div>
|
|
285
|
-
)}
|
|
286
|
-
</div>
|
|
287
|
-
|
|
288
|
-
<div className="mb-4">
|
|
289
|
-
<label
|
|
290
|
-
htmlFor="metaDescription"
|
|
291
|
-
className="mb-1 block text-sm font-medium"
|
|
292
|
-
>
|
|
293
|
-
Meta Description
|
|
294
|
-
</label>
|
|
295
|
-
<InputTextarea
|
|
296
|
-
id="metaDescription"
|
|
297
|
-
className="min-h-[100px] w-full rounded border p-2 text-sm"
|
|
298
|
-
value={pageModel.metaDescription}
|
|
299
|
-
onChange={(e) =>
|
|
300
|
-
handleInputChange("metaDescription", e.target.value)
|
|
301
|
-
}
|
|
302
|
-
placeholder="Enter meta description"
|
|
303
|
-
/>
|
|
304
|
-
</div>
|
|
305
|
-
<div className="mb-4">
|
|
306
|
-
<label
|
|
307
|
-
htmlFor="metaKeywords"
|
|
308
|
-
className="mb-1 block text-sm font-medium"
|
|
309
|
-
>
|
|
310
|
-
Meta Keywords
|
|
311
|
-
</label>
|
|
312
|
-
<InputTextarea
|
|
313
|
-
id="metaKeywords"
|
|
314
|
-
className="min-h-[100px] w-full rounded border p-2 text-sm"
|
|
315
|
-
value={pageModel.metaKeywords}
|
|
316
|
-
onChange={(e) =>
|
|
317
|
-
handleInputChange("metaKeywords", e.target.value)
|
|
318
|
-
}
|
|
319
|
-
placeholder="Enter meta keywords"
|
|
320
|
-
/>
|
|
321
|
-
</div>
|
|
322
|
-
</>
|
|
323
|
-
)}
|
|
324
|
-
</div>
|
|
325
|
-
</div>
|
|
326
|
-
</WizardBox>
|
|
327
|
-
</div>
|
|
328
|
-
);
|
|
329
|
-
}
|