@pablo2410/shared-ui 0.20.0 → 0.22.0
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/{chunk-57T6QK3M.js → chunk-4ERWOH67.js} +43 -1
- package/dist/chunk-4ERWOH67.js.map +1 -0
- package/dist/services/index.d.ts +19 -2
- package/dist/services/index.js +1 -1
- package/dist/shell/index.js +1 -1
- package/dist/shell/oplytics-shell.css +1 -1
- package/dist/tour/index.d.ts +114 -5
- package/dist/tour/index.js +465 -138
- package/dist/tour/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-57T6QK3M.js.map +0 -1
package/dist/tour/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/tour/TourShell.tsx
|
|
2
|
-
import { useEffect, useRef } from "react";
|
|
2
|
+
import { useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
3
3
|
import {
|
|
4
4
|
X,
|
|
5
5
|
ChevronLeft,
|
|
@@ -7,7 +7,167 @@ import {
|
|
|
7
7
|
ArrowRight,
|
|
8
8
|
ExternalLink
|
|
9
9
|
} from "lucide-react";
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
// src/tour/useSpotlight.ts
|
|
12
|
+
import { useEffect, useRef, useState } from "react";
|
|
13
|
+
var RESIZE_DEBOUNCE_MS = 100;
|
|
14
|
+
function useSpotlight(selector) {
|
|
15
|
+
const [rect, setRect] = useState(null);
|
|
16
|
+
const [found, setFound] = useState(false);
|
|
17
|
+
const scrolledForSelector = useRef(null);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (!selector) {
|
|
20
|
+
setRect(null);
|
|
21
|
+
setFound(false);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
let resizeTimer;
|
|
25
|
+
let cancelled = false;
|
|
26
|
+
const measure = () => {
|
|
27
|
+
if (cancelled) return;
|
|
28
|
+
const el = document.querySelector(
|
|
29
|
+
`[data-tour-target="${selector}"]`
|
|
30
|
+
);
|
|
31
|
+
if (!el) {
|
|
32
|
+
setRect(null);
|
|
33
|
+
setFound(false);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const domRect = el.getBoundingClientRect();
|
|
37
|
+
setRect({
|
|
38
|
+
top: domRect.top,
|
|
39
|
+
left: domRect.left,
|
|
40
|
+
width: domRect.width,
|
|
41
|
+
height: domRect.height
|
|
42
|
+
});
|
|
43
|
+
setFound(true);
|
|
44
|
+
if (scrolledForSelector.current !== selector) {
|
|
45
|
+
scrolledForSelector.current = selector;
|
|
46
|
+
el.scrollIntoView({ block: "center", behavior: "smooth" });
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
measure();
|
|
50
|
+
const initialFrame = requestAnimationFrame(measure);
|
|
51
|
+
const onResize = () => {
|
|
52
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
53
|
+
resizeTimer = setTimeout(measure, RESIZE_DEBOUNCE_MS);
|
|
54
|
+
};
|
|
55
|
+
const onScroll = () => measure();
|
|
56
|
+
window.addEventListener("resize", onResize);
|
|
57
|
+
window.addEventListener("scroll", onScroll, { capture: true });
|
|
58
|
+
const observer = new MutationObserver(measure);
|
|
59
|
+
observer.observe(document.body, {
|
|
60
|
+
childList: true,
|
|
61
|
+
subtree: true,
|
|
62
|
+
attributes: true
|
|
63
|
+
});
|
|
64
|
+
return () => {
|
|
65
|
+
cancelled = true;
|
|
66
|
+
cancelAnimationFrame(initialFrame);
|
|
67
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
68
|
+
window.removeEventListener("resize", onResize);
|
|
69
|
+
window.removeEventListener("scroll", onScroll, { capture: true });
|
|
70
|
+
observer?.disconnect();
|
|
71
|
+
};
|
|
72
|
+
}, [selector]);
|
|
73
|
+
return { rect, found };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// src/tour/spotlightMath.ts
|
|
77
|
+
function computeSpotlightFrame(target, viewport) {
|
|
78
|
+
const targetBottom = target.top + target.height;
|
|
79
|
+
const targetRight = target.left + target.width;
|
|
80
|
+
return {
|
|
81
|
+
// Full-width strip above the target.
|
|
82
|
+
top: {
|
|
83
|
+
top: 0,
|
|
84
|
+
left: 0,
|
|
85
|
+
width: viewport.width,
|
|
86
|
+
height: Math.max(0, target.top)
|
|
87
|
+
},
|
|
88
|
+
// Full-width strip below the target.
|
|
89
|
+
bottom: {
|
|
90
|
+
top: targetBottom,
|
|
91
|
+
left: 0,
|
|
92
|
+
width: viewport.width,
|
|
93
|
+
height: Math.max(0, viewport.height - targetBottom)
|
|
94
|
+
},
|
|
95
|
+
// Strip to the left of the target, spanning only the target's own row
|
|
96
|
+
// (the top/bottom strips already cover the rest of those rows).
|
|
97
|
+
left: {
|
|
98
|
+
top: target.top,
|
|
99
|
+
left: 0,
|
|
100
|
+
width: Math.max(0, target.left),
|
|
101
|
+
height: target.height
|
|
102
|
+
},
|
|
103
|
+
// Strip to the right of the target, same row-only span as `left`.
|
|
104
|
+
right: {
|
|
105
|
+
top: target.top,
|
|
106
|
+
left: targetRight,
|
|
107
|
+
width: Math.max(0, viewport.width - targetRight),
|
|
108
|
+
height: target.height
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
var FALLBACK_ORDER = {
|
|
113
|
+
bottom: ["bottom", "top", "right", "left"],
|
|
114
|
+
top: ["top", "bottom", "right", "left"],
|
|
115
|
+
right: ["right", "left", "bottom", "top"],
|
|
116
|
+
left: ["left", "right", "bottom", "top"]
|
|
117
|
+
};
|
|
118
|
+
var AUTO_ORDER = FALLBACK_ORDER.bottom;
|
|
119
|
+
var PANEL_GAP = 12;
|
|
120
|
+
function computePanelPosition(target, panelSize, viewport, placement = "auto") {
|
|
121
|
+
const order = placement === "auto" ? AUTO_ORDER : FALLBACK_ORDER[placement];
|
|
122
|
+
for (const candidate of order) {
|
|
123
|
+
const pos2 = placeAt(candidate, target, panelSize);
|
|
124
|
+
if (fits(pos2, panelSize, viewport)) {
|
|
125
|
+
return { ...pos2, placement: candidate };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const fallback = order[0];
|
|
129
|
+
const pos = placeAt(fallback, target, panelSize);
|
|
130
|
+
return {
|
|
131
|
+
top: clamp(pos.top, 0, Math.max(0, viewport.height - panelSize.height)),
|
|
132
|
+
left: clamp(pos.left, 0, Math.max(0, viewport.width - panelSize.width)),
|
|
133
|
+
placement: fallback
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function placeAt(side, target, panelSize) {
|
|
137
|
+
const targetCenterX = target.left + target.width / 2;
|
|
138
|
+
const targetCenterY = target.top + target.height / 2;
|
|
139
|
+
switch (side) {
|
|
140
|
+
case "bottom":
|
|
141
|
+
return {
|
|
142
|
+
top: target.top + target.height + PANEL_GAP,
|
|
143
|
+
left: targetCenterX - panelSize.width / 2
|
|
144
|
+
};
|
|
145
|
+
case "top":
|
|
146
|
+
return {
|
|
147
|
+
top: target.top - panelSize.height - PANEL_GAP,
|
|
148
|
+
left: targetCenterX - panelSize.width / 2
|
|
149
|
+
};
|
|
150
|
+
case "right":
|
|
151
|
+
return {
|
|
152
|
+
top: targetCenterY - panelSize.height / 2,
|
|
153
|
+
left: target.left + target.width + PANEL_GAP
|
|
154
|
+
};
|
|
155
|
+
case "left":
|
|
156
|
+
return {
|
|
157
|
+
top: targetCenterY - panelSize.height / 2,
|
|
158
|
+
left: target.left - panelSize.width - PANEL_GAP
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function fits(pos, panelSize, viewport) {
|
|
163
|
+
return pos.top >= 0 && pos.left >= 0 && pos.top + panelSize.height <= viewport.height && pos.left + panelSize.width <= viewport.width;
|
|
164
|
+
}
|
|
165
|
+
function clamp(value, min, max) {
|
|
166
|
+
return Math.min(Math.max(value, min), max);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/tour/TourShell.tsx
|
|
170
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11
171
|
var defaultSkin = {
|
|
12
172
|
accent: "#8C34E9",
|
|
13
173
|
overlayBg: "rgba(10,14,26,0.72)",
|
|
@@ -17,6 +177,7 @@ var defaultSkin = {
|
|
|
17
177
|
bodyText: "#c0c6d0",
|
|
18
178
|
softText: "#8890a0"
|
|
19
179
|
};
|
|
180
|
+
var SPOTLIGHT_PANEL_SIZE = { width: 320, height: 280 };
|
|
20
181
|
function TourShell({
|
|
21
182
|
step,
|
|
22
183
|
index,
|
|
@@ -30,19 +191,124 @@ function TourShell({
|
|
|
30
191
|
narrationPending,
|
|
31
192
|
children,
|
|
32
193
|
skin = defaultSkin,
|
|
33
|
-
orb
|
|
194
|
+
orb,
|
|
195
|
+
onSpotlightTargetActivated
|
|
34
196
|
}) {
|
|
35
|
-
const panelRef =
|
|
36
|
-
|
|
197
|
+
const panelRef = useRef2(null);
|
|
198
|
+
const { rect, found } = useSpotlight(step.spotlight?.selector ?? null);
|
|
199
|
+
const isSpotlight = Boolean(step.spotlight) && found && rect !== null;
|
|
200
|
+
useEffect2(() => {
|
|
37
201
|
const onKeyDown = (e) => {
|
|
38
202
|
if (e.key === "Escape") onDismiss();
|
|
39
203
|
};
|
|
40
204
|
document.addEventListener("keydown", onKeyDown);
|
|
41
205
|
return () => document.removeEventListener("keydown", onKeyDown);
|
|
42
206
|
}, [onDismiss]);
|
|
43
|
-
|
|
207
|
+
useEffect2(() => {
|
|
44
208
|
panelRef.current?.focus();
|
|
45
209
|
}, [step.id]);
|
|
210
|
+
useEffect2(() => {
|
|
211
|
+
if (!isSpotlight || !onSpotlightTargetActivated || !step.spotlight) return;
|
|
212
|
+
const selector = step.spotlight.selector;
|
|
213
|
+
const onClickCapture = (e) => {
|
|
214
|
+
const target = e.target;
|
|
215
|
+
if (target?.closest(`[data-tour-target="${selector}"]`)) {
|
|
216
|
+
onSpotlightTargetActivated();
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
document.addEventListener("click", onClickCapture, { capture: true });
|
|
220
|
+
return () => document.removeEventListener("click", onClickCapture, {
|
|
221
|
+
capture: true
|
|
222
|
+
});
|
|
223
|
+
}, [isSpotlight, onSpotlightTargetActivated, step.spotlight]);
|
|
224
|
+
if (isSpotlight && rect) {
|
|
225
|
+
const viewport = { width: window.innerWidth, height: window.innerHeight };
|
|
226
|
+
const frame = computeSpotlightFrame(rect, viewport);
|
|
227
|
+
const panelPos = computePanelPosition(
|
|
228
|
+
rect,
|
|
229
|
+
SPOTLIGHT_PANEL_SIZE,
|
|
230
|
+
viewport,
|
|
231
|
+
step.spotlight?.placement ?? "auto"
|
|
232
|
+
);
|
|
233
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
234
|
+
["top", "bottom", "left", "right"].map((side) => {
|
|
235
|
+
const segment = frame[side];
|
|
236
|
+
if (segment.width <= 0 || segment.height <= 0) return null;
|
|
237
|
+
return /* @__PURE__ */ jsx(
|
|
238
|
+
"div",
|
|
239
|
+
{
|
|
240
|
+
className: "fixed z-50",
|
|
241
|
+
style: {
|
|
242
|
+
top: segment.top,
|
|
243
|
+
left: segment.left,
|
|
244
|
+
width: segment.width,
|
|
245
|
+
height: segment.height,
|
|
246
|
+
background: skin.overlayBg
|
|
247
|
+
},
|
|
248
|
+
onClick: onDismiss
|
|
249
|
+
},
|
|
250
|
+
side
|
|
251
|
+
);
|
|
252
|
+
}),
|
|
253
|
+
/* @__PURE__ */ jsx(
|
|
254
|
+
"div",
|
|
255
|
+
{
|
|
256
|
+
className: "fixed z-50 rounded-xl pointer-events-none transition-all",
|
|
257
|
+
style: {
|
|
258
|
+
top: rect.top - 4,
|
|
259
|
+
left: rect.left - 4,
|
|
260
|
+
width: rect.width + 8,
|
|
261
|
+
height: rect.height + 8,
|
|
262
|
+
boxShadow: `0 0 0 2px ${skin.accent}, 0 0 24px 4px ${skin.accent}66`
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
),
|
|
266
|
+
/* @__PURE__ */ jsxs(
|
|
267
|
+
"div",
|
|
268
|
+
{
|
|
269
|
+
ref: panelRef,
|
|
270
|
+
tabIndex: -1,
|
|
271
|
+
role: "dialog",
|
|
272
|
+
"aria-modal": "true",
|
|
273
|
+
"aria-label": step.label,
|
|
274
|
+
className: "fixed z-50 rounded-xl overflow-hidden flex flex-col outline-none",
|
|
275
|
+
style: {
|
|
276
|
+
top: panelPos.top,
|
|
277
|
+
left: panelPos.left,
|
|
278
|
+
width: SPOTLIGHT_PANEL_SIZE.width,
|
|
279
|
+
maxHeight: SPOTLIGHT_PANEL_SIZE.height,
|
|
280
|
+
background: skin.panelBg,
|
|
281
|
+
border: skin.panelBorder
|
|
282
|
+
},
|
|
283
|
+
children: [
|
|
284
|
+
/* @__PURE__ */ jsx(TourShellHeader, { step, orb, onDismiss }),
|
|
285
|
+
/* @__PURE__ */ jsx(TourShellStepDots, { total, index, skin }),
|
|
286
|
+
/* @__PURE__ */ jsx("div", { className: "overflow-y-auto px-4 py-3 space-y-3", children: /* @__PURE__ */ jsx(
|
|
287
|
+
TourShellBody,
|
|
288
|
+
{
|
|
289
|
+
step,
|
|
290
|
+
narration,
|
|
291
|
+
narrationPending,
|
|
292
|
+
skin,
|
|
293
|
+
children
|
|
294
|
+
}
|
|
295
|
+
) }),
|
|
296
|
+
/* @__PURE__ */ jsx(
|
|
297
|
+
TourShellFooter,
|
|
298
|
+
{
|
|
299
|
+
isFirst,
|
|
300
|
+
isLast,
|
|
301
|
+
onNext,
|
|
302
|
+
onBack,
|
|
303
|
+
onDismiss,
|
|
304
|
+
skin
|
|
305
|
+
}
|
|
306
|
+
)
|
|
307
|
+
]
|
|
308
|
+
}
|
|
309
|
+
)
|
|
310
|
+
] });
|
|
311
|
+
}
|
|
46
312
|
return /* @__PURE__ */ jsx(
|
|
47
313
|
"div",
|
|
48
314
|
{
|
|
@@ -62,140 +328,27 @@ function TourShell({
|
|
|
62
328
|
className: "w-full max-w-md rounded-xl overflow-hidden flex flex-col max-h-[85vh] outline-none",
|
|
63
329
|
style: { background: skin.panelBg, border: skin.panelBorder },
|
|
64
330
|
children: [
|
|
65
|
-
/* @__PURE__ */
|
|
66
|
-
|
|
331
|
+
/* @__PURE__ */ jsx(TourShellHeader, { step, orb, onDismiss }),
|
|
332
|
+
/* @__PURE__ */ jsx(TourShellStepDots, { total, index, skin }),
|
|
333
|
+
/* @__PURE__ */ jsx("div", { className: "overflow-y-auto px-5 py-4 space-y-4", children: /* @__PURE__ */ jsx(
|
|
334
|
+
TourShellBody,
|
|
67
335
|
{
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
children
|
|
73
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 min-w-0", children: [
|
|
74
|
-
orb,
|
|
75
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-white truncate", children: step.label })
|
|
76
|
-
] }),
|
|
77
|
-
/* @__PURE__ */ jsx(
|
|
78
|
-
"button",
|
|
79
|
-
{
|
|
80
|
-
onClick: onDismiss,
|
|
81
|
-
className: "p-1 rounded hover:bg-white/10 transition-colors shrink-0",
|
|
82
|
-
title: "Skip tour",
|
|
83
|
-
children: /* @__PURE__ */ jsx(X, { size: 16, className: "text-white/70" })
|
|
84
|
-
}
|
|
85
|
-
)
|
|
86
|
-
]
|
|
336
|
+
step,
|
|
337
|
+
narration,
|
|
338
|
+
narrationPending,
|
|
339
|
+
skin,
|
|
340
|
+
children
|
|
87
341
|
}
|
|
88
|
-
),
|
|
342
|
+
) }),
|
|
89
343
|
/* @__PURE__ */ jsx(
|
|
90
|
-
|
|
91
|
-
{
|
|
92
|
-
className: "flex items-center gap-1.5 px-5 py-3 shrink-0",
|
|
93
|
-
style: { borderBottom: skin.panelBorder },
|
|
94
|
-
children: Array.from({ length: total }, (_, i) => /* @__PURE__ */ jsx(
|
|
95
|
-
"span",
|
|
96
|
-
{
|
|
97
|
-
className: "h-1.5 rounded-full transition-all",
|
|
98
|
-
style: {
|
|
99
|
-
width: i === index ? 20 : 8,
|
|
100
|
-
background: i === index ? skin.accent : skin.mutedText,
|
|
101
|
-
opacity: i === index ? 1 : 0.4
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
i
|
|
105
|
-
))
|
|
106
|
-
}
|
|
107
|
-
),
|
|
108
|
-
/* @__PURE__ */ jsxs("div", { className: "overflow-y-auto px-5 py-4 space-y-4", children: [
|
|
109
|
-
/* @__PURE__ */ jsx(
|
|
110
|
-
"p",
|
|
111
|
-
{
|
|
112
|
-
className: "text-[13px] leading-relaxed transition-opacity",
|
|
113
|
-
style: {
|
|
114
|
-
color: skin.bodyText,
|
|
115
|
-
opacity: narrationPending ? 0.7 : 1
|
|
116
|
-
},
|
|
117
|
-
children: narration
|
|
118
|
-
}
|
|
119
|
-
),
|
|
120
|
-
step.highlights && step.highlights.length > 0 && /* @__PURE__ */ jsx("ul", { className: "space-y-1.5", children: step.highlights.map((h, i) => /* @__PURE__ */ jsxs(
|
|
121
|
-
"li",
|
|
122
|
-
{
|
|
123
|
-
className: "text-[12.5px] leading-relaxed pl-3 relative",
|
|
124
|
-
style: { color: skin.softText },
|
|
125
|
-
children: [
|
|
126
|
-
/* @__PURE__ */ jsx(
|
|
127
|
-
"span",
|
|
128
|
-
{
|
|
129
|
-
className: "absolute left-0",
|
|
130
|
-
style: { color: skin.mutedText },
|
|
131
|
-
children: "\u2022"
|
|
132
|
-
}
|
|
133
|
-
),
|
|
134
|
-
h
|
|
135
|
-
]
|
|
136
|
-
},
|
|
137
|
-
i
|
|
138
|
-
)) }),
|
|
139
|
-
step.action && /* @__PURE__ */ jsxs(
|
|
140
|
-
"a",
|
|
141
|
-
{
|
|
142
|
-
href: step.action.href,
|
|
143
|
-
target: step.action.external ? "_blank" : void 0,
|
|
144
|
-
rel: step.action.external ? "noopener noreferrer" : void 0,
|
|
145
|
-
className: "inline-flex items-center gap-1.5 px-3.5 py-2 rounded-lg text-[13px] font-semibold transition-opacity hover:opacity-90",
|
|
146
|
-
style: { background: `${skin.accent}20`, color: skin.accent },
|
|
147
|
-
children: [
|
|
148
|
-
step.action.label,
|
|
149
|
-
step.action.external ? /* @__PURE__ */ jsx(ExternalLink, { size: 13 }) : /* @__PURE__ */ jsx(ArrowRight, { size: 13 })
|
|
150
|
-
]
|
|
151
|
-
}
|
|
152
|
-
),
|
|
153
|
-
children
|
|
154
|
-
] }),
|
|
155
|
-
/* @__PURE__ */ jsxs(
|
|
156
|
-
"div",
|
|
344
|
+
TourShellFooter,
|
|
157
345
|
{
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
onClick: onDismiss,
|
|
165
|
-
className: "text-[12px] font-medium transition-colors hover:underline",
|
|
166
|
-
style: { color: skin.mutedText },
|
|
167
|
-
children: "Skip tour"
|
|
168
|
-
}
|
|
169
|
-
),
|
|
170
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
171
|
-
!isFirst && /* @__PURE__ */ jsxs(
|
|
172
|
-
"button",
|
|
173
|
-
{
|
|
174
|
-
onClick: onBack,
|
|
175
|
-
className: "flex items-center gap-1 px-3 py-1.5 rounded-md text-[12.5px] font-medium transition-colors",
|
|
176
|
-
style: { color: skin.bodyText, border: skin.panelBorder },
|
|
177
|
-
children: [
|
|
178
|
-
/* @__PURE__ */ jsx(ChevronLeft, { size: 13 }),
|
|
179
|
-
"Back"
|
|
180
|
-
]
|
|
181
|
-
}
|
|
182
|
-
),
|
|
183
|
-
/* @__PURE__ */ jsxs(
|
|
184
|
-
"button",
|
|
185
|
-
{
|
|
186
|
-
onClick: onNext,
|
|
187
|
-
className: "flex items-center gap-1 px-3.5 py-1.5 rounded-md text-[12.5px] font-bold text-white transition-opacity hover:opacity-90",
|
|
188
|
-
style: {
|
|
189
|
-
background: "linear-gradient(135deg, #8C34E9 0%, #5B1FA6 100%)"
|
|
190
|
-
},
|
|
191
|
-
children: [
|
|
192
|
-
isLast ? "Done" : "Next",
|
|
193
|
-
!isLast && /* @__PURE__ */ jsx(ChevronRight, { size: 13 })
|
|
194
|
-
]
|
|
195
|
-
}
|
|
196
|
-
)
|
|
197
|
-
] })
|
|
198
|
-
]
|
|
346
|
+
isFirst,
|
|
347
|
+
isLast,
|
|
348
|
+
onNext,
|
|
349
|
+
onBack,
|
|
350
|
+
onDismiss,
|
|
351
|
+
skin
|
|
199
352
|
}
|
|
200
353
|
)
|
|
201
354
|
]
|
|
@@ -204,9 +357,180 @@ function TourShell({
|
|
|
204
357
|
}
|
|
205
358
|
);
|
|
206
359
|
}
|
|
360
|
+
function TourShellHeader({
|
|
361
|
+
step,
|
|
362
|
+
orb,
|
|
363
|
+
onDismiss
|
|
364
|
+
}) {
|
|
365
|
+
return /* @__PURE__ */ jsxs(
|
|
366
|
+
"div",
|
|
367
|
+
{
|
|
368
|
+
className: "flex items-center justify-between gap-3 px-5 py-4 shrink-0",
|
|
369
|
+
style: {
|
|
370
|
+
background: "linear-gradient(135deg, #2a1450 0%, #1a0e33 100%)"
|
|
371
|
+
},
|
|
372
|
+
children: [
|
|
373
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 min-w-0", children: [
|
|
374
|
+
orb,
|
|
375
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-white truncate", children: step.label })
|
|
376
|
+
] }),
|
|
377
|
+
/* @__PURE__ */ jsx(
|
|
378
|
+
"button",
|
|
379
|
+
{
|
|
380
|
+
onClick: onDismiss,
|
|
381
|
+
className: "p-1 rounded hover:bg-white/10 transition-colors shrink-0",
|
|
382
|
+
title: "Skip tour",
|
|
383
|
+
children: /* @__PURE__ */ jsx(X, { size: 16, className: "text-white/70" })
|
|
384
|
+
}
|
|
385
|
+
)
|
|
386
|
+
]
|
|
387
|
+
}
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
function TourShellStepDots({
|
|
391
|
+
total,
|
|
392
|
+
index,
|
|
393
|
+
skin
|
|
394
|
+
}) {
|
|
395
|
+
return /* @__PURE__ */ jsx(
|
|
396
|
+
"div",
|
|
397
|
+
{
|
|
398
|
+
className: "flex items-center gap-1.5 px-5 py-3 shrink-0",
|
|
399
|
+
style: { borderBottom: skin.panelBorder },
|
|
400
|
+
children: Array.from({ length: total }, (_, i) => /* @__PURE__ */ jsx(
|
|
401
|
+
"span",
|
|
402
|
+
{
|
|
403
|
+
className: "h-1.5 rounded-full transition-all",
|
|
404
|
+
style: {
|
|
405
|
+
width: i === index ? 20 : 8,
|
|
406
|
+
background: i === index ? skin.accent : skin.mutedText,
|
|
407
|
+
opacity: i === index ? 1 : 0.4
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
i
|
|
411
|
+
))
|
|
412
|
+
}
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
function TourShellBody({
|
|
416
|
+
step,
|
|
417
|
+
narration,
|
|
418
|
+
narrationPending,
|
|
419
|
+
skin,
|
|
420
|
+
children
|
|
421
|
+
}) {
|
|
422
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
423
|
+
/* @__PURE__ */ jsx(
|
|
424
|
+
"p",
|
|
425
|
+
{
|
|
426
|
+
className: "text-[13px] leading-relaxed transition-opacity",
|
|
427
|
+
style: {
|
|
428
|
+
color: skin.bodyText,
|
|
429
|
+
opacity: narrationPending ? 0.7 : 1
|
|
430
|
+
},
|
|
431
|
+
children: narration
|
|
432
|
+
}
|
|
433
|
+
),
|
|
434
|
+
step.features && step.features.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "space-y-2", children: step.features.map((f, i) => /* @__PURE__ */ jsxs("li", { className: "text-[12.5px] leading-relaxed", children: [
|
|
435
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold", style: { color: skin.accent }, children: f.name }),
|
|
436
|
+
/* @__PURE__ */ jsxs("span", { style: { color: skin.softText }, children: [
|
|
437
|
+
" \u2014 ",
|
|
438
|
+
f.detail
|
|
439
|
+
] })
|
|
440
|
+
] }, i)) }) : step.highlights && step.highlights.length > 0 && /* @__PURE__ */ jsx("ul", { className: "space-y-1.5", children: step.highlights.map((h, i) => /* @__PURE__ */ jsxs(
|
|
441
|
+
"li",
|
|
442
|
+
{
|
|
443
|
+
className: "text-[12.5px] leading-relaxed pl-3 relative",
|
|
444
|
+
style: { color: skin.softText },
|
|
445
|
+
children: [
|
|
446
|
+
/* @__PURE__ */ jsx(
|
|
447
|
+
"span",
|
|
448
|
+
{
|
|
449
|
+
className: "absolute left-0",
|
|
450
|
+
style: { color: skin.mutedText },
|
|
451
|
+
children: "\u2022"
|
|
452
|
+
}
|
|
453
|
+
),
|
|
454
|
+
h
|
|
455
|
+
]
|
|
456
|
+
},
|
|
457
|
+
i
|
|
458
|
+
)) }),
|
|
459
|
+
step.action && /* @__PURE__ */ jsxs(
|
|
460
|
+
"a",
|
|
461
|
+
{
|
|
462
|
+
href: step.action.href,
|
|
463
|
+
target: step.action.external ? "_blank" : void 0,
|
|
464
|
+
rel: step.action.external ? "noopener noreferrer" : void 0,
|
|
465
|
+
className: "inline-flex items-center gap-1.5 px-3.5 py-2 rounded-lg text-[13px] font-semibold transition-opacity hover:opacity-90",
|
|
466
|
+
style: { background: `${skin.accent}20`, color: skin.accent },
|
|
467
|
+
children: [
|
|
468
|
+
step.action.label,
|
|
469
|
+
step.action.external ? /* @__PURE__ */ jsx(ExternalLink, { size: 13 }) : /* @__PURE__ */ jsx(ArrowRight, { size: 13 })
|
|
470
|
+
]
|
|
471
|
+
}
|
|
472
|
+
),
|
|
473
|
+
children
|
|
474
|
+
] });
|
|
475
|
+
}
|
|
476
|
+
function TourShellFooter({
|
|
477
|
+
isFirst,
|
|
478
|
+
isLast,
|
|
479
|
+
onNext,
|
|
480
|
+
onBack,
|
|
481
|
+
onDismiss,
|
|
482
|
+
skin
|
|
483
|
+
}) {
|
|
484
|
+
return /* @__PURE__ */ jsxs(
|
|
485
|
+
"div",
|
|
486
|
+
{
|
|
487
|
+
className: "flex items-center justify-between gap-2 px-5 py-3.5 shrink-0",
|
|
488
|
+
style: { borderTop: skin.panelBorder },
|
|
489
|
+
children: [
|
|
490
|
+
/* @__PURE__ */ jsx(
|
|
491
|
+
"button",
|
|
492
|
+
{
|
|
493
|
+
onClick: onDismiss,
|
|
494
|
+
className: "text-[12px] font-medium transition-colors hover:underline",
|
|
495
|
+
style: { color: skin.mutedText },
|
|
496
|
+
children: "Skip tour"
|
|
497
|
+
}
|
|
498
|
+
),
|
|
499
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
500
|
+
!isFirst && /* @__PURE__ */ jsxs(
|
|
501
|
+
"button",
|
|
502
|
+
{
|
|
503
|
+
onClick: onBack,
|
|
504
|
+
className: "flex items-center gap-1 px-3 py-1.5 rounded-md text-[12.5px] font-medium transition-colors",
|
|
505
|
+
style: { color: skin.bodyText, border: skin.panelBorder },
|
|
506
|
+
children: [
|
|
507
|
+
/* @__PURE__ */ jsx(ChevronLeft, { size: 13 }),
|
|
508
|
+
"Back"
|
|
509
|
+
]
|
|
510
|
+
}
|
|
511
|
+
),
|
|
512
|
+
/* @__PURE__ */ jsxs(
|
|
513
|
+
"button",
|
|
514
|
+
{
|
|
515
|
+
onClick: onNext,
|
|
516
|
+
className: "flex items-center gap-1 px-3.5 py-1.5 rounded-md text-[12.5px] font-bold text-white transition-opacity hover:opacity-90",
|
|
517
|
+
style: {
|
|
518
|
+
background: "linear-gradient(135deg, #8C34E9 0%, #5B1FA6 100%)"
|
|
519
|
+
},
|
|
520
|
+
children: [
|
|
521
|
+
isLast ? "Done" : "Next",
|
|
522
|
+
!isLast && /* @__PURE__ */ jsx(ChevronRight, { size: 13 })
|
|
523
|
+
]
|
|
524
|
+
}
|
|
525
|
+
)
|
|
526
|
+
] })
|
|
527
|
+
]
|
|
528
|
+
}
|
|
529
|
+
);
|
|
530
|
+
}
|
|
207
531
|
|
|
208
532
|
// src/tour/useTour.ts
|
|
209
|
-
import { useCallback, useState } from "react";
|
|
533
|
+
import { useCallback, useState as useState2 } from "react";
|
|
210
534
|
|
|
211
535
|
// src/tour/tourMachine.ts
|
|
212
536
|
function resolveInitialIndex(steps, initialStepId) {
|
|
@@ -233,7 +557,7 @@ function useTour(steps, opts = {}) {
|
|
|
233
557
|
if (steps.length === 0) {
|
|
234
558
|
throw new Error("useTour requires at least one step");
|
|
235
559
|
}
|
|
236
|
-
const [index, setIndex] =
|
|
560
|
+
const [index, setIndex] = useState2(
|
|
237
561
|
() => resolveInitialIndex(steps, opts.initialStepId)
|
|
238
562
|
);
|
|
239
563
|
const next = useCallback(() => {
|
|
@@ -277,6 +601,9 @@ function useTour(steps, opts = {}) {
|
|
|
277
601
|
}
|
|
278
602
|
export {
|
|
279
603
|
TourShell,
|
|
604
|
+
computePanelPosition,
|
|
605
|
+
computeSpotlightFrame,
|
|
606
|
+
useSpotlight,
|
|
280
607
|
useTour
|
|
281
608
|
};
|
|
282
609
|
//# sourceMappingURL=index.js.map
|