@ohhwells/bridge 0.1.29 → 0.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -34,6 +34,7 @@ __export(index_exports, {
34
34
  LinkEditorPanel: () => LinkEditorPanel,
35
35
  LinkPopover: () => LinkPopover,
36
36
  OhhwellsBridge: () => OhhwellsBridge,
37
+ SchedulingWidget: () => SchedulingWidget,
37
38
  Toggle: () => Toggle,
38
39
  ToggleGroup: () => ToggleGroup,
39
40
  ToggleGroupItem: () => ToggleGroupItem,
@@ -48,10 +49,762 @@ __export(index_exports, {
48
49
  module.exports = __toCommonJS(index_exports);
49
50
 
50
51
  // src/OhhwellsBridge.tsx
51
- var import_react3 = __toESM(require("react"), 1);
52
+ var import_react5 = __toESM(require("react"), 1);
53
+ var import_client = require("react-dom/client");
54
+ var import_react_dom = require("react-dom");
55
+
56
+ // src/ui/SchedulingWidget.tsx
57
+ var import_react2 = require("react");
58
+
59
+ // src/ui/EmailCaptureModal.tsx
60
+ var import_react = require("react");
61
+ var import_radix_ui = require("radix-ui");
62
+ var import_jsx_runtime = require("react/jsx-runtime");
63
+ function Spinner() {
64
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
65
+ "svg",
66
+ {
67
+ width: "32",
68
+ height: "32",
69
+ viewBox: "0 0 32 32",
70
+ fill: "none",
71
+ style: { animation: "ohw-spin 0.75s linear infinite" },
72
+ children: [
73
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `@keyframes ohw-spin { to { transform: rotate(360deg); } }` }),
74
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "16", cy: "16", r: "12", stroke: "#e5e7eb", strokeWidth: "3" }),
75
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
76
+ "path",
77
+ {
78
+ d: "M16 4a12 12 0 0 1 12 12",
79
+ stroke: "#3b82f6",
80
+ strokeWidth: "3",
81
+ strokeLinecap: "round"
82
+ }
83
+ )
84
+ ]
85
+ }
86
+ );
87
+ }
88
+ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
89
+ const [email, setEmail] = (0, import_react.useState)("");
90
+ const [submittedEmail, setSubmittedEmail] = (0, import_react.useState)("");
91
+ const [loading, setLoading] = (0, import_react.useState)(false);
92
+ const [success, setSuccess] = (0, import_react.useState)(false);
93
+ const [error, setError] = (0, import_react.useState)(null);
94
+ const isBook = title === "Confirm your spot";
95
+ const handleSubmit = async () => {
96
+ if (!email.trim()) return;
97
+ setLoading(true);
98
+ setError(null);
99
+ try {
100
+ await onSubmit(email.trim());
101
+ setSubmittedEmail(email.trim());
102
+ setSuccess(true);
103
+ } catch (e) {
104
+ setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
105
+ } finally {
106
+ setLoading(false);
107
+ }
108
+ };
109
+ const handleKeyDown = (e) => {
110
+ if (e.key === "Enter" && !loading) handleSubmit();
111
+ };
112
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_radix_ui.Dialog.Root, { open: true, onOpenChange: (open) => {
113
+ if (!open) onClose();
114
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_radix_ui.Dialog.Portal, { children: [
115
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
116
+ import_radix_ui.Dialog.Overlay,
117
+ {
118
+ className: "fixed inset-0 z-50",
119
+ style: { background: "rgba(0,0,0,0.45)" }
120
+ }
121
+ ),
122
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
123
+ import_radix_ui.Dialog.Content,
124
+ {
125
+ 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",
126
+ style: { maxWidth: 400 },
127
+ children: [
128
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-start justify-between gap-3 p-6", children: [
129
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-1", children: [
130
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
131
+ import_radix_ui.Dialog.Title,
132
+ {
133
+ className: "font-body text-xl font-bold m-0 leading-tight",
134
+ style: { color: "var(--color-dark,#200C02)" },
135
+ children: success ? isBook ? "Reservation confirmed!" : "You're on the waitlist!" : title
136
+ }
137
+ ),
138
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
139
+ import_radix_ui.Dialog.Description,
140
+ {
141
+ className: "font-body text-sm m-0",
142
+ style: { color: "#6B7280" },
143
+ children: success ? isBook ? `A confirmation email has been sent to ${submittedEmail}.` : "We'll let you know via email if someone cancels." : subtitle
144
+ }
145
+ )
146
+ ] }),
147
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
148
+ import_radix_ui.Dialog.Close,
149
+ {
150
+ 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",
151
+ style: { color: "#6B7280" },
152
+ "aria-label": "Close",
153
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
154
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
155
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
156
+ ] })
157
+ }
158
+ )
159
+ ] }),
160
+ !success && (loading ? (
161
+ /* Loading state — full body replaced */
162
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col items-center justify-center gap-3 px-7 py-12", children: [
163
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}),
164
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "font-body text-sm m-0", style: { color: "#6B7280" }, children: "Please wait" })
165
+ ] })
166
+ ) : (
167
+ /* Email form */
168
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "px-7 pt-2 pb-6", children: [
169
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-1.5 mb-8", children: [
170
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "font-body text-sm font-medium", style: { color: "var(--color-dark,#200C02)" }, children: "Email" }),
171
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
172
+ "input",
173
+ {
174
+ type: "email",
175
+ value: email,
176
+ onChange: (e) => setEmail(e.target.value),
177
+ onKeyDown: handleKeyDown,
178
+ placeholder: "hello@gmail.com",
179
+ autoFocus: true,
180
+ className: "w-full h-10 px-3 rounded-lg border font-body text-sm outline-none box-border",
181
+ style: {
182
+ borderColor: "#E7E5E4",
183
+ background: "#fff",
184
+ color: "var(--color-dark,#200C02)"
185
+ }
186
+ }
187
+ ),
188
+ error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "font-body text-xs text-red-500 m-0", children: error })
189
+ ] }),
190
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
191
+ "button",
192
+ {
193
+ onClick: handleSubmit,
194
+ disabled: !email.trim(),
195
+ className: "h-9 px-5 rounded-lg font-body text-sm font-semibold cursor-pointer border-none disabled:opacity-50 disabled:cursor-not-allowed",
196
+ style: {
197
+ background: "var(--color-primary,#3D312B)",
198
+ color: "var(--color-light,#FEFFF0)"
199
+ },
200
+ children: "Send"
201
+ }
202
+ ) })
203
+ ] })
204
+ ))
205
+ ]
206
+ }
207
+ )
208
+ ] }) });
209
+ }
210
+
211
+ // src/ui/SchedulingWidget.tsx
212
+ var import_jsx_runtime2 = require("react/jsx-runtime");
213
+ var API_URL = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
214
+ var DAY_ABBR = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
215
+ function classRunsOnDate(cls, date, type) {
216
+ if (type === "FIXED") {
217
+ const d = String(date.getDate()).padStart(2, "0");
218
+ const m = String(date.getMonth() + 1).padStart(2, "0");
219
+ return cls.fixedDates?.some((fd) => fd.date === `${d}-${m}-${date.getFullYear()}`) ?? false;
220
+ }
221
+ return cls.weekdays?.some((w) => w.weekday === date.getDay()) ?? false;
222
+ }
223
+ function formatClassTime(cls) {
224
+ let h = parseInt(cls.startTime.hour, 10);
225
+ const m = parseInt(cls.startTime.minutes, 10);
226
+ if (cls.startTime.time === "PM" && h !== 12) h += 12;
227
+ if (cls.startTime.time === "AM" && h === 12) h = 0;
228
+ const endTotal = h * 60 + m + cls.duration;
229
+ const eh = Math.floor(endTotal / 60) % 24;
230
+ const em = endTotal % 60;
231
+ return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
232
+ }
233
+ function getBookingsOnDate(cls, date) {
234
+ if (!cls.bookings?.length) return 0;
235
+ const ds = date.toISOString().split("T")[0];
236
+ return cls.bookings.filter((b) => {
237
+ try {
238
+ return new Date(b.classDate).toISOString().split("T")[0] === ds;
239
+ } catch {
240
+ return false;
241
+ }
242
+ }).length;
243
+ }
244
+ function buildTimezoneLabel(tz) {
245
+ try {
246
+ const now = /* @__PURE__ */ new Date();
247
+ const timeStr = new Intl.DateTimeFormat("en-US", {
248
+ hour: "2-digit",
249
+ minute: "2-digit",
250
+ hour12: false,
251
+ timeZone: tz
252
+ }).format(now);
253
+ const offsetPart = new Intl.DateTimeFormat("en-US", { timeZoneName: "short", timeZone: tz }).formatToParts(now).find((p) => p.type === "timeZoneName")?.value ?? "";
254
+ const city = tz.split("/").pop()?.replace(/_/g, " ") ?? tz;
255
+ return `${timeStr} (${offsetPart}) ${city} time`;
256
+ } catch {
257
+ return tz;
258
+ }
259
+ }
260
+ function EmptyState({ inEditor, insertAfter }) {
261
+ const handleAddSchedule = () => {
262
+ if (inEditor) {
263
+ window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
264
+ }
265
+ };
266
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
267
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "w-10 h-10 bg-[#F5F5F4] rounded-[10px] flex items-center justify-center shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
268
+ "svg",
269
+ {
270
+ width: "20",
271
+ height: "20",
272
+ viewBox: "0 0 24 24",
273
+ fill: "none",
274
+ stroke: "var(--color-accent, #A89B83)",
275
+ strokeWidth: "1.5",
276
+ strokeLinecap: "round",
277
+ strokeLinejoin: "round",
278
+ children: [
279
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
280
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "16", y1: "2", x2: "16", y2: "6" }),
281
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "8", y1: "2", x2: "8", y2: "6" }),
282
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "3", y1: "10", x2: "21", y2: "10" }),
283
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "12", y1: "14", x2: "12", y2: "18" }),
284
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "10", y1: "16", x2: "14", y2: "16" })
285
+ ]
286
+ }
287
+ ) }),
288
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col items-center gap-2", children: [
289
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "font-body text-lg font-medium text-center text-[#0A0A0A] m-0", children: "No schedule yet" }),
290
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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." })
291
+ ] }),
292
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
293
+ "button",
294
+ {
295
+ onClick: handleAddSchedule,
296
+ 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",
297
+ children: "Add Schedule"
298
+ }
299
+ )
300
+ ] });
301
+ }
302
+ function LoadingSkeleton() {
303
+ const shimmer = {
304
+ background: "linear-gradient(90deg,#f0f0f0 25%,#e8e8e8 50%,#f0f0f0 75%)",
305
+ backgroundSize: "200% 100%",
306
+ animation: "ohw-shimmer 1.5s infinite"
307
+ };
308
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full flex flex-col gap-10", children: [
309
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { children: `@keyframes ohw-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}` }),
310
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex h-[70px] items-stretch", children: Array.from({ length: 7 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex-1 flex flex-col justify-between items-center px-1", children: [
311
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "32px", height: "14px", borderRadius: "4px" } }),
312
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "40px", height: "40px", borderRadius: "50%" } })
313
+ ] }, i)) }),
314
+ [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
315
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex gap-4 py-4 sm:hidden", children: [
316
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col gap-2 shrink-0", children: [
317
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "100px", height: "16px", borderRadius: "4px" } }),
318
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "52px", height: "20px", borderRadius: "999px" } }),
319
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "60px", height: "14px", borderRadius: "4px" } })
320
+ ] }),
321
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-1 flex-col gap-2", children: [
322
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "75%", height: "16px", borderRadius: "4px" } }),
323
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "50%", height: "14px", borderRadius: "4px" } }),
324
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "100%", height: "44px", borderRadius: "8px" } })
325
+ ] })
326
+ ] }),
327
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "hidden sm:flex items-center gap-[60px] py-4", children: [
328
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "120px", height: "16px", borderRadius: "4px", flexShrink: 0 } }),
329
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex-1 flex flex-col gap-2", children: [
330
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "55%", height: "16px", borderRadius: "4px" } }),
331
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "38%", height: "14px", borderRadius: "4px" } })
332
+ ] }),
333
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "56px", height: "32px", borderRadius: "4px", flexShrink: 0 } }),
334
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "200px", height: "44px", borderRadius: "8px", flexShrink: 0 } })
335
+ ] }),
336
+ i < 2 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "h-px bg-black/20" })
337
+ ] }, i))
338
+ ] });
339
+ }
340
+ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal }) {
341
+ const todayMs = (0, import_react2.useMemo)(() => {
342
+ const d = /* @__PURE__ */ new Date();
343
+ d.setHours(0, 0, 0, 0);
344
+ return d.getTime();
345
+ }, []);
346
+ const scrollRef = (0, import_react2.useRef)(null);
347
+ const [canScrollLeft, setCanScrollLeft] = (0, import_react2.useState)(false);
348
+ const [canScrollRight, setCanScrollRight] = (0, import_react2.useState)(false);
349
+ const updateScrollState = () => {
350
+ const el = scrollRef.current;
351
+ if (!el) return;
352
+ setCanScrollLeft(el.scrollLeft > 0);
353
+ setCanScrollRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
354
+ };
355
+ (0, import_react2.useEffect)(() => {
356
+ const el = scrollRef.current;
357
+ if (!el) return;
358
+ updateScrollState();
359
+ el.addEventListener("scroll", updateScrollState);
360
+ const ro = new ResizeObserver(updateScrollState);
361
+ ro.observe(el);
362
+ return () => {
363
+ el.removeEventListener("scroll", updateScrollState);
364
+ ro.disconnect();
365
+ };
366
+ }, [dates]);
367
+ const scroll = (dir) => {
368
+ scrollRef.current?.scrollBy({ left: dir === "left" ? -216 : 216, behavior: "smooth" });
369
+ };
370
+ const isDragging = (0, import_react2.useRef)(false);
371
+ const dragStartX = (0, import_react2.useRef)(0);
372
+ const dragStartScrollLeft = (0, import_react2.useRef)(0);
373
+ const onDragStart = (e) => {
374
+ if (!scrollRef.current) return;
375
+ isDragging.current = true;
376
+ dragStartX.current = e.clientX;
377
+ dragStartScrollLeft.current = scrollRef.current.scrollLeft;
378
+ scrollRef.current.style.cursor = "grabbing";
379
+ scrollRef.current.style.userSelect = "none";
380
+ };
381
+ const onDragMove = (e) => {
382
+ if (!isDragging.current || !scrollRef.current) return;
383
+ const delta = e.clientX - dragStartX.current;
384
+ scrollRef.current.scrollLeft = dragStartScrollLeft.current - delta;
385
+ };
386
+ const onDragEnd = () => {
387
+ if (!scrollRef.current) return;
388
+ isDragging.current = false;
389
+ scrollRef.current.style.cursor = "grab";
390
+ scrollRef.current.style.userSelect = "";
391
+ };
392
+ const datesWithClasses = (0, import_react2.useMemo)(
393
+ () => new Set(dates.map(
394
+ (d, i) => schedule.classes?.some((c) => classRunsOnDate(c, d, schedule.type)) ? i : -1
395
+ ).filter((i) => i >= 0)),
396
+ [dates, schedule]
397
+ );
398
+ const selectedDate = dates[selectedIdx];
399
+ const selectedClasses = (0, import_react2.useMemo)(
400
+ () => (schedule.classes ?? []).filter((c) => selectedDate && classRunsOnDate(c, selectedDate, schedule.type)),
401
+ [schedule, selectedDate]
402
+ );
403
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full flex flex-col gap-10", children: [
404
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "relative w-full", children: [
405
+ canScrollLeft && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
406
+ "button",
407
+ {
408
+ onClick: () => scroll("left"),
409
+ 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",
410
+ style: { background: "var(--color-light,#FEFFF0)", boxShadow: "0 1px 4px rgba(0,0,0,0.15)" },
411
+ "aria-label": "Scroll left",
412
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "15 18 9 12 15 6" }) })
413
+ }
414
+ ),
415
+ canScrollRight && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
416
+ "button",
417
+ {
418
+ onClick: () => scroll("right"),
419
+ 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",
420
+ style: { background: "var(--color-light,#FEFFF0)", boxShadow: "0 1px 4px rgba(0,0,0,0.15)" },
421
+ "aria-label": "Scroll right",
422
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "9 18 15 12 9 6" }) })
423
+ }
424
+ ),
425
+ canScrollLeft && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
426
+ "div",
427
+ {
428
+ className: "sm:hidden absolute left-0 top-0 bottom-0 w-10 z-10 pointer-events-none",
429
+ style: { background: "linear-gradient(to right, var(--color-light,#FEFFF0), transparent)" }
430
+ }
431
+ ),
432
+ canScrollRight && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
433
+ "div",
434
+ {
435
+ className: "sm:hidden absolute right-0 top-0 bottom-0 w-10 z-10 pointer-events-none",
436
+ style: { background: "linear-gradient(to left, var(--color-light,#FEFFF0), transparent)" }
437
+ }
438
+ ),
439
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
440
+ "div",
441
+ {
442
+ ref: scrollRef,
443
+ className: "overflow-x-auto w-full",
444
+ style: { scrollbarWidth: "none", msOverflowStyle: "none", touchAction: "pan-x", cursor: "grab" },
445
+ onMouseDown: onDragStart,
446
+ onMouseMove: onDragMove,
447
+ onMouseUp: onDragEnd,
448
+ onMouseLeave: onDragEnd,
449
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex", style: { width: `max(100%, ${dates.length * 60}px)` }, children: dates.map((date, i) => {
450
+ const isToday = date.getTime() === todayMs;
451
+ const isSelected = i === selectedIdx;
452
+ const clickable = datesWithClasses.has(i);
453
+ const label = isToday ? "TODAY" : DAY_ABBR[date.getDay()];
454
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
455
+ "div",
456
+ {
457
+ onClick: () => clickable && onSelectDate(i),
458
+ className: `flex-1 h-[70px] flex flex-col justify-between items-center ${clickable ? "cursor-pointer opacity-100" : "cursor-default opacity-50"}`,
459
+ children: [
460
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-normal text-center text-(--color-dark,#200C02)", children: label }),
461
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
462
+ "div",
463
+ {
464
+ className: "w-10 h-10 rounded-full flex items-center justify-center",
465
+ style: { background: isSelected ? "var(--color-primary, #3D312B)" : "transparent" },
466
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
467
+ "span",
468
+ {
469
+ className: "font-body text-xl font-bold text-center tracking-display-tight",
470
+ style: { color: isSelected ? "var(--color-light, #FEFFF0)" : "var(--color-dark, #200C02)" },
471
+ children: date.getDate()
472
+ }
473
+ )
474
+ }
475
+ )
476
+ ]
477
+ },
478
+ i
479
+ );
480
+ }) })
481
+ }
482
+ )
483
+ ] }),
484
+ selectedClasses.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "font-body text-base text-(--color-accent,#A89B83) text-center py-8 m-0", children: "No classes scheduled for this day." }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex flex-col", children: selectedClasses.map((cls, i) => {
485
+ const booked = getBookingsOnDate(cls, selectedDate);
486
+ const available = cls.maxParticipants - booked;
487
+ const isFull = available <= 0;
488
+ const isPrivate = cls.maxParticipants === 1;
489
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
490
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex gap-4 py-4 sm:items-center sm:gap-[60px] box-border", children: [
491
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col gap-2 shrink-0 sm:contents", children: [
492
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col gap-2 sm:w-[120px] sm:shrink-0", children: [
493
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block", children: formatClassTime(cls) }),
494
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
495
+ "span",
496
+ {
497
+ className: "inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium w-fit",
498
+ style: isPrivate ? { background: "#DDFBE3", color: "#199130", border: "1px solid #199130", fontWeight: 500 } : { background: "#EEEDFF", color: "#5953FF", border: "1px solid #5953FF", fontWeight: 500 },
499
+ children: isPrivate ? "PRIVATE" : "GROUP"
500
+ }
501
+ )
502
+ ] }),
503
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
504
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
505
+ available,
506
+ "/",
507
+ cls.maxParticipants
508
+ ] }),
509
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "available" })
510
+ ] }) })
511
+ ] }),
512
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-1 flex-col gap-2 min-w-0 sm:contents", children: [
513
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex-1 flex flex-col gap-2 min-w-0", children: [
514
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block truncate", children: cls.name }),
515
+ cls.hostName && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName })
516
+ ] }),
517
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "hidden sm:flex w-14 shrink-0 flex-col gap-px", children: isFull ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
518
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
519
+ available,
520
+ "/",
521
+ cls.maxParticipants
522
+ ] }),
523
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "available" })
524
+ ] }) }),
525
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
526
+ "button",
527
+ {
528
+ 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",
529
+ style: isFull ? {
530
+ background: "transparent",
531
+ border: "1px solid var(--color-dark, #200C02)",
532
+ color: "var(--color-dark, #200C02)"
533
+ } : {
534
+ background: "var(--color-primary, #3D312B)",
535
+ border: "none",
536
+ color: "var(--color-light, #FEFFF0)"
537
+ },
538
+ onClick: () => {
539
+ if (!cls.id) return;
540
+ onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
541
+ },
542
+ children: isFull ? "Join Waitlist" : "Book Now"
543
+ }
544
+ )
545
+ ] })
546
+ ] }),
547
+ i < selectedClasses.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "h-px bg-black/20" })
548
+ ] }, cls.id ?? i);
549
+ }) })
550
+ ] });
551
+ }
552
+ function CalendarFoldIcon() {
553
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
554
+ "svg",
555
+ {
556
+ width: "16",
557
+ height: "16",
558
+ viewBox: "0 0 24 24",
559
+ fill: "none",
560
+ stroke: "currentColor",
561
+ strokeWidth: "2",
562
+ strokeLinecap: "round",
563
+ strokeLinejoin: "round",
564
+ style: { flexShrink: 0 },
565
+ children: [
566
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M8 2v4" }),
567
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M16 2v4" }),
568
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M21 17V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h11Z" }),
569
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M3 10h18" }),
570
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M15 22v-4a2 2 0 0 1 2-2h4" })
571
+ ]
572
+ }
573
+ );
574
+ }
575
+ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAfter: insertAfterProp }) {
576
+ const autoId = (0, import_react2.useId)();
577
+ const insertAfter = insertAfterProp ?? autoId;
578
+ const [schedule, setSchedule] = (0, import_react2.useState)(null);
579
+ const [loading, setLoading] = (0, import_react2.useState)(true);
580
+ const [inEditor, setInEditor] = (0, import_react2.useState)(false);
581
+ const [isHovered, setIsHovered] = (0, import_react2.useState)(false);
582
+ const [modalState, setModalState] = (0, import_react2.useState)(null);
583
+ const switchScheduleIdRef = (0, import_react2.useRef)(null);
584
+ const dates = (0, import_react2.useMemo)(() => {
585
+ const today = /* @__PURE__ */ new Date();
586
+ today.setHours(0, 0, 0, 0);
587
+ return Array.from({ length: 14 }, (_, i) => {
588
+ const d = new Date(today);
589
+ d.setDate(today.getDate() + i);
590
+ return d;
591
+ });
592
+ }, []);
593
+ const [selectedIdx, setSelectedIdx] = (0, import_react2.useState)(0);
594
+ (0, import_react2.useEffect)(() => {
595
+ if (!schedule?.classes) return;
596
+ for (let i = 0; i < dates.length; i++) {
597
+ if (schedule.classes.some((c) => classRunsOnDate(c, dates[i], schedule.type))) {
598
+ setSelectedIdx(i);
599
+ return;
600
+ }
601
+ }
602
+ }, [schedule, dates]);
603
+ (0, import_react2.useEffect)(() => {
604
+ if (typeof window === "undefined") return;
605
+ const isInEditor = window.self !== window.top;
606
+ setInEditor(isInEditor);
607
+ function loadWithId(effectiveId) {
608
+ if (isInEditor) {
609
+ const startEmpty = effectiveId === null;
610
+ if (startEmpty) setLoading(false);
611
+ let initialized = startEmpty;
612
+ const timer = !startEmpty ? setTimeout(() => {
613
+ if (!initialized) {
614
+ initialized = true;
615
+ setLoading(false);
616
+ }
617
+ }, 5e3) : null;
618
+ const handler = (e) => {
619
+ if (e.data?.type === "ow:clear-scheduling-widget") {
620
+ if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
621
+ setSchedule(null);
622
+ setLoading(false);
623
+ return;
624
+ }
625
+ if (e.data?.type === "ow:switch-schedule") {
626
+ if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
627
+ switchScheduleIdRef.current = e.data.scheduleId ?? null;
628
+ initialized = false;
629
+ setLoading(true);
630
+ window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
631
+ return;
632
+ }
633
+ if (e.data?.type !== "ow:user-schedules-response") return;
634
+ if (e.data.insertAfter && e.data.insertAfter !== insertAfter) return;
635
+ if (initialized && switchScheduleIdRef.current === null) return;
636
+ initialized = true;
637
+ if (timer) clearTimeout(timer);
638
+ const schedules = e.data.schedules ?? [];
639
+ const isSwitching = switchScheduleIdRef.current !== null;
640
+ const target = isSwitching ? schedules.find((s) => s.id === switchScheduleIdRef.current) ?? schedules[0] ?? null : effectiveId ? schedules.find((s) => s.id === effectiveId) ?? schedules[0] ?? null : schedules[0] ?? null;
641
+ switchScheduleIdRef.current = null;
642
+ setSchedule(target);
643
+ setLoading(false);
644
+ if (notifyOnConnect && target && !isSwitching) {
645
+ window.parent.postMessage({
646
+ type: "ow:schedule-connected",
647
+ schedule: { id: target.id, name: target.name },
648
+ insertAfter
649
+ }, "*");
650
+ window.postMessage({ type: "ow:schedule-linked", scheduleId: target.id, insertAfter }, "*");
651
+ }
652
+ };
653
+ window.addEventListener("message", handler);
654
+ if (!startEmpty) window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
655
+ return () => {
656
+ window.removeEventListener("message", handler);
657
+ if (timer) clearTimeout(timer);
658
+ };
659
+ }
660
+ if (!effectiveId) {
661
+ setLoading(false);
662
+ return;
663
+ }
664
+ ;
665
+ (async () => {
666
+ try {
667
+ const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
668
+ const data = await res.json();
669
+ setSchedule(data?.id ? data : null);
670
+ } catch {
671
+ }
672
+ setLoading(false);
673
+ })();
674
+ }
675
+ if (initialScheduleId === void 0) {
676
+ let done = false;
677
+ let innerCleanup;
678
+ const timer = setTimeout(() => {
679
+ if (!done) {
680
+ done = true;
681
+ setLoading(false);
682
+ }
683
+ }, 2e3);
684
+ const configHandler = (e) => {
685
+ if (e.data?.type !== "ow:schedule-config" || e.data.insertAfter !== insertAfter || done) return;
686
+ done = true;
687
+ clearTimeout(timer);
688
+ window.removeEventListener("message", configHandler);
689
+ innerCleanup = loadWithId(e.data.scheduleId ?? null);
690
+ };
691
+ window.addEventListener("message", configHandler);
692
+ window.postMessage({ type: "ow:request-schedule-config", insertAfter }, "*");
693
+ return () => {
694
+ window.removeEventListener("message", configHandler);
695
+ clearTimeout(timer);
696
+ innerCleanup?.();
697
+ };
698
+ }
699
+ return loadWithId(initialScheduleId) ?? void 0;
700
+ }, []);
701
+ const timezoneLabel = schedule?.timezone ? (() => {
702
+ try {
703
+ return buildTimezoneLabel(schedule.timezone);
704
+ } catch {
705
+ return void 0;
706
+ }
707
+ })() : void 0;
708
+ const handleModalSubmit = async (email) => {
709
+ if (!modalState) return;
710
+ const { mode, classId, classDate } = modalState;
711
+ const endpoint = mode === "book" ? `${API_URL}/api/schedule/class/${classId}/booking` : `${API_URL}/api/schedule/class/${classId}/waitlist`;
712
+ const res = await fetch(endpoint, {
713
+ method: "POST",
714
+ headers: { "Content-Type": "application/json" },
715
+ body: JSON.stringify({ classDate: classDate.toISOString(), email })
716
+ });
717
+ if (!res.ok) {
718
+ const data = await res.json().catch(() => ({}));
719
+ throw new Error(data?.message ?? "Something went wrong. Please try again.");
720
+ }
721
+ };
722
+ const handleReplaceSchedule = () => {
723
+ setIsHovered(false);
724
+ if (schedule) {
725
+ window.parent.postMessage({
726
+ type: "ow:schedule-connected",
727
+ schedule: { id: schedule.id, name: schedule.name },
728
+ insertAfter
729
+ }, "*");
730
+ } else {
731
+ window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
732
+ }
733
+ };
734
+ if (!inEditor && !loading && !schedule) return null;
735
+ const sectionId = `scheduling-${insertAfter}`;
736
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
737
+ "section",
738
+ {
739
+ "data-ohw-section": sectionId,
740
+ "data-ohw-scheduling-anchor": insertAfter,
741
+ className: "w-full box-border py-10 px-5 sm:py-20 sm:px-16 font-body bg-(--color-light,#FEFFF0) relative",
742
+ onMouseEnter: () => inEditor && setIsHovered(true),
743
+ onMouseLeave: () => setIsHovered(false),
744
+ children: [
745
+ inEditor && isHovered && !!schedule && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
746
+ "div",
747
+ {
748
+ className: "absolute inset-0 z-10 pointer-events-auto cursor-pointer",
749
+ onClick: handleReplaceSchedule,
750
+ children: [
751
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "absolute inset-0", style: { background: "#0885FE", opacity: 0.18 } }),
752
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "absolute inset-0", style: { boxShadow: "inset 0 0 0 1.5px #0885FE" } }),
753
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
754
+ "div",
755
+ {
756
+ className: "bg-white border border-[#E7E5E4] rounded-md px-3 py-1.5 flex items-center gap-1.5",
757
+ style: {
758
+ fontSize: 14,
759
+ lineHeight: "24px",
760
+ fontFamily: "'Figtree', system-ui, sans-serif",
761
+ fontWeight: 500,
762
+ color: "#0C0A09"
763
+ },
764
+ children: [
765
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CalendarFoldIcon, {}),
766
+ "Replace schedule"
767
+ ]
768
+ }
769
+ ) })
770
+ ]
771
+ }
772
+ ),
773
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
774
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
775
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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" }),
776
+ schedule?.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
777
+ ] }),
778
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full flex flex-col items-end gap-3", children: [
779
+ timezoneLabel && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm font-normal text-(--color-accent,#A89B83)", children: timezoneLabel }),
780
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "w-full p-0 sm:p-10 box-border", children: loading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LoadingSkeleton, {}) : !schedule ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EmptyState, { inEditor, insertAfter }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
781
+ ScheduleView,
782
+ {
783
+ schedule,
784
+ dates,
785
+ selectedIdx,
786
+ onSelectDate: setSelectedIdx,
787
+ onOpenModal: inEditor ? void 0 : (mode, classId, classDate) => setModalState({ mode, classId, classDate })
788
+ }
789
+ ) })
790
+ ] })
791
+ ] }),
792
+ modalState && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
793
+ EmailCaptureModal,
794
+ {
795
+ title: modalState.mode === "book" ? "Confirm your spot" : "Leave your email",
796
+ subtitle: modalState.mode === "book" ? "We'll send your booking confirmation here." : "We'll let you know when spots open up!",
797
+ onSubmit: handleModalSubmit,
798
+ onClose: () => setModalState(null)
799
+ }
800
+ )
801
+ ]
802
+ }
803
+ );
804
+ }
52
805
 
