@alpaca-editor/core 1.0.3898 → 1.0.3899
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/CardConnector.d.ts +3 -0
- package/dist/components/ui/CardConnector.js +6 -0
- package/dist/components/ui/CardConnector.js.map +1 -0
- package/dist/components/ui/card.d.ts +12 -0
- package/dist/components/ui/card.js +10 -0
- package/dist/components/ui/card.js.map +1 -0
- package/dist/editor/MobileLayout.js +15 -4
- package/dist/editor/MobileLayout.js.map +1 -1
- package/dist/editor/sidebar/SidebarView.js +14 -14
- package/dist/editor/sidebar/SidebarView.js.map +1 -1
- package/dist/editor/ui/SimpleTabs.js +1 -1
- package/dist/editor/ui/SimpleTabs.js.map +1 -1
- package/dist/editor/ui/Splitter.d.ts +1 -0
- package/dist/editor/ui/Splitter.js +119 -58
- package/dist/editor/ui/Splitter.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/page-wizard/WizardBox.d.ts +2 -8
- package/dist/page-wizard/WizardBox.js +3 -5
- package/dist/page-wizard/WizardBox.js.map +1 -1
- package/dist/page-wizard/steps/CollectStep.js +9 -9
- package/dist/page-wizard/steps/CollectStep.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/splash-screen/NewPage.js +12 -11
- package/dist/splash-screen/NewPage.js.map +1 -1
- package/dist/splash-screen/SplashScreen.js +8 -7
- package/dist/splash-screen/SplashScreen.js.map +1 -1
- package/dist/styles.css +72 -18
- package/package.json +1 -1
- package/src/components/ui/CardConnector.tsx +21 -0
- package/src/components/ui/card.tsx +44 -0
- package/src/editor/MobileLayout.tsx +20 -7
- package/src/editor/sidebar/SidebarView.tsx +46 -44
- package/src/editor/ui/SimpleTabs.tsx +1 -1
- package/src/editor/ui/Splitter.tsx +152 -80
- package/src/index.ts +2 -0
- package/src/page-wizard/WizardBox.tsx +3 -39
- package/src/page-wizard/steps/CollectStep.tsx +8 -9
- package/src/revision.ts +2 -2
- package/src/splash-screen/NewPage.tsx +107 -80
- package/src/splash-screen/SplashScreen.tsx +49 -33
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useState, useRef, useEffect, useCallback } from "react";
|
|
2
2
|
import { flushSync } from "react-dom";
|
|
3
|
+
|
|
3
4
|
export type SplitterPanel = {
|
|
4
5
|
defaultSize: number | "auto";
|
|
5
6
|
name: string;
|
|
@@ -13,6 +14,7 @@ interface SplitterProps {
|
|
|
13
14
|
localStorageKey?: string;
|
|
14
15
|
expandLabel?: React.ReactNode;
|
|
15
16
|
growablePanelIndex?: number; // Index of the panel that grows/shrinks
|
|
17
|
+
direction?: "horizontal" | "vertical"; // New prop for direction
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
type StoredSizes = { panels: PanelSizes; lastCollapsed: boolean };
|
|
@@ -22,6 +24,7 @@ export const Splitter: React.FC<SplitterProps> = ({
|
|
|
22
24
|
panels,
|
|
23
25
|
localStorageKey = "splitter-sizes",
|
|
24
26
|
expandLabel = "Expand",
|
|
27
|
+
direction = "horizontal", // Default to horizontal for backward compatibility
|
|
25
28
|
}) => {
|
|
26
29
|
const totalPanels = panels.length;
|
|
27
30
|
|
|
@@ -86,79 +89,6 @@ export const Splitter: React.FC<SplitterProps> = ({
|
|
|
86
89
|
}
|
|
87
90
|
};
|
|
88
91
|
|
|
89
|
-
const handleResize = useCallback(
|
|
90
|
-
(index: number, event: React.MouseEvent<HTMLDivElement>) => {
|
|
91
|
-
event.preventDefault();
|
|
92
|
-
|
|
93
|
-
const iframes = splitterRef.current?.querySelectorAll("iframe");
|
|
94
|
-
iframes?.forEach((iframe) => {
|
|
95
|
-
iframe.classList.add("pointer-events-none");
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
const startX = event.clientX;
|
|
99
|
-
// create a copy with the panel name
|
|
100
|
-
const initialSizes = panelSizes ? { ...panelSizes } : {};
|
|
101
|
-
|
|
102
|
-
const panelElement = panelRefs.current[index];
|
|
103
|
-
const nextPanelElement = panelRefs.current[index + 1];
|
|
104
|
-
|
|
105
|
-
if (!panelElement || !nextPanelElement || !splitterRef.current) {
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const panelWidth = panelElement.offsetWidth;
|
|
110
|
-
const nextPanelWidth = nextPanelElement.offsetWidth;
|
|
111
|
-
|
|
112
|
-
setIsResizing(true);
|
|
113
|
-
|
|
114
|
-
const onMouseMove = (moveEvent: MouseEvent) => {
|
|
115
|
-
const delta = moveEvent.clientX - startX;
|
|
116
|
-
const newPanelWidth = panelWidth + delta;
|
|
117
|
-
const newNextPanelWidth = nextPanelWidth - delta;
|
|
118
|
-
|
|
119
|
-
const minPanelWidth = 50;
|
|
120
|
-
const minNextPanelWidth = 50;
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
newNextPanelWidth < minPanelWidth &&
|
|
124
|
-
index == panels.length - 2 &&
|
|
125
|
-
lastPanelCollapsible
|
|
126
|
-
) {
|
|
127
|
-
setIsLastPanelCollapsed(true);
|
|
128
|
-
setPanelSizes(initialSizes);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (
|
|
132
|
-
newPanelWidth < minPanelWidth ||
|
|
133
|
-
newNextPanelWidth < minNextPanelWidth
|
|
134
|
-
) {
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const updatedSizes: PanelSizes = { ...initialSizes };
|
|
139
|
-
updatedSizes[panels[index]!.name] = newPanelWidth;
|
|
140
|
-
updatedSizes[panels[index + 1]!.name] = newNextPanelWidth;
|
|
141
|
-
setPanelSizes(updatedSizes);
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
const onMouseUp = () => {
|
|
145
|
-
setTimeout(() => {
|
|
146
|
-
setIsResizing(false);
|
|
147
|
-
}, 100);
|
|
148
|
-
iframes?.forEach((iframe) => {
|
|
149
|
-
iframe.classList.remove("pointer-events-none");
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
document.removeEventListener("mousemove", onMouseMove);
|
|
153
|
-
document.removeEventListener("mouseup", onMouseUp, true);
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
document.addEventListener("mousemove", onMouseMove);
|
|
157
|
-
document.addEventListener("mouseup", onMouseUp, true);
|
|
158
|
-
},
|
|
159
|
-
[panels, panelSizes],
|
|
160
|
-
);
|
|
161
|
-
|
|
162
92
|
const isLastResizer = (index: number) => index === panels.length - 2;
|
|
163
93
|
|
|
164
94
|
const getFlexBasis = (index: number): string => {
|
|
@@ -182,11 +112,16 @@ export const Splitter: React.FC<SplitterProps> = ({
|
|
|
182
112
|
};
|
|
183
113
|
|
|
184
114
|
const getExpandButton = () => {
|
|
115
|
+
const isHorizontal = direction === "horizontal";
|
|
116
|
+
|
|
185
117
|
return (
|
|
186
118
|
<div
|
|
187
119
|
onClick={!isResizing ? toggleLastPanelCollapse : undefined}
|
|
188
120
|
className="flex cursor-pointer items-center justify-center bg-gray-200 p-1 text-gray-500 select-none hover:bg-blue-700 hover:text-white"
|
|
189
|
-
style={{
|
|
121
|
+
style={{
|
|
122
|
+
writingMode: isHorizontal ? "vertical-rl" : "horizontal-tb",
|
|
123
|
+
userSelect: "none",
|
|
124
|
+
}}
|
|
190
125
|
>
|
|
191
126
|
{expandLabel}
|
|
192
127
|
</div>
|
|
@@ -194,27 +129,162 @@ export const Splitter: React.FC<SplitterProps> = ({
|
|
|
194
129
|
};
|
|
195
130
|
|
|
196
131
|
const getSplitter = (index: number) => {
|
|
132
|
+
const isHorizontal = direction === "horizontal";
|
|
133
|
+
|
|
134
|
+
const handleDragStart = (
|
|
135
|
+
clientX: number,
|
|
136
|
+
clientY: number,
|
|
137
|
+
event: React.MouseEvent | React.TouchEvent,
|
|
138
|
+
) => {
|
|
139
|
+
const rect = (event.target as HTMLElement).getBoundingClientRect();
|
|
140
|
+
const relativeY = clientY - rect.top;
|
|
141
|
+
|
|
142
|
+
event.stopPropagation();
|
|
143
|
+
event.preventDefault();
|
|
144
|
+
|
|
145
|
+
const isHorizontal = direction === "horizontal";
|
|
146
|
+
const startCoord = isHorizontal ? clientX : clientY;
|
|
147
|
+
const initialSizes = panelSizes ? { ...panelSizes } : {};
|
|
148
|
+
|
|
149
|
+
const panelElement = panelRefs.current[index];
|
|
150
|
+
const nextPanelElement = panelRefs.current[index + 1];
|
|
151
|
+
|
|
152
|
+
if (!panelElement || !nextPanelElement) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const panelSize = isHorizontal
|
|
157
|
+
? panelElement.offsetWidth
|
|
158
|
+
: panelElement.offsetHeight;
|
|
159
|
+
const nextPanelSize = isHorizontal
|
|
160
|
+
? nextPanelElement.offsetWidth
|
|
161
|
+
: nextPanelElement.offsetHeight;
|
|
162
|
+
|
|
163
|
+
setIsResizing(true);
|
|
164
|
+
|
|
165
|
+
// Disable pointer events on panel content during drag
|
|
166
|
+
const allPanels = splitterRef.current?.querySelectorAll(".relative");
|
|
167
|
+
allPanels?.forEach((panel) => {
|
|
168
|
+
(panel as HTMLElement).style.pointerEvents = "none";
|
|
169
|
+
// Also disable on all child elements that might capture events
|
|
170
|
+
const childElements = panel.querySelectorAll("*");
|
|
171
|
+
childElements.forEach((child) => {
|
|
172
|
+
(child as HTMLElement).style.pointerEvents = "none";
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
let isDragging = true;
|
|
177
|
+
|
|
178
|
+
const handleMove = (moveClientX: number, moveClientY: number) => {
|
|
179
|
+
if (!isDragging) return;
|
|
180
|
+
|
|
181
|
+
const currentCoord = isHorizontal ? moveClientX : moveClientY;
|
|
182
|
+
const delta = currentCoord - startCoord;
|
|
183
|
+
const newPanelSize = panelSize + delta;
|
|
184
|
+
const newNextPanelSize = nextPanelSize - delta;
|
|
185
|
+
|
|
186
|
+
const minPanelSize = 50;
|
|
187
|
+
if (newPanelSize < minPanelSize || newNextPanelSize < minPanelSize) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const updatedSizes: PanelSizes = { ...initialSizes };
|
|
192
|
+
updatedSizes[panels[index]!.name] = newPanelSize;
|
|
193
|
+
updatedSizes[panels[index + 1]!.name] = newNextPanelSize;
|
|
194
|
+
setPanelSizes(updatedSizes);
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const handleEnd = () => {
|
|
198
|
+
isDragging = false;
|
|
199
|
+
setIsResizing(false);
|
|
200
|
+
|
|
201
|
+
// Re-enable pointer events on panel content
|
|
202
|
+
allPanels?.forEach((panel) => {
|
|
203
|
+
(panel as HTMLElement).style.pointerEvents = "";
|
|
204
|
+
// Also re-enable on all child elements
|
|
205
|
+
const childElements = panel.querySelectorAll("*");
|
|
206
|
+
childElements.forEach((child) => {
|
|
207
|
+
(child as HTMLElement).style.pointerEvents = "";
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// Remove all event listeners
|
|
212
|
+
window.removeEventListener("mousemove", onMouseMove);
|
|
213
|
+
window.removeEventListener("mouseup", onMouseUp);
|
|
214
|
+
window.removeEventListener("touchmove", onTouchMove);
|
|
215
|
+
window.removeEventListener("touchend", onTouchEnd);
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const onMouseMove = (moveEvent: MouseEvent) => {
|
|
219
|
+
handleMove(moveEvent.clientX, moveEvent.clientY);
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const onMouseUp = () => {
|
|
223
|
+
handleEnd();
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const onTouchMove = (moveEvent: TouchEvent) => {
|
|
227
|
+
if (moveEvent.touches.length === 1) {
|
|
228
|
+
const touch = moveEvent.touches[0];
|
|
229
|
+
if (touch) {
|
|
230
|
+
handleMove(touch.clientX, touch.clientY);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const onTouchEnd = () => {
|
|
236
|
+
handleEnd();
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
// Add both mouse and touch event listeners
|
|
240
|
+
window.addEventListener("mousemove", onMouseMove);
|
|
241
|
+
window.addEventListener("mouseup", onMouseUp);
|
|
242
|
+
window.addEventListener("touchmove", onTouchMove, { passive: false });
|
|
243
|
+
window.addEventListener("touchend", onTouchEnd);
|
|
244
|
+
};
|
|
245
|
+
|
|
197
246
|
if (lastPanelCollapsible && isLastPanelCollapsed && isLastResizer(index)) {
|
|
198
247
|
return getExpandButton();
|
|
199
248
|
}
|
|
200
249
|
|
|
201
250
|
return (
|
|
202
251
|
<div
|
|
203
|
-
className={
|
|
204
|
-
|
|
205
|
-
|
|
252
|
+
className={`relative flex ${
|
|
253
|
+
isHorizontal
|
|
254
|
+
? "h-full w-[4px] w-[12px] cursor-ew-resize md:w-[4px]"
|
|
255
|
+
: "h-[12px] h-[20px] w-full cursor-ns-resize md:h-[12px]"
|
|
256
|
+
} shrink-0 items-center justify-center bg-gray-300 select-none hover:bg-gray-400`}
|
|
257
|
+
style={{
|
|
258
|
+
touchAction: "none",
|
|
259
|
+
minHeight: isHorizontal ? undefined : "12px",
|
|
260
|
+
minWidth: isHorizontal ? "4px" : undefined,
|
|
261
|
+
boxSizing: "border-box",
|
|
262
|
+
userSelect: "none",
|
|
263
|
+
zIndex: 9999, // Ensure we're above any nested splitters
|
|
264
|
+
}}
|
|
206
265
|
onDoubleClick={
|
|
207
266
|
isLastResizer(index) ? toggleLastPanelCollapse : undefined
|
|
208
267
|
}
|
|
209
268
|
onMouseDown={(event) => {
|
|
210
|
-
|
|
269
|
+
handleDragStart(event.clientX, event.clientY, event);
|
|
270
|
+
}}
|
|
271
|
+
onTouchStart={(event) => {
|
|
272
|
+
if (event.touches.length === 1) {
|
|
273
|
+
const touch = event.touches[0];
|
|
274
|
+
if (touch) {
|
|
275
|
+
handleDragStart(touch.clientX, touch.clientY, event);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
211
278
|
}}
|
|
212
279
|
></div>
|
|
213
280
|
);
|
|
214
281
|
};
|
|
215
282
|
|
|
216
283
|
return (
|
|
217
|
-
<div
|
|
284
|
+
<div
|
|
285
|
+
className={`flex ${direction === "horizontal" ? "flex-row" : "flex-col"} h-full w-full overflow-hidden`}
|
|
286
|
+
ref={splitterRef}
|
|
287
|
+
>
|
|
218
288
|
{panels.map((panel, index) => (
|
|
219
289
|
<React.Fragment key={panel.name}>
|
|
220
290
|
<div
|
|
@@ -227,7 +297,8 @@ export const Splitter: React.FC<SplitterProps> = ({
|
|
|
227
297
|
index,
|
|
228
298
|
)}`,
|
|
229
299
|
|
|
230
|
-
minWidth: 0,
|
|
300
|
+
minWidth: direction === "horizontal" ? 0 : undefined,
|
|
301
|
+
minHeight: direction === "vertical" ? 0 : undefined,
|
|
231
302
|
display:
|
|
232
303
|
(panel.collapsible &&
|
|
233
304
|
isLastPanelCollapsed &&
|
|
@@ -241,6 +312,7 @@ export const Splitter: React.FC<SplitterProps> = ({
|
|
|
241
312
|
</div>
|
|
242
313
|
{index < panels.length - 1 &&
|
|
243
314
|
!panels[index]?.hidden &&
|
|
315
|
+
!panels[index + 1]?.hidden &&
|
|
244
316
|
getSplitter(index)}
|
|
245
317
|
</React.Fragment>
|
|
246
318
|
))}
|
package/src/index.ts
CHANGED
|
@@ -1,40 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Card } from "../components/ui/card";
|
|
2
2
|
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
icon,
|
|
6
|
-
title,
|
|
7
|
-
description,
|
|
8
|
-
className,
|
|
9
|
-
noPadding,
|
|
10
|
-
}: {
|
|
11
|
-
children: React.ReactNode;
|
|
12
|
-
icon: React.ReactNode;
|
|
13
|
-
title: string;
|
|
14
|
-
description: string;
|
|
15
|
-
className?: string;
|
|
16
|
-
noPadding?: boolean;
|
|
17
|
-
}) {
|
|
18
|
-
return (
|
|
19
|
-
<div
|
|
20
|
-
className={cn(
|
|
21
|
-
"flex h-full flex-col gap-2 rounded-md bg-white",
|
|
22
|
-
className,
|
|
23
|
-
)}
|
|
24
|
-
>
|
|
25
|
-
<div className="flex flex-col justify-between gap-1 p-6 pb-2">
|
|
26
|
-
<div className="flex items-center gap-2">
|
|
27
|
-
<div className="text-theme-secondary flex h-4 w-4 items-center justify-center rounded-full">
|
|
28
|
-
{icon}
|
|
29
|
-
</div>
|
|
30
|
-
<div className="text-base font-bold text-neutral-800">{title}</div>
|
|
31
|
-
</div>
|
|
32
|
-
<div className="mb-2 text-xs text-neutral-500">{description}</div>
|
|
33
|
-
</div>
|
|
34
|
-
|
|
35
|
-
<div className={cn("flex-1", noPadding ? "" : "p-6 pt-0", className)}>
|
|
36
|
-
{children}
|
|
37
|
-
</div>
|
|
38
|
-
</div>
|
|
39
|
-
);
|
|
40
|
-
}
|
|
3
|
+
// Re-export Card as WizardBox for backward compatibility
|
|
4
|
+
export const WizardBox = Card;
|
|
@@ -7,7 +7,7 @@ import { StepComponentProps } from "../../config/types";
|
|
|
7
7
|
import { ActionButton } from "../../components/ActionButton";
|
|
8
8
|
import { UploadIcon, DocumentIcon } from "../../editor/ui/Icons";
|
|
9
9
|
import { Spinner } from "../../editor/ui/Spinner";
|
|
10
|
-
import {
|
|
10
|
+
import { Card } from "../../components/ui/card";
|
|
11
11
|
import { LinkIcon } from "lucide-react";
|
|
12
12
|
import { InputTextarea } from "primereact/inputtextarea";
|
|
13
13
|
|
|
@@ -171,12 +171,13 @@ export function CollectStep({
|
|
|
171
171
|
return (
|
|
172
172
|
<div className="absolute inset-0 overflow-auto">
|
|
173
173
|
<div className="grid grid-cols-2 gap-4">
|
|
174
|
-
<
|
|
174
|
+
<Card
|
|
175
175
|
icon={<UploadIcon className="text-theme-secondary" />}
|
|
176
176
|
title="Upload a file (optional)"
|
|
177
177
|
description="Upload a file to the page"
|
|
178
178
|
className="flex-1"
|
|
179
179
|
>
|
|
180
|
+
{error && <div className="mt-2 text-sm text-red-500">{error}</div>}
|
|
180
181
|
<div
|
|
181
182
|
className={`flex flex-col items-center justify-center border border-dashed border-gray-300 p-8 ${
|
|
182
183
|
isUploading ? "bg-gray-200" : "bg-white"
|
|
@@ -237,15 +238,13 @@ export function CollectStep({
|
|
|
237
238
|
</div>
|
|
238
239
|
</div>
|
|
239
240
|
</div>
|
|
240
|
-
</
|
|
241
|
-
<
|
|
241
|
+
</Card>
|
|
242
|
+
<Card
|
|
242
243
|
icon={<LinkIcon className="text-theme-secondary" />}
|
|
243
244
|
title="Scrape page from URL (optional)"
|
|
244
245
|
description="Upload a file to the page"
|
|
245
246
|
className="flex-1"
|
|
246
247
|
>
|
|
247
|
-
{error && <div className="mt-2 text-sm text-red-500">{error}</div>}
|
|
248
|
-
|
|
249
248
|
<div className="flex flex-col gap-2">
|
|
250
249
|
<div className="text-sm font-semibold text-gray-700">
|
|
251
250
|
<div className="text-xs font-normal text-gray-500">
|
|
@@ -273,8 +272,8 @@ export function CollectStep({
|
|
|
273
272
|
</ActionButton>
|
|
274
273
|
</div>
|
|
275
274
|
</div>
|
|
276
|
-
</
|
|
277
|
-
<
|
|
275
|
+
</Card>
|
|
276
|
+
<Card
|
|
278
277
|
icon={<DocumentIcon className="text-theme-secondary" />}
|
|
279
278
|
title="Text"
|
|
280
279
|
description="Provide the text you want to use for the page"
|
|
@@ -291,7 +290,7 @@ export function CollectStep({
|
|
|
291
290
|
}))
|
|
292
291
|
}
|
|
293
292
|
/>
|
|
294
|
-
</
|
|
293
|
+
</Card>
|
|
295
294
|
</div>
|
|
296
295
|
</div>
|
|
297
296
|
);
|
package/src/revision.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const version = "1.0.
|
|
2
|
-
export const buildDate = "2025-05-
|
|
1
|
+
export const version = "1.0.3899";
|
|
2
|
+
export const buildDate = "2025-05-26 01:54:10";
|
|
@@ -20,6 +20,8 @@ import { ItemDescriptor } from "../editor/pageModel";
|
|
|
20
20
|
import { useDebouncedCallback } from "use-debounce";
|
|
21
21
|
import { getWizards } from "../page-wizard/service";
|
|
22
22
|
import { Wizard } from "../page-wizard/PageWizard";
|
|
23
|
+
import { Card } from "../components/ui/card";
|
|
24
|
+
import { CardConnector } from "../components/ui/CardConnector";
|
|
23
25
|
export function NewPage({ selectedItemId }: { selectedItemId?: string }) {
|
|
24
26
|
const [selectedItem, setSelectedItem] = useState<ItemDescriptor | null>(null);
|
|
25
27
|
const [isValid, setIsValid] = useState<boolean>(false);
|
|
@@ -143,90 +145,115 @@ export function NewPage({ selectedItemId }: { selectedItemId?: string }) {
|
|
|
143
145
|
};
|
|
144
146
|
|
|
145
147
|
return (
|
|
146
|
-
<div className="flex h-full
|
|
147
|
-
<div className="tour-pick-location flex
|
|
148
|
-
<
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
+
>
|
|
156
|
+
<div className="relative h-full">
|
|
157
|
+
<div className="absolute inset-0 overflow-auto">
|
|
158
|
+
<ScrollingContentTree
|
|
159
|
+
selectedItemId={selectedItem?.id || selectedItemId}
|
|
160
|
+
onSelectionChange={(selection) => {
|
|
161
|
+
const selected = selection[0] as ItemTreeNodeData;
|
|
162
|
+
if (selected) setSelectedItem(selected);
|
|
163
|
+
}}
|
|
164
|
+
/>
|
|
165
|
+
</div>
|
|
158
166
|
</div>
|
|
159
|
-
</
|
|
167
|
+
</Card>
|
|
160
168
|
</div>
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
{!insertOptions?.length && (
|
|
167
|
-
<div>No page templates available here.</div>
|
|
168
|
-
)}
|
|
169
|
-
{insertOptionsAndWizards?.map((option) => (
|
|
170
|
-
<div
|
|
171
|
-
key={option.id}
|
|
172
|
-
onClick={() => setSelectedTemplate(option.id)}
|
|
173
|
-
className={classNames(
|
|
174
|
-
"mb-2 flex cursor-pointer flex-col items-center bg-gray-100 p-2 text-sm",
|
|
175
|
-
selectedTemplate === option.id
|
|
176
|
-
? "tour-selected-template bg-gray-200 outline outline-2 outline-offset-2 outline-gray-200"
|
|
177
|
-
: "bg-gray-100",
|
|
178
|
-
)}
|
|
179
|
-
>
|
|
180
|
-
{
|
|
181
|
-
<img
|
|
182
|
-
src={getAbsoluteIconUrl(option.icon)}
|
|
183
|
-
width="32"
|
|
184
|
-
height="32"
|
|
185
|
-
></img>
|
|
186
|
-
}
|
|
187
|
-
{option.name}
|
|
188
|
-
</div>
|
|
189
|
-
))}
|
|
169
|
+
|
|
170
|
+
{/* Card Connector - only visible when location is selected */}
|
|
171
|
+
{selectedItem && (
|
|
172
|
+
<div className="hidden items-start justify-center pt-10 md:flex">
|
|
173
|
+
<CardConnector />
|
|
190
174
|
</div>
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
175
|
+
)}
|
|
176
|
+
|
|
177
|
+
{/* Second card - only visible when location is selected */}
|
|
178
|
+
{selectedItem && (
|
|
179
|
+
<div className="flex-1">
|
|
180
|
+
<Card
|
|
181
|
+
icon={<i className="pi pi-palette text-sm"></i>}
|
|
182
|
+
title="Choose Template or Wizard"
|
|
183
|
+
description="Select a template or wizard to create your page"
|
|
184
|
+
>
|
|
185
|
+
<div className="tour-choose-template">
|
|
186
|
+
<div className="flex min-h-12 flex-wrap gap-3">
|
|
187
|
+
{!insertOptions?.length && (
|
|
188
|
+
<div>No page templates available here.</div>
|
|
189
|
+
)}
|
|
190
|
+
{insertOptionsAndWizards?.map((option) => (
|
|
191
|
+
<div
|
|
192
|
+
key={option.id}
|
|
193
|
+
onClick={() => setSelectedTemplate(option.id)}
|
|
194
|
+
className={classNames(
|
|
195
|
+
"mb-2 flex cursor-pointer flex-col items-center rounded bg-gray-100 p-2 text-sm",
|
|
196
|
+
selectedTemplate === option.id
|
|
197
|
+
? "tour-selected-template bg-gray-200 outline outline-2 outline-offset-2 outline-gray-200"
|
|
198
|
+
: "bg-gray-100",
|
|
199
|
+
)}
|
|
200
|
+
>
|
|
201
|
+
{
|
|
202
|
+
<img
|
|
203
|
+
src={getAbsoluteIconUrl(option.icon)}
|
|
204
|
+
width="32"
|
|
205
|
+
height="32"
|
|
206
|
+
></img>
|
|
207
|
+
}
|
|
208
|
+
{option.name}
|
|
209
|
+
</div>
|
|
210
|
+
))}
|
|
226
211
|
</div>
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
212
|
+
{selectedTemplate &&
|
|
213
|
+
wizards?.find((x) => x.id === selectedTemplate) && (
|
|
214
|
+
<div className="mt-4">
|
|
215
|
+
<Button
|
|
216
|
+
onClick={launchWizard}
|
|
217
|
+
label="Start Wizard"
|
|
218
|
+
id="launch-wizard-button"
|
|
219
|
+
/>
|
|
220
|
+
</div>
|
|
221
|
+
)}
|
|
222
|
+
{selectedTemplate &&
|
|
223
|
+
insertOptions?.find((x) => x.id === selectedTemplate) && (
|
|
224
|
+
<div className="mt-6 border-t pt-4">
|
|
225
|
+
<div className="mb-3 text-base font-bold text-neutral-800">
|
|
226
|
+
Name Your Page
|
|
227
|
+
</div>
|
|
228
|
+
<InputText
|
|
229
|
+
className="w-full"
|
|
230
|
+
value={name}
|
|
231
|
+
id="new-page-name"
|
|
232
|
+
onChange={(e) => setName(e.target.value)}
|
|
233
|
+
onKeyDown={(ev) => {
|
|
234
|
+
if (ev.key === "Enter" && isValid) handleOk();
|
|
235
|
+
}}
|
|
236
|
+
data-testid="new-page-name"
|
|
237
|
+
/>
|
|
238
|
+
{validationMessage && (
|
|
239
|
+
<div className="mt-2 text-red-500">
|
|
240
|
+
{validationMessage}
|
|
241
|
+
</div>
|
|
242
|
+
)}
|
|
243
|
+
<div className="mt-4">
|
|
244
|
+
<Button
|
|
245
|
+
onClick={handleOk}
|
|
246
|
+
label="Create"
|
|
247
|
+
disabled={!isValid}
|
|
248
|
+
id="create-new-page-button"
|
|
249
|
+
/>
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
252
|
+
)}
|
|
253
|
+
</div>
|
|
254
|
+
</Card>
|
|
255
|
+
</div>
|
|
256
|
+
)}
|
|
230
257
|
</div>
|
|
231
258
|
);
|
|
232
259
|
}
|