@ohhwells/bridge 0.1.29-next.20 → 0.1.29
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/README.md +304 -304
- package/dist/index.cjs +215 -1302
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -7
- package/dist/index.d.ts +1 -7
- package/dist/index.js +191 -1277
- package/dist/index.js.map +1 -1
- package/dist/styles.css +12 -453
- package/package.json +47 -48
package/dist/index.js
CHANGED
|
@@ -1,752 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/OhhwellsBridge.tsx
|
|
4
|
-
import
|
|
5
|
-
import { createRoot } from "react-dom/client";
|
|
6
|
-
import { flushSync } from "react-dom";
|
|
7
|
-
|
|
8
|
-
// src/ui/SchedulingWidget.tsx
|
|
9
|
-
import { useEffect, useMemo, useRef, useState as useState2 } from "react";
|
|
10
|
-
|
|
11
|
-
// src/ui/EmailCaptureModal.tsx
|
|
12
|
-
import { useState } from "react";
|
|
13
|
-
import { Dialog } from "radix-ui";
|
|
14
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
-
function Spinner() {
|
|
16
|
-
return /* @__PURE__ */ jsxs(
|
|
17
|
-
"svg",
|
|
18
|
-
{
|
|
19
|
-
width: "32",
|
|
20
|
-
height: "32",
|
|
21
|
-
viewBox: "0 0 32 32",
|
|
22
|
-
fill: "none",
|
|
23
|
-
style: { animation: "ohw-spin 0.75s linear infinite" },
|
|
24
|
-
children: [
|
|
25
|
-
/* @__PURE__ */ jsx("style", { children: `@keyframes ohw-spin { to { transform: rotate(360deg); } }` }),
|
|
26
|
-
/* @__PURE__ */ jsx("circle", { cx: "16", cy: "16", r: "12", stroke: "#e5e7eb", strokeWidth: "3" }),
|
|
27
|
-
/* @__PURE__ */ jsx(
|
|
28
|
-
"path",
|
|
29
|
-
{
|
|
30
|
-
d: "M16 4a12 12 0 0 1 12 12",
|
|
31
|
-
stroke: "#3b82f6",
|
|
32
|
-
strokeWidth: "3",
|
|
33
|
-
strokeLinecap: "round"
|
|
34
|
-
}
|
|
35
|
-
)
|
|
36
|
-
]
|
|
37
|
-
}
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
41
|
-
const [email, setEmail] = useState("");
|
|
42
|
-
const [submittedEmail, setSubmittedEmail] = useState("");
|
|
43
|
-
const [loading, setLoading] = useState(false);
|
|
44
|
-
const [success, setSuccess] = useState(false);
|
|
45
|
-
const [error, setError] = useState(null);
|
|
46
|
-
const isBook = title === "Confirm your spot";
|
|
47
|
-
const handleSubmit = async () => {
|
|
48
|
-
if (!email.trim()) return;
|
|
49
|
-
setLoading(true);
|
|
50
|
-
setError(null);
|
|
51
|
-
try {
|
|
52
|
-
await onSubmit(email.trim());
|
|
53
|
-
setSubmittedEmail(email.trim());
|
|
54
|
-
setSuccess(true);
|
|
55
|
-
} catch (e) {
|
|
56
|
-
setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
|
|
57
|
-
} finally {
|
|
58
|
-
setLoading(false);
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
const handleKeyDown = (e) => {
|
|
62
|
-
if (e.key === "Enter" && !loading) handleSubmit();
|
|
63
|
-
};
|
|
64
|
-
return /* @__PURE__ */ jsx(Dialog.Root, { open: true, onOpenChange: (open) => {
|
|
65
|
-
if (!open) onClose();
|
|
66
|
-
}, children: /* @__PURE__ */ jsxs(Dialog.Portal, { children: [
|
|
67
|
-
/* @__PURE__ */ jsx(
|
|
68
|
-
Dialog.Overlay,
|
|
69
|
-
{
|
|
70
|
-
className: "fixed inset-0 z-50",
|
|
71
|
-
style: { background: "rgba(0,0,0,0.45)" }
|
|
72
|
-
}
|
|
73
|
-
),
|
|
74
|
-
/* @__PURE__ */ jsxs(
|
|
75
|
-
Dialog.Content,
|
|
76
|
-
{
|
|
77
|
-
className: "fixed left-1/2 top-1/2 z-50 w-full -translate-x-1/2 -translate-y-1/2 bg-white rounded-xl shadow-xl outline-none font-body box-border overflow-hidden",
|
|
78
|
-
style: { maxWidth: 400 },
|
|
79
|
-
children: [
|
|
80
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3 p-6", children: [
|
|
81
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
82
|
-
/* @__PURE__ */ jsx(
|
|
83
|
-
Dialog.Title,
|
|
84
|
-
{
|
|
85
|
-
className: "font-body text-xl font-bold m-0 leading-tight",
|
|
86
|
-
style: { color: "var(--color-dark,#200C02)" },
|
|
87
|
-
children: success ? isBook ? "Reservation confirmed!" : "You're on the waitlist!" : title
|
|
88
|
-
}
|
|
89
|
-
),
|
|
90
|
-
/* @__PURE__ */ jsx(
|
|
91
|
-
Dialog.Description,
|
|
92
|
-
{
|
|
93
|
-
className: "font-body text-sm m-0",
|
|
94
|
-
style: { color: "#6B7280" },
|
|
95
|
-
children: success ? isBook ? `A confirmation email has been sent to ${submittedEmail}.` : "We'll let you know via email if someone cancels." : subtitle
|
|
96
|
-
}
|
|
97
|
-
)
|
|
98
|
-
] }),
|
|
99
|
-
/* @__PURE__ */ jsx(
|
|
100
|
-
Dialog.Close,
|
|
101
|
-
{
|
|
102
|
-
className: "shrink-0 w-7 h-7 flex items-center justify-center rounded-full bg-transparent border-none cursor-pointer mt-0.5 absolute top-2.5 right-1.5",
|
|
103
|
-
style: { color: "#6B7280" },
|
|
104
|
-
"aria-label": "Close",
|
|
105
|
-
children: /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
106
|
-
/* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
107
|
-
/* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
108
|
-
] })
|
|
109
|
-
}
|
|
110
|
-
)
|
|
111
|
-
] }),
|
|
112
|
-
!success && (loading ? (
|
|
113
|
-
/* Loading state — full body replaced */
|
|
114
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-3 px-7 py-12", children: [
|
|
115
|
-
/* @__PURE__ */ jsx(Spinner, {}),
|
|
116
|
-
/* @__PURE__ */ jsx("p", { className: "font-body text-sm m-0", style: { color: "#6B7280" }, children: "Please wait" })
|
|
117
|
-
] })
|
|
118
|
-
) : (
|
|
119
|
-
/* Email form */
|
|
120
|
-
/* @__PURE__ */ jsxs("div", { className: "px-7 pt-2 pb-6", children: [
|
|
121
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 mb-8", children: [
|
|
122
|
-
/* @__PURE__ */ jsx("label", { className: "font-body text-sm font-medium", style: { color: "var(--color-dark,#200C02)" }, children: "Email" }),
|
|
123
|
-
/* @__PURE__ */ jsx(
|
|
124
|
-
"input",
|
|
125
|
-
{
|
|
126
|
-
type: "email",
|
|
127
|
-
value: email,
|
|
128
|
-
onChange: (e) => setEmail(e.target.value),
|
|
129
|
-
onKeyDown: handleKeyDown,
|
|
130
|
-
placeholder: "hello@gmail.com",
|
|
131
|
-
autoFocus: true,
|
|
132
|
-
className: "w-full h-10 px-3 rounded-lg border font-body text-sm outline-none box-border",
|
|
133
|
-
style: {
|
|
134
|
-
borderColor: "#E7E5E4",
|
|
135
|
-
background: "#fff",
|
|
136
|
-
color: "var(--color-dark,#200C02)"
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
),
|
|
140
|
-
error && /* @__PURE__ */ jsx("p", { className: "font-body text-xs text-red-500 m-0", children: error })
|
|
141
|
-
] }),
|
|
142
|
-
/* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(
|
|
143
|
-
"button",
|
|
144
|
-
{
|
|
145
|
-
onClick: handleSubmit,
|
|
146
|
-
disabled: !email.trim(),
|
|
147
|
-
className: "h-9 px-5 rounded-lg font-body text-sm font-semibold cursor-pointer border-none disabled:opacity-50 disabled:cursor-not-allowed",
|
|
148
|
-
style: {
|
|
149
|
-
background: "var(--color-primary,#3D312B)",
|
|
150
|
-
color: "var(--color-light,#FEFFF0)"
|
|
151
|
-
},
|
|
152
|
-
children: "Send"
|
|
153
|
-
}
|
|
154
|
-
) })
|
|
155
|
-
] })
|
|
156
|
-
))
|
|
157
|
-
]
|
|
158
|
-
}
|
|
159
|
-
)
|
|
160
|
-
] }) });
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// src/ui/SchedulingWidget.tsx
|
|
164
|
-
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
165
|
-
var API_URL = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
166
|
-
var DAY_ABBR = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
|
|
167
|
-
function getApiDomain() {
|
|
168
|
-
const h = window.location.hostname;
|
|
169
|
-
for (const base of ["ohhwells.site", "theflowops-staging.com", "theflowops.com"]) {
|
|
170
|
-
if (h.endsWith(`.${base}`)) return h.slice(0, -(base.length + 1));
|
|
171
|
-
}
|
|
172
|
-
return h;
|
|
173
|
-
}
|
|
174
|
-
function classRunsOnDate(cls, date, type) {
|
|
175
|
-
if (type === "FIXED") {
|
|
176
|
-
const d = String(date.getDate()).padStart(2, "0");
|
|
177
|
-
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
178
|
-
return cls.fixedDates?.some((fd) => fd.date === `${d}-${m}-${date.getFullYear()}`) ?? false;
|
|
179
|
-
}
|
|
180
|
-
return cls.weekdays?.some((w) => w.weekday === date.getDay()) ?? false;
|
|
181
|
-
}
|
|
182
|
-
function formatClassTime(cls) {
|
|
183
|
-
let h = parseInt(cls.startTime.hour, 10);
|
|
184
|
-
const m = parseInt(cls.startTime.minutes, 10);
|
|
185
|
-
if (cls.startTime.time === "PM" && h !== 12) h += 12;
|
|
186
|
-
if (cls.startTime.time === "AM" && h === 12) h = 0;
|
|
187
|
-
const endTotal = h * 60 + m + cls.duration;
|
|
188
|
-
const eh = Math.floor(endTotal / 60) % 24;
|
|
189
|
-
const em = endTotal % 60;
|
|
190
|
-
return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
|
|
191
|
-
}
|
|
192
|
-
function getBookingsOnDate(cls, date) {
|
|
193
|
-
if (!cls.bookings?.length) return 0;
|
|
194
|
-
const ds = date.toISOString().split("T")[0];
|
|
195
|
-
return cls.bookings.filter((b) => {
|
|
196
|
-
try {
|
|
197
|
-
return new Date(b.classDate).toISOString().split("T")[0] === ds;
|
|
198
|
-
} catch {
|
|
199
|
-
return false;
|
|
200
|
-
}
|
|
201
|
-
}).length;
|
|
202
|
-
}
|
|
203
|
-
function buildTimezoneLabel(tz) {
|
|
204
|
-
try {
|
|
205
|
-
const now = /* @__PURE__ */ new Date();
|
|
206
|
-
const timeStr = new Intl.DateTimeFormat("en-US", {
|
|
207
|
-
hour: "2-digit",
|
|
208
|
-
minute: "2-digit",
|
|
209
|
-
hour12: false,
|
|
210
|
-
timeZone: tz
|
|
211
|
-
}).format(now);
|
|
212
|
-
const offsetPart = new Intl.DateTimeFormat("en-US", { timeZoneName: "short", timeZone: tz }).formatToParts(now).find((p) => p.type === "timeZoneName")?.value ?? "";
|
|
213
|
-
const city = tz.split("/").pop()?.replace(/_/g, " ") ?? tz;
|
|
214
|
-
return `${timeStr} (${offsetPart}) ${city} time`;
|
|
215
|
-
} catch {
|
|
216
|
-
return tz;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
function EmptyState({ inEditor }) {
|
|
220
|
-
const handleAddSchedule = () => {
|
|
221
|
-
if (inEditor) {
|
|
222
|
-
window.parent.postMessage({ type: "ow:scheduling-not-connected" }, "*");
|
|
223
|
-
}
|
|
224
|
-
};
|
|
225
|
-
return /* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center justify-center gap-6 p-12 bg-[#FAFAF9] border-2 border-dashed border-[#E7E5E4] rounded-[10px] h-[264px] w-full box-border", children: [
|
|
226
|
-
/* @__PURE__ */ jsx2("div", { className: "w-10 h-10 bg-[#F5F5F4] rounded-[10px] flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsxs2(
|
|
227
|
-
"svg",
|
|
228
|
-
{
|
|
229
|
-
width: "20",
|
|
230
|
-
height: "20",
|
|
231
|
-
viewBox: "0 0 24 24",
|
|
232
|
-
fill: "none",
|
|
233
|
-
stroke: "var(--color-accent, #A89B83)",
|
|
234
|
-
strokeWidth: "1.5",
|
|
235
|
-
strokeLinecap: "round",
|
|
236
|
-
strokeLinejoin: "round",
|
|
237
|
-
children: [
|
|
238
|
-
/* @__PURE__ */ jsx2("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
|
|
239
|
-
/* @__PURE__ */ jsx2("line", { x1: "16", y1: "2", x2: "16", y2: "6" }),
|
|
240
|
-
/* @__PURE__ */ jsx2("line", { x1: "8", y1: "2", x2: "8", y2: "6" }),
|
|
241
|
-
/* @__PURE__ */ jsx2("line", { x1: "3", y1: "10", x2: "21", y2: "10" }),
|
|
242
|
-
/* @__PURE__ */ jsx2("line", { x1: "12", y1: "14", x2: "12", y2: "18" }),
|
|
243
|
-
/* @__PURE__ */ jsx2("line", { x1: "10", y1: "16", x2: "14", y2: "16" })
|
|
244
|
-
]
|
|
245
|
-
}
|
|
246
|
-
) }),
|
|
247
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center gap-2", children: [
|
|
248
|
-
/* @__PURE__ */ jsx2("p", { className: "font-body text-lg font-medium text-center text-[#0A0A0A] m-0", children: "No schedule yet" }),
|
|
249
|
-
/* @__PURE__ */ jsx2("p", { className: "font-body text-base font-normal text-center text-(--color-accent,#A89B83) m-0", children: "Add a scheduling widget to get instant bookings." })
|
|
250
|
-
] }),
|
|
251
|
-
/* @__PURE__ */ jsx2(
|
|
252
|
-
"button",
|
|
253
|
-
{
|
|
254
|
-
onClick: handleAddSchedule,
|
|
255
|
-
className: "h-9 px-2 py-1.5 flex items-center justify-center bg-white border border-[#E7E5E4] rounded-md font-body text-sm font-medium text-(--color-dark,#200C02) cursor-pointer",
|
|
256
|
-
children: "Add Schedule"
|
|
257
|
-
}
|
|
258
|
-
)
|
|
259
|
-
] });
|
|
260
|
-
}
|
|
261
|
-
function LoadingSkeleton() {
|
|
262
|
-
const shimmer = {
|
|
263
|
-
background: "linear-gradient(90deg,#f0f0f0 25%,#e8e8e8 50%,#f0f0f0 75%)",
|
|
264
|
-
backgroundSize: "200% 100%",
|
|
265
|
-
animation: "ohw-shimmer 1.5s infinite"
|
|
266
|
-
};
|
|
267
|
-
return /* @__PURE__ */ jsxs2("div", { className: "w-full flex flex-col gap-10", children: [
|
|
268
|
-
/* @__PURE__ */ jsx2("style", { children: `@keyframes ohw-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}` }),
|
|
269
|
-
/* @__PURE__ */ jsx2("div", { className: "flex h-[70px] items-stretch", children: Array.from({ length: 7 }).map((_, i) => /* @__PURE__ */ jsxs2("div", { className: "flex-1 flex flex-col justify-between items-center px-1", children: [
|
|
270
|
-
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "32px", height: "14px", borderRadius: "4px" } }),
|
|
271
|
-
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "40px", height: "40px", borderRadius: "50%" } })
|
|
272
|
-
] }, i)) }),
|
|
273
|
-
[0, 1, 2].map((i) => /* @__PURE__ */ jsxs2("div", { children: [
|
|
274
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex gap-4 py-4 sm:hidden", children: [
|
|
275
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-2 shrink-0", children: [
|
|
276
|
-
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "100px", height: "16px", borderRadius: "4px" } }),
|
|
277
|
-
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "52px", height: "20px", borderRadius: "999px" } }),
|
|
278
|
-
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "60px", height: "14px", borderRadius: "4px" } })
|
|
279
|
-
] }),
|
|
280
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex flex-1 flex-col gap-2", children: [
|
|
281
|
-
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "75%", height: "16px", borderRadius: "4px" } }),
|
|
282
|
-
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "50%", height: "14px", borderRadius: "4px" } }),
|
|
283
|
-
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "100%", height: "44px", borderRadius: "8px" } })
|
|
284
|
-
] })
|
|
285
|
-
] }),
|
|
286
|
-
/* @__PURE__ */ jsxs2("div", { className: "hidden sm:flex items-center gap-[60px] py-4", children: [
|
|
287
|
-
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "120px", height: "16px", borderRadius: "4px", flexShrink: 0 } }),
|
|
288
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex-1 flex flex-col gap-2", children: [
|
|
289
|
-
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "55%", height: "16px", borderRadius: "4px" } }),
|
|
290
|
-
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "38%", height: "14px", borderRadius: "4px" } })
|
|
291
|
-
] }),
|
|
292
|
-
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "56px", height: "32px", borderRadius: "4px", flexShrink: 0 } }),
|
|
293
|
-
/* @__PURE__ */ jsx2("div", { style: { ...shimmer, width: "200px", height: "44px", borderRadius: "8px", flexShrink: 0 } })
|
|
294
|
-
] }),
|
|
295
|
-
i < 2 && /* @__PURE__ */ jsx2("div", { className: "h-px bg-black/20" })
|
|
296
|
-
] }, i))
|
|
297
|
-
] });
|
|
298
|
-
}
|
|
299
|
-
function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal }) {
|
|
300
|
-
const todayMs = useMemo(() => {
|
|
301
|
-
const d = /* @__PURE__ */ new Date();
|
|
302
|
-
d.setHours(0, 0, 0, 0);
|
|
303
|
-
return d.getTime();
|
|
304
|
-
}, []);
|
|
305
|
-
const scrollRef = useRef(null);
|
|
306
|
-
const [canScrollLeft, setCanScrollLeft] = useState2(false);
|
|
307
|
-
const [canScrollRight, setCanScrollRight] = useState2(false);
|
|
308
|
-
const updateScrollState = () => {
|
|
309
|
-
const el = scrollRef.current;
|
|
310
|
-
if (!el) return;
|
|
311
|
-
setCanScrollLeft(el.scrollLeft > 0);
|
|
312
|
-
setCanScrollRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
|
|
313
|
-
};
|
|
314
|
-
useEffect(() => {
|
|
315
|
-
const el = scrollRef.current;
|
|
316
|
-
if (!el) return;
|
|
317
|
-
updateScrollState();
|
|
318
|
-
el.addEventListener("scroll", updateScrollState);
|
|
319
|
-
const ro = new ResizeObserver(updateScrollState);
|
|
320
|
-
ro.observe(el);
|
|
321
|
-
return () => {
|
|
322
|
-
el.removeEventListener("scroll", updateScrollState);
|
|
323
|
-
ro.disconnect();
|
|
324
|
-
};
|
|
325
|
-
}, [dates]);
|
|
326
|
-
const scroll = (dir) => {
|
|
327
|
-
scrollRef.current?.scrollBy({ left: dir === "left" ? -216 : 216, behavior: "smooth" });
|
|
328
|
-
};
|
|
329
|
-
const isDragging = useRef(false);
|
|
330
|
-
const dragStartX = useRef(0);
|
|
331
|
-
const dragStartScrollLeft = useRef(0);
|
|
332
|
-
const onDragStart = (e) => {
|
|
333
|
-
if (!scrollRef.current) return;
|
|
334
|
-
isDragging.current = true;
|
|
335
|
-
dragStartX.current = e.clientX;
|
|
336
|
-
dragStartScrollLeft.current = scrollRef.current.scrollLeft;
|
|
337
|
-
scrollRef.current.style.cursor = "grabbing";
|
|
338
|
-
scrollRef.current.style.userSelect = "none";
|
|
339
|
-
};
|
|
340
|
-
const onDragMove = (e) => {
|
|
341
|
-
if (!isDragging.current || !scrollRef.current) return;
|
|
342
|
-
const delta = e.clientX - dragStartX.current;
|
|
343
|
-
scrollRef.current.scrollLeft = dragStartScrollLeft.current - delta;
|
|
344
|
-
};
|
|
345
|
-
const onDragEnd = () => {
|
|
346
|
-
if (!scrollRef.current) return;
|
|
347
|
-
isDragging.current = false;
|
|
348
|
-
scrollRef.current.style.cursor = "grab";
|
|
349
|
-
scrollRef.current.style.userSelect = "";
|
|
350
|
-
};
|
|
351
|
-
const datesWithClasses = useMemo(
|
|
352
|
-
() => new Set(dates.map(
|
|
353
|
-
(d, i) => schedule.classes?.some((c) => classRunsOnDate(c, d, schedule.type)) ? i : -1
|
|
354
|
-
).filter((i) => i >= 0)),
|
|
355
|
-
[dates, schedule]
|
|
356
|
-
);
|
|
357
|
-
const selectedDate = dates[selectedIdx];
|
|
358
|
-
const selectedClasses = useMemo(
|
|
359
|
-
() => (schedule.classes ?? []).filter((c) => selectedDate && classRunsOnDate(c, selectedDate, schedule.type)),
|
|
360
|
-
[schedule, selectedDate]
|
|
361
|
-
);
|
|
362
|
-
return /* @__PURE__ */ jsxs2("div", { className: "w-full flex flex-col gap-10", children: [
|
|
363
|
-
/* @__PURE__ */ jsxs2("div", { className: "relative w-full", children: [
|
|
364
|
-
canScrollLeft && /* @__PURE__ */ jsx2(
|
|
365
|
-
"button",
|
|
366
|
-
{
|
|
367
|
-
onClick: () => scroll("left"),
|
|
368
|
-
className: "hidden sm:flex absolute left-0 top-1/2 -translate-y-1/2 z-10 w-8 h-8 items-center justify-center rounded-full border-none cursor-pointer",
|
|
369
|
-
style: { background: "var(--color-light,#FEFFF0)", boxShadow: "0 1px 4px rgba(0,0,0,0.15)" },
|
|
370
|
-
"aria-label": "Scroll left",
|
|
371
|
-
children: /* @__PURE__ */ jsx2("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "var(--color-dark,#200C02)", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx2("polyline", { points: "15 18 9 12 15 6" }) })
|
|
372
|
-
}
|
|
373
|
-
),
|
|
374
|
-
canScrollRight && /* @__PURE__ */ jsx2(
|
|
375
|
-
"button",
|
|
376
|
-
{
|
|
377
|
-
onClick: () => scroll("right"),
|
|
378
|
-
className: "hidden sm:flex absolute right-0 top-1/2 -translate-y-1/2 z-10 w-8 h-8 items-center justify-center rounded-full border-none cursor-pointer",
|
|
379
|
-
style: { background: "var(--color-light,#FEFFF0)", boxShadow: "0 1px 4px rgba(0,0,0,0.15)" },
|
|
380
|
-
"aria-label": "Scroll right",
|
|
381
|
-
children: /* @__PURE__ */ jsx2("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "var(--color-dark,#200C02)", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx2("polyline", { points: "9 18 15 12 9 6" }) })
|
|
382
|
-
}
|
|
383
|
-
),
|
|
384
|
-
canScrollLeft && /* @__PURE__ */ jsx2(
|
|
385
|
-
"div",
|
|
386
|
-
{
|
|
387
|
-
className: "sm:hidden absolute left-0 top-0 bottom-0 w-10 z-10 pointer-events-none",
|
|
388
|
-
style: { background: "linear-gradient(to right, var(--color-light,#FEFFF0), transparent)" }
|
|
389
|
-
}
|
|
390
|
-
),
|
|
391
|
-
canScrollRight && /* @__PURE__ */ jsx2(
|
|
392
|
-
"div",
|
|
393
|
-
{
|
|
394
|
-
className: "sm:hidden absolute right-0 top-0 bottom-0 w-10 z-10 pointer-events-none",
|
|
395
|
-
style: { background: "linear-gradient(to left, var(--color-light,#FEFFF0), transparent)" }
|
|
396
|
-
}
|
|
397
|
-
),
|
|
398
|
-
/* @__PURE__ */ jsx2(
|
|
399
|
-
"div",
|
|
400
|
-
{
|
|
401
|
-
ref: scrollRef,
|
|
402
|
-
className: "overflow-x-auto w-full",
|
|
403
|
-
style: { scrollbarWidth: "none", msOverflowStyle: "none", touchAction: "pan-x", cursor: "grab" },
|
|
404
|
-
onMouseDown: onDragStart,
|
|
405
|
-
onMouseMove: onDragMove,
|
|
406
|
-
onMouseUp: onDragEnd,
|
|
407
|
-
onMouseLeave: onDragEnd,
|
|
408
|
-
children: /* @__PURE__ */ jsx2("div", { className: "flex", style: { width: `max(100%, ${dates.length * 60}px)` }, children: dates.map((date, i) => {
|
|
409
|
-
const isToday = date.getTime() === todayMs;
|
|
410
|
-
const isSelected = i === selectedIdx;
|
|
411
|
-
const clickable = datesWithClasses.has(i);
|
|
412
|
-
const label = isToday ? "TODAY" : DAY_ABBR[date.getDay()];
|
|
413
|
-
return /* @__PURE__ */ jsxs2(
|
|
414
|
-
"div",
|
|
415
|
-
{
|
|
416
|
-
onClick: () => clickable && onSelectDate(i),
|
|
417
|
-
className: `flex-1 h-[70px] flex flex-col justify-between items-center ${clickable ? "cursor-pointer opacity-100" : "cursor-default opacity-50"}`,
|
|
418
|
-
children: [
|
|
419
|
-
/* @__PURE__ */ jsx2("span", { className: "font-body text-base font-normal text-center text-(--color-dark,#200C02)", children: label }),
|
|
420
|
-
/* @__PURE__ */ jsx2(
|
|
421
|
-
"div",
|
|
422
|
-
{
|
|
423
|
-
className: "w-10 h-10 rounded-full flex items-center justify-center",
|
|
424
|
-
style: { background: isSelected ? "var(--color-primary, #3D312B)" : "transparent" },
|
|
425
|
-
children: /* @__PURE__ */ jsx2(
|
|
426
|
-
"span",
|
|
427
|
-
{
|
|
428
|
-
className: "font-body text-xl font-bold text-center tracking-display-tight",
|
|
429
|
-
style: { color: isSelected ? "var(--color-light, #FEFFF0)" : "var(--color-dark, #200C02)" },
|
|
430
|
-
children: date.getDate()
|
|
431
|
-
}
|
|
432
|
-
)
|
|
433
|
-
}
|
|
434
|
-
)
|
|
435
|
-
]
|
|
436
|
-
},
|
|
437
|
-
i
|
|
438
|
-
);
|
|
439
|
-
}) })
|
|
440
|
-
}
|
|
441
|
-
)
|
|
442
|
-
] }),
|
|
443
|
-
selectedClasses.length === 0 ? /* @__PURE__ */ jsx2("p", { className: "font-body text-base text-(--color-accent,#A89B83) text-center py-8 m-0", children: "No classes scheduled for this day." }) : /* @__PURE__ */ jsx2("div", { className: "flex flex-col", children: selectedClasses.map((cls, i) => {
|
|
444
|
-
const booked = getBookingsOnDate(cls, selectedDate);
|
|
445
|
-
const available = cls.maxParticipants - booked;
|
|
446
|
-
const isFull = available <= 0;
|
|
447
|
-
return /* @__PURE__ */ jsxs2("div", { children: [
|
|
448
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex gap-4 py-4 sm:items-center sm:gap-[60px] box-border", children: [
|
|
449
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-2 shrink-0 sm:contents", children: [
|
|
450
|
-
/* @__PURE__ */ jsx2("div", { className: "sm:w-[120px] sm:shrink-0", children: /* @__PURE__ */ jsx2("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block", children: formatClassTime(cls) }) }),
|
|
451
|
-
/* @__PURE__ */ jsx2(
|
|
452
|
-
"span",
|
|
453
|
-
{
|
|
454
|
-
className: "inline-flex items-center px-2 py-0.5 rounded-full border text-xs font-medium sm:hidden",
|
|
455
|
-
style: { borderColor: "#0885FE", color: "#0885FE" },
|
|
456
|
-
children: "GROUP"
|
|
457
|
-
}
|
|
458
|
-
),
|
|
459
|
-
/* @__PURE__ */ jsx2("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
460
|
-
/* @__PURE__ */ jsxs2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
461
|
-
available,
|
|
462
|
-
"/",
|
|
463
|
-
cls.maxParticipants
|
|
464
|
-
] }),
|
|
465
|
-
/* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "available" })
|
|
466
|
-
] }) })
|
|
467
|
-
] }),
|
|
468
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex flex-1 flex-col gap-2 min-w-0 sm:contents", children: [
|
|
469
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex-1 flex flex-col gap-2 min-w-0", children: [
|
|
470
|
-
/* @__PURE__ */ jsx2("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block truncate", children: cls.name }),
|
|
471
|
-
cls.hostName && /* @__PURE__ */ jsx2("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName })
|
|
472
|
-
] }),
|
|
473
|
-
/* @__PURE__ */ jsx2("div", { className: "hidden sm:flex w-14 shrink-0 flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
474
|
-
/* @__PURE__ */ jsxs2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
475
|
-
available,
|
|
476
|
-
"/",
|
|
477
|
-
cls.maxParticipants
|
|
478
|
-
] }),
|
|
479
|
-
/* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "available" })
|
|
480
|
-
] }) }),
|
|
481
|
-
/* @__PURE__ */ jsx2(
|
|
482
|
-
"button",
|
|
483
|
-
{
|
|
484
|
-
className: "w-full sm:w-[200px] sm:shrink-0 px-5 py-[10px] flex items-center justify-center rounded-lg font-body text-base font-bold cursor-pointer box-border",
|
|
485
|
-
style: isFull ? {
|
|
486
|
-
background: "transparent",
|
|
487
|
-
border: "1px solid var(--color-dark, #200C02)",
|
|
488
|
-
color: "var(--color-dark, #200C02)"
|
|
489
|
-
} : {
|
|
490
|
-
background: "var(--color-primary, #3D312B)",
|
|
491
|
-
border: "none",
|
|
492
|
-
color: "var(--color-light, #FEFFF0)"
|
|
493
|
-
},
|
|
494
|
-
onClick: () => {
|
|
495
|
-
if (!cls.id) return;
|
|
496
|
-
onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
|
|
497
|
-
},
|
|
498
|
-
children: isFull ? "Join Waitlist" : "Book Now"
|
|
499
|
-
}
|
|
500
|
-
)
|
|
501
|
-
] })
|
|
502
|
-
] }),
|
|
503
|
-
i < selectedClasses.length - 1 && /* @__PURE__ */ jsx2("div", { className: "h-px bg-black/20" })
|
|
504
|
-
] }, cls.id ?? i);
|
|
505
|
-
}) })
|
|
506
|
-
] });
|
|
507
|
-
}
|
|
508
|
-
function CalendarFoldIcon() {
|
|
509
|
-
return /* @__PURE__ */ jsxs2(
|
|
510
|
-
"svg",
|
|
511
|
-
{
|
|
512
|
-
width: "16",
|
|
513
|
-
height: "16",
|
|
514
|
-
viewBox: "0 0 24 24",
|
|
515
|
-
fill: "none",
|
|
516
|
-
stroke: "currentColor",
|
|
517
|
-
strokeWidth: "2",
|
|
518
|
-
strokeLinecap: "round",
|
|
519
|
-
strokeLinejoin: "round",
|
|
520
|
-
style: { flexShrink: 0 },
|
|
521
|
-
children: [
|
|
522
|
-
/* @__PURE__ */ jsx2("path", { d: "M8 2v4" }),
|
|
523
|
-
/* @__PURE__ */ jsx2("path", { d: "M16 2v4" }),
|
|
524
|
-
/* @__PURE__ */ jsx2("path", { d: "M21 17V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h11Z" }),
|
|
525
|
-
/* @__PURE__ */ jsx2("path", { d: "M3 10h18" }),
|
|
526
|
-
/* @__PURE__ */ jsx2("path", { d: "M15 22v-4a2 2 0 0 1 2-2h4" })
|
|
527
|
-
]
|
|
528
|
-
}
|
|
529
|
-
);
|
|
530
|
-
}
|
|
531
|
-
function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAfter }) {
|
|
532
|
-
const [schedule, setSchedule] = useState2(null);
|
|
533
|
-
const [loading, setLoading] = useState2(true);
|
|
534
|
-
const [inEditor, setInEditor] = useState2(false);
|
|
535
|
-
const [isHovered, setIsHovered] = useState2(false);
|
|
536
|
-
const [modalState, setModalState] = useState2(null);
|
|
537
|
-
const switchScheduleIdRef = useRef(null);
|
|
538
|
-
const dates = useMemo(() => {
|
|
539
|
-
const today = /* @__PURE__ */ new Date();
|
|
540
|
-
today.setHours(0, 0, 0, 0);
|
|
541
|
-
return Array.from({ length: 14 }, (_, i) => {
|
|
542
|
-
const d = new Date(today);
|
|
543
|
-
d.setDate(today.getDate() + i);
|
|
544
|
-
return d;
|
|
545
|
-
});
|
|
546
|
-
}, []);
|
|
547
|
-
const [selectedIdx, setSelectedIdx] = useState2(0);
|
|
548
|
-
useEffect(() => {
|
|
549
|
-
if (!schedule?.classes) return;
|
|
550
|
-
for (let i = 0; i < dates.length; i++) {
|
|
551
|
-
if (schedule.classes.some((c) => classRunsOnDate(c, dates[i], schedule.type))) {
|
|
552
|
-
setSelectedIdx(i);
|
|
553
|
-
return;
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
}, [schedule, dates]);
|
|
557
|
-
useEffect(() => {
|
|
558
|
-
if (typeof window === "undefined") return;
|
|
559
|
-
const isInEditor = window.self !== window.top;
|
|
560
|
-
setInEditor(isInEditor);
|
|
561
|
-
if (isInEditor) {
|
|
562
|
-
const startEmpty = initialScheduleId === null;
|
|
563
|
-
if (startEmpty) setLoading(false);
|
|
564
|
-
let initialized = startEmpty;
|
|
565
|
-
const timer = !startEmpty ? setTimeout(() => {
|
|
566
|
-
if (!initialized) {
|
|
567
|
-
initialized = true;
|
|
568
|
-
setLoading(false);
|
|
569
|
-
}
|
|
570
|
-
}, 5e3) : null;
|
|
571
|
-
const handler = (e) => {
|
|
572
|
-
if (e.data?.type === "ow:clear-scheduling-widget") {
|
|
573
|
-
if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
|
|
574
|
-
setSchedule(null);
|
|
575
|
-
setLoading(false);
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
|
-
if (e.data?.type === "ow:switch-schedule") {
|
|
579
|
-
if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
|
|
580
|
-
switchScheduleIdRef.current = e.data.scheduleId ?? null;
|
|
581
|
-
initialized = false;
|
|
582
|
-
setLoading(true);
|
|
583
|
-
window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
|
|
584
|
-
return;
|
|
585
|
-
}
|
|
586
|
-
if (e.data?.type !== "ow:user-schedules-response") return;
|
|
587
|
-
if (e.data.insertAfter && e.data.insertAfter !== insertAfter) return;
|
|
588
|
-
if (initialized && switchScheduleIdRef.current === null) return;
|
|
589
|
-
initialized = true;
|
|
590
|
-
if (timer) clearTimeout(timer);
|
|
591
|
-
const schedules = e.data.schedules ?? [];
|
|
592
|
-
const isSwitching = switchScheduleIdRef.current !== null;
|
|
593
|
-
const target = isSwitching ? schedules.find((s) => s.id === switchScheduleIdRef.current) ?? schedules[0] ?? null : initialScheduleId ? schedules.find((s) => s.id === initialScheduleId) ?? schedules[0] ?? null : schedules[0] ?? null;
|
|
594
|
-
switchScheduleIdRef.current = null;
|
|
595
|
-
setSchedule(target);
|
|
596
|
-
setLoading(false);
|
|
597
|
-
if (notifyOnConnect && target && !isSwitching) {
|
|
598
|
-
window.parent.postMessage({
|
|
599
|
-
type: "ow:schedule-connected",
|
|
600
|
-
schedule: { id: target.id, name: target.name },
|
|
601
|
-
insertAfter
|
|
602
|
-
}, "*");
|
|
603
|
-
window.postMessage({ type: "ow:schedule-linked", scheduleId: target.id, insertAfter }, "*");
|
|
604
|
-
}
|
|
605
|
-
};
|
|
606
|
-
window.addEventListener("message", handler);
|
|
607
|
-
if (!startEmpty) window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
|
|
608
|
-
return () => {
|
|
609
|
-
window.removeEventListener("message", handler);
|
|
610
|
-
if (timer) clearTimeout(timer);
|
|
611
|
-
};
|
|
612
|
-
}
|
|
613
|
-
if (initialScheduleId === null) {
|
|
614
|
-
setLoading(false);
|
|
615
|
-
return;
|
|
616
|
-
}
|
|
617
|
-
;
|
|
618
|
-
(async () => {
|
|
619
|
-
try {
|
|
620
|
-
if (initialScheduleId) {
|
|
621
|
-
const res = await fetch(`${API_URL}/api/schedule/id/${initialScheduleId}`);
|
|
622
|
-
const data = await res.json();
|
|
623
|
-
setSchedule(data?.id ? data : null);
|
|
624
|
-
} else {
|
|
625
|
-
const domain = getApiDomain();
|
|
626
|
-
const sitemapRes = await fetch(`${API_URL}/api/schedule/sitemap/${domain}`);
|
|
627
|
-
const slugs = await sitemapRes.json();
|
|
628
|
-
if (!Array.isArray(slugs) || !slugs.length) {
|
|
629
|
-
setLoading(false);
|
|
630
|
-
return;
|
|
631
|
-
}
|
|
632
|
-
const { slug } = [...slugs].sort(
|
|
633
|
-
(a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()
|
|
634
|
-
)[0];
|
|
635
|
-
const res = await fetch(`${API_URL}/api/schedule/${domain}/${slug}`);
|
|
636
|
-
const data = await res.json();
|
|
637
|
-
setSchedule(data?.id ? data : null);
|
|
638
|
-
}
|
|
639
|
-
} catch {
|
|
640
|
-
}
|
|
641
|
-
setLoading(false);
|
|
642
|
-
})();
|
|
643
|
-
}, []);
|
|
644
|
-
const timezoneLabel = schedule?.timezone ? (() => {
|
|
645
|
-
try {
|
|
646
|
-
return buildTimezoneLabel(schedule.timezone);
|
|
647
|
-
} catch {
|
|
648
|
-
return void 0;
|
|
649
|
-
}
|
|
650
|
-
})() : void 0;
|
|
651
|
-
const handleModalSubmit = async (email) => {
|
|
652
|
-
if (!modalState) return;
|
|
653
|
-
const { mode, classId, classDate } = modalState;
|
|
654
|
-
const endpoint = mode === "book" ? `${API_URL}/api/schedule/class/${classId}/booking` : `${API_URL}/api/schedule/class/${classId}/waitlist`;
|
|
655
|
-
const res = await fetch(endpoint, {
|
|
656
|
-
method: "POST",
|
|
657
|
-
headers: { "Content-Type": "application/json" },
|
|
658
|
-
body: JSON.stringify({ classDate: classDate.toISOString(), email })
|
|
659
|
-
});
|
|
660
|
-
if (!res.ok) {
|
|
661
|
-
const data = await res.json().catch(() => ({}));
|
|
662
|
-
throw new Error(data?.message ?? "Something went wrong. Please try again.");
|
|
663
|
-
}
|
|
664
|
-
};
|
|
665
|
-
const handleReplaceSchedule = () => {
|
|
666
|
-
setIsHovered(false);
|
|
667
|
-
if (schedule) {
|
|
668
|
-
window.parent.postMessage({
|
|
669
|
-
type: "ow:schedule-connected",
|
|
670
|
-
schedule: { id: schedule.id, name: schedule.name },
|
|
671
|
-
insertAfter
|
|
672
|
-
}, "*");
|
|
673
|
-
} else {
|
|
674
|
-
window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
|
|
675
|
-
}
|
|
676
|
-
};
|
|
677
|
-
const sectionId = `scheduling-${insertAfter}`;
|
|
678
|
-
return /* @__PURE__ */ jsxs2(
|
|
679
|
-
"section",
|
|
680
|
-
{
|
|
681
|
-
"data-ohw-section": sectionId,
|
|
682
|
-
"data-ohw-scheduling-anchor": insertAfter,
|
|
683
|
-
className: "w-full box-border py-10 px-5 sm:py-20 sm:px-16 font-body bg-(--color-light,#FEFFF0) relative",
|
|
684
|
-
onMouseEnter: () => inEditor && setIsHovered(true),
|
|
685
|
-
onMouseLeave: () => setIsHovered(false),
|
|
686
|
-
children: [
|
|
687
|
-
inEditor && isHovered && !!schedule && /* @__PURE__ */ jsxs2(
|
|
688
|
-
"div",
|
|
689
|
-
{
|
|
690
|
-
className: "absolute inset-0 z-10 pointer-events-auto cursor-pointer",
|
|
691
|
-
onClick: handleReplaceSchedule,
|
|
692
|
-
children: [
|
|
693
|
-
/* @__PURE__ */ jsx2("div", { className: "absolute inset-0", style: { background: "#0885FE", opacity: 0.18 } }),
|
|
694
|
-
/* @__PURE__ */ jsx2("div", { className: "absolute inset-0", style: { boxShadow: "inset 0 0 0 1.5px #0885FE" } }),
|
|
695
|
-
/* @__PURE__ */ jsx2("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs2(
|
|
696
|
-
"div",
|
|
697
|
-
{
|
|
698
|
-
className: "bg-white border border-[#E7E5E4] rounded-md px-3 py-1.5 flex items-center gap-1.5",
|
|
699
|
-
style: {
|
|
700
|
-
fontSize: 14,
|
|
701
|
-
lineHeight: "24px",
|
|
702
|
-
fontFamily: "'Figtree', system-ui, sans-serif",
|
|
703
|
-
fontWeight: 500,
|
|
704
|
-
color: "#0C0A09"
|
|
705
|
-
},
|
|
706
|
-
children: [
|
|
707
|
-
/* @__PURE__ */ jsx2(CalendarFoldIcon, {}),
|
|
708
|
-
"Replace schedule"
|
|
709
|
-
]
|
|
710
|
-
}
|
|
711
|
-
) })
|
|
712
|
-
]
|
|
713
|
-
}
|
|
714
|
-
),
|
|
715
|
-
/* @__PURE__ */ jsxs2("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
|
|
716
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center gap-4", children: [
|
|
717
|
-
/* @__PURE__ */ jsx2("h2", { className: "font-display text-4xl sm:text-5xl font-bold text-center m-0 text-(--color-dark,#200C02)", children: schedule?.name ?? "Book an appointment" }),
|
|
718
|
-
schedule?.description && /* @__PURE__ */ jsx2("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
|
|
719
|
-
] }),
|
|
720
|
-
/* @__PURE__ */ jsxs2("div", { className: "w-full flex flex-col items-end gap-3", children: [
|
|
721
|
-
timezoneLabel && /* @__PURE__ */ jsx2("span", { className: "font-body text-sm font-normal text-(--color-accent,#A89B83)", children: timezoneLabel }),
|
|
722
|
-
/* @__PURE__ */ jsx2("div", { className: "w-full p-0 sm:p-10 box-border", children: loading ? /* @__PURE__ */ jsx2(LoadingSkeleton, {}) : !schedule ? /* @__PURE__ */ jsx2(EmptyState, { inEditor }) : /* @__PURE__ */ jsx2(
|
|
723
|
-
ScheduleView,
|
|
724
|
-
{
|
|
725
|
-
schedule,
|
|
726
|
-
dates,
|
|
727
|
-
selectedIdx,
|
|
728
|
-
onSelectDate: setSelectedIdx,
|
|
729
|
-
onOpenModal: inEditor ? void 0 : (mode, classId, classDate) => setModalState({ mode, classId, classDate })
|
|
730
|
-
}
|
|
731
|
-
) })
|
|
732
|
-
] })
|
|
733
|
-
] }),
|
|
734
|
-
modalState && /* @__PURE__ */ jsx2(
|
|
735
|
-
EmailCaptureModal,
|
|
736
|
-
{
|
|
737
|
-
title: modalState.mode === "book" ? "Confirm your spot" : "Leave your email",
|
|
738
|
-
subtitle: modalState.mode === "book" ? "We'll send your booking confirmation here." : "We'll let you know when spots open up!",
|
|
739
|
-
onSubmit: handleModalSubmit,
|
|
740
|
-
onClose: () => setModalState(null)
|
|
741
|
-
}
|
|
742
|
-
)
|
|
743
|
-
]
|
|
744
|
-
}
|
|
745
|
-
);
|
|
746
|
-
}
|
|
4
|
+
import React4, { useCallback as useCallback2, useEffect as useEffect2, useLayoutEffect, useRef as useRef2, useState as useState3 } from "react";
|
|
747
5
|
|
|
748
6
|
// src/ui/toggle-group.tsx
|
|
749
|
-
import * as
|
|
7
|
+
import * as React from "react";
|
|
750
8
|
|
|
751
9
|
// node_modules/clsx/dist/clsx.mjs
|
|
752
10
|
function r(e) {
|
|
@@ -4066,7 +3324,7 @@ var cva = (base, config) => (props) => {
|
|
|
4066
3324
|
|
|
4067
3325
|
// src/ui/toggle.tsx
|
|
4068
3326
|
import { Toggle as TogglePrimitive } from "radix-ui";
|
|
4069
|
-
import { jsx
|
|
3327
|
+
import { jsx } from "react/jsx-runtime";
|
|
4070
3328
|
var toggleVariants = cva(
|
|
4071
3329
|
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
4072
3330
|
{
|
|
@@ -4093,7 +3351,7 @@ function Toggle({
|
|
|
4093
3351
|
size,
|
|
4094
3352
|
...props
|
|
4095
3353
|
}) {
|
|
4096
|
-
return /* @__PURE__ */
|
|
3354
|
+
return /* @__PURE__ */ jsx(
|
|
4097
3355
|
TogglePrimitive.Root,
|
|
4098
3356
|
{
|
|
4099
3357
|
"data-slot": "toggle",
|
|
@@ -4104,8 +3362,8 @@ function Toggle({
|
|
|
4104
3362
|
}
|
|
4105
3363
|
|
|
4106
3364
|
// src/ui/toggle-group.tsx
|
|
4107
|
-
import { jsx as
|
|
4108
|
-
var ToggleGroupContext =
|
|
3365
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
3366
|
+
var ToggleGroupContext = React.createContext({
|
|
4109
3367
|
value: "",
|
|
4110
3368
|
onValueChange: () => {
|
|
4111
3369
|
}
|
|
@@ -4117,13 +3375,13 @@ function ToggleGroup({
|
|
|
4117
3375
|
children,
|
|
4118
3376
|
...props
|
|
4119
3377
|
}) {
|
|
4120
|
-
return /* @__PURE__ */
|
|
3378
|
+
return /* @__PURE__ */ jsx2(
|
|
4121
3379
|
"div",
|
|
4122
3380
|
{
|
|
4123
3381
|
role: "group",
|
|
4124
3382
|
className: cn("flex items-center gap-1 p-1 bg-muted rounded-md", className),
|
|
4125
3383
|
...props,
|
|
4126
|
-
children: /* @__PURE__ */
|
|
3384
|
+
children: /* @__PURE__ */ jsx2(ToggleGroupContext.Provider, { value: { value, onValueChange }, children })
|
|
4127
3385
|
}
|
|
4128
3386
|
);
|
|
4129
3387
|
}
|
|
@@ -4133,8 +3391,8 @@ function ToggleGroupItem({
|
|
|
4133
3391
|
children,
|
|
4134
3392
|
...props
|
|
4135
3393
|
}) {
|
|
4136
|
-
const { value: groupValue, onValueChange } =
|
|
4137
|
-
return /* @__PURE__ */
|
|
3394
|
+
const { value: groupValue, onValueChange } = React.useContext(ToggleGroupContext);
|
|
3395
|
+
return /* @__PURE__ */ jsx2(
|
|
4138
3396
|
Toggle,
|
|
4139
3397
|
{
|
|
4140
3398
|
pressed: groupValue === value,
|
|
@@ -4448,9 +3706,9 @@ function calcPopoverPos(rect, parentScroll, approxW = 483, approxH = 320) {
|
|
|
4448
3706
|
}
|
|
4449
3707
|
|
|
4450
3708
|
// src/ui/button.tsx
|
|
4451
|
-
import * as
|
|
3709
|
+
import * as React2 from "react";
|
|
4452
3710
|
import { Slot } from "radix-ui";
|
|
4453
|
-
import { jsx as
|
|
3711
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
4454
3712
|
var buttonVariants = cva(
|
|
4455
3713
|
"inline-flex items-center justify-center gap-1 whitespace-nowrap rounded-md text-sm font-medium transition-colors outline-none disabled:pointer-events-none disabled:opacity-50 min-w-[80px] px-3 py-2",
|
|
4456
3714
|
{
|
|
@@ -4471,10 +3729,10 @@ var buttonVariants = cva(
|
|
|
4471
3729
|
}
|
|
4472
3730
|
}
|
|
4473
3731
|
);
|
|
4474
|
-
var Button =
|
|
3732
|
+
var Button = React2.forwardRef(
|
|
4475
3733
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
4476
3734
|
const Comp = asChild ? Slot.Root : "button";
|
|
4477
|
-
return /* @__PURE__ */
|
|
3735
|
+
return /* @__PURE__ */ jsx3(
|
|
4478
3736
|
Comp,
|
|
4479
3737
|
{
|
|
4480
3738
|
ref,
|
|
@@ -4488,75 +3746,75 @@ var Button = React3.forwardRef(
|
|
|
4488
3746
|
Button.displayName = "Button";
|
|
4489
3747
|
|
|
4490
3748
|
// src/ui/icons.tsx
|
|
4491
|
-
import { jsx as
|
|
3749
|
+
import { jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
4492
3750
|
function IconX({ className, ...props }) {
|
|
4493
|
-
return /* @__PURE__ */
|
|
4494
|
-
/* @__PURE__ */
|
|
4495
|
-
/* @__PURE__ */
|
|
3751
|
+
return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
3752
|
+
/* @__PURE__ */ jsx4("path", { d: "M18 6 6 18" }),
|
|
3753
|
+
/* @__PURE__ */ jsx4("path", { d: "m6 6 12 12" })
|
|
4496
3754
|
] });
|
|
4497
3755
|
}
|
|
4498
3756
|
function IconChevronDown({ className, ...props }) {
|
|
4499
|
-
return /* @__PURE__ */
|
|
3757
|
+
return /* @__PURE__ */ jsx4("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: /* @__PURE__ */ jsx4("path", { d: "m6 9 6 6 6-6" }) });
|
|
4500
3758
|
}
|
|
4501
3759
|
function IconFile({ className, ...props }) {
|
|
4502
|
-
return /* @__PURE__ */
|
|
4503
|
-
/* @__PURE__ */
|
|
4504
|
-
/* @__PURE__ */
|
|
3760
|
+
return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
3761
|
+
/* @__PURE__ */ jsx4("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
|
|
3762
|
+
/* @__PURE__ */ jsx4("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
|
|
4505
3763
|
] });
|
|
4506
3764
|
}
|
|
4507
3765
|
function IconInfo({ className, ...props }) {
|
|
4508
|
-
return /* @__PURE__ */
|
|
4509
|
-
/* @__PURE__ */
|
|
4510
|
-
/* @__PURE__ */
|
|
4511
|
-
/* @__PURE__ */
|
|
3766
|
+
return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
3767
|
+
/* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "10" }),
|
|
3768
|
+
/* @__PURE__ */ jsx4("path", { d: "M12 16v-4" }),
|
|
3769
|
+
/* @__PURE__ */ jsx4("path", { d: "M12 8h.01" })
|
|
4512
3770
|
] });
|
|
4513
3771
|
}
|
|
4514
3772
|
function IconArrowRight({ className, ...props }) {
|
|
4515
|
-
return /* @__PURE__ */
|
|
4516
|
-
/* @__PURE__ */
|
|
4517
|
-
/* @__PURE__ */
|
|
3773
|
+
return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
3774
|
+
/* @__PURE__ */ jsx4("path", { d: "M5 12h14" }),
|
|
3775
|
+
/* @__PURE__ */ jsx4("path", { d: "m12 5 7 7-7 7" })
|
|
4518
3776
|
] });
|
|
4519
3777
|
}
|
|
4520
3778
|
function IconSection({ className, ...props }) {
|
|
4521
|
-
return /* @__PURE__ */
|
|
4522
|
-
/* @__PURE__ */
|
|
4523
|
-
/* @__PURE__ */
|
|
4524
|
-
/* @__PURE__ */
|
|
3779
|
+
return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
3780
|
+
/* @__PURE__ */ jsx4("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
|
|
3781
|
+
/* @__PURE__ */ jsx4("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
|
|
3782
|
+
/* @__PURE__ */ jsx4("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
|
|
4525
3783
|
] });
|
|
4526
3784
|
}
|
|
4527
3785
|
|
|
4528
3786
|
// src/ui/link-modal/DestinationBreadcrumb.tsx
|
|
4529
|
-
import { jsx as
|
|
3787
|
+
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
4530
3788
|
function DestinationBreadcrumb({ pageTitle, sectionLabel }) {
|
|
4531
|
-
return /* @__PURE__ */
|
|
4532
|
-
/* @__PURE__ */
|
|
4533
|
-
/* @__PURE__ */
|
|
4534
|
-
/* @__PURE__ */
|
|
4535
|
-
/* @__PURE__ */
|
|
4536
|
-
/* @__PURE__ */
|
|
3789
|
+
return /* @__PURE__ */ jsxs2("div", { className: "flex w-full flex-col gap-2", children: [
|
|
3790
|
+
/* @__PURE__ */ jsx5("p", { className: "text-sm font-medium text-foreground", children: "Destination" }),
|
|
3791
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3", children: [
|
|
3792
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
|
|
3793
|
+
/* @__PURE__ */ jsx5(IconFile, { className: "shrink-0 text-foreground", "aria-hidden": true }),
|
|
3794
|
+
/* @__PURE__ */ jsx5("span", { className: "text-sm font-medium leading-none text-foreground", children: pageTitle })
|
|
4537
3795
|
] }),
|
|
4538
|
-
/* @__PURE__ */
|
|
4539
|
-
/* @__PURE__ */
|
|
4540
|
-
/* @__PURE__ */
|
|
4541
|
-
/* @__PURE__ */
|
|
3796
|
+
/* @__PURE__ */ jsx5(IconArrowRight, { className: "shrink-0 text-muted-foreground", "aria-hidden": true }),
|
|
3797
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
3798
|
+
/* @__PURE__ */ jsx5(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
|
|
3799
|
+
/* @__PURE__ */ jsx5("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
|
|
4542
3800
|
] })
|
|
4543
3801
|
] })
|
|
4544
3802
|
] });
|
|
4545
3803
|
}
|
|
4546
3804
|
|
|
4547
3805
|
// src/ui/link-modal/SectionTreeItem.tsx
|
|
4548
|
-
import { jsx as
|
|
3806
|
+
import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
4549
3807
|
function SectionTreeItem({ section, onSelect, selected }) {
|
|
4550
3808
|
const interactive = Boolean(onSelect);
|
|
4551
|
-
return /* @__PURE__ */
|
|
4552
|
-
/* @__PURE__ */
|
|
3809
|
+
return /* @__PURE__ */ jsxs3("div", { className: "flex h-9 w-full items-end pl-3", children: [
|
|
3810
|
+
/* @__PURE__ */ jsx6(
|
|
4553
3811
|
"div",
|
|
4554
3812
|
{
|
|
4555
3813
|
className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
|
|
4556
3814
|
"aria-hidden": true
|
|
4557
3815
|
}
|
|
4558
3816
|
),
|
|
4559
|
-
/* @__PURE__ */
|
|
3817
|
+
/* @__PURE__ */ jsxs3(
|
|
4560
3818
|
"div",
|
|
4561
3819
|
{
|
|
4562
3820
|
role: interactive ? "button" : void 0,
|
|
@@ -4574,8 +3832,8 @@ function SectionTreeItem({ section, onSelect, selected }) {
|
|
|
4574
3832
|
interactive && selected && "border-primary"
|
|
4575
3833
|
),
|
|
4576
3834
|
children: [
|
|
4577
|
-
/* @__PURE__ */
|
|
4578
|
-
/* @__PURE__ */
|
|
3835
|
+
/* @__PURE__ */ jsx6(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
|
|
3836
|
+
/* @__PURE__ */ jsx6("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
|
|
4579
3837
|
]
|
|
4580
3838
|
}
|
|
4581
3839
|
)
|
|
@@ -4583,23 +3841,23 @@ function SectionTreeItem({ section, onSelect, selected }) {
|
|
|
4583
3841
|
}
|
|
4584
3842
|
function SectionPickerList({ sections, onSelect }) {
|
|
4585
3843
|
if (sections.length === 0) {
|
|
4586
|
-
return /* @__PURE__ */
|
|
3844
|
+
return /* @__PURE__ */ jsx6("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
|
|
4587
3845
|
}
|
|
4588
|
-
return /* @__PURE__ */
|
|
4589
|
-
/* @__PURE__ */
|
|
4590
|
-
sections.map((section) => /* @__PURE__ */
|
|
3846
|
+
return /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-1", children: [
|
|
3847
|
+
/* @__PURE__ */ jsx6("p", { className: "text-sm text-muted-foreground", children: "Pick a section this link should scroll to." }),
|
|
3848
|
+
sections.map((section) => /* @__PURE__ */ jsx6(SectionTreeItem, { section, onSelect }, section.id))
|
|
4591
3849
|
] });
|
|
4592
3850
|
}
|
|
4593
3851
|
|
|
4594
3852
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
4595
|
-
import { useId, useRef
|
|
3853
|
+
import { useId, useRef, useState } from "react";
|
|
4596
3854
|
|
|
4597
3855
|
// src/ui/input.tsx
|
|
4598
|
-
import * as
|
|
4599
|
-
import { jsx as
|
|
4600
|
-
var Input =
|
|
3856
|
+
import * as React3 from "react";
|
|
3857
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
3858
|
+
var Input = React3.forwardRef(
|
|
4601
3859
|
({ className, type, ...props }, ref) => {
|
|
4602
|
-
return /* @__PURE__ */
|
|
3860
|
+
return /* @__PURE__ */ jsx7(
|
|
4603
3861
|
"input",
|
|
4604
3862
|
{
|
|
4605
3863
|
type,
|
|
@@ -4618,9 +3876,9 @@ Input.displayName = "Input";
|
|
|
4618
3876
|
|
|
4619
3877
|
// src/ui/label.tsx
|
|
4620
3878
|
import { Label as LabelPrimitive } from "radix-ui";
|
|
4621
|
-
import { jsx as
|
|
3879
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
4622
3880
|
function Label({ className, ...props }) {
|
|
4623
|
-
return /* @__PURE__ */
|
|
3881
|
+
return /* @__PURE__ */ jsx8(
|
|
4624
3882
|
LabelPrimitive.Root,
|
|
4625
3883
|
{
|
|
4626
3884
|
"data-slot": "label",
|
|
@@ -4632,12 +3890,12 @@ function Label({ className, ...props }) {
|
|
|
4632
3890
|
|
|
4633
3891
|
// src/ui/popover.tsx
|
|
4634
3892
|
import { Popover as PopoverPrimitive } from "radix-ui";
|
|
4635
|
-
import { jsx as
|
|
3893
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
4636
3894
|
function Popover({ ...props }) {
|
|
4637
|
-
return /* @__PURE__ */
|
|
3895
|
+
return /* @__PURE__ */ jsx9(PopoverPrimitive.Root, { "data-slot": "popover", ...props });
|
|
4638
3896
|
}
|
|
4639
3897
|
function PopoverTrigger({ ...props }) {
|
|
4640
|
-
return /* @__PURE__ */
|
|
3898
|
+
return /* @__PURE__ */ jsx9(PopoverPrimitive.Trigger, { "data-slot": "popover-trigger", ...props });
|
|
4641
3899
|
}
|
|
4642
3900
|
function PopoverContent({
|
|
4643
3901
|
className,
|
|
@@ -4645,7 +3903,7 @@ function PopoverContent({
|
|
|
4645
3903
|
sideOffset = 6,
|
|
4646
3904
|
...props
|
|
4647
3905
|
}) {
|
|
4648
|
-
return /* @__PURE__ */
|
|
3906
|
+
return /* @__PURE__ */ jsx9(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx9(
|
|
4649
3907
|
PopoverPrimitive.Content,
|
|
4650
3908
|
{
|
|
4651
3909
|
"data-slot": "popover-content",
|
|
@@ -4661,9 +3919,9 @@ function PopoverContent({
|
|
|
4661
3919
|
}
|
|
4662
3920
|
|
|
4663
3921
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
4664
|
-
import { jsx as
|
|
3922
|
+
import { jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
4665
3923
|
function FieldChevron({ onClick }) {
|
|
4666
|
-
return /* @__PURE__ */
|
|
3924
|
+
return /* @__PURE__ */ jsx10(
|
|
4667
3925
|
"button",
|
|
4668
3926
|
{
|
|
4669
3927
|
type: "button",
|
|
@@ -4671,7 +3929,7 @@ function FieldChevron({ onClick }) {
|
|
|
4671
3929
|
onClick,
|
|
4672
3930
|
"aria-label": "Open page list",
|
|
4673
3931
|
tabIndex: -1,
|
|
4674
|
-
children: /* @__PURE__ */
|
|
3932
|
+
children: /* @__PURE__ */ jsx10(IconChevronDown, {})
|
|
4675
3933
|
}
|
|
4676
3934
|
);
|
|
4677
3935
|
}
|
|
@@ -4688,8 +3946,8 @@ function UrlOrPageInput({
|
|
|
4688
3946
|
urlError
|
|
4689
3947
|
}) {
|
|
4690
3948
|
const inputId = useId();
|
|
4691
|
-
const inputRef =
|
|
4692
|
-
const [isFocused, setIsFocused] =
|
|
3949
|
+
const inputRef = useRef(null);
|
|
3950
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
4693
3951
|
const openDropdown = () => {
|
|
4694
3952
|
if (readOnly || filteredPages.length === 0) return;
|
|
4695
3953
|
onDropdownOpenChange(true);
|
|
@@ -4710,12 +3968,12 @@ function UrlOrPageInput({
|
|
|
4710
3968
|
"data-ohw-link-field flex h-10 w-full items-center overflow-hidden rounded-md border bg-background pl-3 pr-3 py-2 outline-none transition-[border-color,box-shadow]",
|
|
4711
3969
|
urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
|
|
4712
3970
|
);
|
|
4713
|
-
return /* @__PURE__ */
|
|
4714
|
-
/* @__PURE__ */
|
|
4715
|
-
/* @__PURE__ */
|
|
4716
|
-
/* @__PURE__ */
|
|
4717
|
-
selectedPage ? /* @__PURE__ */
|
|
4718
|
-
readOnly ? /* @__PURE__ */
|
|
3971
|
+
return /* @__PURE__ */ jsxs4("div", { className: "flex w-full flex-col gap-2 p-0", children: [
|
|
3972
|
+
/* @__PURE__ */ jsx10(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
|
|
3973
|
+
/* @__PURE__ */ jsxs4(Popover, { open: dropdownOpen && !readOnly, onOpenChange: onDropdownOpenChange, children: [
|
|
3974
|
+
/* @__PURE__ */ jsx10(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs4("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
|
|
3975
|
+
selectedPage ? /* @__PURE__ */ jsx10("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx10(IconFile, { className: "text-foreground", "aria-hidden": true }) }) : null,
|
|
3976
|
+
readOnly ? /* @__PURE__ */ jsx10("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ jsx10(
|
|
4719
3977
|
Input,
|
|
4720
3978
|
{
|
|
4721
3979
|
ref: inputRef,
|
|
@@ -4734,7 +3992,7 @@ function UrlOrPageInput({
|
|
|
4734
3992
|
)
|
|
4735
3993
|
}
|
|
4736
3994
|
),
|
|
4737
|
-
selectedPage && !readOnly ? /* @__PURE__ */
|
|
3995
|
+
selectedPage && !readOnly ? /* @__PURE__ */ jsx10(
|
|
4738
3996
|
"button",
|
|
4739
3997
|
{
|
|
4740
3998
|
type: "button",
|
|
@@ -4742,31 +4000,31 @@ function UrlOrPageInput({
|
|
|
4742
4000
|
onMouseDown: clearSelection,
|
|
4743
4001
|
"aria-label": "Clear selected page",
|
|
4744
4002
|
tabIndex: -1,
|
|
4745
|
-
children: /* @__PURE__ */
|
|
4003
|
+
children: /* @__PURE__ */ jsx10(IconX, { "aria-hidden": true })
|
|
4746
4004
|
}
|
|
4747
4005
|
) : null,
|
|
4748
|
-
!readOnly ? /* @__PURE__ */
|
|
4006
|
+
!readOnly ? /* @__PURE__ */ jsx10(FieldChevron, { onClick: toggleDropdown }) : null
|
|
4749
4007
|
] }) }),
|
|
4750
|
-
filteredPages.length > 0 && /* @__PURE__ */
|
|
4008
|
+
filteredPages.length > 0 && /* @__PURE__ */ jsx10(PopoverContent, { "data-ohw-link-popover-root": "", onOpenAutoFocus: (e) => e.preventDefault(), children: filteredPages.map((page) => /* @__PURE__ */ jsxs4(
|
|
4751
4009
|
"button",
|
|
4752
4010
|
{
|
|
4753
4011
|
type: "button",
|
|
4754
4012
|
className: "flex h-9 w-full items-center gap-2 border-0 bg-transparent px-3 text-left text-sm leading-5 text-foreground outline-none hover:bg-muted",
|
|
4755
4013
|
onClick: () => onPageSelect(page),
|
|
4756
4014
|
children: [
|
|
4757
|
-
/* @__PURE__ */
|
|
4758
|
-
/* @__PURE__ */
|
|
4015
|
+
/* @__PURE__ */ jsx10(IconFile, { className: "shrink-0", "aria-hidden": true }),
|
|
4016
|
+
/* @__PURE__ */ jsx10("span", { className: "truncate", children: page.title })
|
|
4759
4017
|
]
|
|
4760
4018
|
},
|
|
4761
4019
|
page.path
|
|
4762
4020
|
)) })
|
|
4763
4021
|
] }),
|
|
4764
|
-
urlError ? /* @__PURE__ */
|
|
4022
|
+
urlError ? /* @__PURE__ */ jsx10("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
|
|
4765
4023
|
] });
|
|
4766
4024
|
}
|
|
4767
4025
|
|
|
4768
4026
|
// src/ui/link-modal/useLinkModalState.ts
|
|
4769
|
-
import { useCallback, useEffect
|
|
4027
|
+
import { useCallback, useEffect, useMemo, useState as useState2 } from "react";
|
|
4770
4028
|
function useLinkModalState({
|
|
4771
4029
|
open,
|
|
4772
4030
|
mode,
|
|
@@ -4778,16 +4036,16 @@ function useLinkModalState({
|
|
|
4778
4036
|
onClose,
|
|
4779
4037
|
onSubmit
|
|
4780
4038
|
}) {
|
|
4781
|
-
const availablePages =
|
|
4039
|
+
const availablePages = useMemo(
|
|
4782
4040
|
() => mode === "create" ? filterAvailablePages(pages, existingTargets) : pages,
|
|
4783
4041
|
[mode, pages, existingTargets]
|
|
4784
4042
|
);
|
|
4785
|
-
const [searchValue, setSearchValue] =
|
|
4786
|
-
const [selectedPage, setSelectedPage] =
|
|
4787
|
-
const [selectedSection, setSelectedSection] =
|
|
4788
|
-
const [step, setStep] =
|
|
4789
|
-
const [dropdownOpen, setDropdownOpen] =
|
|
4790
|
-
const [urlError, setUrlError] =
|
|
4043
|
+
const [searchValue, setSearchValue] = useState2("");
|
|
4044
|
+
const [selectedPage, setSelectedPage] = useState2(null);
|
|
4045
|
+
const [selectedSection, setSelectedSection] = useState2(null);
|
|
4046
|
+
const [step, setStep] = useState2("input");
|
|
4047
|
+
const [dropdownOpen, setDropdownOpen] = useState2(false);
|
|
4048
|
+
const [urlError, setUrlError] = useState2("");
|
|
4791
4049
|
const reset = useCallback(() => {
|
|
4792
4050
|
setSearchValue("");
|
|
4793
4051
|
setSelectedPage(null);
|
|
@@ -4796,7 +4054,7 @@ function useLinkModalState({
|
|
|
4796
4054
|
setDropdownOpen(false);
|
|
4797
4055
|
setUrlError("");
|
|
4798
4056
|
}, []);
|
|
4799
|
-
|
|
4057
|
+
useEffect(() => {
|
|
4800
4058
|
if (!open) return;
|
|
4801
4059
|
if (mode === "edit" && initialTarget) {
|
|
4802
4060
|
const { pageRoute } = parseTarget(initialTarget);
|
|
@@ -4812,11 +4070,11 @@ function useLinkModalState({
|
|
|
4812
4070
|
setDropdownOpen(false);
|
|
4813
4071
|
setUrlError("");
|
|
4814
4072
|
}, [open, mode, initialTarget, pages, sectionsByPath, reset]);
|
|
4815
|
-
const filteredPages =
|
|
4073
|
+
const filteredPages = useMemo(() => {
|
|
4816
4074
|
if (!searchValue.trim()) return availablePages;
|
|
4817
4075
|
return availablePages.filter((p) => p.title.toLowerCase().startsWith(searchValue.toLowerCase()));
|
|
4818
4076
|
}, [availablePages, searchValue]);
|
|
4819
|
-
const activeSections =
|
|
4077
|
+
const activeSections = useMemo(() => {
|
|
4820
4078
|
if (!selectedPage) return [];
|
|
4821
4079
|
return getSectionsForPath(sectionsByPath, selectedPage.path);
|
|
4822
4080
|
}, [selectedPage, sectionsByPath]);
|
|
@@ -4862,7 +4120,7 @@ function useLinkModalState({
|
|
|
4862
4120
|
reset();
|
|
4863
4121
|
onClose();
|
|
4864
4122
|
};
|
|
4865
|
-
const isValid =
|
|
4123
|
+
const isValid = useMemo(() => {
|
|
4866
4124
|
if (urlError) return false;
|
|
4867
4125
|
if (showBreadcrumb) return true;
|
|
4868
4126
|
if (selectedPage) return true;
|
|
@@ -4929,7 +4187,7 @@ function useLinkModalState({
|
|
|
4929
4187
|
}
|
|
4930
4188
|
|
|
4931
4189
|
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
4932
|
-
import { Fragment
|
|
4190
|
+
import { Fragment, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
4933
4191
|
function LinkEditorPanel({
|
|
4934
4192
|
open = true,
|
|
4935
4193
|
mode = "create",
|
|
@@ -4953,26 +4211,26 @@ function LinkEditorPanel({
|
|
|
4953
4211
|
onSubmit
|
|
4954
4212
|
});
|
|
4955
4213
|
const isCancel = state.secondaryLabel === "Cancel";
|
|
4956
|
-
return /* @__PURE__ */
|
|
4957
|
-
/* @__PURE__ */
|
|
4214
|
+
return /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
4215
|
+
/* @__PURE__ */ jsx11(
|
|
4958
4216
|
"button",
|
|
4959
4217
|
{
|
|
4960
4218
|
type: "button",
|
|
4961
4219
|
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
4962
4220
|
onClick: state.handleClose,
|
|
4963
4221
|
"aria-label": "Close",
|
|
4964
|
-
children: /* @__PURE__ */
|
|
4222
|
+
children: /* @__PURE__ */ jsx11(IconX, { "aria-hidden": true })
|
|
4965
4223
|
}
|
|
4966
4224
|
),
|
|
4967
|
-
/* @__PURE__ */
|
|
4968
|
-
/* @__PURE__ */
|
|
4969
|
-
state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */
|
|
4225
|
+
/* @__PURE__ */ jsx11("header", { className: "flex w-full flex-col gap-1.5 p-6 pr-12", children: /* @__PURE__ */ jsx11("h2", { className: "m-0 w-full break-words text-lg font-semibold leading-none tracking-tight text-card-foreground", children: state.title }) }),
|
|
4226
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
|
|
4227
|
+
state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ jsx11(
|
|
4970
4228
|
DestinationBreadcrumb,
|
|
4971
4229
|
{
|
|
4972
4230
|
pageTitle: state.selectedPage.title,
|
|
4973
4231
|
sectionLabel: state.selectedSection.label
|
|
4974
4232
|
}
|
|
4975
|
-
) : /* @__PURE__ */
|
|
4233
|
+
) : /* @__PURE__ */ jsx11(
|
|
4976
4234
|
UrlOrPageInput,
|
|
4977
4235
|
{
|
|
4978
4236
|
value: state.searchValue,
|
|
@@ -4985,18 +4243,18 @@ function LinkEditorPanel({
|
|
|
4985
4243
|
urlError: state.urlError
|
|
4986
4244
|
}
|
|
4987
4245
|
),
|
|
4988
|
-
state.showChooseSection ? /* @__PURE__ */
|
|
4989
|
-
/* @__PURE__ */
|
|
4990
|
-
/* @__PURE__ */
|
|
4991
|
-
/* @__PURE__ */
|
|
4992
|
-
/* @__PURE__ */
|
|
4246
|
+
state.showChooseSection ? /* @__PURE__ */ jsxs5("div", { className: "flex flex-col justify-center gap-2", children: [
|
|
4247
|
+
/* @__PURE__ */ jsx11(Button, { type: "button", variant: "outline", className: "w-fit cursor-pointer", size: "sm", onClick: state.handleChooseSection, children: "Choose a section" }),
|
|
4248
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
|
|
4249
|
+
/* @__PURE__ */ jsx11(IconInfo, { className: "shrink-0", "aria-hidden": true }),
|
|
4250
|
+
/* @__PURE__ */ jsx11("span", { children: "Pick a section this link should scroll to." })
|
|
4993
4251
|
] })
|
|
4994
4252
|
] }) : null,
|
|
4995
|
-
state.showSectionPicker ? /* @__PURE__ */
|
|
4996
|
-
state.showSectionRow && state.selectedSection ? /* @__PURE__ */
|
|
4253
|
+
state.showSectionPicker ? /* @__PURE__ */ jsx11(SectionPickerList, { sections: state.activeSections, onSelect: state.handleSectionSelect }) : null,
|
|
4254
|
+
state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx11(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
|
|
4997
4255
|
] }),
|
|
4998
|
-
/* @__PURE__ */
|
|
4999
|
-
/* @__PURE__ */
|
|
4256
|
+
/* @__PURE__ */ jsxs5("footer", { className: "flex w-full items-center justify-end gap-2 px-6 pb-6", children: [
|
|
4257
|
+
/* @__PURE__ */ jsx11(
|
|
5000
4258
|
Button,
|
|
5001
4259
|
{
|
|
5002
4260
|
type: "button",
|
|
@@ -5011,7 +4269,7 @@ function LinkEditorPanel({
|
|
|
5011
4269
|
children: state.secondaryLabel
|
|
5012
4270
|
}
|
|
5013
4271
|
),
|
|
5014
|
-
/* @__PURE__ */
|
|
4272
|
+
/* @__PURE__ */ jsx11(
|
|
5015
4273
|
Button,
|
|
5016
4274
|
{
|
|
5017
4275
|
type: "button",
|
|
@@ -5030,7 +4288,7 @@ function LinkEditorPanel({
|
|
|
5030
4288
|
}
|
|
5031
4289
|
|
|
5032
4290
|
// src/ui/link-modal/LinkPopover.tsx
|
|
5033
|
-
import { jsx as
|
|
4291
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
5034
4292
|
function LinkPopover({
|
|
5035
4293
|
rect,
|
|
5036
4294
|
parentScroll,
|
|
@@ -5038,7 +4296,7 @@ function LinkPopover({
|
|
|
5038
4296
|
...editorProps
|
|
5039
4297
|
}) {
|
|
5040
4298
|
const { top, left, transform } = calcPopoverPos(rect, parentScroll);
|
|
5041
|
-
return /* @__PURE__ */
|
|
4299
|
+
return /* @__PURE__ */ jsx12(
|
|
5042
4300
|
"div",
|
|
5043
4301
|
{
|
|
5044
4302
|
ref: panelRef,
|
|
@@ -5051,7 +4309,7 @@ function LinkPopover({
|
|
|
5051
4309
|
),
|
|
5052
4310
|
style: { top, left, transform },
|
|
5053
4311
|
onMouseDown: (e) => e.stopPropagation(),
|
|
5054
|
-
children: /* @__PURE__ */
|
|
4312
|
+
children: /* @__PURE__ */ jsx12(LinkEditorPanel, { ...editorProps, open: true })
|
|
5055
4313
|
}
|
|
5056
4314
|
);
|
|
5057
4315
|
}
|
|
@@ -5114,30 +4372,8 @@ function shouldUseDevFixtures() {
|
|
|
5114
4372
|
return new URLSearchParams(q).get("ohw-fixtures") === "1";
|
|
5115
4373
|
}
|
|
5116
4374
|
|
|
5117
|
-
// src/ui/badge.tsx
|
|
5118
|
-
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
5119
|
-
var badgeVariants = cva(
|
|
5120
|
-
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
5121
|
-
{
|
|
5122
|
-
variants: {
|
|
5123
|
-
variant: {
|
|
5124
|
-
default: "border-transparent bg-primary text-primary-foreground",
|
|
5125
|
-
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
5126
|
-
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
5127
|
-
outline: "text-foreground"
|
|
5128
|
-
}
|
|
5129
|
-
},
|
|
5130
|
-
defaultVariants: {
|
|
5131
|
-
variant: "default"
|
|
5132
|
-
}
|
|
5133
|
-
}
|
|
5134
|
-
);
|
|
5135
|
-
function Badge({ className, variant, ...props }) {
|
|
5136
|
-
return /* @__PURE__ */ jsx15("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
5137
|
-
}
|
|
5138
|
-
|
|
5139
4375
|
// src/OhhwellsBridge.tsx
|
|
5140
|
-
import { Fragment as
|
|
4376
|
+
import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
5141
4377
|
var PRIMARY = "#0885FE";
|
|
5142
4378
|
var IMAGE_FADE_MS = 300;
|
|
5143
4379
|
function runOpacityFade(el, onDone) {
|
|
@@ -5188,163 +4424,6 @@ function fadeInBgImage(el, url, onReady) {
|
|
|
5188
4424
|
if (!prevPos || prevPos === "static") el.style.position = prevPos;
|
|
5189
4425
|
});
|
|
5190
4426
|
}
|
|
5191
|
-
function getSectionsTracker() {
|
|
5192
|
-
let el = document.querySelector("[data-ohw-sections-tracker]");
|
|
5193
|
-
if (!el) {
|
|
5194
|
-
el = document.createElement("div");
|
|
5195
|
-
el.setAttribute("data-ohw-sections-tracker", "");
|
|
5196
|
-
el.style.display = "none";
|
|
5197
|
-
document.body.appendChild(el);
|
|
5198
|
-
}
|
|
5199
|
-
return el;
|
|
5200
|
-
}
|
|
5201
|
-
function updateSectionScheduleId(insertAfter, scheduleId) {
|
|
5202
|
-
const tracker = getSectionsTracker();
|
|
5203
|
-
let sections = [];
|
|
5204
|
-
try {
|
|
5205
|
-
sections = JSON.parse(tracker.textContent || "[]");
|
|
5206
|
-
} catch {
|
|
5207
|
-
}
|
|
5208
|
-
const currentPath = window.location.pathname;
|
|
5209
|
-
const updated = sections.map((s) => {
|
|
5210
|
-
if (s.type !== "scheduling" || s.insertAfter !== insertAfter) return s;
|
|
5211
|
-
if (s.pagePath && s.pagePath !== currentPath) return s;
|
|
5212
|
-
return { ...s, scheduleId };
|
|
5213
|
-
});
|
|
5214
|
-
tracker.textContent = JSON.stringify(updated);
|
|
5215
|
-
return tracker.textContent ?? "[]";
|
|
5216
|
-
}
|
|
5217
|
-
function schedulingSectionId(insertAfter) {
|
|
5218
|
-
return `scheduling-${insertAfter}`;
|
|
5219
|
-
}
|
|
5220
|
-
var INSERT_BEFORE_MARKER = ":before:";
|
|
5221
|
-
function parseSchedulingInsertAfter(insertAfter) {
|
|
5222
|
-
const idx = insertAfter.indexOf(INSERT_BEFORE_MARKER);
|
|
5223
|
-
if (idx < 0) return { anchor: insertAfter, insertBefore: null };
|
|
5224
|
-
return {
|
|
5225
|
-
anchor: insertAfter.slice(0, idx),
|
|
5226
|
-
insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
|
|
5227
|
-
};
|
|
5228
|
-
}
|
|
5229
|
-
function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
|
|
5230
|
-
const parsed = parseSchedulingInsertAfter(insertAfter);
|
|
5231
|
-
const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
|
|
5232
|
-
const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
|
|
5233
|
-
return { effectiveInsertAfter, insertBefore };
|
|
5234
|
-
}
|
|
5235
|
-
function getSchedulingMountPoint(insertAfter) {
|
|
5236
|
-
const { anchor } = parseSchedulingInsertAfter(insertAfter);
|
|
5237
|
-
let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
|
|
5238
|
-
if (!anchorEl && anchor === "scheduling") {
|
|
5239
|
-
const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
|
|
5240
|
-
anchorEl = widgets.at(-1) ?? null;
|
|
5241
|
-
}
|
|
5242
|
-
if (!anchorEl) return null;
|
|
5243
|
-
return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
5244
|
-
}
|
|
5245
|
-
function schedulingMountDepth(insertAfter) {
|
|
5246
|
-
if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
|
|
5247
|
-
return insertAfter.split(INSERT_BEFORE_MARKER).length - 1;
|
|
5248
|
-
}
|
|
5249
|
-
function getPageSchedulingEntries(raw) {
|
|
5250
|
-
if (!raw) return [];
|
|
5251
|
-
try {
|
|
5252
|
-
const entries = JSON.parse(raw);
|
|
5253
|
-
const currentPath = window.location.pathname;
|
|
5254
|
-
return entries.filter((e) => e.type === "scheduling" && (!e.pagePath || e.pagePath === currentPath));
|
|
5255
|
-
} catch {
|
|
5256
|
-
return [];
|
|
5257
|
-
}
|
|
5258
|
-
}
|
|
5259
|
-
function isSchedulingWidgetMissing(entry) {
|
|
5260
|
-
const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
|
|
5261
|
-
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
|
|
5262
|
-
}
|
|
5263
|
-
function hasMissingSchedulingWidgets(entries) {
|
|
5264
|
-
return entries.some(isSchedulingWidgetMissing);
|
|
5265
|
-
}
|
|
5266
|
-
function retryMissingSchedulingMounts(entries, notifyOnConnect = false) {
|
|
5267
|
-
if (!hasMissingSchedulingWidgets(entries)) return;
|
|
5268
|
-
mountSchedulingEntries(entries, notifyOnConnect);
|
|
5269
|
-
}
|
|
5270
|
-
function initSectionsFromContent(content, removeExisting = false) {
|
|
5271
|
-
const raw = content["__ohw_sections"];
|
|
5272
|
-
if (!raw) return;
|
|
5273
|
-
try {
|
|
5274
|
-
if (removeExisting) {
|
|
5275
|
-
document.querySelectorAll('[data-ohw-section-container="scheduling"]').forEach((el) => el.remove());
|
|
5276
|
-
}
|
|
5277
|
-
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
5278
|
-
if (inEditor) getSectionsTracker().textContent = raw;
|
|
5279
|
-
const pageEntries = getPageSchedulingEntries(raw);
|
|
5280
|
-
mountSchedulingEntries(pageEntries, false);
|
|
5281
|
-
requestAnimationFrame(() => retryMissingSchedulingMounts(pageEntries, false));
|
|
5282
|
-
setTimeout(() => retryMissingSchedulingMounts(pageEntries, false), 250);
|
|
5283
|
-
} catch {
|
|
5284
|
-
}
|
|
5285
|
-
}
|
|
5286
|
-
function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
|
|
5287
|
-
const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
|
|
5288
|
-
const sectionId = schedulingSectionId(effectiveInsertAfter);
|
|
5289
|
-
if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
|
|
5290
|
-
const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
|
|
5291
|
-
if (!mountPoint) return false;
|
|
5292
|
-
const container = document.createElement("div");
|
|
5293
|
-
container.dataset.ohwSectionContainer = "scheduling";
|
|
5294
|
-
if (insertBefore) {
|
|
5295
|
-
const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
|
|
5296
|
-
const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
|
|
5297
|
-
if (!beforePoint) return false;
|
|
5298
|
-
beforePoint.insertAdjacentElement("beforebegin", container);
|
|
5299
|
-
} else {
|
|
5300
|
-
let tail = mountPoint;
|
|
5301
|
-
while (tail.nextElementSibling?.dataset.ohwSectionContainer === "scheduling") {
|
|
5302
|
-
tail = tail.nextElementSibling;
|
|
5303
|
-
}
|
|
5304
|
-
tail.insertAdjacentElement("afterend", container);
|
|
5305
|
-
}
|
|
5306
|
-
const root = createRoot(container);
|
|
5307
|
-
flushSync(() => {
|
|
5308
|
-
root.render(
|
|
5309
|
-
/* @__PURE__ */ jsx16(
|
|
5310
|
-
SchedulingWidget,
|
|
5311
|
-
{
|
|
5312
|
-
notifyOnConnect,
|
|
5313
|
-
initialScheduleId: scheduleId,
|
|
5314
|
-
insertAfter: effectiveInsertAfter
|
|
5315
|
-
}
|
|
5316
|
-
)
|
|
5317
|
-
);
|
|
5318
|
-
});
|
|
5319
|
-
const tracker = getSectionsTracker();
|
|
5320
|
-
let sections = [];
|
|
5321
|
-
try {
|
|
5322
|
-
sections = JSON.parse(tracker.textContent || "[]");
|
|
5323
|
-
} catch {
|
|
5324
|
-
}
|
|
5325
|
-
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
5326
|
-
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
|
|
5327
|
-
sections.push({
|
|
5328
|
-
type: "scheduling",
|
|
5329
|
-
insertAfter: effectiveInsertAfter,
|
|
5330
|
-
pagePath: window.location.pathname,
|
|
5331
|
-
...scheduleId ? { scheduleId } : {}
|
|
5332
|
-
});
|
|
5333
|
-
tracker.textContent = JSON.stringify(sections);
|
|
5334
|
-
}
|
|
5335
|
-
return true;
|
|
5336
|
-
}
|
|
5337
|
-
function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
5338
|
-
const pending = entries.filter((e) => e.type === "scheduling").sort((a, b) => schedulingMountDepth(a.insertAfter) - schedulingMountDepth(b.insertAfter));
|
|
5339
|
-
for (let attempt = 0; attempt < pending.length + 1 && pending.length > 0; attempt++) {
|
|
5340
|
-
for (let i = pending.length - 1; i >= 0; i--) {
|
|
5341
|
-
const { insertAfter, scheduleId } = pending[i];
|
|
5342
|
-
if (mountSchedulingWidget(insertAfter, notifyOnConnect, scheduleId)) {
|
|
5343
|
-
pending.splice(i, 1);
|
|
5344
|
-
}
|
|
5345
|
-
}
|
|
5346
|
-
}
|
|
5347
|
-
}
|
|
5348
4427
|
function getLinkHref(el) {
|
|
5349
4428
|
const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
|
|
5350
4429
|
return anchor?.getAttribute("href") ?? "";
|
|
@@ -5544,7 +4623,7 @@ var TOOLBAR_GROUPS = [
|
|
|
5544
4623
|
];
|
|
5545
4624
|
function GlowFrame({ rect, elRef }) {
|
|
5546
4625
|
const GAP = 6;
|
|
5547
|
-
return /* @__PURE__ */
|
|
4626
|
+
return /* @__PURE__ */ jsx13(
|
|
5548
4627
|
"div",
|
|
5549
4628
|
{
|
|
5550
4629
|
ref: elRef,
|
|
@@ -5597,7 +4676,7 @@ function FloatingToolbar({
|
|
|
5597
4676
|
onEditLink
|
|
5598
4677
|
}) {
|
|
5599
4678
|
const { top, left, transform } = calcToolbarPos(rect, parentScroll);
|
|
5600
|
-
return /* @__PURE__ */
|
|
4679
|
+
return /* @__PURE__ */ jsxs6(
|
|
5601
4680
|
"div",
|
|
5602
4681
|
{
|
|
5603
4682
|
ref: elRef,
|
|
@@ -5622,11 +4701,11 @@ function FloatingToolbar({
|
|
|
5622
4701
|
},
|
|
5623
4702
|
onMouseDown: (e) => e.stopPropagation(),
|
|
5624
4703
|
children: [
|
|
5625
|
-
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */
|
|
5626
|
-
gi > 0 && /* @__PURE__ */
|
|
4704
|
+
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs6(React4.Fragment, { children: [
|
|
4705
|
+
gi > 0 && /* @__PURE__ */ jsx13("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
|
|
5627
4706
|
btns.map((btn) => {
|
|
5628
4707
|
const isActive = activeCommands.has(btn.cmd);
|
|
5629
|
-
return /* @__PURE__ */
|
|
4708
|
+
return /* @__PURE__ */ jsx13(
|
|
5630
4709
|
"button",
|
|
5631
4710
|
{
|
|
5632
4711
|
title: btn.title,
|
|
@@ -5652,7 +4731,7 @@ function FloatingToolbar({
|
|
|
5652
4731
|
flexShrink: 0,
|
|
5653
4732
|
padding: 6
|
|
5654
4733
|
},
|
|
5655
|
-
children: /* @__PURE__ */
|
|
4734
|
+
children: /* @__PURE__ */ jsx13(
|
|
5656
4735
|
"svg",
|
|
5657
4736
|
{
|
|
5658
4737
|
width: "16",
|
|
@@ -5672,7 +4751,7 @@ function FloatingToolbar({
|
|
|
5672
4751
|
);
|
|
5673
4752
|
})
|
|
5674
4753
|
] }, gi)),
|
|
5675
|
-
showEditLink ? /* @__PURE__ */
|
|
4754
|
+
showEditLink ? /* @__PURE__ */ jsx13(
|
|
5676
4755
|
"button",
|
|
5677
4756
|
{
|
|
5678
4757
|
type: "button",
|
|
@@ -5704,9 +4783,9 @@ function FloatingToolbar({
|
|
|
5704
4783
|
flexShrink: 0,
|
|
5705
4784
|
padding: 6
|
|
5706
4785
|
},
|
|
5707
|
-
children: /* @__PURE__ */
|
|
5708
|
-
/* @__PURE__ */
|
|
5709
|
-
/* @__PURE__ */
|
|
4786
|
+
children: /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
4787
|
+
/* @__PURE__ */ jsx13("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
|
|
4788
|
+
/* @__PURE__ */ jsx13("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
|
|
5710
4789
|
] })
|
|
5711
4790
|
}
|
|
5712
4791
|
) : null
|
|
@@ -5724,7 +4803,7 @@ function StateToggle({
|
|
|
5724
4803
|
states,
|
|
5725
4804
|
onStateChange
|
|
5726
4805
|
}) {
|
|
5727
|
-
return /* @__PURE__ */
|
|
4806
|
+
return /* @__PURE__ */ jsx13(
|
|
5728
4807
|
ToggleGroup,
|
|
5729
4808
|
{
|
|
5730
4809
|
"data-ohw-state-toggle": "",
|
|
@@ -5738,35 +4817,18 @@ function StateToggle({
|
|
|
5738
4817
|
left: rect.right - 8,
|
|
5739
4818
|
transform: "translateX(-100%)"
|
|
5740
4819
|
},
|
|
5741
|
-
children: states.map((state) => /* @__PURE__ */
|
|
4820
|
+
children: states.map((state) => /* @__PURE__ */ jsx13(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
5742
4821
|
}
|
|
5743
4822
|
);
|
|
5744
4823
|
}
|
|
5745
4824
|
var contentCache = /* @__PURE__ */ new Map();
|
|
5746
|
-
function resolveSubdomain(subdomainFromQuery) {
|
|
5747
|
-
if (subdomainFromQuery) return subdomainFromQuery;
|
|
5748
|
-
if (typeof window !== "undefined") {
|
|
5749
|
-
const parts = window.location.hostname.split(".");
|
|
5750
|
-
if (parts.length >= 3 && parts[0] !== "www") return parts[0];
|
|
5751
|
-
}
|
|
5752
|
-
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL;
|
|
5753
|
-
if (siteUrl) {
|
|
5754
|
-
try {
|
|
5755
|
-
const host = new URL(siteUrl).hostname;
|
|
5756
|
-
const siteParts = host.split(".");
|
|
5757
|
-
if (siteParts.length >= 3 && siteParts[0] !== "www") return siteParts[0];
|
|
5758
|
-
} catch {
|
|
5759
|
-
}
|
|
5760
|
-
}
|
|
5761
|
-
return "";
|
|
5762
|
-
}
|
|
5763
4825
|
function OhhwellsBridge() {
|
|
5764
4826
|
const pathname = usePathname();
|
|
5765
4827
|
const router = useRouter();
|
|
5766
4828
|
const searchParams = useSearchParams();
|
|
5767
4829
|
const isEditMode = isEditSessionActive();
|
|
5768
|
-
const [bridgeRoot, setBridgeRoot] =
|
|
5769
|
-
|
|
4830
|
+
const [bridgeRoot, setBridgeRoot] = useState3(null);
|
|
4831
|
+
useEffect2(() => {
|
|
5770
4832
|
const figtreeFontId = "ohw-figtree-font";
|
|
5771
4833
|
if (!document.getElementById(figtreeFontId)) {
|
|
5772
4834
|
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
@@ -5789,47 +4851,50 @@ function OhhwellsBridge() {
|
|
|
5789
4851
|
};
|
|
5790
4852
|
}, []);
|
|
5791
4853
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
5792
|
-
const subdomain =
|
|
4854
|
+
const subdomain = subdomainFromQuery ?? (() => {
|
|
4855
|
+
if (typeof window === "undefined") return "";
|
|
4856
|
+
const parts = window.location.hostname.split(".");
|
|
4857
|
+
return parts.length >= 3 && parts[0] !== "www" ? parts[0] : "";
|
|
4858
|
+
})();
|
|
5793
4859
|
const postToParent = useCallback2((data) => {
|
|
5794
4860
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
5795
4861
|
window.parent.postMessage(data, "*");
|
|
5796
4862
|
}
|
|
5797
4863
|
}, []);
|
|
5798
|
-
const [fetchState, setFetchState] =
|
|
5799
|
-
const autoSaveTimers =
|
|
5800
|
-
const activeElRef =
|
|
5801
|
-
const originalContentRef =
|
|
5802
|
-
const activeStateElRef =
|
|
5803
|
-
const parentScrollRef =
|
|
5804
|
-
const toolbarElRef =
|
|
5805
|
-
const glowElRef =
|
|
5806
|
-
const hoveredImageRef =
|
|
5807
|
-
const hoveredImageHasTextOverlapRef =
|
|
5808
|
-
const
|
|
5809
|
-
const
|
|
5810
|
-
const
|
|
5811
|
-
const
|
|
5812
|
-
const activateRef = useRef3(() => {
|
|
4864
|
+
const [fetchState, setFetchState] = useState3("idle");
|
|
4865
|
+
const autoSaveTimers = useRef2(/* @__PURE__ */ new Map());
|
|
4866
|
+
const activeElRef = useRef2(null);
|
|
4867
|
+
const originalContentRef = useRef2(null);
|
|
4868
|
+
const activeStateElRef = useRef2(null);
|
|
4869
|
+
const parentScrollRef = useRef2(null);
|
|
4870
|
+
const toolbarElRef = useRef2(null);
|
|
4871
|
+
const glowElRef = useRef2(null);
|
|
4872
|
+
const hoveredImageRef = useRef2(null);
|
|
4873
|
+
const hoveredImageHasTextOverlapRef = useRef2(false);
|
|
4874
|
+
const imageUnhoverTimerRef = useRef2(null);
|
|
4875
|
+
const imageShowTimerRef = useRef2(null);
|
|
4876
|
+
const editStylesRef = useRef2(null);
|
|
4877
|
+
const activateRef = useRef2(() => {
|
|
5813
4878
|
});
|
|
5814
|
-
const deactivateRef =
|
|
4879
|
+
const deactivateRef = useRef2(() => {
|
|
5815
4880
|
});
|
|
5816
|
-
const refreshActiveCommandsRef =
|
|
4881
|
+
const refreshActiveCommandsRef = useRef2(() => {
|
|
5817
4882
|
});
|
|
5818
|
-
const postToParentRef =
|
|
4883
|
+
const postToParentRef = useRef2(postToParent);
|
|
5819
4884
|
postToParentRef.current = postToParent;
|
|
5820
|
-
const [toolbarRect, setToolbarRect] =
|
|
5821
|
-
const [toggleState, setToggleState] =
|
|
5822
|
-
const [maxBadge, setMaxBadge] =
|
|
5823
|
-
const [activeCommands, setActiveCommands] =
|
|
5824
|
-
const [toolbarShowEditLink, setToolbarShowEditLink] =
|
|
5825
|
-
const [linkPopover, setLinkPopover] =
|
|
5826
|
-
const [sitePages, setSitePages] =
|
|
5827
|
-
const [sectionsByPath, setSectionsByPath] =
|
|
5828
|
-
const sectionsPrefetchGenRef =
|
|
5829
|
-
const setLinkPopoverRef =
|
|
5830
|
-
const linkPopoverPanelRef =
|
|
5831
|
-
const linkPopoverOpenRef =
|
|
5832
|
-
const linkPopoverGraceUntilRef =
|
|
4885
|
+
const [toolbarRect, setToolbarRect] = useState3(null);
|
|
4886
|
+
const [toggleState, setToggleState] = useState3(null);
|
|
4887
|
+
const [maxBadge, setMaxBadge] = useState3(null);
|
|
4888
|
+
const [activeCommands, setActiveCommands] = useState3(/* @__PURE__ */ new Set());
|
|
4889
|
+
const [toolbarShowEditLink, setToolbarShowEditLink] = useState3(false);
|
|
4890
|
+
const [linkPopover, setLinkPopover] = useState3(null);
|
|
4891
|
+
const [sitePages, setSitePages] = useState3([]);
|
|
4892
|
+
const [sectionsByPath, setSectionsByPath] = useState3({});
|
|
4893
|
+
const sectionsPrefetchGenRef = useRef2(0);
|
|
4894
|
+
const setLinkPopoverRef = useRef2(setLinkPopover);
|
|
4895
|
+
const linkPopoverPanelRef = useRef2(null);
|
|
4896
|
+
const linkPopoverOpenRef = useRef2(false);
|
|
4897
|
+
const linkPopoverGraceUntilRef = useRef2(0);
|
|
5833
4898
|
setLinkPopoverRef.current = setLinkPopover;
|
|
5834
4899
|
const bumpLinkPopoverGrace = () => {
|
|
5835
4900
|
linkPopoverGraceUntilRef.current = Date.now() + 350;
|
|
@@ -5853,9 +4918,9 @@ function OhhwellsBridge() {
|
|
|
5853
4918
|
);
|
|
5854
4919
|
});
|
|
5855
4920
|
}, [isEditMode, pathname]);
|
|
5856
|
-
const runSectionsPrefetchRef =
|
|
4921
|
+
const runSectionsPrefetchRef = useRef2(runSectionsPrefetch);
|
|
5857
4922
|
runSectionsPrefetchRef.current = runSectionsPrefetch;
|
|
5858
|
-
|
|
4923
|
+
useEffect2(() => {
|
|
5859
4924
|
if (!linkPopover) return;
|
|
5860
4925
|
if (hoveredImageRef.current) {
|
|
5861
4926
|
hoveredImageRef.current = null;
|
|
@@ -5863,7 +4928,7 @@ function OhhwellsBridge() {
|
|
|
5863
4928
|
}
|
|
5864
4929
|
postToParent({ type: "ow:image-unhover" });
|
|
5865
4930
|
}, [linkPopover, postToParent]);
|
|
5866
|
-
|
|
4931
|
+
useEffect2(() => {
|
|
5867
4932
|
if (!isEditMode) return;
|
|
5868
4933
|
const useFixtures = shouldUseDevFixtures();
|
|
5869
4934
|
if (useFixtures) {
|
|
@@ -5887,15 +4952,14 @@ function OhhwellsBridge() {
|
|
|
5887
4952
|
if (!useFixtures) postToParent({ type: "ow:request-site-pages" });
|
|
5888
4953
|
return () => window.removeEventListener("message", onSitePages);
|
|
5889
4954
|
}, [isEditMode, postToParent]);
|
|
5890
|
-
|
|
5891
|
-
useEffect3(() => {
|
|
4955
|
+
useEffect2(() => {
|
|
5892
4956
|
if (!isEditMode || shouldUseDevFixtures()) return;
|
|
5893
4957
|
void loadAllSectionsManifest().then((manifest) => {
|
|
5894
4958
|
if (Object.keys(manifest).length === 0) return;
|
|
5895
4959
|
setSectionsByPath((prev) => ({ ...manifest, ...prev }));
|
|
5896
4960
|
});
|
|
5897
4961
|
}, [isEditMode]);
|
|
5898
|
-
|
|
4962
|
+
useEffect2(() => {
|
|
5899
4963
|
const update = () => {
|
|
5900
4964
|
const el = activeElRef.current;
|
|
5901
4965
|
if (el) setToolbarRect(el.getBoundingClientRect());
|
|
@@ -5903,12 +4967,6 @@ function OhhwellsBridge() {
|
|
|
5903
4967
|
if (!prev || !activeStateElRef.current) return prev;
|
|
5904
4968
|
return { ...prev, rect: activeStateElRef.current.getBoundingClientRect() };
|
|
5905
4969
|
});
|
|
5906
|
-
setSectionGap((prev) => {
|
|
5907
|
-
if (!prev) return prev;
|
|
5908
|
-
const anchor = document.querySelector(`[data-ohw-section="${prev.insertAfter}"]`);
|
|
5909
|
-
if (!anchor) return prev;
|
|
5910
|
-
return { ...prev, y: anchor.getBoundingClientRect().bottom };
|
|
5911
|
-
});
|
|
5912
4970
|
};
|
|
5913
4971
|
const vvp = window.visualViewport;
|
|
5914
4972
|
if (!vvp) return;
|
|
@@ -5975,7 +5033,6 @@ function OhhwellsBridge() {
|
|
|
5975
5033
|
const applyContent = (content) => {
|
|
5976
5034
|
const imageLoads = [];
|
|
5977
5035
|
for (const [key, val] of Object.entries(content)) {
|
|
5978
|
-
if (key === "__ohw_sections") continue;
|
|
5979
5036
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
5980
5037
|
if (el.dataset.ohwEditable === "image") {
|
|
5981
5038
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -5997,7 +5054,6 @@ function OhhwellsBridge() {
|
|
|
5997
5054
|
});
|
|
5998
5055
|
applyLinkByKey(key, val);
|
|
5999
5056
|
}
|
|
6000
|
-
initSectionsFromContent(content, true);
|
|
6001
5057
|
return imageLoads.length > 0 ? Promise.all(imageLoads).then(() => {
|
|
6002
5058
|
}) : Promise.resolve();
|
|
6003
5059
|
};
|
|
@@ -6022,15 +5078,12 @@ function OhhwellsBridge() {
|
|
|
6022
5078
|
cancelled = true;
|
|
6023
5079
|
};
|
|
6024
5080
|
}, [subdomain, isEditMode, pathname]);
|
|
6025
|
-
|
|
5081
|
+
useEffect2(() => {
|
|
6026
5082
|
if (!subdomain || isEditMode) return;
|
|
6027
|
-
let debounceTimer = null;
|
|
6028
5083
|
const applyFromCache = () => {
|
|
6029
5084
|
const content = contentCache.get(subdomain);
|
|
6030
5085
|
if (!content) return;
|
|
6031
|
-
retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
|
|
6032
5086
|
for (const [key, val] of Object.entries(content)) {
|
|
6033
|
-
if (key === "__ohw_sections") continue;
|
|
6034
5087
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
6035
5088
|
if (el.dataset.ohwEditable === "image") {
|
|
6036
5089
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6047,28 +5100,21 @@ function OhhwellsBridge() {
|
|
|
6047
5100
|
applyLinkByKey(key, val);
|
|
6048
5101
|
}
|
|
6049
5102
|
};
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
debounceTimer = setTimeout(applyFromCache, 150);
|
|
6053
|
-
};
|
|
6054
|
-
scheduleApply();
|
|
6055
|
-
const observer = new MutationObserver(scheduleApply);
|
|
5103
|
+
applyFromCache();
|
|
5104
|
+
const observer = new MutationObserver(applyFromCache);
|
|
6056
5105
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
6057
|
-
return () =>
|
|
6058
|
-
|
|
6059
|
-
if (debounceTimer) clearTimeout(debounceTimer);
|
|
6060
|
-
};
|
|
6061
|
-
}, [subdomain, isEditMode, pathname]);
|
|
5106
|
+
return () => observer.disconnect();
|
|
5107
|
+
}, [subdomain, isEditMode]);
|
|
6062
5108
|
useLayoutEffect(() => {
|
|
6063
5109
|
const el = document.getElementById("ohw-loader");
|
|
6064
5110
|
if (!el) return;
|
|
6065
5111
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
6066
5112
|
el.style.display = visible ? "flex" : "none";
|
|
6067
5113
|
}, [subdomain, fetchState]);
|
|
6068
|
-
|
|
5114
|
+
useEffect2(() => {
|
|
6069
5115
|
postToParent({ type: "ow:navigation", path: pathname });
|
|
6070
5116
|
}, [pathname, postToParent]);
|
|
6071
|
-
|
|
5117
|
+
useEffect2(() => {
|
|
6072
5118
|
if (!isEditMode) return;
|
|
6073
5119
|
const measure = () => {
|
|
6074
5120
|
const h = document.body.scrollHeight;
|
|
@@ -6092,7 +5138,7 @@ function OhhwellsBridge() {
|
|
|
6092
5138
|
window.removeEventListener("resize", handleResize);
|
|
6093
5139
|
};
|
|
6094
5140
|
}, [pathname, isEditMode, postToParent]);
|
|
6095
|
-
|
|
5141
|
+
useEffect2(() => {
|
|
6096
5142
|
if (!subdomainFromQuery || isEditMode) return;
|
|
6097
5143
|
const handleClick = (e) => {
|
|
6098
5144
|
const anchor = e.target.closest("a");
|
|
@@ -6108,7 +5154,7 @@ function OhhwellsBridge() {
|
|
|
6108
5154
|
document.addEventListener("click", handleClick, true);
|
|
6109
5155
|
return () => document.removeEventListener("click", handleClick, true);
|
|
6110
5156
|
}, [subdomainFromQuery, isEditMode, router]);
|
|
6111
|
-
|
|
5157
|
+
useEffect2(() => {
|
|
6112
5158
|
if (!isEditMode) {
|
|
6113
5159
|
editStylesRef.current?.base.remove();
|
|
6114
5160
|
editStylesRef.current?.forceHover.remove();
|
|
@@ -6409,15 +5455,6 @@ function OhhwellsBridge() {
|
|
|
6409
5455
|
textEditable.setAttribute("data-ohw-hovered", "");
|
|
6410
5456
|
return;
|
|
6411
5457
|
}
|
|
6412
|
-
if (hoveredGapRef.current) {
|
|
6413
|
-
if (hoveredImageRef.current) {
|
|
6414
|
-
hoveredImageRef.current = null;
|
|
6415
|
-
resumeAnimTracks();
|
|
6416
|
-
postToParentRef.current({ type: "ow:image-unhover" });
|
|
6417
|
-
}
|
|
6418
|
-
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
6419
|
-
return;
|
|
6420
|
-
}
|
|
6421
5458
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
6422
5459
|
if (imgEl !== hoveredImageRef.current || hoveredImageHasTextOverlapRef.current) {
|
|
6423
5460
|
hoveredImageRef.current = imgEl;
|
|
@@ -6483,30 +5520,8 @@ function OhhwellsBridge() {
|
|
|
6483
5520
|
}
|
|
6484
5521
|
}
|
|
6485
5522
|
};
|
|
6486
|
-
const probeSectionGapAt = (clientX, clientY, fromParentViewport = false) => {
|
|
6487
|
-
const { y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
6488
|
-
const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
|
|
6489
|
-
const ZONE = 20;
|
|
6490
|
-
for (let i = 0; i < sections.length; i++) {
|
|
6491
|
-
const a = sections[i];
|
|
6492
|
-
const b = sections[i + 1] ?? null;
|
|
6493
|
-
const boundaryY = a.getBoundingClientRect().bottom;
|
|
6494
|
-
if (Math.abs(y - boundaryY) <= ZONE) {
|
|
6495
|
-
const insertAfter = a.dataset.ohwSection ?? "";
|
|
6496
|
-
const insertBefore = b?.dataset.ohwSection ?? null;
|
|
6497
|
-
hoveredGapRef.current = { insertAfter, insertBefore };
|
|
6498
|
-
setSectionGap({ insertAfter, insertBefore, y: boundaryY });
|
|
6499
|
-
return;
|
|
6500
|
-
}
|
|
6501
|
-
}
|
|
6502
|
-
if (hoveredGapRef.current) {
|
|
6503
|
-
hoveredGapRef.current = null;
|
|
6504
|
-
setSectionGap(null);
|
|
6505
|
-
}
|
|
6506
|
-
};
|
|
6507
5523
|
const handleMouseMove = (e) => {
|
|
6508
5524
|
const { clientX, clientY } = e;
|
|
6509
|
-
probeSectionGapAt(clientX, clientY);
|
|
6510
5525
|
probeImageAt(clientX, clientY);
|
|
6511
5526
|
probeHoverCardsAt(clientX, clientY);
|
|
6512
5527
|
};
|
|
@@ -6514,7 +5529,6 @@ function OhhwellsBridge() {
|
|
|
6514
5529
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
6515
5530
|
const { clientX, clientY } = e.data;
|
|
6516
5531
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
6517
|
-
probeSectionGapAt(clientX, clientY);
|
|
6518
5532
|
probeImageAt(clientX, clientY);
|
|
6519
5533
|
probeHoverCardsAt(clientX, clientY);
|
|
6520
5534
|
};
|
|
@@ -6672,12 +5686,7 @@ function OhhwellsBridge() {
|
|
|
6672
5686
|
if (e.data?.type !== "ow:hydrate") return;
|
|
6673
5687
|
const content = e.data.content;
|
|
6674
5688
|
if (!content) return;
|
|
6675
|
-
let sectionsJson = null;
|
|
6676
5689
|
for (const [key, val] of Object.entries(content)) {
|
|
6677
|
-
if (key === "__ohw_sections") {
|
|
6678
|
-
sectionsJson = val;
|
|
6679
|
-
continue;
|
|
6680
|
-
}
|
|
6681
5690
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
6682
5691
|
if (el.dataset.ohwEditable === "image") {
|
|
6683
5692
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6692,9 +5701,6 @@ function OhhwellsBridge() {
|
|
|
6692
5701
|
});
|
|
6693
5702
|
applyLinkByKey(key, val);
|
|
6694
5703
|
}
|
|
6695
|
-
if (sectionsJson) {
|
|
6696
|
-
initSectionsFromContent({ __ohw_sections: sectionsJson }, true);
|
|
6697
|
-
}
|
|
6698
5704
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
6699
5705
|
};
|
|
6700
5706
|
window.addEventListener("message", handleHydrate);
|
|
@@ -6747,63 +5753,7 @@ function OhhwellsBridge() {
|
|
|
6747
5753
|
};
|
|
6748
5754
|
const handleSave = (e) => {
|
|
6749
5755
|
if (e.data?.type !== "ow:save") return;
|
|
6750
|
-
|
|
6751
|
-
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
6752
|
-
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
6753
|
-
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
6754
|
-
};
|
|
6755
|
-
const handleInsertSection = (e) => {
|
|
6756
|
-
if (e.data?.type !== "ow:insert-section") return;
|
|
6757
|
-
const { widgetType, insertAfter, insertBefore } = e.data;
|
|
6758
|
-
if (widgetType !== "scheduling") return;
|
|
6759
|
-
const inserted = mountSchedulingWidget(insertAfter, true, void 0, insertBefore ?? null);
|
|
6760
|
-
if (inserted) {
|
|
6761
|
-
const tracker = getSectionsTracker();
|
|
6762
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
|
|
6763
|
-
const h = document.documentElement.scrollHeight;
|
|
6764
|
-
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
6765
|
-
}
|
|
6766
|
-
};
|
|
6767
|
-
const handleSwitchSchedule = (e) => {
|
|
6768
|
-
if (e.data?.type !== "ow:switch-schedule") return;
|
|
6769
|
-
const scheduleId = e.data.scheduleId;
|
|
6770
|
-
const insertAfter = e.data.insertAfter;
|
|
6771
|
-
if (!scheduleId || !insertAfter) return;
|
|
6772
|
-
const text = updateSectionScheduleId(insertAfter, scheduleId);
|
|
6773
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text }] });
|
|
6774
|
-
};
|
|
6775
|
-
const handleScheduleLinked = (e) => {
|
|
6776
|
-
if (e.data?.type !== "ow:schedule-linked") return;
|
|
6777
|
-
const scheduleId = e.data.scheduleId;
|
|
6778
|
-
const insertAfter = e.data.insertAfter;
|
|
6779
|
-
if (!scheduleId || !insertAfter) return;
|
|
6780
|
-
const text = updateSectionScheduleId(insertAfter, scheduleId);
|
|
6781
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text }] });
|
|
6782
|
-
};
|
|
6783
|
-
const handleClearSchedulingWidget = (e) => {
|
|
6784
|
-
if (e.data?.type !== "ow:clear-scheduling-widget") return;
|
|
6785
|
-
const insertAfter = e.data.insertAfter;
|
|
6786
|
-
if (!insertAfter) return;
|
|
6787
|
-
const text = updateSectionScheduleId(insertAfter, null);
|
|
6788
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text }] });
|
|
6789
|
-
};
|
|
6790
|
-
const handleRemoveSchedulingSection = (e) => {
|
|
6791
|
-
if (e.data?.type !== "ow:remove-scheduling-section") return;
|
|
6792
|
-
document.querySelectorAll('[data-ohw-section-container="scheduling"]').forEach((el) => {
|
|
6793
|
-
el.remove();
|
|
6794
|
-
});
|
|
6795
|
-
const tracker = getSectionsTracker();
|
|
6796
|
-
let sections = [];
|
|
6797
|
-
try {
|
|
6798
|
-
sections = JSON.parse(tracker.textContent || "[]");
|
|
6799
|
-
} catch {
|
|
6800
|
-
}
|
|
6801
|
-
const currentPath = window.location.pathname;
|
|
6802
|
-
const updated = sections.filter((s) => !(s.type === "scheduling" && s.pagePath === currentPath));
|
|
6803
|
-
tracker.textContent = JSON.stringify(updated);
|
|
6804
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
|
|
6805
|
-
const h = document.documentElement.scrollHeight;
|
|
6806
|
-
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
5756
|
+
postToParentRef.current({ type: "ow:save-result", nodes: collectEditableNodes() });
|
|
6807
5757
|
};
|
|
6808
5758
|
const handleSelectionChange = () => {
|
|
6809
5759
|
if (!activeElRef.current) return;
|
|
@@ -6908,11 +5858,6 @@ function OhhwellsBridge() {
|
|
|
6908
5858
|
deactivateRef.current();
|
|
6909
5859
|
};
|
|
6910
5860
|
window.addEventListener("message", handleSave);
|
|
6911
|
-
window.addEventListener("message", handleInsertSection);
|
|
6912
|
-
window.addEventListener("message", handleSwitchSchedule);
|
|
6913
|
-
window.addEventListener("message", handleScheduleLinked);
|
|
6914
|
-
window.addEventListener("message", handleClearSchedulingWidget);
|
|
6915
|
-
window.addEventListener("message", handleRemoveSchedulingSection);
|
|
6916
5861
|
window.addEventListener("message", handleImageUrl);
|
|
6917
5862
|
window.addEventListener("message", handleAnimLock);
|
|
6918
5863
|
window.addEventListener("message", handleCanvasHeight);
|
|
@@ -6947,11 +5892,6 @@ function OhhwellsBridge() {
|
|
|
6947
5892
|
document.removeEventListener("selectionchange", handleSelectionChange);
|
|
6948
5893
|
window.removeEventListener("scroll", handleScroll, true);
|
|
6949
5894
|
window.removeEventListener("message", handleSave);
|
|
6950
|
-
window.removeEventListener("message", handleInsertSection);
|
|
6951
|
-
window.removeEventListener("message", handleSwitchSchedule);
|
|
6952
|
-
window.removeEventListener("message", handleScheduleLinked);
|
|
6953
|
-
window.removeEventListener("message", handleClearSchedulingWidget);
|
|
6954
|
-
window.removeEventListener("message", handleRemoveSchedulingSection);
|
|
6955
5895
|
window.removeEventListener("message", handleImageUrl);
|
|
6956
5896
|
window.removeEventListener("message", handleAnimLock);
|
|
6957
5897
|
window.removeEventListener("message", handleCanvasHeight);
|
|
@@ -6966,7 +5906,7 @@ function OhhwellsBridge() {
|
|
|
6966
5906
|
if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
|
|
6967
5907
|
};
|
|
6968
5908
|
}, [isEditMode, refreshStateRules]);
|
|
6969
|
-
|
|
5909
|
+
useEffect2(() => {
|
|
6970
5910
|
if (!isEditMode) return;
|
|
6971
5911
|
document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
|
|
6972
5912
|
el.removeAttribute("data-ohw-active-state");
|
|
@@ -6995,7 +5935,7 @@ function OhhwellsBridge() {
|
|
|
6995
5935
|
clearTimeout(timer);
|
|
6996
5936
|
};
|
|
6997
5937
|
}, [pathname, isEditMode, refreshStateRules, postToParent]);
|
|
6998
|
-
|
|
5938
|
+
useEffect2(() => {
|
|
6999
5939
|
scrollToHashSectionWhenReady();
|
|
7000
5940
|
const onHashChange = () => scrollToHashSectionWhenReady();
|
|
7001
5941
|
window.addEventListener("hashchange", onHashChange);
|
|
@@ -7045,10 +5985,10 @@ function OhhwellsBridge() {
|
|
|
7045
5985
|
const currentSections = sectionsByPath[pathname] ?? [];
|
|
7046
5986
|
linkPopoverOpenRef.current = linkPopover !== null;
|
|
7047
5987
|
return bridgeRoot ? createPortal(
|
|
7048
|
-
/* @__PURE__ */
|
|
7049
|
-
toolbarRect && /* @__PURE__ */
|
|
7050
|
-
/* @__PURE__ */
|
|
7051
|
-
/* @__PURE__ */
|
|
5988
|
+
/* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
5989
|
+
toolbarRect && /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
5990
|
+
/* @__PURE__ */ jsx13(GlowFrame, { rect: toolbarRect, elRef: glowElRef }),
|
|
5991
|
+
/* @__PURE__ */ jsx13(
|
|
7052
5992
|
FloatingToolbar,
|
|
7053
5993
|
{
|
|
7054
5994
|
rect: toolbarRect,
|
|
@@ -7061,7 +6001,7 @@ function OhhwellsBridge() {
|
|
|
7061
6001
|
}
|
|
7062
6002
|
)
|
|
7063
6003
|
] }),
|
|
7064
|
-
maxBadge && /* @__PURE__ */
|
|
6004
|
+
maxBadge && /* @__PURE__ */ jsxs6(
|
|
7065
6005
|
"div",
|
|
7066
6006
|
{
|
|
7067
6007
|
"data-ohw-max-badge": "",
|
|
@@ -7087,7 +6027,7 @@ function OhhwellsBridge() {
|
|
|
7087
6027
|
]
|
|
7088
6028
|
}
|
|
7089
6029
|
),
|
|
7090
|
-
toggleState && /* @__PURE__ */
|
|
6030
|
+
toggleState && /* @__PURE__ */ jsx13(
|
|
7091
6031
|
StateToggle,
|
|
7092
6032
|
{
|
|
7093
6033
|
rect: toggleState.rect,
|
|
@@ -7096,7 +6036,7 @@ function OhhwellsBridge() {
|
|
|
7096
6036
|
onStateChange: handleStateChange
|
|
7097
6037
|
}
|
|
7098
6038
|
),
|
|
7099
|
-
linkPopover ? /* @__PURE__ */
|
|
6039
|
+
linkPopover ? /* @__PURE__ */ jsx13(
|
|
7100
6040
|
LinkPopover,
|
|
7101
6041
|
{
|
|
7102
6042
|
rect: linkPopover.rect,
|
|
@@ -7111,32 +6051,7 @@ function OhhwellsBridge() {
|
|
|
7111
6051
|
onClose: closeLinkPopover,
|
|
7112
6052
|
onSubmit: handleLinkPopoverSubmit
|
|
7113
6053
|
}
|
|
7114
|
-
) : null
|
|
7115
|
-
sectionGap && /* @__PURE__ */ jsxs8(
|
|
7116
|
-
"div",
|
|
7117
|
-
{
|
|
7118
|
-
"data-ohw-section-insert-line": "",
|
|
7119
|
-
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
7120
|
-
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
7121
|
-
children: [
|
|
7122
|
-
/* @__PURE__ */ jsx16("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
7123
|
-
/* @__PURE__ */ jsx16(
|
|
7124
|
-
Badge,
|
|
7125
|
-
{
|
|
7126
|
-
className: "px-8 py-1 bg-primary hover:bg-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
|
|
7127
|
-
onClick: () => {
|
|
7128
|
-
window.parent.postMessage(
|
|
7129
|
-
{ type: "ow:add-section", insertAfter: sectionGap.insertAfter, insertBefore: sectionGap.insertBefore },
|
|
7130
|
-
"*"
|
|
7131
|
-
);
|
|
7132
|
-
},
|
|
7133
|
-
children: "Add Section"
|
|
7134
|
-
}
|
|
7135
|
-
),
|
|
7136
|
-
/* @__PURE__ */ jsx16("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
7137
|
-
]
|
|
7138
|
-
}
|
|
7139
|
-
)
|
|
6054
|
+
) : null
|
|
7140
6055
|
] }),
|
|
7141
6056
|
bridgeRoot
|
|
7142
6057
|
) : null;
|
|
@@ -7145,7 +6060,6 @@ export {
|
|
|
7145
6060
|
LinkEditorPanel,
|
|
7146
6061
|
LinkPopover,
|
|
7147
6062
|
OhhwellsBridge,
|
|
7148
|
-
SchedulingWidget,
|
|
7149
6063
|
Toggle,
|
|
7150
6064
|
ToggleGroup,
|
|
7151
6065
|
ToggleGroupItem,
|