53
806
  // src/ui/toggle-group.tsx
54
- var React = __toESM(require("react"), 1);
807
+ var React2 = __toESM(require("react"), 1);
55
808
 
56
809
  // node_modules/clsx/dist/clsx.mjs
57
810
  function r(e) {
@@ -3370,8 +4123,8 @@ var cva = (base, config) => (props) => {
3370
4123
  };
3371
4124
 
3372
4125
  // src/ui/toggle.tsx
3373
- var import_radix_ui = require("radix-ui");
3374
- var import_jsx_runtime = require("react/jsx-runtime");
4126
+ var import_radix_ui2 = require("radix-ui");
4127
+ var import_jsx_runtime3 = require("react/jsx-runtime");
3375
4128
  var toggleVariants = cva(
3376
4129
  "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",
3377
4130
  {
@@ -3398,8 +4151,8 @@ function Toggle({
3398
4151
  size,
3399
4152
  ...props
3400
4153
  }) {
3401
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3402
- import_radix_ui.Toggle.Root,
4154
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4155
+ import_radix_ui2.Toggle.Root,
3403
4156
  {
3404
4157
  "data-slot": "toggle",
3405
4158
  className: cn(toggleVariants({ variant, size, className })),
@@ -3409,8 +4162,8 @@ function Toggle({
3409
4162
  }
3410
4163
 
3411
4164
  // src/ui/toggle-group.tsx
3412
- var import_jsx_runtime2 = require("react/jsx-runtime");
3413
- var ToggleGroupContext = React.createContext({
4165
+ var import_jsx_runtime4 = require("react/jsx-runtime");
4166
+ var ToggleGroupContext = React2.createContext({
3414
4167
  value: "",
3415
4168
  onValueChange: () => {
3416
4169
  }
@@ -3422,13 +4175,13 @@ function ToggleGroup({
3422
4175
  children,
3423
4176
  ...props
3424
4177
  }) {
3425
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
4178
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3426
4179
  "div",
3427
4180
  {
3428
4181
  role: "group",
3429
4182
  className: cn("flex items-center gap-1 p-1 bg-muted rounded-md", className),
3430
4183
  ...props,
3431
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ToggleGroupContext.Provider, { value: { value, onValueChange }, children })
4184
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ToggleGroupContext.Provider, { value: { value, onValueChange }, children })
3432
4185
  }
3433
4186
  );
3434
4187
  }
@@ -3438,8 +4191,8 @@ function ToggleGroupItem({
3438
4191
  children,
3439
4192
  ...props
3440
4193
  }) {
3441
- const { value: groupValue, onValueChange } = React.useContext(ToggleGroupContext);
3442
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
4194
+ const { value: groupValue, onValueChange } = React2.useContext(ToggleGroupContext);
4195
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3443
4196
  Toggle,
3444
4197
  {
3445
4198
  pressed: groupValue === value,
@@ -3459,7 +4212,7 @@ function ToggleGroupItem({
3459
4212
  }
3460
4213
 
3461
4214
  // src/OhhwellsBridge.tsx
3462
- var import_react_dom = require("react-dom");
4215
+ var import_react_dom2 = require("react-dom");
3463
4216
  var import_navigation = require("next/navigation");
3464
4217
 
3465
4218
  // src/lib/session-search.ts
@@ -3753,9 +4506,9 @@ function calcPopoverPos(rect, parentScroll, approxW = 483, approxH = 320) {
3753
4506
  }
3754
4507
 
3755
4508
  // src/ui/button.tsx
3756
- var React2 = __toESM(require("react"), 1);
3757
- var import_radix_ui2 = require("radix-ui");
3758
- var import_jsx_runtime3 = require("react/jsx-runtime");
4509
+ var React3 = __toESM(require("react"), 1);
4510
+ var import_radix_ui3 = require("radix-ui");
4511
+ var import_jsx_runtime5 = require("react/jsx-runtime");
3759
4512
  var buttonVariants = cva(
3760
4513
  "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",
3761
4514
  {
@@ -3776,10 +4529,10 @@ var buttonVariants = cva(
3776
4529
  }
3777
4530
  }
3778
4531
  );
3779
- var Button = React2.forwardRef(
4532
+ var Button = React3.forwardRef(
3780
4533
  ({ className, variant, size, asChild = false, ...props }, ref) => {
3781
- const Comp = asChild ? import_radix_ui2.Slot.Root : "button";
3782
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4534
+ const Comp = asChild ? import_radix_ui3.Slot.Root : "button";
4535
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3783
4536
  Comp,
3784
4537
  {
3785
4538
  ref,
@@ -3793,75 +4546,75 @@ var Button = React2.forwardRef(
3793
4546
  Button.displayName = "Button";
3794
4547
 
3795
4548
  // src/ui/icons.tsx
3796
- var import_jsx_runtime4 = require("react/jsx-runtime");
4549
+ var import_jsx_runtime6 = require("react/jsx-runtime");
3797
4550
  function IconX({ className, ...props }) {
3798
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
3799
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M18 6 6 18" }),
3800
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "m6 6 12 12" })
4551
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4552
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M18 6 6 18" }),
4553
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m6 6 12 12" })
3801
4554
  ] });
3802
4555
  }
3803
4556
  function IconChevronDown({ className, ...props }) {
3804
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "m6 9 6 6 6-6" }) });
4557
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m6 9 6 6 6-6" }) });
3805
4558
  }
3806
4559
  function IconFile({ className, ...props }) {
3807
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
3808
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
3809
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
4560
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4561
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
4562
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
3810
4563
  ] });
3811
4564
  }
3812
4565
  function IconInfo({ className, ...props }) {
3813
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
3814
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
3815
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12 16v-4" }),
3816
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12 8h.01" })
4566
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4567
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
4568
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M12 16v-4" }),
4569
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M12 8h.01" })
3817
4570
  ] });
3818
4571
  }
3819
4572
  function IconArrowRight({ className, ...props }) {
3820
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
3821
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M5 12h14" }),
3822
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "m12 5 7 7-7 7" })
4573
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4574
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M5 12h14" }),
4575
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m12 5 7 7-7 7" })
3823
4576
  ] });
3824
4577
  }
3825
4578
  function IconSection({ className, ...props }) {
3826
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
3827
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
3828
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
3829
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
4579
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4580
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
4581
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
4582
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
3830
4583
  ] });
3831
4584
  }
3832
4585
 
3833
4586
  // src/ui/link-modal/DestinationBreadcrumb.tsx
3834
- var import_jsx_runtime5 = require("react/jsx-runtime");
4587
+ var import_jsx_runtime7 = require("react/jsx-runtime");
3835
4588
  function DestinationBreadcrumb({ pageTitle, sectionLabel }) {
3836
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
3837
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-sm font-medium text-foreground", children: "Destination" }),
3838
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-3", children: [
3839
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2", children: [
3840
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(IconFile, { className: "shrink-0 text-foreground", "aria-hidden": true }),
3841
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-sm font-medium leading-none text-foreground", children: pageTitle })
4589
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
4590
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-sm font-medium text-foreground", children: "Destination" }),
4591
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-3", children: [
4592
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-2", children: [
4593
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconFile, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4594
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-sm font-medium leading-none text-foreground", children: pageTitle })
3842
4595
  ] }),
3843
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(IconArrowRight, { className: "shrink-0 text-muted-foreground", "aria-hidden": true }),
3844
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
3845
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
3846
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
4596
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconArrowRight, { className: "shrink-0 text-muted-foreground", "aria-hidden": true }),
4597
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
4598
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4599
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
3847
4600
  ] })
3848
4601
  ] })
3849
4602
  ] });
3850
4603
  }
3851
4604
 
3852
4605
  // src/ui/link-modal/SectionTreeItem.tsx
3853
- var import_jsx_runtime6 = require("react/jsx-runtime");
4606
+ var import_jsx_runtime8 = require("react/jsx-runtime");
3854
4607
  function SectionTreeItem({ section, onSelect, selected }) {
3855
4608
  const interactive = Boolean(onSelect);
3856
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
3857
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4609
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
4610
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3858
4611
  "div",
3859
4612
  {
3860
4613
  className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
3861
4614
  "aria-hidden": true
3862
4615
  }
3863
4616
  ),
3864
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
4617
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
3865
4618
  "div",
3866
4619
  {
3867
4620
  role: interactive ? "button" : void 0,
@@ -3879,8 +4632,8 @@ function SectionTreeItem({ section, onSelect, selected }) {
3879
4632
  interactive && selected && "border-primary"
3880
4633
  ),
3881
4634
  children: [
3882
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
3883
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
4635
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4636
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
3884
4637
  ]
3885
4638
  }
3886
4639
  )
@@ -3888,23 +4641,23 @@ function SectionTreeItem({ section, onSelect, selected }) {
3888
4641
  }
3889
4642
  function SectionPickerList({ sections, onSelect }) {
3890
4643
  if (sections.length === 0) {
3891
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
4644
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
3892
4645
  }
3893
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-col gap-1", children: [
3894
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-sm text-muted-foreground", children: "Pick a section this link should scroll to." }),
3895
- sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SectionTreeItem, { section, onSelect }, section.id))
4646
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col gap-1", children: [
4647
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-sm text-muted-foreground", children: "Pick a section this link should scroll to." }),
4648
+ sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SectionTreeItem, { section, onSelect }, section.id))
3896
4649
  ] });
3897
4650
  }
3898
4651
 
3899
4652
  // src/ui/link-modal/UrlOrPageInput.tsx
3900
- var import_react = require("react");
4653
+ var import_react3 = require("react");
3901
4654
 
3902
4655
  // src/ui/input.tsx
3903
- var React3 = __toESM(require("react"), 1);
3904
- var import_jsx_runtime7 = require("react/jsx-runtime");
3905
- var Input = React3.forwardRef(
4656
+ var React4 = __toESM(require("react"), 1);
4657
+ var import_jsx_runtime9 = require("react/jsx-runtime");
4658
+ var Input = React4.forwardRef(
3906
4659
  ({ className, type, ...props }, ref) => {
3907
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4660
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
3908
4661
  "input",
3909
4662
  {
3910
4663
  type,
@@ -3922,11 +4675,11 @@ var Input = React3.forwardRef(
3922
4675
  Input.displayName = "Input";
3923
4676
 
3924
4677
  // src/ui/label.tsx
3925
- var import_radix_ui3 = require("radix-ui");
3926
- var import_jsx_runtime8 = require("react/jsx-runtime");
4678
+ var import_radix_ui4 = require("radix-ui");
4679
+ var import_jsx_runtime10 = require("react/jsx-runtime");
3927
4680
  function Label({ className, ...props }) {
3928
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3929
- import_radix_ui3.Label.Root,
4681
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4682
+ import_radix_ui4.Label.Root,
3930
4683
  {
3931
4684
  "data-slot": "label",
3932
4685
  className: cn("text-sm font-medium leading-5 text-foreground", className),
@@ -3936,13 +4689,13 @@ function Label({ className, ...props }) {
3936
4689
  }
3937
4690
 
3938
4691
  // src/ui/popover.tsx
3939
- var import_radix_ui4 = require("radix-ui");
3940
- var import_jsx_runtime9 = require("react/jsx-runtime");
4692
+ var import_radix_ui5 = require("radix-ui");
4693
+ var import_jsx_runtime11 = require("react/jsx-runtime");
3941
4694
  function Popover({ ...props }) {
3942
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_radix_ui4.Popover.Root, { "data-slot": "popover", ...props });
4695
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_radix_ui5.Popover.Root, { "data-slot": "popover", ...props });
3943
4696
  }
3944
4697
  function PopoverTrigger({ ...props }) {
3945
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_radix_ui4.Popover.Trigger, { "data-slot": "popover-trigger", ...props });
4698
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_radix_ui5.Popover.Trigger, { "data-slot": "popover-trigger", ...props });
3946
4699
  }
3947
4700
  function PopoverContent({
3948
4701
  className,
@@ -3950,8 +4703,8 @@ function PopoverContent({
3950
4703
  sideOffset = 6,
3951
4704
  ...props
3952
4705
  }) {
3953
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_radix_ui4.Popover.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
3954
- import_radix_ui4.Popover.Content,
4706
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_radix_ui5.Popover.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4707
+ import_radix_ui5.Popover.Content,
3955
4708
  {
3956
4709
  "data-slot": "popover-content",
3957
4710
  align,
@@ -3966,9 +4719,9 @@ function PopoverContent({
3966
4719
  }
3967
4720
 
3968
4721
  // src/ui/link-modal/UrlOrPageInput.tsx
3969
- var import_jsx_runtime10 = require("react/jsx-runtime");
4722
+ var import_jsx_runtime12 = require("react/jsx-runtime");
3970
4723
  function FieldChevron({ onClick }) {
3971
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4724
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3972
4725
  "button",
3973
4726
  {
3974
4727
  type: "button",
@@ -3976,7 +4729,7 @@ function FieldChevron({ onClick }) {
3976
4729
  onClick,
3977
4730
  "aria-label": "Open page list",
3978
4731
  tabIndex: -1,
3979
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IconChevronDown, {})
4732
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconChevronDown, {})
3980
4733
  }
3981
4734
  );
3982
4735
  }
@@ -3992,9 +4745,9 @@ function UrlOrPageInput({
3992
4745
  readOnly = false,
3993
4746
  urlError
3994
4747
  }) {
3995
- const inputId = (0, import_react.useId)();
3996
- const inputRef = (0, import_react.useRef)(null);
3997
- const [isFocused, setIsFocused] = (0, import_react.useState)(false);
4748
+ const inputId = (0, import_react3.useId)();
4749
+ const inputRef = (0, import_react3.useRef)(null);
4750
+ const [isFocused, setIsFocused] = (0, import_react3.useState)(false);
3998
4751
  const openDropdown = () => {
3999
4752
  if (readOnly || filteredPages.length === 0) return;
4000
4753
  onDropdownOpenChange(true);
@@ -4015,12 +4768,12 @@ function UrlOrPageInput({
4015
4768
  "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]",
4016
4769
  urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
4017
4770
  );
4018
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
4019
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
4020
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Popover, { open: dropdownOpen && !readOnly, onOpenChange: onDropdownOpenChange, children: [
4021
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
4022
- selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IconFile, { className: "text-foreground", "aria-hidden": true }) }) : null,
4023
- readOnly ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4771
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
4772
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
4773
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Popover, { open: dropdownOpen && !readOnly, onOpenChange: onDropdownOpenChange, children: [
4774
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
4775
+ selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconFile, { className: "text-foreground", "aria-hidden": true }) }) : null,
4776
+ readOnly ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4024
4777
  Input,
4025
4778
  {
4026
4779
  ref: inputRef,
@@ -4039,7 +4792,7 @@ function UrlOrPageInput({
4039
4792
  )
4040
4793
  }
4041
4794
  ),
4042
- selectedPage && !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4795
+ selectedPage && !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4043
4796
  "button",
4044
4797
  {
4045
4798
  type: "button",
@@ -4047,31 +4800,31 @@ function UrlOrPageInput({
4047
4800
  onMouseDown: clearSelection,
4048
4801
  "aria-label": "Clear selected page",
4049
4802
  tabIndex: -1,
4050
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IconX, { "aria-hidden": true })
4803
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconX, { "aria-hidden": true })
4051
4804
  }
4052
4805
  ) : null,
4053
- !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
4806
+ !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
4054
4807
  ] }) }),
4055
- filteredPages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PopoverContent, { "data-ohw-link-popover-root": "", onOpenAutoFocus: (e) => e.preventDefault(), children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4808
+ filteredPages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PopoverContent, { "data-ohw-link-popover-root": "", onOpenAutoFocus: (e) => e.preventDefault(), children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4056
4809
  "button",
4057
4810
  {
4058
4811
  type: "button",
4059
4812
  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",
4060
4813
  onClick: () => onPageSelect(page),
4061
4814
  children: [
4062
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IconFile, { className: "shrink-0", "aria-hidden": true }),
4063
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "truncate", children: page.title })
4815
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconFile, { className: "shrink-0", "aria-hidden": true }),
4816
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "truncate", children: page.title })
4064
4817
  ]
4065
4818
  },
4066
4819
  page.path
4067
4820
  )) })
4068
4821
  ] }),
4069
- urlError ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
4822
+ urlError ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
4070
4823
  ] });
4071
4824
  }
4072
4825
 
4073
4826
  // src/ui/link-modal/useLinkModalState.ts
4074
- var import_react2 = require("react");
4827
+ var import_react4 = require("react");
4075
4828
  function useLinkModalState({
4076
4829
  open,
4077
4830
  mode,
@@ -4083,17 +4836,17 @@ function useLinkModalState({
4083
4836
  onClose,
4084
4837
  onSubmit
4085
4838
  }) {
4086
- const availablePages = (0, import_react2.useMemo)(
4839
+ const availablePages = (0, import_react4.useMemo)(
4087
4840
  () => mode === "create" ? filterAvailablePages(pages, existingTargets) : pages,
4088
4841
  [mode, pages, existingTargets]
4089
4842
  );
4090
- const [searchValue, setSearchValue] = (0, import_react2.useState)("");
4091
- const [selectedPage, setSelectedPage] = (0, import_react2.useState)(null);
4092
- const [selectedSection, setSelectedSection] = (0, import_react2.useState)(null);
4093
- const [step, setStep] = (0, import_react2.useState)("input");
4094
- const [dropdownOpen, setDropdownOpen] = (0, import_react2.useState)(false);
4095
- const [urlError, setUrlError] = (0, import_react2.useState)("");
4096
- const reset = (0, import_react2.useCallback)(() => {
4843
+ const [searchValue, setSearchValue] = (0, import_react4.useState)("");
4844
+ const [selectedPage, setSelectedPage] = (0, import_react4.useState)(null);
4845
+ const [selectedSection, setSelectedSection] = (0, import_react4.useState)(null);
4846
+ const [step, setStep] = (0, import_react4.useState)("input");
4847
+ const [dropdownOpen, setDropdownOpen] = (0, import_react4.useState)(false);
4848
+ const [urlError, setUrlError] = (0, import_react4.useState)("");
4849
+ const reset = (0, import_react4.useCallback)(() => {
4097
4850
  setSearchValue("");
4098
4851
  setSelectedPage(null);
4099
4852
  setSelectedSection(null);
@@ -4101,7 +4854,7 @@ function useLinkModalState({
4101
4854
  setDropdownOpen(false);
4102
4855
  setUrlError("");
4103
4856
  }, []);
4104
- (0, import_react2.useEffect)(() => {
4857
+ (0, import_react4.useEffect)(() => {
4105
4858
  if (!open) return;
4106
4859
  if (mode === "edit" && initialTarget) {
4107
4860
  const { pageRoute } = parseTarget(initialTarget);
@@ -4117,11 +4870,11 @@ function useLinkModalState({
4117
4870
  setDropdownOpen(false);
4118
4871
  setUrlError("");
4119
4872
  }, [open, mode, initialTarget, pages, sectionsByPath, reset]);
4120
- const filteredPages = (0, import_react2.useMemo)(() => {
4873
+ const filteredPages = (0, import_react4.useMemo)(() => {
4121
4874
  if (!searchValue.trim()) return availablePages;
4122
4875
  return availablePages.filter((p) => p.title.toLowerCase().startsWith(searchValue.toLowerCase()));
4123
4876
  }, [availablePages, searchValue]);
4124
- const activeSections = (0, import_react2.useMemo)(() => {
4877
+ const activeSections = (0, import_react4.useMemo)(() => {
4125
4878
  if (!selectedPage) return [];
4126
4879
  return getSectionsForPath(sectionsByPath, selectedPage.path);
4127
4880
  }, [selectedPage, sectionsByPath]);
@@ -4167,7 +4920,7 @@ function useLinkModalState({
4167
4920
  reset();
4168
4921
  onClose();
4169
4922
  };
4170
- const isValid = (0, import_react2.useMemo)(() => {
4923
+ const isValid = (0, import_react4.useMemo)(() => {
4171
4924
  if (urlError) return false;
4172
4925
  if (showBreadcrumb) return true;
4173
4926
  if (selectedPage) return true;
@@ -4234,7 +4987,7 @@ function useLinkModalState({
4234
4987
  }
4235
4988
 
4236
4989
  // src/ui/link-modal/LinkEditorPanel.tsx
4237
- var import_jsx_runtime11 = require("react/jsx-runtime");
4990
+ var import_jsx_runtime13 = require("react/jsx-runtime");
4238
4991
  function LinkEditorPanel({
4239
4992
  open = true,
4240
4993
  mode = "create",
@@ -4258,26 +5011,26 @@ function LinkEditorPanel({
4258
5011
  onSubmit
4259
5012
  });
4260
5013
  const isCancel = state.secondaryLabel === "Cancel";
4261
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
4262
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5014
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
5015
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4263
5016
  "button",
4264
5017
  {
4265
5018
  type: "button",
4266
5019
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
4267
5020
  onClick: state.handleClose,
4268
5021
  "aria-label": "Close",
4269
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconX, { "aria-hidden": true })
5022
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(IconX, { "aria-hidden": true })
4270
5023
  }
4271
5024
  ),
4272
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("header", { className: "flex w-full flex-col gap-1.5 p-6 pr-12", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h2", { className: "m-0 w-full break-words text-lg font-semibold leading-none tracking-tight text-card-foreground", children: state.title }) }),
4273
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
4274
- state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5025
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("header", { className: "flex w-full flex-col gap-1.5 p-6 pr-12", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { className: "m-0 w-full break-words text-lg font-semibold leading-none tracking-tight text-card-foreground", children: state.title }) }),
5026
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
5027
+ state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4275
5028
  DestinationBreadcrumb,
4276
5029
  {
4277
5030
  pageTitle: state.selectedPage.title,
4278
5031
  sectionLabel: state.selectedSection.label
4279
5032
  }
4280
- ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5033
+ ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4281
5034
  UrlOrPageInput,
4282
5035
  {
4283
5036
  value: state.searchValue,
@@ -4290,18 +5043,18 @@ function LinkEditorPanel({
4290
5043
  urlError: state.urlError
4291
5044
  }
4292
5045
  ),
4293
- state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
4294
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Button, { type: "button", variant: "outline", className: "w-fit cursor-pointer", size: "sm", onClick: state.handleChooseSection, children: "Choose a section" }),
4295
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
4296
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconInfo, { className: "shrink-0", "aria-hidden": true }),
4297
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Pick a section this link should scroll to." })
5046
+ state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
5047
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Button, { type: "button", variant: "outline", className: "w-fit cursor-pointer", size: "sm", onClick: state.handleChooseSection, children: "Choose a section" }),
5048
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
5049
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(IconInfo, { className: "shrink-0", "aria-hidden": true }),
5050
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Pick a section this link should scroll to." })
4298
5051
  ] })
4299
5052
  ] }) : null,
4300
- state.showSectionPicker ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SectionPickerList, { sections: state.activeSections, onSelect: state.handleSectionSelect }) : null,
4301
- state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5053
+ state.showSectionPicker ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SectionPickerList, { sections: state.activeSections, onSelect: state.handleSectionSelect }) : null,
5054
+ state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
4302
5055
  ] }),
4303
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("footer", { className: "flex w-full items-center justify-end gap-2 px-6 pb-6", children: [
4304
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5056
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("footer", { className: "flex w-full items-center justify-end gap-2 px-6 pb-6", children: [
5057
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4305
5058
  Button,
4306
5059
  {
4307
5060
  type: "button",
@@ -4316,7 +5069,7 @@ function LinkEditorPanel({
4316
5069
  children: state.secondaryLabel
4317
5070
  }
4318
5071
  ),
4319
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5072
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4320
5073
  Button,
4321
5074
  {
4322
5075
  type: "button",
@@ -4335,7 +5088,7 @@ function LinkEditorPanel({
4335
5088
  }
4336
5089
 
4337
5090
  // src/ui/link-modal/LinkPopover.tsx
4338
- var import_jsx_runtime12 = require("react/jsx-runtime");
5091
+ var import_jsx_runtime14 = require("react/jsx-runtime");
4339
5092
  function LinkPopover({
4340
5093
  rect,
4341
5094
  parentScroll,
@@ -4343,7 +5096,7 @@ function LinkPopover({
4343
5096
  ...editorProps
4344
5097
  }) {
4345
5098
  const { top, left, transform } = calcPopoverPos(rect, parentScroll);
4346
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5099
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4347
5100
  "div",
4348
5101
  {
4349
5102
  ref: panelRef,
@@ -4356,7 +5109,7 @@ function LinkPopover({
4356
5109
  ),
4357
5110
  style: { top, left, transform },
4358
5111
  onMouseDown: (e) => e.stopPropagation(),
4359
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(LinkEditorPanel, { ...editorProps, open: true })
5112
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(LinkEditorPanel, { ...editorProps, open: true })
4360
5113
  }
4361
5114
  );
4362
5115
  }
@@ -4419,8 +5172,30 @@ function shouldUseDevFixtures() {
4419
5172
  return new URLSearchParams(q).get("ohw-fixtures") === "1";
4420
5173
  }
4421
5174
 
5175
+ // src/ui/badge.tsx
5176
+ var import_jsx_runtime15 = require("react/jsx-runtime");
5177
+ var badgeVariants = cva(
5178
+ "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",
5179
+ {
5180
+ variants: {
5181
+ variant: {
5182
+ default: "border-transparent bg-primary text-primary-foreground",
5183
+ secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
5184
+ destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
5185
+ outline: "text-foreground"
5186
+ }
5187
+ },
5188
+ defaultVariants: {
5189
+ variant: "default"
5190
+ }
5191
+ }
5192
+ );
5193
+ function Badge({ className, variant, ...props }) {
5194
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
5195
+ }
5196
+
4422
5197
  // src/OhhwellsBridge.tsx
4423
- var import_jsx_runtime13 = require("react/jsx-runtime");
5198
+ var import_jsx_runtime16 = require("react/jsx-runtime");
4424
5199
  var PRIMARY = "#0885FE";
4425
5200
  var IMAGE_FADE_MS = 300;
4426
5201
  function runOpacityFade(el, onDone) {
@@ -4471,6 +5246,169 @@ function fadeInBgImage(el, url, onReady) {
4471
5246
  if (!prevPos || prevPos === "static") el.style.position = prevPos;
4472
5247
  });
4473
5248
  }
5249
+ function getSectionsTracker() {
5250
+ let el = document.querySelector("[data-ohw-sections-tracker]");
5251
+ if (!el) {
5252
+ el = document.createElement("div");
5253
+ el.setAttribute("data-ohw-sections-tracker", "");
5254
+ el.style.display = "none";
5255
+ document.body.appendChild(el);
5256
+ }
5257
+ return el;
5258
+ }
5259
+ function updateSectionScheduleId(insertAfter, scheduleId) {
5260
+ const tracker = getSectionsTracker();
5261
+ let sections = [];
5262
+ try {
5263
+ sections = JSON.parse(tracker.textContent || "[]");
5264
+ } catch {
5265
+ }
5266
+ const currentPath = window.location.pathname;
5267
+ const updated = sections.map((s) => {
5268
+ if (s.type !== "scheduling" || s.insertAfter !== insertAfter) return s;
5269
+ if (s.pagePath && s.pagePath !== currentPath) return s;
5270
+ return { ...s, scheduleId };
5271
+ });
5272
+ tracker.textContent = JSON.stringify(updated);
5273
+ return tracker.textContent ?? "[]";
5274
+ }
5275
+ function schedulingSectionId(insertAfter) {
5276
+ return `scheduling-${insertAfter}`;
5277
+ }
5278
+ var INSERT_BEFORE_MARKER = ":before:";
5279
+ function parseSchedulingInsertAfter(insertAfter) {
5280
+ const idx = insertAfter.indexOf(INSERT_BEFORE_MARKER);
5281
+ if (idx < 0) return { anchor: insertAfter, insertBefore: null };
5282
+ return {
5283
+ anchor: insertAfter.slice(0, idx),
5284
+ insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
5285
+ };
5286
+ }
5287
+ function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
5288
+ const parsed = parseSchedulingInsertAfter(insertAfter);
5289
+ const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
5290
+ const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
5291
+ return { effectiveInsertAfter, insertBefore };
5292
+ }
5293
+ function getSchedulingMountPoint(insertAfter) {
5294
+ const { anchor } = parseSchedulingInsertAfter(insertAfter);
5295
+ let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
5296
+ if (!anchorEl && anchor === "scheduling") {
5297
+ const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
5298
+ anchorEl = widgets.at(-1) ?? null;
5299
+ }
5300
+ if (!anchorEl) return null;
5301
+ return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
5302
+ }
5303
+ function schedulingMountDepth(insertAfter) {
5304
+ if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
5305
+ return insertAfter.split(INSERT_BEFORE_MARKER).length - 1;
5306
+ }
5307
+ function getPageSchedulingEntries(raw) {
5308
+ if (!raw) return [];
5309
+ try {
5310
+ const entries = JSON.parse(raw);
5311
+ const currentPath = window.location.pathname;
5312
+ return entries.filter((e) => e.type === "scheduling" && (!e.pagePath || e.pagePath === currentPath));
5313
+ } catch {
5314
+ return [];
5315
+ }
5316
+ }
5317
+ function isSchedulingWidgetMissing(entry) {
5318
+ const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
5319
+ return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
5320
+ }
5321
+ function hasMissingSchedulingWidgets(entries) {
5322
+ return entries.some(isSchedulingWidgetMissing);
5323
+ }
5324
+ function retryMissingSchedulingMounts(entries, notifyOnConnect = false) {
5325
+ if (!hasMissingSchedulingWidgets(entries)) return;
5326
+ mountSchedulingEntries(entries, notifyOnConnect);
5327
+ }
5328
+ function initSectionsFromContent(content, removeExisting = false) {
5329
+ const raw = content["__ohw_sections"];
5330
+ if (!raw) return;
5331
+ try {
5332
+ if (removeExisting) {
5333
+ document.querySelectorAll('[data-ohw-section-container="scheduling"]').forEach((el) => el.remove());
5334
+ }
5335
+ const inEditor = typeof window !== "undefined" && window.self !== window.top;
5336
+ if (inEditor) getSectionsTracker().textContent = raw;
5337
+ const pageEntries = getPageSchedulingEntries(raw);
5338
+ const preExisting = pageEntries.filter((e) => !isSchedulingWidgetMissing(e));
5339
+ const notifyForEntry = inEditor ? (e) => !e.scheduleId : false;
5340
+ mountSchedulingEntries(pageEntries, notifyForEntry);
5341
+ requestAnimationFrame(() => retryMissingSchedulingMounts(pageEntries, notifyForEntry));
5342
+ setTimeout(() => retryMissingSchedulingMounts(pageEntries, notifyForEntry), 250);
5343
+ for (const entry of preExisting) {
5344
+ window.postMessage({ type: "ow:schedule-config", insertAfter: entry.insertAfter, scheduleId: entry.scheduleId ?? null }, "*");
5345
+ }
5346
+ } catch {
5347
+ }
5348
+ }
5349
+ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
5350
+ const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
5351
+ const sectionId = schedulingSectionId(effectiveInsertAfter);
5352
+ if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
5353
+ const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
5354
+ if (!mountPoint) return false;
5355
+ const container = document.createElement("div");
5356
+ container.dataset.ohwSectionContainer = "scheduling";
5357
+ if (insertBefore) {
5358
+ const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
5359
+ const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
5360
+ if (!beforePoint) return false;
5361
+ beforePoint.insertAdjacentElement("beforebegin", container);
5362
+ } else {
5363
+ let tail = mountPoint;
5364
+ while (tail.nextElementSibling?.dataset.ohwSectionContainer === "scheduling") {
5365
+ tail = tail.nextElementSibling;
5366
+ }
5367
+ tail.insertAdjacentElement("afterend", container);
5368
+ }
5369
+ const root = (0, import_client.createRoot)(container);
5370
+ (0, import_react_dom.flushSync)(() => {
5371
+ root.render(
5372
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5373
+ SchedulingWidget,
5374
+ {
5375
+ notifyOnConnect,
5376
+ initialScheduleId: scheduleId,
5377
+ insertAfter: effectiveInsertAfter
5378
+ }
5379
+ )
5380
+ );
5381
+ });
5382
+ const tracker = getSectionsTracker();
5383
+ let sections = [];
5384
+ try {
5385
+ sections = JSON.parse(tracker.textContent || "[]");
5386
+ } catch {
5387
+ }
5388
+ const inEditor = typeof window !== "undefined" && window.self !== window.top;
5389
+ if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
5390
+ sections.push({
5391
+ type: "scheduling",
5392
+ insertAfter: effectiveInsertAfter,
5393
+ pagePath: window.location.pathname,
5394
+ ...scheduleId ? { scheduleId } : {}
5395
+ });
5396
+ tracker.textContent = JSON.stringify(sections);
5397
+ }
5398
+ return true;
5399
+ }
5400
+ function mountSchedulingEntries(entries, notifyOnConnect = false) {
5401
+ const pending = entries.filter((e) => e.type === "scheduling").sort((a, b) => schedulingMountDepth(a.insertAfter) - schedulingMountDepth(b.insertAfter));
5402
+ for (let attempt = 0; attempt < pending.length + 1 && pending.length > 0; attempt++) {
5403
+ for (let i = pending.length - 1; i >= 0; i--) {
5404
+ const entry = pending[i];
5405
+ const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
5406
+ if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId)) {
5407
+ pending.splice(i, 1);
5408
+ }
5409
+ }
5410
+ }
5411
+ }
4474
5412
  function getLinkHref(el) {
4475
5413
  const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
4476
5414
  return anchor?.getAttribute("href") ?? "";
@@ -4670,7 +5608,7 @@ var TOOLBAR_GROUPS = [
4670
5608
  ];
4671
5609
  function GlowFrame({ rect, elRef }) {
4672
5610
  const GAP = 6;
4673
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5611
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4674
5612
  "div",
4675
5613
  {
4676
5614
  ref: elRef,
@@ -4723,7 +5661,7 @@ function FloatingToolbar({
4723
5661
  onEditLink
4724
5662
  }) {
4725
5663
  const { top, left, transform } = calcToolbarPos(rect, parentScroll);
4726
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
5664
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
4727
5665
  "div",
4728
5666
  {
4729
5667
  ref: elRef,
@@ -4748,11 +5686,11 @@ function FloatingToolbar({
4748
5686
  },
4749
5687
  onMouseDown: (e) => e.stopPropagation(),
4750
5688
  children: [
4751
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react3.default.Fragment, { children: [
4752
- gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
5689
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react5.default.Fragment, { children: [
5690
+ gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
4753
5691
  btns.map((btn) => {
4754
5692
  const isActive = activeCommands.has(btn.cmd);
4755
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5693
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4756
5694
  "button",
4757
5695
  {
4758
5696
  title: btn.title,
@@ -4778,7 +5716,7 @@ function FloatingToolbar({
4778
5716
  flexShrink: 0,
4779
5717
  padding: 6
4780
5718
  },
4781
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5719
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4782
5720
  "svg",
4783
5721
  {
4784
5722
  width: "16",
@@ -4798,7 +5736,7 @@ function FloatingToolbar({
4798
5736
  );
4799
5737
  })
4800
5738
  ] }, gi)),
4801
- showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5739
+ showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4802
5740
  "button",
4803
5741
  {
4804
5742
  type: "button",
@@ -4830,9 +5768,9 @@ function FloatingToolbar({
4830
5768
  flexShrink: 0,
4831
5769
  padding: 6
4832
5770
  },
4833
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("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: [
4834
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
4835
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
5771
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("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: [
5772
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
5773
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
4836
5774
  ] })
4837
5775
  }
4838
5776
  ) : null
@@ -4850,7 +5788,7 @@ function StateToggle({
4850
5788
  states,
4851
5789
  onStateChange
4852
5790
  }) {
4853
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5791
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4854
5792
  ToggleGroup,
4855
5793
  {
4856
5794
  "data-ohw-state-toggle": "",
@@ -4864,18 +5802,35 @@ function StateToggle({
4864
5802
  left: rect.right - 8,
4865
5803
  transform: "translateX(-100%)"
4866
5804
  },
4867
- children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
5805
+ children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
4868
5806
  }
4869
5807
  );
4870
5808
  }
4871
5809
  var contentCache = /* @__PURE__ */ new Map();
5810
+ function resolveSubdomain(subdomainFromQuery) {
5811
+ if (subdomainFromQuery) return subdomainFromQuery;
5812
+ if (typeof window !== "undefined") {
5813
+ const parts = window.location.hostname.split(".");
5814
+ if (parts.length >= 3 && parts[0] !== "www") return parts[0];
5815
+ }
5816
+ const siteUrl = process.env.NEXT_PUBLIC_SITE_URL;
5817
+ if (siteUrl) {
5818
+ try {
5819
+ const host = new URL(siteUrl).hostname;
5820
+ const siteParts = host.split(".");
5821
+ if (siteParts.length >= 3 && siteParts[0] !== "www") return siteParts[0];
5822
+ } catch {
5823
+ }
5824
+ }
5825
+ return "";
5826
+ }
4872
5827
  function OhhwellsBridge() {
4873
5828
  const pathname = (0, import_navigation.usePathname)();
4874
5829
  const router = (0, import_navigation.useRouter)();
4875
5830
  const searchParams = (0, import_navigation.useSearchParams)();
4876
5831
  const isEditMode = isEditSessionActive();
4877
- const [bridgeRoot, setBridgeRoot] = (0, import_react3.useState)(null);
4878
- (0, import_react3.useEffect)(() => {
5832
+ const [bridgeRoot, setBridgeRoot] = (0, import_react5.useState)(null);
5833
+ (0, import_react5.useEffect)(() => {
4879
5834
  const figtreeFontId = "ohw-figtree-font";
4880
5835
  if (!document.getElementById(figtreeFontId)) {
4881
5836
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -4898,55 +5853,55 @@ function OhhwellsBridge() {
4898
5853
  };
4899
5854
  }, []);
4900
5855
  const subdomainFromQuery = searchParams.get("subdomain");
4901
- const subdomain = subdomainFromQuery ?? (() => {
4902
- if (typeof window === "undefined") return "";
4903
- const parts = window.location.hostname.split(".");
4904
- return parts.length >= 3 && parts[0] !== "www" ? parts[0] : "";
4905
- })();
4906
- const postToParent = (0, import_react3.useCallback)((data) => {
5856
+ const subdomain = resolveSubdomain(subdomainFromQuery);
5857
+ const postToParent = (0, import_react5.useCallback)((data) => {
4907
5858
  if (typeof window !== "undefined" && window.parent !== window) {
4908
5859
  window.parent.postMessage(data, "*");
4909
5860
  }
4910
5861
  }, []);
4911
- const [fetchState, setFetchState] = (0, import_react3.useState)("idle");
4912
- const autoSaveTimers = (0, import_react3.useRef)(/* @__PURE__ */ new Map());
4913
- const activeElRef = (0, import_react3.useRef)(null);
4914
- const originalContentRef = (0, import_react3.useRef)(null);
4915
- const activeStateElRef = (0, import_react3.useRef)(null);
4916
- const parentScrollRef = (0, import_react3.useRef)(null);
4917
- const toolbarElRef = (0, import_react3.useRef)(null);
4918
- const glowElRef = (0, import_react3.useRef)(null);
4919
- const hoveredImageRef = (0, import_react3.useRef)(null);
4920
- const hoveredImageHasTextOverlapRef = (0, import_react3.useRef)(false);
4921
- const imageUnhoverTimerRef = (0, import_react3.useRef)(null);
4922
- const imageShowTimerRef = (0, import_react3.useRef)(null);
4923
- const editStylesRef = (0, import_react3.useRef)(null);
4924
- const activateRef = (0, import_react3.useRef)(() => {
5862
+ const [fetchState, setFetchState] = (0, import_react5.useState)("idle");
5863
+ const autoSaveTimers = (0, import_react5.useRef)(/* @__PURE__ */ new Map());
5864
+ const activeElRef = (0, import_react5.useRef)(null);
5865
+ const originalContentRef = (0, import_react5.useRef)(null);
5866
+ const activeStateElRef = (0, import_react5.useRef)(null);
5867
+ const parentScrollRef = (0, import_react5.useRef)(null);
5868
+ const toolbarElRef = (0, import_react5.useRef)(null);
5869
+ const glowElRef = (0, import_react5.useRef)(null);
5870
+ const hoveredImageRef = (0, import_react5.useRef)(null);
5871
+ const hoveredImageHasTextOverlapRef = (0, import_react5.useRef)(false);
5872
+ const hoveredGapRef = (0, import_react5.useRef)(null);
5873
+ const imageUnhoverTimerRef = (0, import_react5.useRef)(null);
5874
+ const imageShowTimerRef = (0, import_react5.useRef)(null);
5875
+ const editStylesRef = (0, import_react5.useRef)(null);
5876
+ const activateRef = (0, import_react5.useRef)(() => {
4925
5877
  });
4926
- const deactivateRef = (0, import_react3.useRef)(() => {
5878
+ const deactivateRef = (0, import_react5.useRef)(() => {
4927
5879
  });
4928
- const refreshActiveCommandsRef = (0, import_react3.useRef)(() => {
5880
+ const refreshActiveCommandsRef = (0, import_react5.useRef)(() => {
4929
5881
  });
4930
- const postToParentRef = (0, import_react3.useRef)(postToParent);
5882
+ const postToParentRef = (0, import_react5.useRef)(postToParent);
4931
5883
  postToParentRef.current = postToParent;
4932
- const [toolbarRect, setToolbarRect] = (0, import_react3.useState)(null);
4933
- const [toggleState, setToggleState] = (0, import_react3.useState)(null);
4934
- const [maxBadge, setMaxBadge] = (0, import_react3.useState)(null);
4935
- const [activeCommands, setActiveCommands] = (0, import_react3.useState)(/* @__PURE__ */ new Set());
4936
- const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react3.useState)(false);
4937
- const [linkPopover, setLinkPopover] = (0, import_react3.useState)(null);
4938
- const [sitePages, setSitePages] = (0, import_react3.useState)([]);
4939
- const [sectionsByPath, setSectionsByPath] = (0, import_react3.useState)({});
4940
- const sectionsPrefetchGenRef = (0, import_react3.useRef)(0);
4941
- const setLinkPopoverRef = (0, import_react3.useRef)(setLinkPopover);
4942
- const linkPopoverPanelRef = (0, import_react3.useRef)(null);
4943
- const linkPopoverOpenRef = (0, import_react3.useRef)(false);
4944
- const linkPopoverGraceUntilRef = (0, import_react3.useRef)(0);
5884
+ const sectionsLoadedRef = (0, import_react5.useRef)(false);
5885
+ const pendingScheduleConfigRequests = (0, import_react5.useRef)([]);
5886
+ const [toolbarRect, setToolbarRect] = (0, import_react5.useState)(null);
5887
+ const [toggleState, setToggleState] = (0, import_react5.useState)(null);
5888
+ const [maxBadge, setMaxBadge] = (0, import_react5.useState)(null);
5889
+ const [activeCommands, setActiveCommands] = (0, import_react5.useState)(/* @__PURE__ */ new Set());
5890
+ const [sectionGap, setSectionGap] = (0, import_react5.useState)(null);
5891
+ const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react5.useState)(false);
5892
+ const [linkPopover, setLinkPopover] = (0, import_react5.useState)(null);
5893
+ const [sitePages, setSitePages] = (0, import_react5.useState)([]);
5894
+ const [sectionsByPath, setSectionsByPath] = (0, import_react5.useState)({});
5895
+ const sectionsPrefetchGenRef = (0, import_react5.useRef)(0);
5896
+ const setLinkPopoverRef = (0, import_react5.useRef)(setLinkPopover);
5897
+ const linkPopoverPanelRef = (0, import_react5.useRef)(null);
5898
+ const linkPopoverOpenRef = (0, import_react5.useRef)(false);
5899
+ const linkPopoverGraceUntilRef = (0, import_react5.useRef)(0);
4945
5900
  setLinkPopoverRef.current = setLinkPopover;
4946
5901
  const bumpLinkPopoverGrace = () => {
4947
5902
  linkPopoverGraceUntilRef.current = Date.now() + 350;
4948
5903
  };
4949
- const runSectionsPrefetch = (0, import_react3.useCallback)((pages) => {
5904
+ const runSectionsPrefetch = (0, import_react5.useCallback)((pages) => {
4950
5905
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
4951
5906
  const gen = ++sectionsPrefetchGenRef.current;
4952
5907
  const paths = pages.map((p) => p.path);
@@ -4965,9 +5920,9 @@ function OhhwellsBridge() {
4965
5920
  );
4966
5921
  });
4967
5922
  }, [isEditMode, pathname]);
4968
- const runSectionsPrefetchRef = (0, import_react3.useRef)(runSectionsPrefetch);
5923
+ const runSectionsPrefetchRef = (0, import_react5.useRef)(runSectionsPrefetch);
4969
5924
  runSectionsPrefetchRef.current = runSectionsPrefetch;
4970
- (0, import_react3.useEffect)(() => {
5925
+ (0, import_react5.useEffect)(() => {
4971
5926
  if (!linkPopover) return;
4972
5927
  if (hoveredImageRef.current) {
4973
5928
  hoveredImageRef.current = null;
@@ -4975,7 +5930,7 @@ function OhhwellsBridge() {
4975
5930
  }
4976
5931
  postToParent({ type: "ow:image-unhover" });
4977
5932
  }, [linkPopover, postToParent]);
4978
- (0, import_react3.useEffect)(() => {
5933
+ (0, import_react5.useEffect)(() => {
4979
5934
  if (!isEditMode) return;
4980
5935
  const useFixtures = shouldUseDevFixtures();
4981
5936
  if (useFixtures) {
@@ -4999,14 +5954,14 @@ function OhhwellsBridge() {
4999
5954
  if (!useFixtures) postToParent({ type: "ow:request-site-pages" });
5000
5955
  return () => window.removeEventListener("message", onSitePages);
5001
5956
  }, [isEditMode, postToParent]);
5002
- (0, import_react3.useEffect)(() => {
5957
+ (0, import_react5.useEffect)(() => {
5003
5958
  if (!isEditMode || shouldUseDevFixtures()) return;
5004
5959
  void loadAllSectionsManifest().then((manifest) => {
5005
5960
  if (Object.keys(manifest).length === 0) return;
5006
5961
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
5007
5962
  });
5008
5963
  }, [isEditMode]);
5009
- (0, import_react3.useEffect)(() => {
5964
+ (0, import_react5.useEffect)(() => {
5010
5965
  const update = () => {
5011
5966
  const el = activeElRef.current;
5012
5967
  if (el) setToolbarRect(el.getBoundingClientRect());
@@ -5014,6 +5969,12 @@ function OhhwellsBridge() {
5014
5969
  if (!prev || !activeStateElRef.current) return prev;
5015
5970
  return { ...prev, rect: activeStateElRef.current.getBoundingClientRect() };
5016
5971
  });
5972
+ setSectionGap((prev) => {
5973
+ if (!prev) return prev;
5974
+ const anchor = document.querySelector(`[data-ohw-section="${prev.insertAfter}"]`);
5975
+ if (!anchor) return prev;
5976
+ return { ...prev, y: anchor.getBoundingClientRect().bottom };
5977
+ });
5017
5978
  };
5018
5979
  const vvp = window.visualViewport;
5019
5980
  if (!vvp) return;
@@ -5024,10 +5985,33 @@ function OhhwellsBridge() {
5024
5985
  vvp.removeEventListener("resize", update);
5025
5986
  };
5026
5987
  }, []);
5027
- const refreshStateRules = (0, import_react3.useCallback)(() => {
5988
+ const refreshStateRules = (0, import_react5.useCallback)(() => {
5028
5989
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
5029
5990
  }, []);
5030
- const deactivate = (0, import_react3.useCallback)(() => {
5991
+ const processConfigRequest = (0, import_react5.useCallback)((insertAfterVal) => {
5992
+ const tracker = getSectionsTracker();
5993
+ let entries = [];
5994
+ try {
5995
+ entries = JSON.parse(tracker.textContent || "[]");
5996
+ } catch {
5997
+ }
5998
+ const path = window.location.pathname;
5999
+ const entry = entries.find(
6000
+ (e) => e.type === "scheduling" && e.insertAfter === insertAfterVal && (!e.pagePath || e.pagePath === path)
6001
+ );
6002
+ if (entry) {
6003
+ window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: entry.scheduleId ?? null }, "*");
6004
+ return;
6005
+ }
6006
+ const newEntry = { type: "scheduling", insertAfter: insertAfterVal, pagePath: path };
6007
+ entries.push(newEntry);
6008
+ tracker.textContent = JSON.stringify(entries);
6009
+ if (isEditMode) {
6010
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
6011
+ }
6012
+ window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
6013
+ }, [isEditMode]);
6014
+ const deactivate = (0, import_react5.useCallback)(() => {
5031
6015
  const el = activeElRef.current;
5032
6016
  if (!el) return;
5033
6017
  const key = el.dataset.ohwKey;
@@ -5053,7 +6037,7 @@ function OhhwellsBridge() {
5053
6037
  setToolbarShowEditLink(false);
5054
6038
  postToParent({ type: "ow:exit-edit" });
5055
6039
  }, [postToParent]);
5056
- const activate = (0, import_react3.useCallback)((el) => {
6040
+ const activate = (0, import_react5.useCallback)((el) => {
5057
6041
  if (activeElRef.current === el) return;
5058
6042
  deactivate();
5059
6043
  if (hoveredImageRef.current) {
@@ -5072,7 +6056,7 @@ function OhhwellsBridge() {
5072
6056
  }, [deactivate, postToParent]);
5073
6057
  activateRef.current = activate;
5074
6058
  deactivateRef.current = deactivate;
5075
- (0, import_react3.useLayoutEffect)(() => {
6059
+ (0, import_react5.useLayoutEffect)(() => {
5076
6060
  if (!subdomain || isEditMode) {
5077
6061
  setFetchState("done");
5078
6062
  return;
@@ -5080,6 +6064,7 @@ function OhhwellsBridge() {
5080
6064
  const applyContent = (content) => {
5081
6065
  const imageLoads = [];
5082
6066
  for (const [key, val] of Object.entries(content)) {
6067
+ if (key === "__ohw_sections") continue;
5083
6068
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
5084
6069
  if (el.dataset.ohwEditable === "image") {
5085
6070
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -5101,6 +6086,9 @@ function OhhwellsBridge() {
5101
6086
  });
5102
6087
  applyLinkByKey(key, val);
5103
6088
  }
6089
+ initSectionsFromContent(content, true);
6090
+ sectionsLoadedRef.current = true;
6091
+ pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
5104
6092
  return imageLoads.length > 0 ? Promise.all(imageLoads).then(() => {
5105
6093
  }) : Promise.resolve();
5106
6094
  };
@@ -5125,12 +6113,15 @@ function OhhwellsBridge() {
5125
6113
  cancelled = true;
5126
6114
  };
5127
6115
  }, [subdomain, isEditMode, pathname]);
5128
- (0, import_react3.useEffect)(() => {
6116
+ (0, import_react5.useEffect)(() => {
5129
6117
  if (!subdomain || isEditMode) return;
6118
+ let debounceTimer = null;
5130
6119
  const applyFromCache = () => {
5131
6120
  const content = contentCache.get(subdomain);
5132
6121
  if (!content) return;
6122
+ retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
5133
6123
  for (const [key, val] of Object.entries(content)) {
6124
+ if (key === "__ohw_sections") continue;
5134
6125
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
5135
6126
  if (el.dataset.ohwEditable === "image") {
5136
6127
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -5147,21 +6138,28 @@ function OhhwellsBridge() {
5147
6138
  applyLinkByKey(key, val);
5148
6139
  }
5149
6140
  };
5150
- applyFromCache();
5151
- const observer = new MutationObserver(applyFromCache);
6141
+ const scheduleApply = () => {
6142
+ if (debounceTimer) clearTimeout(debounceTimer);
6143
+ debounceTimer = setTimeout(applyFromCache, 150);
6144
+ };
6145
+ scheduleApply();
6146
+ const observer = new MutationObserver(scheduleApply);
5152
6147
  observer.observe(document.body, { childList: true, subtree: true });
5153
- return () => observer.disconnect();
5154
- }, [subdomain, isEditMode]);
5155
- (0, import_react3.useLayoutEffect)(() => {
6148
+ return () => {
6149
+ observer.disconnect();
6150
+ if (debounceTimer) clearTimeout(debounceTimer);
6151
+ };
6152
+ }, [subdomain, isEditMode, pathname]);
6153
+ (0, import_react5.useLayoutEffect)(() => {
5156
6154
  const el = document.getElementById("ohw-loader");
5157
6155
  if (!el) return;
5158
6156
  const visible = Boolean(subdomain) && fetchState !== "done";
5159
6157
  el.style.display = visible ? "flex" : "none";
5160
6158
  }, [subdomain, fetchState]);
5161
- (0, import_react3.useEffect)(() => {
6159
+ (0, import_react5.useEffect)(() => {
5162
6160
  postToParent({ type: "ow:navigation", path: pathname });
5163
6161
  }, [pathname, postToParent]);
5164
- (0, import_react3.useEffect)(() => {
6162
+ (0, import_react5.useEffect)(() => {
5165
6163
  if (!isEditMode) return;
5166
6164
  const measure = () => {
5167
6165
  const h = document.body.scrollHeight;
@@ -5185,7 +6183,7 @@ function OhhwellsBridge() {
5185
6183
  window.removeEventListener("resize", handleResize);
5186
6184
  };
5187
6185
  }, [pathname, isEditMode, postToParent]);
5188
- (0, import_react3.useEffect)(() => {
6186
+ (0, import_react5.useEffect)(() => {
5189
6187
  if (!subdomainFromQuery || isEditMode) return;
5190
6188
  const handleClick = (e) => {
5191
6189
  const anchor = e.target.closest("a");
@@ -5201,7 +6199,7 @@ function OhhwellsBridge() {
5201
6199
  document.addEventListener("click", handleClick, true);
5202
6200
  return () => document.removeEventListener("click", handleClick, true);
5203
6201
  }, [subdomainFromQuery, isEditMode, router]);
5204
- (0, import_react3.useEffect)(() => {
6202
+ (0, import_react5.useEffect)(() => {
5205
6203
  if (!isEditMode) {
5206
6204
  editStylesRef.current?.base.remove();
5207
6205
  editStylesRef.current?.forceHover.remove();
@@ -5502,6 +6500,15 @@ function OhhwellsBridge() {
5502
6500
  textEditable.setAttribute("data-ohw-hovered", "");
5503
6501
  return;
5504
6502
  }
6503
+ if (hoveredGapRef.current) {
6504
+ if (hoveredImageRef.current) {
6505
+ hoveredImageRef.current = null;
6506
+ resumeAnimTracks();
6507
+ postToParentRef.current({ type: "ow:image-unhover" });
6508
+ }
6509
+ document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
6510
+ return;
6511
+ }
5505
6512
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
5506
6513
  if (imgEl !== hoveredImageRef.current || hoveredImageHasTextOverlapRef.current) {
5507
6514
  hoveredImageRef.current = imgEl;
@@ -5567,8 +6574,30 @@ function OhhwellsBridge() {
5567
6574
  }
5568
6575
  }
5569
6576
  };
6577
+ const probeSectionGapAt = (clientX, clientY, fromParentViewport = false) => {
6578
+ const { y } = toProbeCoords(clientX, clientY, fromParentViewport);
6579
+ const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
6580
+ const ZONE = 20;
6581
+ for (let i = 0; i < sections.length; i++) {
6582
+ const a = sections[i];
6583
+ const b = sections[i + 1] ?? null;
6584
+ const boundaryY = a.getBoundingClientRect().bottom;
6585
+ if (Math.abs(y - boundaryY) <= ZONE) {
6586
+ const insertAfter = a.dataset.ohwSection ?? "";
6587
+ const insertBefore = b?.dataset.ohwSection ?? null;
6588
+ hoveredGapRef.current = { insertAfter, insertBefore };
6589
+ setSectionGap({ insertAfter, insertBefore, y: boundaryY });
6590
+ return;
6591
+ }
6592
+ }
6593
+ if (hoveredGapRef.current) {
6594
+ hoveredGapRef.current = null;
6595
+ setSectionGap(null);
6596
+ }
6597
+ };
5570
6598
  const handleMouseMove = (e) => {
5571
6599
  const { clientX, clientY } = e;
6600
+ probeSectionGapAt(clientX, clientY);
5572
6601
  probeImageAt(clientX, clientY);
5573
6602
  probeHoverCardsAt(clientX, clientY);
5574
6603
  };
@@ -5576,6 +6605,7 @@ function OhhwellsBridge() {
5576
6605
  if (e.data?.type !== "ow:pointer-sync") return;
5577
6606
  const { clientX, clientY } = e.data;
5578
6607
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
6608
+ probeSectionGapAt(clientX, clientY);
5579
6609
  probeImageAt(clientX, clientY);
5580
6610
  probeHoverCardsAt(clientX, clientY);
5581
6611
  };
@@ -5733,7 +6763,12 @@ function OhhwellsBridge() {
5733
6763
  if (e.data?.type !== "ow:hydrate") return;
5734
6764
  const content = e.data.content;
5735
6765
  if (!content) return;
6766
+ let sectionsJson = null;
5736
6767
  for (const [key, val] of Object.entries(content)) {
6768
+ if (key === "__ohw_sections") {
6769
+ sectionsJson = val;
6770
+ continue;
6771
+ }
5737
6772
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
5738
6773
  if (el.dataset.ohwEditable === "image") {
5739
6774
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -5748,6 +6783,11 @@ function OhhwellsBridge() {
5748
6783
  });
5749
6784
  applyLinkByKey(key, val);
5750
6785
  }
6786
+ if (sectionsJson) {
6787
+ initSectionsFromContent({ __ohw_sections: sectionsJson }, true);
6788
+ sectionsLoadedRef.current = true;
6789
+ pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
6790
+ }
5751
6791
  postToParentRef.current({ type: "ow:hydrate-done" });
5752
6792
  };
5753
6793
  window.addEventListener("message", handleHydrate);
@@ -5800,7 +6840,63 @@ function OhhwellsBridge() {
5800
6840
  };
5801
6841
  const handleSave = (e) => {
5802
6842
  if (e.data?.type !== "ow:save") return;
5803
- postToParentRef.current({ type: "ow:save-result", nodes: collectEditableNodes() });
6843
+ const nodes = collectEditableNodes();
6844
+ const tracker = document.querySelector("[data-ohw-sections-tracker]");
6845
+ if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
6846
+ postToParentRef.current({ type: "ow:save-result", nodes });
6847
+ };
6848
+ const handleInsertSection = (e) => {
6849
+ if (e.data?.type !== "ow:insert-section") return;
6850
+ const { widgetType, insertAfter, insertBefore } = e.data;
6851
+ if (widgetType !== "scheduling") return;
6852
+ const inserted = mountSchedulingWidget(insertAfter, true, void 0, insertBefore ?? null);
6853
+ if (inserted) {
6854
+ const tracker = getSectionsTracker();
6855
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
6856
+ const h = document.documentElement.scrollHeight;
6857
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
6858
+ }
6859
+ };
6860
+ const handleSwitchSchedule = (e) => {
6861
+ if (e.data?.type !== "ow:switch-schedule") return;
6862
+ const scheduleId = e.data.scheduleId;
6863
+ const insertAfter = e.data.insertAfter;
6864
+ if (!scheduleId || !insertAfter) return;
6865
+ const text = updateSectionScheduleId(insertAfter, scheduleId);
6866
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text }] });
6867
+ };
6868
+ const handleScheduleLinked = (e) => {
6869
+ if (e.data?.type !== "ow:schedule-linked") return;
6870
+ const scheduleId = e.data.scheduleId;
6871
+ const insertAfter = e.data.insertAfter;
6872
+ if (!scheduleId || !insertAfter) return;
6873
+ const text = updateSectionScheduleId(insertAfter, scheduleId);
6874
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text }] });
6875
+ };
6876
+ const handleClearSchedulingWidget = (e) => {
6877
+ if (e.data?.type !== "ow:clear-scheduling-widget") return;
6878
+ const insertAfter = e.data.insertAfter;
6879
+ if (!insertAfter) return;
6880
+ const text = updateSectionScheduleId(insertAfter, null);
6881
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text }] });
6882
+ };
6883
+ const handleRemoveSchedulingSection = (e) => {
6884
+ if (e.data?.type !== "ow:remove-scheduling-section") return;
6885
+ document.querySelectorAll('[data-ohw-section-container="scheduling"]').forEach((el) => {
6886
+ el.remove();
6887
+ });
6888
+ const tracker = getSectionsTracker();
6889
+ let sections = [];
6890
+ try {
6891
+ sections = JSON.parse(tracker.textContent || "[]");
6892
+ } catch {
6893
+ }
6894
+ const currentPath = window.location.pathname;
6895
+ const updated = sections.filter((s) => !(s.type === "scheduling" && s.pagePath === currentPath));
6896
+ tracker.textContent = JSON.stringify(updated);
6897
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
6898
+ const h = document.documentElement.scrollHeight;
6899
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
5804
6900
  };
5805
6901
  const handleSelectionChange = () => {
5806
6902
  if (!activeElRef.current) return;
@@ -5905,6 +7001,11 @@ function OhhwellsBridge() {
5905
7001
  deactivateRef.current();
5906
7002
  };
5907
7003
  window.addEventListener("message", handleSave);
7004
+ window.addEventListener("message", handleInsertSection);
7005
+ window.addEventListener("message", handleSwitchSchedule);
7006
+ window.addEventListener("message", handleScheduleLinked);
7007
+ window.addEventListener("message", handleClearSchedulingWidget);
7008
+ window.addEventListener("message", handleRemoveSchedulingSection);
5908
7009
  window.addEventListener("message", handleImageUrl);
5909
7010
  window.addEventListener("message", handleAnimLock);
5910
7011
  window.addEventListener("message", handleCanvasHeight);
@@ -5939,6 +7040,11 @@ function OhhwellsBridge() {
5939
7040
  document.removeEventListener("selectionchange", handleSelectionChange);
5940
7041
  window.removeEventListener("scroll", handleScroll, true);
5941
7042
  window.removeEventListener("message", handleSave);
7043
+ window.removeEventListener("message", handleInsertSection);
7044
+ window.removeEventListener("message", handleSwitchSchedule);
7045
+ window.removeEventListener("message", handleScheduleLinked);
7046
+ window.removeEventListener("message", handleClearSchedulingWidget);
7047
+ window.removeEventListener("message", handleRemoveSchedulingSection);
5942
7048
  window.removeEventListener("message", handleImageUrl);
5943
7049
  window.removeEventListener("message", handleAnimLock);
5944
7050
  window.removeEventListener("message", handleCanvasHeight);
@@ -5953,7 +7059,23 @@ function OhhwellsBridge() {
5953
7059
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
5954
7060
  };
5955
7061
  }, [isEditMode, refreshStateRules]);
5956
- (0, import_react3.useEffect)(() => {
7062
+ (0, import_react5.useEffect)(() => {
7063
+ const handler = (e) => {
7064
+ if (e.data?.type !== "ow:request-schedule-config") return;
7065
+ const insertAfterVal = e.data.insertAfter;
7066
+ if (!insertAfterVal) return;
7067
+ if (!sectionsLoadedRef.current) {
7068
+ if (!pendingScheduleConfigRequests.current.includes(insertAfterVal)) {
7069
+ pendingScheduleConfigRequests.current.push(insertAfterVal);
7070
+ }
7071
+ return;
7072
+ }
7073
+ processConfigRequest(insertAfterVal);
7074
+ };
7075
+ window.addEventListener("message", handler);
7076
+ return () => window.removeEventListener("message", handler);
7077
+ }, [processConfigRequest]);
7078
+ (0, import_react5.useEffect)(() => {
5957
7079
  if (!isEditMode) return;
5958
7080
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
5959
7081
  el.removeAttribute("data-ohw-active-state");
@@ -5982,19 +7104,19 @@ function OhhwellsBridge() {
5982
7104
  clearTimeout(timer);
5983
7105
  };
5984
7106
  }, [pathname, isEditMode, refreshStateRules, postToParent]);
5985
- (0, import_react3.useEffect)(() => {
7107
+ (0, import_react5.useEffect)(() => {
5986
7108
  scrollToHashSectionWhenReady();
5987
7109
  const onHashChange = () => scrollToHashSectionWhenReady();
5988
7110
  window.addEventListener("hashchange", onHashChange);
5989
7111
  return () => window.removeEventListener("hashchange", onHashChange);
5990
7112
  }, [pathname]);
5991
- const handleCommand = (0, import_react3.useCallback)((cmd) => {
7113
+ const handleCommand = (0, import_react5.useCallback)((cmd) => {
5992
7114
  document.execCommand(cmd, false);
5993
7115
  activeElRef.current?.focus();
5994
7116
  if (activeElRef.current) setToolbarRect(activeElRef.current.getBoundingClientRect());
5995
7117
  refreshActiveCommandsRef.current();
5996
7118
  }, []);
5997
- const handleStateChange = (0, import_react3.useCallback)((state) => {
7119
+ const handleStateChange = (0, import_react5.useCallback)((state) => {
5998
7120
  if (!activeStateElRef.current) return;
5999
7121
  const el = activeStateElRef.current;
6000
7122
  if (state === "Default") {
@@ -6007,8 +7129,8 @@ function OhhwellsBridge() {
6007
7129
  }
6008
7130
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
6009
7131
  }, [deactivate]);
6010
- const closeLinkPopover = (0, import_react3.useCallback)(() => setLinkPopover(null), []);
6011
- const openLinkPopoverForActive = (0, import_react3.useCallback)(() => {
7132
+ const closeLinkPopover = (0, import_react5.useCallback)(() => setLinkPopover(null), []);
7133
+ const openLinkPopoverForActive = (0, import_react5.useCallback)(() => {
6012
7134
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
6013
7135
  if (!hrefCtx) return;
6014
7136
  bumpLinkPopoverGrace();
@@ -6018,7 +7140,7 @@ function OhhwellsBridge() {
6018
7140
  rect: hrefCtx.anchor.getBoundingClientRect()
6019
7141
  });
6020
7142
  }, []);
6021
- const handleLinkPopoverSubmit = (0, import_react3.useCallback)(
7143
+ const handleLinkPopoverSubmit = (0, import_react5.useCallback)(
6022
7144
  (target) => {
6023
7145
  if (!linkPopover) return;
6024
7146
  const { key } = linkPopover;
@@ -6031,11 +7153,11 @@ function OhhwellsBridge() {
6031
7153
  const showEditLink = toolbarShowEditLink;
6032
7154
  const currentSections = sectionsByPath[pathname] ?? [];
6033
7155
  linkPopoverOpenRef.current = linkPopover !== null;
6034
- return bridgeRoot ? (0, import_react_dom.createPortal)(
6035
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
6036
- toolbarRect && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
6037
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(GlowFrame, { rect: toolbarRect, elRef: glowElRef }),
6038
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7156
+ return bridgeRoot ? (0, import_react_dom2.createPortal)(
7157
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
7158
+ toolbarRect && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
7159
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(GlowFrame, { rect: toolbarRect, elRef: glowElRef }),
7160
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6039
7161
  FloatingToolbar,
6040
7162
  {
6041
7163
  rect: toolbarRect,
@@ -6048,7 +7170,7 @@ function OhhwellsBridge() {
6048
7170
  }
6049
7171
  )
6050
7172
  ] }),
6051
- maxBadge && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
7173
+ maxBadge && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
6052
7174
  "div",
6053
7175
  {
6054
7176
  "data-ohw-max-badge": "",
@@ -6074,7 +7196,7 @@ function OhhwellsBridge() {
6074
7196
  ]
6075
7197
  }
6076
7198
  ),
6077
- toggleState && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7199
+ toggleState && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6078
7200
  StateToggle,
6079
7201
  {
6080
7202
  rect: toggleState.rect,
@@ -6083,7 +7205,32 @@ function OhhwellsBridge() {
6083
7205
  onStateChange: handleStateChange
6084
7206
  }
6085
7207
  ),
6086
- linkPopover ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7208
+ sectionGap && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
7209
+ "div",
7210
+ {
7211
+ "data-ohw-section-insert-line": "",
7212
+ className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
7213
+ style: { top: sectionGap.y, transform: "translateY(-50%)" },
7214
+ children: [
7215
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
7216
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7217
+ Badge,
7218
+ {
7219
+ 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",
7220
+ onClick: () => {
7221
+ window.parent.postMessage(
7222
+ { type: "ow:add-section", insertAfter: sectionGap.insertAfter, insertBefore: sectionGap.insertBefore },
7223
+ "*"
7224
+ );
7225
+ },
7226
+ children: "Add Section"
7227
+ }
7228
+ ),
7229
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
7230
+ ]
7231
+ }
7232
+ ),
7233
+ linkPopover ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6087
7234
  LinkPopover,
6088
7235
  {
6089
7236
  rect: linkPopover.rect,
@@ -6108,6 +7255,7 @@ function OhhwellsBridge() {
6108
7255
  LinkEditorPanel,
6109
7256
  LinkPopover,
6110
7257
  OhhwellsBridge,
7258
+ SchedulingWidget,
6111
7259
  Toggle,
6112
7260
  ToggleGroup,
6113
7261
  ToggleGroupItem,