@ohhwells/bridge 0.1.29-next.20 → 0.1.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +304 -304
- package/dist/index.cjs +215 -1302
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -7
- package/dist/index.d.ts +1 -7
- package/dist/index.js +191 -1277
- package/dist/index.js.map +1 -1
- package/dist/styles.css +12 -453
- package/package.json +47 -48
package/dist/index.cjs
CHANGED
|
@@ -34,7 +34,6 @@ __export(index_exports, {
|
|
|
34
34
|
LinkEditorPanel: () => LinkEditorPanel,
|
|
35
35
|
LinkPopover: () => LinkPopover,
|
|
36
36
|
OhhwellsBridge: () => OhhwellsBridge,
|
|
37
|
-
SchedulingWidget: () => SchedulingWidget,
|
|
38
37
|
Toggle: () => Toggle,
|
|
39
38
|
ToggleGroup: () => ToggleGroup,
|
|
40
39
|
ToggleGroupItem: () => ToggleGroupItem,
|
|
@@ -49,752 +48,10 @@ __export(index_exports, {
|
|
|
49
48
|
module.exports = __toCommonJS(index_exports);
|
|
50
49
|
|
|
51
50
|
// src/OhhwellsBridge.tsx
|
|
52
|
-
var
|
|
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 getApiDomain() {
|
|
216
|
-
const h = window.location.hostname;
|
|
217
|
-
for (const base of ["ohhwells.site", "theflowops-staging.com", "theflowops.com"]) {
|
|
218
|
-
if (h.endsWith(`.${base}`)) return h.slice(0, -(base.length + 1));
|
|
219
|
-
}
|
|
220
|
-
return h;
|
|
221
|
-
}
|
|
222
|
-
function classRunsOnDate(cls, date, type) {
|
|
223
|
-
if (type === "FIXED") {
|
|
224
|
-
const d = String(date.getDate()).padStart(2, "0");
|
|
225
|
-
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
226
|
-
return cls.fixedDates?.some((fd) => fd.date === `${d}-${m}-${date.getFullYear()}`) ?? false;
|
|
227
|
-
}
|
|
228
|
-
return cls.weekdays?.some((w) => w.weekday === date.getDay()) ?? false;
|
|
229
|
-
}
|
|
230
|
-
function formatClassTime(cls) {
|
|
231
|
-
let h = parseInt(cls.startTime.hour, 10);
|
|
232
|
-
const m = parseInt(cls.startTime.minutes, 10);
|
|
233
|
-
if (cls.startTime.time === "PM" && h !== 12) h += 12;
|
|
234
|
-
if (cls.startTime.time === "AM" && h === 12) h = 0;
|
|
235
|
-
const endTotal = h * 60 + m + cls.duration;
|
|
236
|
-
const eh = Math.floor(endTotal / 60) % 24;
|
|
237
|
-
const em = endTotal % 60;
|
|
238
|
-
return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
|
|
239
|
-
}
|
|
240
|
-
function getBookingsOnDate(cls, date) {
|
|
241
|
-
if (!cls.bookings?.length) return 0;
|
|
242
|
-
const ds = date.toISOString().split("T")[0];
|
|
243
|
-
return cls.bookings.filter((b) => {
|
|
244
|
-
try {
|
|
245
|
-
return new Date(b.classDate).toISOString().split("T")[0] === ds;
|
|
246
|
-
} catch {
|
|
247
|
-
return false;
|
|
248
|
-
}
|
|
249
|
-
}).length;
|
|
250
|
-
}
|
|
251
|
-
function buildTimezoneLabel(tz) {
|
|
252
|
-
try {
|
|
253
|
-
const now = /* @__PURE__ */ new Date();
|
|
254
|
-
const timeStr = new Intl.DateTimeFormat("en-US", {
|
|
255
|
-
hour: "2-digit",
|
|
256
|
-
minute: "2-digit",
|
|
257
|
-
hour12: false,
|
|
258
|
-
timeZone: tz
|
|
259
|
-
}).format(now);
|
|
260
|
-
const offsetPart = new Intl.DateTimeFormat("en-US", { timeZoneName: "short", timeZone: tz }).formatToParts(now).find((p) => p.type === "timeZoneName")?.value ?? "";
|
|
261
|
-
const city = tz.split("/").pop()?.replace(/_/g, " ") ?? tz;
|
|
262
|
-
return `${timeStr} (${offsetPart}) ${city} time`;
|
|
263
|
-
} catch {
|
|
264
|
-
return tz;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
function EmptyState({ inEditor }) {
|
|
268
|
-
const handleAddSchedule = () => {
|
|
269
|
-
if (inEditor) {
|
|
270
|
-
window.parent.postMessage({ type: "ow:scheduling-not-connected" }, "*");
|
|
271
|
-
}
|
|
272
|
-
};
|
|
273
|
-
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: [
|
|
274
|
-
/* @__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)(
|
|
275
|
-
"svg",
|
|
276
|
-
{
|
|
277
|
-
width: "20",
|
|
278
|
-
height: "20",
|
|
279
|
-
viewBox: "0 0 24 24",
|
|
280
|
-
fill: "none",
|
|
281
|
-
stroke: "var(--color-accent, #A89B83)",
|
|
282
|
-
strokeWidth: "1.5",
|
|
283
|
-
strokeLinecap: "round",
|
|
284
|
-
strokeLinejoin: "round",
|
|
285
|
-
children: [
|
|
286
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
|
|
287
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "16", y1: "2", x2: "16", y2: "6" }),
|
|
288
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "8", y1: "2", x2: "8", y2: "6" }),
|
|
289
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "3", y1: "10", x2: "21", y2: "10" }),
|
|
290
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "12", y1: "14", x2: "12", y2: "18" }),
|
|
291
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "10", y1: "16", x2: "14", y2: "16" })
|
|
292
|
-
]
|
|
293
|
-
}
|
|
294
|
-
) }),
|
|
295
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col items-center gap-2", children: [
|
|
296
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "font-body text-lg font-medium text-center text-[#0A0A0A] m-0", children: "No schedule yet" }),
|
|
297
|
-
/* @__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." })
|
|
298
|
-
] }),
|
|
299
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
300
|
-
"button",
|
|
301
|
-
{
|
|
302
|
-
onClick: handleAddSchedule,
|
|
303
|
-
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",
|
|
304
|
-
children: "Add Schedule"
|
|
305
|
-
}
|
|
306
|
-
)
|
|
307
|
-
] });
|
|
308
|
-
}
|
|
309
|
-
function LoadingSkeleton() {
|
|
310
|
-
const shimmer = {
|
|
311
|
-
background: "linear-gradient(90deg,#f0f0f0 25%,#e8e8e8 50%,#f0f0f0 75%)",
|
|
312
|
-
backgroundSize: "200% 100%",
|
|
313
|
-
animation: "ohw-shimmer 1.5s infinite"
|
|
314
|
-
};
|
|
315
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full flex flex-col gap-10", children: [
|
|
316
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { children: `@keyframes ohw-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}` }),
|
|
317
|
-
/* @__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: [
|
|
318
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "32px", height: "14px", borderRadius: "4px" } }),
|
|
319
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "40px", height: "40px", borderRadius: "50%" } })
|
|
320
|
-
] }, i)) }),
|
|
321
|
-
[0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
322
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex gap-4 py-4 sm:hidden", children: [
|
|
323
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col gap-2 shrink-0", children: [
|
|
324
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "100px", height: "16px", borderRadius: "4px" } }),
|
|
325
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "52px", height: "20px", borderRadius: "999px" } }),
|
|
326
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "60px", height: "14px", borderRadius: "4px" } })
|
|
327
|
-
] }),
|
|
328
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-1 flex-col gap-2", children: [
|
|
329
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "75%", height: "16px", borderRadius: "4px" } }),
|
|
330
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "50%", height: "14px", borderRadius: "4px" } }),
|
|
331
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "100%", height: "44px", borderRadius: "8px" } })
|
|
332
|
-
] })
|
|
333
|
-
] }),
|
|
334
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "hidden sm:flex items-center gap-[60px] py-4", children: [
|
|
335
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "120px", height: "16px", borderRadius: "4px", flexShrink: 0 } }),
|
|
336
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex-1 flex flex-col gap-2", children: [
|
|
337
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "55%", height: "16px", borderRadius: "4px" } }),
|
|
338
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "38%", height: "14px", borderRadius: "4px" } })
|
|
339
|
-
] }),
|
|
340
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "56px", height: "32px", borderRadius: "4px", flexShrink: 0 } }),
|
|
341
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...shimmer, width: "200px", height: "44px", borderRadius: "8px", flexShrink: 0 } })
|
|
342
|
-
] }),
|
|
343
|
-
i < 2 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "h-px bg-black/20" })
|
|
344
|
-
] }, i))
|
|
345
|
-
] });
|
|
346
|
-
}
|
|
347
|
-
function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal }) {
|
|
348
|
-
const todayMs = (0, import_react2.useMemo)(() => {
|
|
349
|
-
const d = /* @__PURE__ */ new Date();
|
|
350
|
-
d.setHours(0, 0, 0, 0);
|
|
351
|
-
return d.getTime();
|
|
352
|
-
}, []);
|
|
353
|
-
const scrollRef = (0, import_react2.useRef)(null);
|
|
354
|
-
const [canScrollLeft, setCanScrollLeft] = (0, import_react2.useState)(false);
|
|
355
|
-
const [canScrollRight, setCanScrollRight] = (0, import_react2.useState)(false);
|
|
356
|
-
const updateScrollState = () => {
|
|
357
|
-
const el = scrollRef.current;
|
|
358
|
-
if (!el) return;
|
|
359
|
-
setCanScrollLeft(el.scrollLeft > 0);
|
|
360
|
-
setCanScrollRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
|
|
361
|
-
};
|
|
362
|
-
(0, import_react2.useEffect)(() => {
|
|
363
|
-
const el = scrollRef.current;
|
|
364
|
-
if (!el) return;
|
|
365
|
-
updateScrollState();
|
|
366
|
-
el.addEventListener("scroll", updateScrollState);
|
|
367
|
-
const ro = new ResizeObserver(updateScrollState);
|
|
368
|
-
ro.observe(el);
|
|
369
|
-
return () => {
|
|
370
|
-
el.removeEventListener("scroll", updateScrollState);
|
|
371
|
-
ro.disconnect();
|
|
372
|
-
};
|
|
373
|
-
}, [dates]);
|
|
374
|
-
const scroll = (dir) => {
|
|
375
|
-
scrollRef.current?.scrollBy({ left: dir === "left" ? -216 : 216, behavior: "smooth" });
|
|
376
|
-
};
|
|
377
|
-
const isDragging = (0, import_react2.useRef)(false);
|
|
378
|
-
const dragStartX = (0, import_react2.useRef)(0);
|
|
379
|
-
const dragStartScrollLeft = (0, import_react2.useRef)(0);
|
|
380
|
-
const onDragStart = (e) => {
|
|
381
|
-
if (!scrollRef.current) return;
|
|
382
|
-
isDragging.current = true;
|
|
383
|
-
dragStartX.current = e.clientX;
|
|
384
|
-
dragStartScrollLeft.current = scrollRef.current.scrollLeft;
|
|
385
|
-
scrollRef.current.style.cursor = "grabbing";
|
|
386
|
-
scrollRef.current.style.userSelect = "none";
|
|
387
|
-
};
|
|
388
|
-
const onDragMove = (e) => {
|
|
389
|
-
if (!isDragging.current || !scrollRef.current) return;
|
|
390
|
-
const delta = e.clientX - dragStartX.current;
|
|
391
|
-
scrollRef.current.scrollLeft = dragStartScrollLeft.current - delta;
|
|
392
|
-
};
|
|
393
|
-
const onDragEnd = () => {
|
|
394
|
-
if (!scrollRef.current) return;
|
|
395
|
-
isDragging.current = false;
|
|
396
|
-
scrollRef.current.style.cursor = "grab";
|
|
397
|
-
scrollRef.current.style.userSelect = "";
|
|
398
|
-
};
|
|
399
|
-
const datesWithClasses = (0, import_react2.useMemo)(
|
|
400
|
-
() => new Set(dates.map(
|
|
401
|
-
(d, i) => schedule.classes?.some((c) => classRunsOnDate(c, d, schedule.type)) ? i : -1
|
|
402
|
-
).filter((i) => i >= 0)),
|
|
403
|
-
[dates, schedule]
|
|
404
|
-
);
|
|
405
|
-
const selectedDate = dates[selectedIdx];
|
|
406
|
-
const selectedClasses = (0, import_react2.useMemo)(
|
|
407
|
-
() => (schedule.classes ?? []).filter((c) => selectedDate && classRunsOnDate(c, selectedDate, schedule.type)),
|
|
408
|
-
[schedule, selectedDate]
|
|
409
|
-
);
|
|
410
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full flex flex-col gap-10", children: [
|
|
411
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "relative w-full", children: [
|
|
412
|
-
canScrollLeft && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
413
|
-
"button",
|
|
414
|
-
{
|
|
415
|
-
onClick: () => scroll("left"),
|
|
416
|
-
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",
|
|
417
|
-
style: { background: "var(--color-light,#FEFFF0)", boxShadow: "0 1px 4px rgba(0,0,0,0.15)" },
|
|
418
|
-
"aria-label": "Scroll left",
|
|
419
|
-
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" }) })
|
|
420
|
-
}
|
|
421
|
-
),
|
|
422
|
-
canScrollRight && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
423
|
-
"button",
|
|
424
|
-
{
|
|
425
|
-
onClick: () => scroll("right"),
|
|
426
|
-
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",
|
|
427
|
-
style: { background: "var(--color-light,#FEFFF0)", boxShadow: "0 1px 4px rgba(0,0,0,0.15)" },
|
|
428
|
-
"aria-label": "Scroll right",
|
|
429
|
-
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" }) })
|
|
430
|
-
}
|
|
431
|
-
),
|
|
432
|
-
canScrollLeft && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
433
|
-
"div",
|
|
434
|
-
{
|
|
435
|
-
className: "sm:hidden absolute left-0 top-0 bottom-0 w-10 z-10 pointer-events-none",
|
|
436
|
-
style: { background: "linear-gradient(to right, var(--color-light,#FEFFF0), transparent)" }
|
|
437
|
-
}
|
|
438
|
-
),
|
|
439
|
-
canScrollRight && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
440
|
-
"div",
|
|
441
|
-
{
|
|
442
|
-
className: "sm:hidden absolute right-0 top-0 bottom-0 w-10 z-10 pointer-events-none",
|
|
443
|
-
style: { background: "linear-gradient(to left, var(--color-light,#FEFFF0), transparent)" }
|
|
444
|
-
}
|
|
445
|
-
),
|
|
446
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
447
|
-
"div",
|
|
448
|
-
{
|
|
449
|
-
ref: scrollRef,
|
|
450
|
-
className: "overflow-x-auto w-full",
|
|
451
|
-
style: { scrollbarWidth: "none", msOverflowStyle: "none", touchAction: "pan-x", cursor: "grab" },
|
|
452
|
-
onMouseDown: onDragStart,
|
|
453
|
-
onMouseMove: onDragMove,
|
|
454
|
-
onMouseUp: onDragEnd,
|
|
455
|
-
onMouseLeave: onDragEnd,
|
|
456
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex", style: { width: `max(100%, ${dates.length * 60}px)` }, children: dates.map((date, i) => {
|
|
457
|
-
const isToday = date.getTime() === todayMs;
|
|
458
|
-
const isSelected = i === selectedIdx;
|
|
459
|
-
const clickable = datesWithClasses.has(i);
|
|
460
|
-
const label = isToday ? "TODAY" : DAY_ABBR[date.getDay()];
|
|
461
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
462
|
-
"div",
|
|
463
|
-
{
|
|
464
|
-
onClick: () => clickable && onSelectDate(i),
|
|
465
|
-
className: `flex-1 h-[70px] flex flex-col justify-between items-center ${clickable ? "cursor-pointer opacity-100" : "cursor-default opacity-50"}`,
|
|
466
|
-
children: [
|
|
467
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-normal text-center text-(--color-dark,#200C02)", children: label }),
|
|
468
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
469
|
-
"div",
|
|
470
|
-
{
|
|
471
|
-
className: "w-10 h-10 rounded-full flex items-center justify-center",
|
|
472
|
-
style: { background: isSelected ? "var(--color-primary, #3D312B)" : "transparent" },
|
|
473
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
474
|
-
"span",
|
|
475
|
-
{
|
|
476
|
-
className: "font-body text-xl font-bold text-center tracking-display-tight",
|
|
477
|
-
style: { color: isSelected ? "var(--color-light, #FEFFF0)" : "var(--color-dark, #200C02)" },
|
|
478
|
-
children: date.getDate()
|
|
479
|
-
}
|
|
480
|
-
)
|
|
481
|
-
}
|
|
482
|
-
)
|
|
483
|
-
]
|
|
484
|
-
},
|
|
485
|
-
i
|
|
486
|
-
);
|
|
487
|
-
}) })
|
|
488
|
-
}
|
|
489
|
-
)
|
|
490
|
-
] }),
|
|
491
|
-
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) => {
|
|
492
|
-
const booked = getBookingsOnDate(cls, selectedDate);
|
|
493
|
-
const available = cls.maxParticipants - booked;
|
|
494
|
-
const isFull = available <= 0;
|
|
495
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
496
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex gap-4 py-4 sm:items-center sm:gap-[60px] box-border", children: [
|
|
497
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col gap-2 shrink-0 sm:contents", children: [
|
|
498
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "sm:w-[120px] sm:shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block", children: formatClassTime(cls) }) }),
|
|
499
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
500
|
-
"span",
|
|
501
|
-
{
|
|
502
|
-
className: "inline-flex items-center px-2 py-0.5 rounded-full border text-xs font-medium sm:hidden",
|
|
503
|
-
style: { borderColor: "#0885FE", color: "#0885FE" },
|
|
504
|
-
children: "GROUP"
|
|
505
|
-
}
|
|
506
|
-
),
|
|
507
|
-
/* @__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: [
|
|
508
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
509
|
-
available,
|
|
510
|
-
"/",
|
|
511
|
-
cls.maxParticipants
|
|
512
|
-
] }),
|
|
513
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "available" })
|
|
514
|
-
] }) })
|
|
515
|
-
] }),
|
|
516
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-1 flex-col gap-2 min-w-0 sm:contents", children: [
|
|
517
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex-1 flex flex-col gap-2 min-w-0", children: [
|
|
518
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block truncate", children: cls.name }),
|
|
519
|
-
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 })
|
|
520
|
-
] }),
|
|
521
|
-
/* @__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: [
|
|
522
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
523
|
-
available,
|
|
524
|
-
"/",
|
|
525
|
-
cls.maxParticipants
|
|
526
|
-
] }),
|
|
527
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "available" })
|
|
528
|
-
] }) }),
|
|
529
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
530
|
-
"button",
|
|
531
|
-
{
|
|
532
|
-
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",
|
|
533
|
-
style: isFull ? {
|
|
534
|
-
background: "transparent",
|
|
535
|
-
border: "1px solid var(--color-dark, #200C02)",
|
|
536
|
-
color: "var(--color-dark, #200C02)"
|
|
537
|
-
} : {
|
|
538
|
-
background: "var(--color-primary, #3D312B)",
|
|
539
|
-
border: "none",
|
|
540
|
-
color: "var(--color-light, #FEFFF0)"
|
|
541
|
-
},
|
|
542
|
-
onClick: () => {
|
|
543
|
-
if (!cls.id) return;
|
|
544
|
-
onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
|
|
545
|
-
},
|
|
546
|
-
children: isFull ? "Join Waitlist" : "Book Now"
|
|
547
|
-
}
|
|
548
|
-
)
|
|
549
|
-
] })
|
|
550
|
-
] }),
|
|
551
|
-
i < selectedClasses.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "h-px bg-black/20" })
|
|
552
|
-
] }, cls.id ?? i);
|
|
553
|
-
}) })
|
|
554
|
-
] });
|
|
555
|
-
}
|
|
556
|
-
function CalendarFoldIcon() {
|
|
557
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
558
|
-
"svg",
|
|
559
|
-
{
|
|
560
|
-
width: "16",
|
|
561
|
-
height: "16",
|
|
562
|
-
viewBox: "0 0 24 24",
|
|
563
|
-
fill: "none",
|
|
564
|
-
stroke: "currentColor",
|
|
565
|
-
strokeWidth: "2",
|
|
566
|
-
strokeLinecap: "round",
|
|
567
|
-
strokeLinejoin: "round",
|
|
568
|
-
style: { flexShrink: 0 },
|
|
569
|
-
children: [
|
|
570
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M8 2v4" }),
|
|
571
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M16 2v4" }),
|
|
572
|
-
/* @__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" }),
|
|
573
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M3 10h18" }),
|
|
574
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M15 22v-4a2 2 0 0 1 2-2h4" })
|
|
575
|
-
]
|
|
576
|
-
}
|
|
577
|
-
);
|
|
578
|
-
}
|
|
579
|
-
function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAfter }) {
|
|
580
|
-
const [schedule, setSchedule] = (0, import_react2.useState)(null);
|
|
581
|
-
const [loading, setLoading] = (0, import_react2.useState)(true);
|
|
582
|
-
const [inEditor, setInEditor] = (0, import_react2.useState)(false);
|
|
583
|
-
const [isHovered, setIsHovered] = (0, import_react2.useState)(false);
|
|
584
|
-
const [modalState, setModalState] = (0, import_react2.useState)(null);
|
|
585
|
-
const switchScheduleIdRef = (0, import_react2.useRef)(null);
|
|
586
|
-
const dates = (0, import_react2.useMemo)(() => {
|
|
587
|
-
const today = /* @__PURE__ */ new Date();
|
|
588
|
-
today.setHours(0, 0, 0, 0);
|
|
589
|
-
return Array.from({ length: 14 }, (_, i) => {
|
|
590
|
-
const d = new Date(today);
|
|
591
|
-
d.setDate(today.getDate() + i);
|
|
592
|
-
return d;
|
|
593
|
-
});
|
|
594
|
-
}, []);
|
|
595
|
-
const [selectedIdx, setSelectedIdx] = (0, import_react2.useState)(0);
|
|
596
|
-
(0, import_react2.useEffect)(() => {
|
|
597
|
-
if (!schedule?.classes) return;
|
|
598
|
-
for (let i = 0; i < dates.length; i++) {
|
|
599
|
-
if (schedule.classes.some((c) => classRunsOnDate(c, dates[i], schedule.type))) {
|
|
600
|
-
setSelectedIdx(i);
|
|
601
|
-
return;
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
}, [schedule, dates]);
|
|
605
|
-
(0, import_react2.useEffect)(() => {
|
|
606
|
-
if (typeof window === "undefined") return;
|
|
607
|
-
const isInEditor = window.self !== window.top;
|
|
608
|
-
setInEditor(isInEditor);
|
|
609
|
-
if (isInEditor) {
|
|
610
|
-
const startEmpty = initialScheduleId === null;
|
|
611
|
-
if (startEmpty) setLoading(false);
|
|
612
|
-
let initialized = startEmpty;
|
|
613
|
-
const timer = !startEmpty ? setTimeout(() => {
|
|
614
|
-
if (!initialized) {
|
|
615
|
-
initialized = true;
|
|
616
|
-
setLoading(false);
|
|
617
|
-
}
|
|
618
|
-
}, 5e3) : null;
|
|
619
|
-
const handler = (e) => {
|
|
620
|
-
if (e.data?.type === "ow:clear-scheduling-widget") {
|
|
621
|
-
if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
|
|
622
|
-
setSchedule(null);
|
|
623
|
-
setLoading(false);
|
|
624
|
-
return;
|
|
625
|
-
}
|
|
626
|
-
if (e.data?.type === "ow:switch-schedule") {
|
|
627
|
-
if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
|
|
628
|
-
switchScheduleIdRef.current = e.data.scheduleId ?? null;
|
|
629
|
-
initialized = false;
|
|
630
|
-
setLoading(true);
|
|
631
|
-
window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
|
|
632
|
-
return;
|
|
633
|
-
}
|
|
634
|
-
if (e.data?.type !== "ow:user-schedules-response") return;
|
|
635
|
-
if (e.data.insertAfter && e.data.insertAfter !== insertAfter) return;
|
|
636
|
-
if (initialized && switchScheduleIdRef.current === null) return;
|
|
637
|
-
initialized = true;
|
|
638
|
-
if (timer) clearTimeout(timer);
|
|
639
|
-
const schedules = e.data.schedules ?? [];
|
|
640
|
-
const isSwitching = switchScheduleIdRef.current !== null;
|
|
641
|
-
const target = isSwitching ? schedules.find((s) => s.id === switchScheduleIdRef.current) ?? schedules[0] ?? null : initialScheduleId ? schedules.find((s) => s.id === initialScheduleId) ?? schedules[0] ?? null : schedules[0] ?? null;
|
|
642
|
-
switchScheduleIdRef.current = null;
|
|
643
|
-
setSchedule(target);
|
|
644
|
-
setLoading(false);
|
|
645
|
-
if (notifyOnConnect && target && !isSwitching) {
|
|
646
|
-
window.parent.postMessage({
|
|
647
|
-
type: "ow:schedule-connected",
|
|
648
|
-
schedule: { id: target.id, name: target.name },
|
|
649
|
-
insertAfter
|
|
650
|
-
}, "*");
|
|
651
|
-
window.postMessage({ type: "ow:schedule-linked", scheduleId: target.id, insertAfter }, "*");
|
|
652
|
-
}
|
|
653
|
-
};
|
|
654
|
-
window.addEventListener("message", handler);
|
|
655
|
-
if (!startEmpty) window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
|
|
656
|
-
return () => {
|
|
657
|
-
window.removeEventListener("message", handler);
|
|
658
|
-
if (timer) clearTimeout(timer);
|
|
659
|
-
};
|
|
660
|
-
}
|
|
661
|
-
if (initialScheduleId === null) {
|
|
662
|
-
setLoading(false);
|
|
663
|
-
return;
|
|
664
|
-
}
|
|
665
|
-
;
|
|
666
|
-
(async () => {
|
|
667
|
-
try {
|
|
668
|
-
if (initialScheduleId) {
|
|
669
|
-
const res = await fetch(`${API_URL}/api/schedule/id/${initialScheduleId}`);
|
|
670
|
-
const data = await res.json();
|
|
671
|
-
setSchedule(data?.id ? data : null);
|
|
672
|
-
} else {
|
|
673
|
-
const domain = getApiDomain();
|
|
674
|
-
const sitemapRes = await fetch(`${API_URL}/api/schedule/sitemap/${domain}`);
|
|
675
|
-
const slugs = await sitemapRes.json();
|
|
676
|
-
if (!Array.isArray(slugs) || !slugs.length) {
|
|
677
|
-
setLoading(false);
|
|
678
|
-
return;
|
|
679
|
-
}
|
|
680
|
-
const { slug } = [...slugs].sort(
|
|
681
|
-
(a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()
|
|
682
|
-
)[0];
|
|
683
|
-
const res = await fetch(`${API_URL}/api/schedule/${domain}/${slug}`);
|
|
684
|
-
const data = await res.json();
|
|
685
|
-
setSchedule(data?.id ? data : null);
|
|
686
|
-
}
|
|
687
|
-
} catch {
|
|
688
|
-
}
|
|
689
|
-
setLoading(false);
|
|
690
|
-
})();
|
|
691
|
-
}, []);
|
|
692
|
-
const timezoneLabel = schedule?.timezone ? (() => {
|
|
693
|
-
try {
|
|
694
|
-
return buildTimezoneLabel(schedule.timezone);
|
|
695
|
-
} catch {
|
|
696
|
-
return void 0;
|
|
697
|
-
}
|
|
698
|
-
})() : void 0;
|
|
699
|
-
const handleModalSubmit = async (email) => {
|
|
700
|
-
if (!modalState) return;
|
|
701
|
-
const { mode, classId, classDate } = modalState;
|
|
702
|
-
const endpoint = mode === "book" ? `${API_URL}/api/schedule/class/${classId}/booking` : `${API_URL}/api/schedule/class/${classId}/waitlist`;
|
|
703
|
-
const res = await fetch(endpoint, {
|
|
704
|
-
method: "POST",
|
|
705
|
-
headers: { "Content-Type": "application/json" },
|
|
706
|
-
body: JSON.stringify({ classDate: classDate.toISOString(), email })
|
|
707
|
-
});
|
|
708
|
-
if (!res.ok) {
|
|
709
|
-
const data = await res.json().catch(() => ({}));
|
|
710
|
-
throw new Error(data?.message ?? "Something went wrong. Please try again.");
|
|
711
|
-
}
|
|
712
|
-
};
|
|
713
|
-
const handleReplaceSchedule = () => {
|
|
714
|
-
setIsHovered(false);
|
|
715
|
-
if (schedule) {
|
|
716
|
-
window.parent.postMessage({
|
|
717
|
-
type: "ow:schedule-connected",
|
|
718
|
-
schedule: { id: schedule.id, name: schedule.name },
|
|
719
|
-
insertAfter
|
|
720
|
-
}, "*");
|
|
721
|
-
} else {
|
|
722
|
-
window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
|
|
723
|
-
}
|
|
724
|
-
};
|
|
725
|
-
const sectionId = `scheduling-${insertAfter}`;
|
|
726
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
727
|
-
"section",
|
|
728
|
-
{
|
|
729
|
-
"data-ohw-section": sectionId,
|
|
730
|
-
"data-ohw-scheduling-anchor": insertAfter,
|
|
731
|
-
className: "w-full box-border py-10 px-5 sm:py-20 sm:px-16 font-body bg-(--color-light,#FEFFF0) relative",
|
|
732
|
-
onMouseEnter: () => inEditor && setIsHovered(true),
|
|
733
|
-
onMouseLeave: () => setIsHovered(false),
|
|
734
|
-
children: [
|
|
735
|
-
inEditor && isHovered && !!schedule && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
736
|
-
"div",
|
|
737
|
-
{
|
|
738
|
-
className: "absolute inset-0 z-10 pointer-events-auto cursor-pointer",
|
|
739
|
-
onClick: handleReplaceSchedule,
|
|
740
|
-
children: [
|
|
741
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "absolute inset-0", style: { background: "#0885FE", opacity: 0.18 } }),
|
|
742
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "absolute inset-0", style: { boxShadow: "inset 0 0 0 1.5px #0885FE" } }),
|
|
743
|
-
/* @__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)(
|
|
744
|
-
"div",
|
|
745
|
-
{
|
|
746
|
-
className: "bg-white border border-[#E7E5E4] rounded-md px-3 py-1.5 flex items-center gap-1.5",
|
|
747
|
-
style: {
|
|
748
|
-
fontSize: 14,
|
|
749
|
-
lineHeight: "24px",
|
|
750
|
-
fontFamily: "'Figtree', system-ui, sans-serif",
|
|
751
|
-
fontWeight: 500,
|
|
752
|
-
color: "#0C0A09"
|
|
753
|
-
},
|
|
754
|
-
children: [
|
|
755
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CalendarFoldIcon, {}),
|
|
756
|
-
"Replace schedule"
|
|
757
|
-
]
|
|
758
|
-
}
|
|
759
|
-
) })
|
|
760
|
-
]
|
|
761
|
-
}
|
|
762
|
-
),
|
|
763
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
|
|
764
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
|
|
765
|
-
/* @__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" }),
|
|
766
|
-
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 })
|
|
767
|
-
] }),
|
|
768
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full flex flex-col items-end gap-3", children: [
|
|
769
|
-
timezoneLabel && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm font-normal text-(--color-accent,#A89B83)", children: timezoneLabel }),
|
|
770
|
-
/* @__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 }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
771
|
-
ScheduleView,
|
|
772
|
-
{
|
|
773
|
-
schedule,
|
|
774
|
-
dates,
|
|
775
|
-
selectedIdx,
|
|
776
|
-
onSelectDate: setSelectedIdx,
|
|
777
|
-
onOpenModal: inEditor ? void 0 : (mode, classId, classDate) => setModalState({ mode, classId, classDate })
|
|
778
|
-
}
|
|
779
|
-
) })
|
|
780
|
-
] })
|
|
781
|
-
] }),
|
|
782
|
-
modalState && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
783
|
-
EmailCaptureModal,
|
|
784
|
-
{
|
|
785
|
-
title: modalState.mode === "book" ? "Confirm your spot" : "Leave your email",
|
|
786
|
-
subtitle: modalState.mode === "book" ? "We'll send your booking confirmation here." : "We'll let you know when spots open up!",
|
|
787
|
-
onSubmit: handleModalSubmit,
|
|
788
|
-
onClose: () => setModalState(null)
|
|
789
|
-
}
|
|
790
|
-
)
|
|
791
|
-
]
|
|
792
|
-
}
|
|
793
|
-
);
|
|
794
|
-
}
|
|
51
|
+
var import_react3 = __toESM(require("react"), 1);
|
|
795
52
|
|
|
796
53
|
// src/ui/toggle-group.tsx
|
|
797
|
-
var
|
|
54
|
+
var React = __toESM(require("react"), 1);
|
|
798
55
|
|
|
799
56
|
// node_modules/clsx/dist/clsx.mjs
|
|
800
57
|
function r(e) {
|
|
@@ -4113,8 +3370,8 @@ var cva = (base, config) => (props) => {
|
|
|
4113
3370
|
};
|
|
4114
3371
|
|
|
4115
3372
|
// src/ui/toggle.tsx
|
|
4116
|
-
var
|
|
4117
|
-
var
|
|
3373
|
+
var import_radix_ui = require("radix-ui");
|
|
3374
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
4118
3375
|
var toggleVariants = cva(
|
|
4119
3376
|
"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",
|
|
4120
3377
|
{
|
|
@@ -4141,8 +3398,8 @@ function Toggle({
|
|
|
4141
3398
|
size,
|
|
4142
3399
|
...props
|
|
4143
3400
|
}) {
|
|
4144
|
-
return /* @__PURE__ */ (0,
|
|
4145
|
-
|
|
3401
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
3402
|
+
import_radix_ui.Toggle.Root,
|
|
4146
3403
|
{
|
|
4147
3404
|
"data-slot": "toggle",
|
|
4148
3405
|
className: cn(toggleVariants({ variant, size, className })),
|
|
@@ -4152,8 +3409,8 @@ function Toggle({
|
|
|
4152
3409
|
}
|
|
4153
3410
|
|
|
4154
3411
|
// src/ui/toggle-group.tsx
|
|
4155
|
-
var
|
|
4156
|
-
var ToggleGroupContext =
|
|
3412
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
3413
|
+
var ToggleGroupContext = React.createContext({
|
|
4157
3414
|
value: "",
|
|
4158
3415
|
onValueChange: () => {
|
|
4159
3416
|
}
|
|
@@ -4165,13 +3422,13 @@ function ToggleGroup({
|
|
|
4165
3422
|
children,
|
|
4166
3423
|
...props
|
|
4167
3424
|
}) {
|
|
4168
|
-
return /* @__PURE__ */ (0,
|
|
3425
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
4169
3426
|
"div",
|
|
4170
3427
|
{
|
|
4171
3428
|
role: "group",
|
|
4172
3429
|
className: cn("flex items-center gap-1 p-1 bg-muted rounded-md", className),
|
|
4173
3430
|
...props,
|
|
4174
|
-
children: /* @__PURE__ */ (0,
|
|
3431
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ToggleGroupContext.Provider, { value: { value, onValueChange }, children })
|
|
4175
3432
|
}
|
|
4176
3433
|
);
|
|
4177
3434
|
}
|
|
@@ -4181,8 +3438,8 @@ function ToggleGroupItem({
|
|
|
4181
3438
|
children,
|
|
4182
3439
|
...props
|
|
4183
3440
|
}) {
|
|
4184
|
-
const { value: groupValue, onValueChange } =
|
|
4185
|
-
return /* @__PURE__ */ (0,
|
|
3441
|
+
const { value: groupValue, onValueChange } = React.useContext(ToggleGroupContext);
|
|
3442
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
4186
3443
|
Toggle,
|
|
4187
3444
|
{
|
|
4188
3445
|
pressed: groupValue === value,
|
|
@@ -4202,7 +3459,7 @@ function ToggleGroupItem({
|
|
|
4202
3459
|
}
|
|
4203
3460
|
|
|
4204
3461
|
// src/OhhwellsBridge.tsx
|
|
4205
|
-
var
|
|
3462
|
+
var import_react_dom = require("react-dom");
|
|
4206
3463
|
var import_navigation = require("next/navigation");
|
|
4207
3464
|
|
|
4208
3465
|
// src/lib/session-search.ts
|
|
@@ -4496,9 +3753,9 @@ function calcPopoverPos(rect, parentScroll, approxW = 483, approxH = 320) {
|
|
|
4496
3753
|
}
|
|
4497
3754
|
|
|
4498
3755
|
// src/ui/button.tsx
|
|
4499
|
-
var
|
|
4500
|
-
var
|
|
4501
|
-
var
|
|
3756
|
+
var React2 = __toESM(require("react"), 1);
|
|
3757
|
+
var import_radix_ui2 = require("radix-ui");
|
|
3758
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
4502
3759
|
var buttonVariants = cva(
|
|
4503
3760
|
"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",
|
|
4504
3761
|
{
|
|
@@ -4519,10 +3776,10 @@ var buttonVariants = cva(
|
|
|
4519
3776
|
}
|
|
4520
3777
|
}
|
|
4521
3778
|
);
|
|
4522
|
-
var Button =
|
|
3779
|
+
var Button = React2.forwardRef(
|
|
4523
3780
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
4524
|
-
const Comp = asChild ?
|
|
4525
|
-
return /* @__PURE__ */ (0,
|
|
3781
|
+
const Comp = asChild ? import_radix_ui2.Slot.Root : "button";
|
|
3782
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
4526
3783
|
Comp,
|
|
4527
3784
|
{
|
|
4528
3785
|
ref,
|
|
@@ -4536,75 +3793,75 @@ var Button = React3.forwardRef(
|
|
|
4536
3793
|
Button.displayName = "Button";
|
|
4537
3794
|
|
|
4538
3795
|
// src/ui/icons.tsx
|
|
4539
|
-
var
|
|
3796
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
4540
3797
|
function IconX({ className, ...props }) {
|
|
4541
|
-
return /* @__PURE__ */ (0,
|
|
4542
|
-
/* @__PURE__ */ (0,
|
|
4543
|
-
/* @__PURE__ */ (0,
|
|
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" })
|
|
4544
3801
|
] });
|
|
4545
3802
|
}
|
|
4546
3803
|
function IconChevronDown({ className, ...props }) {
|
|
4547
|
-
return /* @__PURE__ */ (0,
|
|
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" }) });
|
|
4548
3805
|
}
|
|
4549
3806
|
function IconFile({ className, ...props }) {
|
|
4550
|
-
return /* @__PURE__ */ (0,
|
|
4551
|
-
/* @__PURE__ */ (0,
|
|
4552
|
-
/* @__PURE__ */ (0,
|
|
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" })
|
|
4553
3810
|
] });
|
|
4554
3811
|
}
|
|
4555
3812
|
function IconInfo({ className, ...props }) {
|
|
4556
|
-
return /* @__PURE__ */ (0,
|
|
4557
|
-
/* @__PURE__ */ (0,
|
|
4558
|
-
/* @__PURE__ */ (0,
|
|
4559
|
-
/* @__PURE__ */ (0,
|
|
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" })
|
|
4560
3817
|
] });
|
|
4561
3818
|
}
|
|
4562
3819
|
function IconArrowRight({ className, ...props }) {
|
|
4563
|
-
return /* @__PURE__ */ (0,
|
|
4564
|
-
/* @__PURE__ */ (0,
|
|
4565
|
-
/* @__PURE__ */ (0,
|
|
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" })
|
|
4566
3823
|
] });
|
|
4567
3824
|
}
|
|
4568
3825
|
function IconSection({ className, ...props }) {
|
|
4569
|
-
return /* @__PURE__ */ (0,
|
|
4570
|
-
/* @__PURE__ */ (0,
|
|
4571
|
-
/* @__PURE__ */ (0,
|
|
4572
|
-
/* @__PURE__ */ (0,
|
|
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" })
|
|
4573
3830
|
] });
|
|
4574
3831
|
}
|
|
4575
3832
|
|
|
4576
3833
|
// src/ui/link-modal/DestinationBreadcrumb.tsx
|
|
4577
|
-
var
|
|
3834
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
4578
3835
|
function DestinationBreadcrumb({ pageTitle, sectionLabel }) {
|
|
4579
|
-
return /* @__PURE__ */ (0,
|
|
4580
|
-
/* @__PURE__ */ (0,
|
|
4581
|
-
/* @__PURE__ */ (0,
|
|
4582
|
-
/* @__PURE__ */ (0,
|
|
4583
|
-
/* @__PURE__ */ (0,
|
|
4584
|
-
/* @__PURE__ */ (0,
|
|
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 })
|
|
4585
3842
|
] }),
|
|
4586
|
-
/* @__PURE__ */ (0,
|
|
4587
|
-
/* @__PURE__ */ (0,
|
|
4588
|
-
/* @__PURE__ */ (0,
|
|
4589
|
-
/* @__PURE__ */ (0,
|
|
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 })
|
|
4590
3847
|
] })
|
|
4591
3848
|
] })
|
|
4592
3849
|
] });
|
|
4593
3850
|
}
|
|
4594
3851
|
|
|
4595
3852
|
// src/ui/link-modal/SectionTreeItem.tsx
|
|
4596
|
-
var
|
|
3853
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
4597
3854
|
function SectionTreeItem({ section, onSelect, selected }) {
|
|
4598
3855
|
const interactive = Boolean(onSelect);
|
|
4599
|
-
return /* @__PURE__ */ (0,
|
|
4600
|
-
/* @__PURE__ */ (0,
|
|
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)(
|
|
4601
3858
|
"div",
|
|
4602
3859
|
{
|
|
4603
3860
|
className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
|
|
4604
3861
|
"aria-hidden": true
|
|
4605
3862
|
}
|
|
4606
3863
|
),
|
|
4607
|
-
/* @__PURE__ */ (0,
|
|
3864
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
4608
3865
|
"div",
|
|
4609
3866
|
{
|
|
4610
3867
|
role: interactive ? "button" : void 0,
|
|
@@ -4622,8 +3879,8 @@ function SectionTreeItem({ section, onSelect, selected }) {
|
|
|
4622
3879
|
interactive && selected && "border-primary"
|
|
4623
3880
|
),
|
|
4624
3881
|
children: [
|
|
4625
|
-
/* @__PURE__ */ (0,
|
|
4626
|
-
/* @__PURE__ */ (0,
|
|
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 })
|
|
4627
3884
|
]
|
|
4628
3885
|
}
|
|
4629
3886
|
)
|
|
@@ -4631,23 +3888,23 @@ function SectionTreeItem({ section, onSelect, selected }) {
|
|
|
4631
3888
|
}
|
|
4632
3889
|
function SectionPickerList({ sections, onSelect }) {
|
|
4633
3890
|
if (sections.length === 0) {
|
|
4634
|
-
return /* @__PURE__ */ (0,
|
|
3891
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
|
|
4635
3892
|
}
|
|
4636
|
-
return /* @__PURE__ */ (0,
|
|
4637
|
-
/* @__PURE__ */ (0,
|
|
4638
|
-
sections.map((section) => /* @__PURE__ */ (0,
|
|
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))
|
|
4639
3896
|
] });
|
|
4640
3897
|
}
|
|
4641
3898
|
|
|
4642
3899
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
4643
|
-
var
|
|
3900
|
+
var import_react = require("react");
|
|
4644
3901
|
|
|
4645
3902
|
// src/ui/input.tsx
|
|
4646
|
-
var
|
|
4647
|
-
var
|
|
4648
|
-
var Input =
|
|
3903
|
+
var React3 = __toESM(require("react"), 1);
|
|
3904
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
3905
|
+
var Input = React3.forwardRef(
|
|
4649
3906
|
({ className, type, ...props }, ref) => {
|
|
4650
|
-
return /* @__PURE__ */ (0,
|
|
3907
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4651
3908
|
"input",
|
|
4652
3909
|
{
|
|
4653
3910
|
type,
|
|
@@ -4665,11 +3922,11 @@ var Input = React4.forwardRef(
|
|
|
4665
3922
|
Input.displayName = "Input";
|
|
4666
3923
|
|
|
4667
3924
|
// src/ui/label.tsx
|
|
4668
|
-
var
|
|
4669
|
-
var
|
|
3925
|
+
var import_radix_ui3 = require("radix-ui");
|
|
3926
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
4670
3927
|
function Label({ className, ...props }) {
|
|
4671
|
-
return /* @__PURE__ */ (0,
|
|
4672
|
-
|
|
3928
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3929
|
+
import_radix_ui3.Label.Root,
|
|
4673
3930
|
{
|
|
4674
3931
|
"data-slot": "label",
|
|
4675
3932
|
className: cn("text-sm font-medium leading-5 text-foreground", className),
|
|
@@ -4679,13 +3936,13 @@ function Label({ className, ...props }) {
|
|
|
4679
3936
|
}
|
|
4680
3937
|
|
|
4681
3938
|
// src/ui/popover.tsx
|
|
4682
|
-
var
|
|
4683
|
-
var
|
|
3939
|
+
var import_radix_ui4 = require("radix-ui");
|
|
3940
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
4684
3941
|
function Popover({ ...props }) {
|
|
4685
|
-
return /* @__PURE__ */ (0,
|
|
3942
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_radix_ui4.Popover.Root, { "data-slot": "popover", ...props });
|
|
4686
3943
|
}
|
|
4687
3944
|
function PopoverTrigger({ ...props }) {
|
|
4688
|
-
return /* @__PURE__ */ (0,
|
|
3945
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_radix_ui4.Popover.Trigger, { "data-slot": "popover-trigger", ...props });
|
|
4689
3946
|
}
|
|
4690
3947
|
function PopoverContent({
|
|
4691
3948
|
className,
|
|
@@ -4693,8 +3950,8 @@ function PopoverContent({
|
|
|
4693
3950
|
sideOffset = 6,
|
|
4694
3951
|
...props
|
|
4695
3952
|
}) {
|
|
4696
|
-
return /* @__PURE__ */ (0,
|
|
4697
|
-
|
|
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,
|
|
4698
3955
|
{
|
|
4699
3956
|
"data-slot": "popover-content",
|
|
4700
3957
|
align,
|
|
@@ -4709,9 +3966,9 @@ function PopoverContent({
|
|
|
4709
3966
|
}
|
|
4710
3967
|
|
|
4711
3968
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
4712
|
-
var
|
|
3969
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
4713
3970
|
function FieldChevron({ onClick }) {
|
|
4714
|
-
return /* @__PURE__ */ (0,
|
|
3971
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4715
3972
|
"button",
|
|
4716
3973
|
{
|
|
4717
3974
|
type: "button",
|
|
@@ -4719,7 +3976,7 @@ function FieldChevron({ onClick }) {
|
|
|
4719
3976
|
onClick,
|
|
4720
3977
|
"aria-label": "Open page list",
|
|
4721
3978
|
tabIndex: -1,
|
|
4722
|
-
children: /* @__PURE__ */ (0,
|
|
3979
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IconChevronDown, {})
|
|
4723
3980
|
}
|
|
4724
3981
|
);
|
|
4725
3982
|
}
|
|
@@ -4735,9 +3992,9 @@ function UrlOrPageInput({
|
|
|
4735
3992
|
readOnly = false,
|
|
4736
3993
|
urlError
|
|
4737
3994
|
}) {
|
|
4738
|
-
const inputId = (0,
|
|
4739
|
-
const inputRef = (0,
|
|
4740
|
-
const [isFocused, setIsFocused] = (0,
|
|
3995
|
+
const inputId = (0, import_react.useId)();
|
|
3996
|
+
const inputRef = (0, import_react.useRef)(null);
|
|
3997
|
+
const [isFocused, setIsFocused] = (0, import_react.useState)(false);
|
|
4741
3998
|
const openDropdown = () => {
|
|
4742
3999
|
if (readOnly || filteredPages.length === 0) return;
|
|
4743
4000
|
onDropdownOpenChange(true);
|
|
@@ -4758,12 +4015,12 @@ function UrlOrPageInput({
|
|
|
4758
4015
|
"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]",
|
|
4759
4016
|
urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
|
|
4760
4017
|
);
|
|
4761
|
-
return /* @__PURE__ */ (0,
|
|
4762
|
-
/* @__PURE__ */ (0,
|
|
4763
|
-
/* @__PURE__ */ (0,
|
|
4764
|
-
/* @__PURE__ */ (0,
|
|
4765
|
-
selectedPage ? /* @__PURE__ */ (0,
|
|
4766
|
-
readOnly ? /* @__PURE__ */ (0,
|
|
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)(
|
|
4767
4024
|
Input,
|
|
4768
4025
|
{
|
|
4769
4026
|
ref: inputRef,
|
|
@@ -4782,7 +4039,7 @@ function UrlOrPageInput({
|
|
|
4782
4039
|
)
|
|
4783
4040
|
}
|
|
4784
4041
|
),
|
|
4785
|
-
selectedPage && !readOnly ? /* @__PURE__ */ (0,
|
|
4042
|
+
selectedPage && !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4786
4043
|
"button",
|
|
4787
4044
|
{
|
|
4788
4045
|
type: "button",
|
|
@@ -4790,31 +4047,31 @@ function UrlOrPageInput({
|
|
|
4790
4047
|
onMouseDown: clearSelection,
|
|
4791
4048
|
"aria-label": "Clear selected page",
|
|
4792
4049
|
tabIndex: -1,
|
|
4793
|
-
children: /* @__PURE__ */ (0,
|
|
4050
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IconX, { "aria-hidden": true })
|
|
4794
4051
|
}
|
|
4795
4052
|
) : null,
|
|
4796
|
-
!readOnly ? /* @__PURE__ */ (0,
|
|
4053
|
+
!readOnly ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
|
|
4797
4054
|
] }) }),
|
|
4798
|
-
filteredPages.length > 0 && /* @__PURE__ */ (0,
|
|
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)(
|
|
4799
4056
|
"button",
|
|
4800
4057
|
{
|
|
4801
4058
|
type: "button",
|
|
4802
4059
|
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",
|
|
4803
4060
|
onClick: () => onPageSelect(page),
|
|
4804
4061
|
children: [
|
|
4805
|
-
/* @__PURE__ */ (0,
|
|
4806
|
-
/* @__PURE__ */ (0,
|
|
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 })
|
|
4807
4064
|
]
|
|
4808
4065
|
},
|
|
4809
4066
|
page.path
|
|
4810
4067
|
)) })
|
|
4811
4068
|
] }),
|
|
4812
|
-
urlError ? /* @__PURE__ */ (0,
|
|
4069
|
+
urlError ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
|
|
4813
4070
|
] });
|
|
4814
4071
|
}
|
|
4815
4072
|
|
|
4816
4073
|
// src/ui/link-modal/useLinkModalState.ts
|
|
4817
|
-
var
|
|
4074
|
+
var import_react2 = require("react");
|
|
4818
4075
|
function useLinkModalState({
|
|
4819
4076
|
open,
|
|
4820
4077
|
mode,
|
|
@@ -4826,17 +4083,17 @@ function useLinkModalState({
|
|
|
4826
4083
|
onClose,
|
|
4827
4084
|
onSubmit
|
|
4828
4085
|
}) {
|
|
4829
|
-
const availablePages = (0,
|
|
4086
|
+
const availablePages = (0, import_react2.useMemo)(
|
|
4830
4087
|
() => mode === "create" ? filterAvailablePages(pages, existingTargets) : pages,
|
|
4831
4088
|
[mode, pages, existingTargets]
|
|
4832
4089
|
);
|
|
4833
|
-
const [searchValue, setSearchValue] = (0,
|
|
4834
|
-
const [selectedPage, setSelectedPage] = (0,
|
|
4835
|
-
const [selectedSection, setSelectedSection] = (0,
|
|
4836
|
-
const [step, setStep] = (0,
|
|
4837
|
-
const [dropdownOpen, setDropdownOpen] = (0,
|
|
4838
|
-
const [urlError, setUrlError] = (0,
|
|
4839
|
-
const reset = (0,
|
|
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)(() => {
|
|
4840
4097
|
setSearchValue("");
|
|
4841
4098
|
setSelectedPage(null);
|
|
4842
4099
|
setSelectedSection(null);
|
|
@@ -4844,7 +4101,7 @@ function useLinkModalState({
|
|
|
4844
4101
|
setDropdownOpen(false);
|
|
4845
4102
|
setUrlError("");
|
|
4846
4103
|
}, []);
|
|
4847
|
-
(0,
|
|
4104
|
+
(0, import_react2.useEffect)(() => {
|
|
4848
4105
|
if (!open) return;
|
|
4849
4106
|
if (mode === "edit" && initialTarget) {
|
|
4850
4107
|
const { pageRoute } = parseTarget(initialTarget);
|
|
@@ -4860,11 +4117,11 @@ function useLinkModalState({
|
|
|
4860
4117
|
setDropdownOpen(false);
|
|
4861
4118
|
setUrlError("");
|
|
4862
4119
|
}, [open, mode, initialTarget, pages, sectionsByPath, reset]);
|
|
4863
|
-
const filteredPages = (0,
|
|
4120
|
+
const filteredPages = (0, import_react2.useMemo)(() => {
|
|
4864
4121
|
if (!searchValue.trim()) return availablePages;
|
|
4865
4122
|
return availablePages.filter((p) => p.title.toLowerCase().startsWith(searchValue.toLowerCase()));
|
|
4866
4123
|
}, [availablePages, searchValue]);
|
|
4867
|
-
const activeSections = (0,
|
|
4124
|
+
const activeSections = (0, import_react2.useMemo)(() => {
|
|
4868
4125
|
if (!selectedPage) return [];
|
|
4869
4126
|
return getSectionsForPath(sectionsByPath, selectedPage.path);
|
|
4870
4127
|
}, [selectedPage, sectionsByPath]);
|
|
@@ -4910,7 +4167,7 @@ function useLinkModalState({
|
|
|
4910
4167
|
reset();
|
|
4911
4168
|
onClose();
|
|
4912
4169
|
};
|
|
4913
|
-
const isValid = (0,
|
|
4170
|
+
const isValid = (0, import_react2.useMemo)(() => {
|
|
4914
4171
|
if (urlError) return false;
|
|
4915
4172
|
if (showBreadcrumb) return true;
|
|
4916
4173
|
if (selectedPage) return true;
|
|
@@ -4977,7 +4234,7 @@ function useLinkModalState({
|
|
|
4977
4234
|
}
|
|
4978
4235
|
|
|
4979
4236
|
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
4980
|
-
var
|
|
4237
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
4981
4238
|
function LinkEditorPanel({
|
|
4982
4239
|
open = true,
|
|
4983
4240
|
mode = "create",
|
|
@@ -5001,26 +4258,26 @@ function LinkEditorPanel({
|
|
|
5001
4258
|
onSubmit
|
|
5002
4259
|
});
|
|
5003
4260
|
const isCancel = state.secondaryLabel === "Cancel";
|
|
5004
|
-
return /* @__PURE__ */ (0,
|
|
5005
|
-
/* @__PURE__ */ (0,
|
|
4261
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
4262
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
5006
4263
|
"button",
|
|
5007
4264
|
{
|
|
5008
4265
|
type: "button",
|
|
5009
4266
|
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
5010
4267
|
onClick: state.handleClose,
|
|
5011
4268
|
"aria-label": "Close",
|
|
5012
|
-
children: /* @__PURE__ */ (0,
|
|
4269
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconX, { "aria-hidden": true })
|
|
5013
4270
|
}
|
|
5014
4271
|
),
|
|
5015
|
-
/* @__PURE__ */ (0,
|
|
5016
|
-
/* @__PURE__ */ (0,
|
|
5017
|
-
state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0,
|
|
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)(
|
|
5018
4275
|
DestinationBreadcrumb,
|
|
5019
4276
|
{
|
|
5020
4277
|
pageTitle: state.selectedPage.title,
|
|
5021
4278
|
sectionLabel: state.selectedSection.label
|
|
5022
4279
|
}
|
|
5023
|
-
) : /* @__PURE__ */ (0,
|
|
4280
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
5024
4281
|
UrlOrPageInput,
|
|
5025
4282
|
{
|
|
5026
4283
|
value: state.searchValue,
|
|
@@ -5033,18 +4290,18 @@ function LinkEditorPanel({
|
|
|
5033
4290
|
urlError: state.urlError
|
|
5034
4291
|
}
|
|
5035
4292
|
),
|
|
5036
|
-
state.showChooseSection ? /* @__PURE__ */ (0,
|
|
5037
|
-
/* @__PURE__ */ (0,
|
|
5038
|
-
/* @__PURE__ */ (0,
|
|
5039
|
-
/* @__PURE__ */ (0,
|
|
5040
|
-
/* @__PURE__ */ (0,
|
|
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." })
|
|
5041
4298
|
] })
|
|
5042
4299
|
] }) : null,
|
|
5043
|
-
state.showSectionPicker ? /* @__PURE__ */ (0,
|
|
5044
|
-
state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0,
|
|
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
|
|
5045
4302
|
] }),
|
|
5046
|
-
/* @__PURE__ */ (0,
|
|
5047
|
-
/* @__PURE__ */ (0,
|
|
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)(
|
|
5048
4305
|
Button,
|
|
5049
4306
|
{
|
|
5050
4307
|
type: "button",
|
|
@@ -5059,7 +4316,7 @@ function LinkEditorPanel({
|
|
|
5059
4316
|
children: state.secondaryLabel
|
|
5060
4317
|
}
|
|
5061
4318
|
),
|
|
5062
|
-
/* @__PURE__ */ (0,
|
|
4319
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
5063
4320
|
Button,
|
|
5064
4321
|
{
|
|
5065
4322
|
type: "button",
|
|
@@ -5078,7 +4335,7 @@ function LinkEditorPanel({
|
|
|
5078
4335
|
}
|
|
5079
4336
|
|
|
5080
4337
|
// src/ui/link-modal/LinkPopover.tsx
|
|
5081
|
-
var
|
|
4338
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
5082
4339
|
function LinkPopover({
|
|
5083
4340
|
rect,
|
|
5084
4341
|
parentScroll,
|
|
@@ -5086,7 +4343,7 @@ function LinkPopover({
|
|
|
5086
4343
|
...editorProps
|
|
5087
4344
|
}) {
|
|
5088
4345
|
const { top, left, transform } = calcPopoverPos(rect, parentScroll);
|
|
5089
|
-
return /* @__PURE__ */ (0,
|
|
4346
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5090
4347
|
"div",
|
|
5091
4348
|
{
|
|
5092
4349
|
ref: panelRef,
|
|
@@ -5099,7 +4356,7 @@ function LinkPopover({
|
|
|
5099
4356
|
),
|
|
5100
4357
|
style: { top, left, transform },
|
|
5101
4358
|
onMouseDown: (e) => e.stopPropagation(),
|
|
5102
|
-
children: /* @__PURE__ */ (0,
|
|
4359
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(LinkEditorPanel, { ...editorProps, open: true })
|
|
5103
4360
|
}
|
|
5104
4361
|
);
|
|
5105
4362
|
}
|
|
@@ -5162,30 +4419,8 @@ function shouldUseDevFixtures() {
|
|
|
5162
4419
|
return new URLSearchParams(q).get("ohw-fixtures") === "1";
|
|
5163
4420
|
}
|
|
5164
4421
|
|
|
5165
|
-
// src/ui/badge.tsx
|
|
5166
|
-
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
5167
|
-
var badgeVariants = cva(
|
|
5168
|
-
"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",
|
|
5169
|
-
{
|
|
5170
|
-
variants: {
|
|
5171
|
-
variant: {
|
|
5172
|
-
default: "border-transparent bg-primary text-primary-foreground",
|
|
5173
|
-
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
5174
|
-
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
5175
|
-
outline: "text-foreground"
|
|
5176
|
-
}
|
|
5177
|
-
},
|
|
5178
|
-
defaultVariants: {
|
|
5179
|
-
variant: "default"
|
|
5180
|
-
}
|
|
5181
|
-
}
|
|
5182
|
-
);
|
|
5183
|
-
function Badge({ className, variant, ...props }) {
|
|
5184
|
-
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
5185
|
-
}
|
|
5186
|
-
|
|
5187
4422
|
// src/OhhwellsBridge.tsx
|
|
5188
|
-
var
|
|
4423
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
5189
4424
|
var PRIMARY = "#0885FE";
|
|
5190
4425
|
var IMAGE_FADE_MS = 300;
|
|
5191
4426
|
function runOpacityFade(el, onDone) {
|
|
@@ -5236,163 +4471,6 @@ function fadeInBgImage(el, url, onReady) {
|
|
|
5236
4471
|
if (!prevPos || prevPos === "static") el.style.position = prevPos;
|
|
5237
4472
|
});
|
|
5238
4473
|
}
|
|
5239
|
-
function getSectionsTracker() {
|
|
5240
|
-
let el = document.querySelector("[data-ohw-sections-tracker]");
|
|
5241
|
-
if (!el) {
|
|
5242
|
-
el = document.createElement("div");
|
|
5243
|
-
el.setAttribute("data-ohw-sections-tracker", "");
|
|
5244
|
-
el.style.display = "none";
|
|
5245
|
-
document.body.appendChild(el);
|
|
5246
|
-
}
|
|
5247
|
-
return el;
|
|
5248
|
-
}
|
|
5249
|
-
function updateSectionScheduleId(insertAfter, scheduleId) {
|
|
5250
|
-
const tracker = getSectionsTracker();
|
|
5251
|
-
let sections = [];
|
|
5252
|
-
try {
|
|
5253
|
-
sections = JSON.parse(tracker.textContent || "[]");
|
|
5254
|
-
} catch {
|
|
5255
|
-
}
|
|
5256
|
-
const currentPath = window.location.pathname;
|
|
5257
|
-
const updated = sections.map((s) => {
|
|
5258
|
-
if (s.type !== "scheduling" || s.insertAfter !== insertAfter) return s;
|
|
5259
|
-
if (s.pagePath && s.pagePath !== currentPath) return s;
|
|
5260
|
-
return { ...s, scheduleId };
|
|
5261
|
-
});
|
|
5262
|
-
tracker.textContent = JSON.stringify(updated);
|
|
5263
|
-
return tracker.textContent ?? "[]";
|
|
5264
|
-
}
|
|
5265
|
-
function schedulingSectionId(insertAfter) {
|
|
5266
|
-
return `scheduling-${insertAfter}`;
|
|
5267
|
-
}
|
|
5268
|
-
var INSERT_BEFORE_MARKER = ":before:";
|
|
5269
|
-
function parseSchedulingInsertAfter(insertAfter) {
|
|
5270
|
-
const idx = insertAfter.indexOf(INSERT_BEFORE_MARKER);
|
|
5271
|
-
if (idx < 0) return { anchor: insertAfter, insertBefore: null };
|
|
5272
|
-
return {
|
|
5273
|
-
anchor: insertAfter.slice(0, idx),
|
|
5274
|
-
insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
|
|
5275
|
-
};
|
|
5276
|
-
}
|
|
5277
|
-
function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
|
|
5278
|
-
const parsed = parseSchedulingInsertAfter(insertAfter);
|
|
5279
|
-
const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
|
|
5280
|
-
const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
|
|
5281
|
-
return { effectiveInsertAfter, insertBefore };
|
|
5282
|
-
}
|
|
5283
|
-
function getSchedulingMountPoint(insertAfter) {
|
|
5284
|
-
const { anchor } = parseSchedulingInsertAfter(insertAfter);
|
|
5285
|
-
let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
|
|
5286
|
-
if (!anchorEl && anchor === "scheduling") {
|
|
5287
|
-
const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
|
|
5288
|
-
anchorEl = widgets.at(-1) ?? null;
|
|
5289
|
-
}
|
|
5290
|
-
if (!anchorEl) return null;
|
|
5291
|
-
return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
5292
|
-
}
|
|
5293
|
-
function schedulingMountDepth(insertAfter) {
|
|
5294
|
-
if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
|
|
5295
|
-
return insertAfter.split(INSERT_BEFORE_MARKER).length - 1;
|
|
5296
|
-
}
|
|
5297
|
-
function getPageSchedulingEntries(raw) {
|
|
5298
|
-
if (!raw) return [];
|
|
5299
|
-
try {
|
|
5300
|
-
const entries = JSON.parse(raw);
|
|
5301
|
-
const currentPath = window.location.pathname;
|
|
5302
|
-
return entries.filter((e) => e.type === "scheduling" && (!e.pagePath || e.pagePath === currentPath));
|
|
5303
|
-
} catch {
|
|
5304
|
-
return [];
|
|
5305
|
-
}
|
|
5306
|
-
}
|
|
5307
|
-
function isSchedulingWidgetMissing(entry) {
|
|
5308
|
-
const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
|
|
5309
|
-
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
|
|
5310
|
-
}
|
|
5311
|
-
function hasMissingSchedulingWidgets(entries) {
|
|
5312
|
-
return entries.some(isSchedulingWidgetMissing);
|
|
5313
|
-
}
|
|
5314
|
-
function retryMissingSchedulingMounts(entries, notifyOnConnect = false) {
|
|
5315
|
-
if (!hasMissingSchedulingWidgets(entries)) return;
|
|
5316
|
-
mountSchedulingEntries(entries, notifyOnConnect);
|
|
5317
|
-
}
|
|
5318
|
-
function initSectionsFromContent(content, removeExisting = false) {
|
|
5319
|
-
const raw = content["__ohw_sections"];
|
|
5320
|
-
if (!raw) return;
|
|
5321
|
-
try {
|
|
5322
|
-
if (removeExisting) {
|
|
5323
|
-
document.querySelectorAll('[data-ohw-section-container="scheduling"]').forEach((el) => el.remove());
|
|
5324
|
-
}
|
|
5325
|
-
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
5326
|
-
if (inEditor) getSectionsTracker().textContent = raw;
|
|
5327
|
-
const pageEntries = getPageSchedulingEntries(raw);
|
|
5328
|
-
mountSchedulingEntries(pageEntries, false);
|
|
5329
|
-
requestAnimationFrame(() => retryMissingSchedulingMounts(pageEntries, false));
|
|
5330
|
-
setTimeout(() => retryMissingSchedulingMounts(pageEntries, false), 250);
|
|
5331
|
-
} catch {
|
|
5332
|
-
}
|
|
5333
|
-
}
|
|
5334
|
-
function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
|
|
5335
|
-
const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
|
|
5336
|
-
const sectionId = schedulingSectionId(effectiveInsertAfter);
|
|
5337
|
-
if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
|
|
5338
|
-
const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
|
|
5339
|
-
if (!mountPoint) return false;
|
|
5340
|
-
const container = document.createElement("div");
|
|
5341
|
-
container.dataset.ohwSectionContainer = "scheduling";
|
|
5342
|
-
if (insertBefore) {
|
|
5343
|
-
const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
|
|
5344
|
-
const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
|
|
5345
|
-
if (!beforePoint) return false;
|
|
5346
|
-
beforePoint.insertAdjacentElement("beforebegin", container);
|
|
5347
|
-
} else {
|
|
5348
|
-
let tail = mountPoint;
|
|
5349
|
-
while (tail.nextElementSibling?.dataset.ohwSectionContainer === "scheduling") {
|
|
5350
|
-
tail = tail.nextElementSibling;
|
|
5351
|
-
}
|
|
5352
|
-
tail.insertAdjacentElement("afterend", container);
|
|
5353
|
-
}
|
|
5354
|
-
const root = (0, import_client.createRoot)(container);
|
|
5355
|
-
(0, import_react_dom.flushSync)(() => {
|
|
5356
|
-
root.render(
|
|
5357
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5358
|
-
SchedulingWidget,
|
|
5359
|
-
{
|
|
5360
|
-
notifyOnConnect,
|
|
5361
|
-
initialScheduleId: scheduleId,
|
|
5362
|
-
insertAfter: effectiveInsertAfter
|
|
5363
|
-
}
|
|
5364
|
-
)
|
|
5365
|
-
);
|
|
5366
|
-
});
|
|
5367
|
-
const tracker = getSectionsTracker();
|
|
5368
|
-
let sections = [];
|
|
5369
|
-
try {
|
|
5370
|
-
sections = JSON.parse(tracker.textContent || "[]");
|
|
5371
|
-
} catch {
|
|
5372
|
-
}
|
|
5373
|
-
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
5374
|
-
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
|
|
5375
|
-
sections.push({
|
|
5376
|
-
type: "scheduling",
|
|
5377
|
-
insertAfter: effectiveInsertAfter,
|
|
5378
|
-
pagePath: window.location.pathname,
|
|
5379
|
-
...scheduleId ? { scheduleId } : {}
|
|
5380
|
-
});
|
|
5381
|
-
tracker.textContent = JSON.stringify(sections);
|
|
5382
|
-
}
|
|
5383
|
-
return true;
|
|
5384
|
-
}
|
|
5385
|
-
function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
5386
|
-
const pending = entries.filter((e) => e.type === "scheduling").sort((a, b) => schedulingMountDepth(a.insertAfter) - schedulingMountDepth(b.insertAfter));
|
|
5387
|
-
for (let attempt = 0; attempt < pending.length + 1 && pending.length > 0; attempt++) {
|
|
5388
|
-
for (let i = pending.length - 1; i >= 0; i--) {
|
|
5389
|
-
const { insertAfter, scheduleId } = pending[i];
|
|
5390
|
-
if (mountSchedulingWidget(insertAfter, notifyOnConnect, scheduleId)) {
|
|
5391
|
-
pending.splice(i, 1);
|
|
5392
|
-
}
|
|
5393
|
-
}
|
|
5394
|
-
}
|
|
5395
|
-
}
|
|
5396
4474
|
function getLinkHref(el) {
|
|
5397
4475
|
const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
|
|
5398
4476
|
return anchor?.getAttribute("href") ?? "";
|
|
@@ -5592,7 +4670,7 @@ var TOOLBAR_GROUPS = [
|
|
|
5592
4670
|
];
|
|
5593
4671
|
function GlowFrame({ rect, elRef }) {
|
|
5594
4672
|
const GAP = 6;
|
|
5595
|
-
return /* @__PURE__ */ (0,
|
|
4673
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
5596
4674
|
"div",
|
|
5597
4675
|
{
|
|
5598
4676
|
ref: elRef,
|
|
@@ -5645,7 +4723,7 @@ function FloatingToolbar({
|
|
|
5645
4723
|
onEditLink
|
|
5646
4724
|
}) {
|
|
5647
4725
|
const { top, left, transform } = calcToolbarPos(rect, parentScroll);
|
|
5648
|
-
return /* @__PURE__ */ (0,
|
|
4726
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
5649
4727
|
"div",
|
|
5650
4728
|
{
|
|
5651
4729
|
ref: elRef,
|
|
@@ -5670,11 +4748,11 @@ function FloatingToolbar({
|
|
|
5670
4748
|
},
|
|
5671
4749
|
onMouseDown: (e) => e.stopPropagation(),
|
|
5672
4750
|
children: [
|
|
5673
|
-
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0,
|
|
5674
|
-
gi > 0 && /* @__PURE__ */ (0,
|
|
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 } }),
|
|
5675
4753
|
btns.map((btn) => {
|
|
5676
4754
|
const isActive = activeCommands.has(btn.cmd);
|
|
5677
|
-
return /* @__PURE__ */ (0,
|
|
4755
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
5678
4756
|
"button",
|
|
5679
4757
|
{
|
|
5680
4758
|
title: btn.title,
|
|
@@ -5700,7 +4778,7 @@ function FloatingToolbar({
|
|
|
5700
4778
|
flexShrink: 0,
|
|
5701
4779
|
padding: 6
|
|
5702
4780
|
},
|
|
5703
|
-
children: /* @__PURE__ */ (0,
|
|
4781
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
5704
4782
|
"svg",
|
|
5705
4783
|
{
|
|
5706
4784
|
width: "16",
|
|
@@ -5720,7 +4798,7 @@ function FloatingToolbar({
|
|
|
5720
4798
|
);
|
|
5721
4799
|
})
|
|
5722
4800
|
] }, gi)),
|
|
5723
|
-
showEditLink ? /* @__PURE__ */ (0,
|
|
4801
|
+
showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
5724
4802
|
"button",
|
|
5725
4803
|
{
|
|
5726
4804
|
type: "button",
|
|
@@ -5752,9 +4830,9 @@ function FloatingToolbar({
|
|
|
5752
4830
|
flexShrink: 0,
|
|
5753
4831
|
padding: 6
|
|
5754
4832
|
},
|
|
5755
|
-
children: /* @__PURE__ */ (0,
|
|
5756
|
-
/* @__PURE__ */ (0,
|
|
5757
|
-
/* @__PURE__ */ (0,
|
|
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" })
|
|
5758
4836
|
] })
|
|
5759
4837
|
}
|
|
5760
4838
|
) : null
|
|
@@ -5772,7 +4850,7 @@ function StateToggle({
|
|
|
5772
4850
|
states,
|
|
5773
4851
|
onStateChange
|
|
5774
4852
|
}) {
|
|
5775
|
-
return /* @__PURE__ */ (0,
|
|
4853
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
5776
4854
|
ToggleGroup,
|
|
5777
4855
|
{
|
|
5778
4856
|
"data-ohw-state-toggle": "",
|
|
@@ -5786,35 +4864,18 @@ function StateToggle({
|
|
|
5786
4864
|
left: rect.right - 8,
|
|
5787
4865
|
transform: "translateX(-100%)"
|
|
5788
4866
|
},
|
|
5789
|
-
children: states.map((state) => /* @__PURE__ */ (0,
|
|
4867
|
+
children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
5790
4868
|
}
|
|
5791
4869
|
);
|
|
5792
4870
|
}
|
|
5793
4871
|
var contentCache = /* @__PURE__ */ new Map();
|
|
5794
|
-
function resolveSubdomain(subdomainFromQuery) {
|
|
5795
|
-
if (subdomainFromQuery) return subdomainFromQuery;
|
|
5796
|
-
if (typeof window !== "undefined") {
|
|
5797
|
-
const parts = window.location.hostname.split(".");
|
|
5798
|
-
if (parts.length >= 3 && parts[0] !== "www") return parts[0];
|
|
5799
|
-
}
|
|
5800
|
-
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL;
|
|
5801
|
-
if (siteUrl) {
|
|
5802
|
-
try {
|
|
5803
|
-
const host = new URL(siteUrl).hostname;
|
|
5804
|
-
const siteParts = host.split(".");
|
|
5805
|
-
if (siteParts.length >= 3 && siteParts[0] !== "www") return siteParts[0];
|
|
5806
|
-
} catch {
|
|
5807
|
-
}
|
|
5808
|
-
}
|
|
5809
|
-
return "";
|
|
5810
|
-
}
|
|
5811
4872
|
function OhhwellsBridge() {
|
|
5812
4873
|
const pathname = (0, import_navigation.usePathname)();
|
|
5813
4874
|
const router = (0, import_navigation.useRouter)();
|
|
5814
4875
|
const searchParams = (0, import_navigation.useSearchParams)();
|
|
5815
4876
|
const isEditMode = isEditSessionActive();
|
|
5816
|
-
const [bridgeRoot, setBridgeRoot] = (0,
|
|
5817
|
-
(0,
|
|
4877
|
+
const [bridgeRoot, setBridgeRoot] = (0, import_react3.useState)(null);
|
|
4878
|
+
(0, import_react3.useEffect)(() => {
|
|
5818
4879
|
const figtreeFontId = "ohw-figtree-font";
|
|
5819
4880
|
if (!document.getElementById(figtreeFontId)) {
|
|
5820
4881
|
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
@@ -5837,52 +4898,55 @@ function OhhwellsBridge() {
|
|
|
5837
4898
|
};
|
|
5838
4899
|
}, []);
|
|
5839
4900
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
5840
|
-
const subdomain =
|
|
5841
|
-
|
|
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) => {
|
|
5842
4907
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
5843
4908
|
window.parent.postMessage(data, "*");
|
|
5844
4909
|
}
|
|
5845
4910
|
}, []);
|
|
5846
|
-
const [fetchState, setFetchState] = (0,
|
|
5847
|
-
const autoSaveTimers = (0,
|
|
5848
|
-
const activeElRef = (0,
|
|
5849
|
-
const originalContentRef = (0,
|
|
5850
|
-
const activeStateElRef = (0,
|
|
5851
|
-
const parentScrollRef = (0,
|
|
5852
|
-
const toolbarElRef = (0,
|
|
5853
|
-
const glowElRef = (0,
|
|
5854
|
-
const hoveredImageRef = (0,
|
|
5855
|
-
const hoveredImageHasTextOverlapRef = (0,
|
|
5856
|
-
const
|
|
5857
|
-
const
|
|
5858
|
-
const
|
|
5859
|
-
const
|
|
5860
|
-
const activateRef = (0, import_react5.useRef)(() => {
|
|
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)(() => {
|
|
5861
4925
|
});
|
|
5862
|
-
const deactivateRef = (0,
|
|
4926
|
+
const deactivateRef = (0, import_react3.useRef)(() => {
|
|
5863
4927
|
});
|
|
5864
|
-
const refreshActiveCommandsRef = (0,
|
|
4928
|
+
const refreshActiveCommandsRef = (0, import_react3.useRef)(() => {
|
|
5865
4929
|
});
|
|
5866
|
-
const postToParentRef = (0,
|
|
4930
|
+
const postToParentRef = (0, import_react3.useRef)(postToParent);
|
|
5867
4931
|
postToParentRef.current = postToParent;
|
|
5868
|
-
const [toolbarRect, setToolbarRect] = (0,
|
|
5869
|
-
const [toggleState, setToggleState] = (0,
|
|
5870
|
-
const [maxBadge, setMaxBadge] = (0,
|
|
5871
|
-
const [activeCommands, setActiveCommands] = (0,
|
|
5872
|
-
const [toolbarShowEditLink, setToolbarShowEditLink] = (0,
|
|
5873
|
-
const [linkPopover, setLinkPopover] = (0,
|
|
5874
|
-
const [sitePages, setSitePages] = (0,
|
|
5875
|
-
const [sectionsByPath, setSectionsByPath] = (0,
|
|
5876
|
-
const sectionsPrefetchGenRef = (0,
|
|
5877
|
-
const setLinkPopoverRef = (0,
|
|
5878
|
-
const linkPopoverPanelRef = (0,
|
|
5879
|
-
const linkPopoverOpenRef = (0,
|
|
5880
|
-
const linkPopoverGraceUntilRef = (0,
|
|
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);
|
|
5881
4945
|
setLinkPopoverRef.current = setLinkPopover;
|
|
5882
4946
|
const bumpLinkPopoverGrace = () => {
|
|
5883
4947
|
linkPopoverGraceUntilRef.current = Date.now() + 350;
|
|
5884
4948
|
};
|
|
5885
|
-
const runSectionsPrefetch = (0,
|
|
4949
|
+
const runSectionsPrefetch = (0, import_react3.useCallback)((pages) => {
|
|
5886
4950
|
if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
|
|
5887
4951
|
const gen = ++sectionsPrefetchGenRef.current;
|
|
5888
4952
|
const paths = pages.map((p) => p.path);
|
|
@@ -5901,9 +4965,9 @@ function OhhwellsBridge() {
|
|
|
5901
4965
|
);
|
|
5902
4966
|
});
|
|
5903
4967
|
}, [isEditMode, pathname]);
|
|
5904
|
-
const runSectionsPrefetchRef = (0,
|
|
4968
|
+
const runSectionsPrefetchRef = (0, import_react3.useRef)(runSectionsPrefetch);
|
|
5905
4969
|
runSectionsPrefetchRef.current = runSectionsPrefetch;
|
|
5906
|
-
(0,
|
|
4970
|
+
(0, import_react3.useEffect)(() => {
|
|
5907
4971
|
if (!linkPopover) return;
|
|
5908
4972
|
if (hoveredImageRef.current) {
|
|
5909
4973
|
hoveredImageRef.current = null;
|
|
@@ -5911,7 +4975,7 @@ function OhhwellsBridge() {
|
|
|
5911
4975
|
}
|
|
5912
4976
|
postToParent({ type: "ow:image-unhover" });
|
|
5913
4977
|
}, [linkPopover, postToParent]);
|
|
5914
|
-
(0,
|
|
4978
|
+
(0, import_react3.useEffect)(() => {
|
|
5915
4979
|
if (!isEditMode) return;
|
|
5916
4980
|
const useFixtures = shouldUseDevFixtures();
|
|
5917
4981
|
if (useFixtures) {
|
|
@@ -5935,15 +4999,14 @@ function OhhwellsBridge() {
|
|
|
5935
4999
|
if (!useFixtures) postToParent({ type: "ow:request-site-pages" });
|
|
5936
5000
|
return () => window.removeEventListener("message", onSitePages);
|
|
5937
5001
|
}, [isEditMode, postToParent]);
|
|
5938
|
-
|
|
5939
|
-
(0, import_react5.useEffect)(() => {
|
|
5002
|
+
(0, import_react3.useEffect)(() => {
|
|
5940
5003
|
if (!isEditMode || shouldUseDevFixtures()) return;
|
|
5941
5004
|
void loadAllSectionsManifest().then((manifest) => {
|
|
5942
5005
|
if (Object.keys(manifest).length === 0) return;
|
|
5943
5006
|
setSectionsByPath((prev) => ({ ...manifest, ...prev }));
|
|
5944
5007
|
});
|
|
5945
5008
|
}, [isEditMode]);
|
|
5946
|
-
(0,
|
|
5009
|
+
(0, import_react3.useEffect)(() => {
|
|
5947
5010
|
const update = () => {
|
|
5948
5011
|
const el = activeElRef.current;
|
|
5949
5012
|
if (el) setToolbarRect(el.getBoundingClientRect());
|
|
@@ -5951,12 +5014,6 @@ function OhhwellsBridge() {
|
|
|
5951
5014
|
if (!prev || !activeStateElRef.current) return prev;
|
|
5952
5015
|
return { ...prev, rect: activeStateElRef.current.getBoundingClientRect() };
|
|
5953
5016
|
});
|
|
5954
|
-
setSectionGap((prev) => {
|
|
5955
|
-
if (!prev) return prev;
|
|
5956
|
-
const anchor = document.querySelector(`[data-ohw-section="${prev.insertAfter}"]`);
|
|
5957
|
-
if (!anchor) return prev;
|
|
5958
|
-
return { ...prev, y: anchor.getBoundingClientRect().bottom };
|
|
5959
|
-
});
|
|
5960
5017
|
};
|
|
5961
5018
|
const vvp = window.visualViewport;
|
|
5962
5019
|
if (!vvp) return;
|
|
@@ -5967,10 +5024,10 @@ function OhhwellsBridge() {
|
|
|
5967
5024
|
vvp.removeEventListener("resize", update);
|
|
5968
5025
|
};
|
|
5969
5026
|
}, []);
|
|
5970
|
-
const refreshStateRules = (0,
|
|
5027
|
+
const refreshStateRules = (0, import_react3.useCallback)(() => {
|
|
5971
5028
|
editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
|
|
5972
5029
|
}, []);
|
|
5973
|
-
const deactivate = (0,
|
|
5030
|
+
const deactivate = (0, import_react3.useCallback)(() => {
|
|
5974
5031
|
const el = activeElRef.current;
|
|
5975
5032
|
if (!el) return;
|
|
5976
5033
|
const key = el.dataset.ohwKey;
|
|
@@ -5996,7 +5053,7 @@ function OhhwellsBridge() {
|
|
|
5996
5053
|
setToolbarShowEditLink(false);
|
|
5997
5054
|
postToParent({ type: "ow:exit-edit" });
|
|
5998
5055
|
}, [postToParent]);
|
|
5999
|
-
const activate = (0,
|
|
5056
|
+
const activate = (0, import_react3.useCallback)((el) => {
|
|
6000
5057
|
if (activeElRef.current === el) return;
|
|
6001
5058
|
deactivate();
|
|
6002
5059
|
if (hoveredImageRef.current) {
|
|
@@ -6015,7 +5072,7 @@ function OhhwellsBridge() {
|
|
|
6015
5072
|
}, [deactivate, postToParent]);
|
|
6016
5073
|
activateRef.current = activate;
|
|
6017
5074
|
deactivateRef.current = deactivate;
|
|
6018
|
-
(0,
|
|
5075
|
+
(0, import_react3.useLayoutEffect)(() => {
|
|
6019
5076
|
if (!subdomain || isEditMode) {
|
|
6020
5077
|
setFetchState("done");
|
|
6021
5078
|
return;
|
|
@@ -6023,7 +5080,6 @@ function OhhwellsBridge() {
|
|
|
6023
5080
|
const applyContent = (content) => {
|
|
6024
5081
|
const imageLoads = [];
|
|
6025
5082
|
for (const [key, val] of Object.entries(content)) {
|
|
6026
|
-
if (key === "__ohw_sections") continue;
|
|
6027
5083
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
6028
5084
|
if (el.dataset.ohwEditable === "image") {
|
|
6029
5085
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6045,7 +5101,6 @@ function OhhwellsBridge() {
|
|
|
6045
5101
|
});
|
|
6046
5102
|
applyLinkByKey(key, val);
|
|
6047
5103
|
}
|
|
6048
|
-
initSectionsFromContent(content, true);
|
|
6049
5104
|
return imageLoads.length > 0 ? Promise.all(imageLoads).then(() => {
|
|
6050
5105
|
}) : Promise.resolve();
|
|
6051
5106
|
};
|
|
@@ -6070,15 +5125,12 @@ function OhhwellsBridge() {
|
|
|
6070
5125
|
cancelled = true;
|
|
6071
5126
|
};
|
|
6072
5127
|
}, [subdomain, isEditMode, pathname]);
|
|
6073
|
-
(0,
|
|
5128
|
+
(0, import_react3.useEffect)(() => {
|
|
6074
5129
|
if (!subdomain || isEditMode) return;
|
|
6075
|
-
let debounceTimer = null;
|
|
6076
5130
|
const applyFromCache = () => {
|
|
6077
5131
|
const content = contentCache.get(subdomain);
|
|
6078
5132
|
if (!content) return;
|
|
6079
|
-
retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
|
|
6080
5133
|
for (const [key, val] of Object.entries(content)) {
|
|
6081
|
-
if (key === "__ohw_sections") continue;
|
|
6082
5134
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
6083
5135
|
if (el.dataset.ohwEditable === "image") {
|
|
6084
5136
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6095,28 +5147,21 @@ function OhhwellsBridge() {
|
|
|
6095
5147
|
applyLinkByKey(key, val);
|
|
6096
5148
|
}
|
|
6097
5149
|
};
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
debounceTimer = setTimeout(applyFromCache, 150);
|
|
6101
|
-
};
|
|
6102
|
-
scheduleApply();
|
|
6103
|
-
const observer = new MutationObserver(scheduleApply);
|
|
5150
|
+
applyFromCache();
|
|
5151
|
+
const observer = new MutationObserver(applyFromCache);
|
|
6104
5152
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
6105
|
-
return () =>
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
};
|
|
6109
|
-
}, [subdomain, isEditMode, pathname]);
|
|
6110
|
-
(0, import_react5.useLayoutEffect)(() => {
|
|
5153
|
+
return () => observer.disconnect();
|
|
5154
|
+
}, [subdomain, isEditMode]);
|
|
5155
|
+
(0, import_react3.useLayoutEffect)(() => {
|
|
6111
5156
|
const el = document.getElementById("ohw-loader");
|
|
6112
5157
|
if (!el) return;
|
|
6113
5158
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
6114
5159
|
el.style.display = visible ? "flex" : "none";
|
|
6115
5160
|
}, [subdomain, fetchState]);
|
|
6116
|
-
(0,
|
|
5161
|
+
(0, import_react3.useEffect)(() => {
|
|
6117
5162
|
postToParent({ type: "ow:navigation", path: pathname });
|
|
6118
5163
|
}, [pathname, postToParent]);
|
|
6119
|
-
(0,
|
|
5164
|
+
(0, import_react3.useEffect)(() => {
|
|
6120
5165
|
if (!isEditMode) return;
|
|
6121
5166
|
const measure = () => {
|
|
6122
5167
|
const h = document.body.scrollHeight;
|
|
@@ -6140,7 +5185,7 @@ function OhhwellsBridge() {
|
|
|
6140
5185
|
window.removeEventListener("resize", handleResize);
|
|
6141
5186
|
};
|
|
6142
5187
|
}, [pathname, isEditMode, postToParent]);
|
|
6143
|
-
(0,
|
|
5188
|
+
(0, import_react3.useEffect)(() => {
|
|
6144
5189
|
if (!subdomainFromQuery || isEditMode) return;
|
|
6145
5190
|
const handleClick = (e) => {
|
|
6146
5191
|
const anchor = e.target.closest("a");
|
|
@@ -6156,7 +5201,7 @@ function OhhwellsBridge() {
|
|
|
6156
5201
|
document.addEventListener("click", handleClick, true);
|
|
6157
5202
|
return () => document.removeEventListener("click", handleClick, true);
|
|
6158
5203
|
}, [subdomainFromQuery, isEditMode, router]);
|
|
6159
|
-
(0,
|
|
5204
|
+
(0, import_react3.useEffect)(() => {
|
|
6160
5205
|
if (!isEditMode) {
|
|
6161
5206
|
editStylesRef.current?.base.remove();
|
|
6162
5207
|
editStylesRef.current?.forceHover.remove();
|
|
@@ -6457,15 +5502,6 @@ function OhhwellsBridge() {
|
|
|
6457
5502
|
textEditable.setAttribute("data-ohw-hovered", "");
|
|
6458
5503
|
return;
|
|
6459
5504
|
}
|
|
6460
|
-
if (hoveredGapRef.current) {
|
|
6461
|
-
if (hoveredImageRef.current) {
|
|
6462
|
-
hoveredImageRef.current = null;
|
|
6463
|
-
resumeAnimTracks();
|
|
6464
|
-
postToParentRef.current({ type: "ow:image-unhover" });
|
|
6465
|
-
}
|
|
6466
|
-
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
6467
|
-
return;
|
|
6468
|
-
}
|
|
6469
5505
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
6470
5506
|
if (imgEl !== hoveredImageRef.current || hoveredImageHasTextOverlapRef.current) {
|
|
6471
5507
|
hoveredImageRef.current = imgEl;
|
|
@@ -6531,30 +5567,8 @@ function OhhwellsBridge() {
|
|
|
6531
5567
|
}
|
|
6532
5568
|
}
|
|
6533
5569
|
};
|
|
6534
|
-
const probeSectionGapAt = (clientX, clientY, fromParentViewport = false) => {
|
|
6535
|
-
const { y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
6536
|
-
const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
|
|
6537
|
-
const ZONE = 20;
|
|
6538
|
-
for (let i = 0; i < sections.length; i++) {
|
|
6539
|
-
const a = sections[i];
|
|
6540
|
-
const b = sections[i + 1] ?? null;
|
|
6541
|
-
const boundaryY = a.getBoundingClientRect().bottom;
|
|
6542
|
-
if (Math.abs(y - boundaryY) <= ZONE) {
|
|
6543
|
-
const insertAfter = a.dataset.ohwSection ?? "";
|
|
6544
|
-
const insertBefore = b?.dataset.ohwSection ?? null;
|
|
6545
|
-
hoveredGapRef.current = { insertAfter, insertBefore };
|
|
6546
|
-
setSectionGap({ insertAfter, insertBefore, y: boundaryY });
|
|
6547
|
-
return;
|
|
6548
|
-
}
|
|
6549
|
-
}
|
|
6550
|
-
if (hoveredGapRef.current) {
|
|
6551
|
-
hoveredGapRef.current = null;
|
|
6552
|
-
setSectionGap(null);
|
|
6553
|
-
}
|
|
6554
|
-
};
|
|
6555
5570
|
const handleMouseMove = (e) => {
|
|
6556
5571
|
const { clientX, clientY } = e;
|
|
6557
|
-
probeSectionGapAt(clientX, clientY);
|
|
6558
5572
|
probeImageAt(clientX, clientY);
|
|
6559
5573
|
probeHoverCardsAt(clientX, clientY);
|
|
6560
5574
|
};
|
|
@@ -6562,7 +5576,6 @@ function OhhwellsBridge() {
|
|
|
6562
5576
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
6563
5577
|
const { clientX, clientY } = e.data;
|
|
6564
5578
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
6565
|
-
probeSectionGapAt(clientX, clientY);
|
|
6566
5579
|
probeImageAt(clientX, clientY);
|
|
6567
5580
|
probeHoverCardsAt(clientX, clientY);
|
|
6568
5581
|
};
|
|
@@ -6720,12 +5733,7 @@ function OhhwellsBridge() {
|
|
|
6720
5733
|
if (e.data?.type !== "ow:hydrate") return;
|
|
6721
5734
|
const content = e.data.content;
|
|
6722
5735
|
if (!content) return;
|
|
6723
|
-
let sectionsJson = null;
|
|
6724
5736
|
for (const [key, val] of Object.entries(content)) {
|
|
6725
|
-
if (key === "__ohw_sections") {
|
|
6726
|
-
sectionsJson = val;
|
|
6727
|
-
continue;
|
|
6728
|
-
}
|
|
6729
5737
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
6730
5738
|
if (el.dataset.ohwEditable === "image") {
|
|
6731
5739
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6740,9 +5748,6 @@ function OhhwellsBridge() {
|
|
|
6740
5748
|
});
|
|
6741
5749
|
applyLinkByKey(key, val);
|
|
6742
5750
|
}
|
|
6743
|
-
if (sectionsJson) {
|
|
6744
|
-
initSectionsFromContent({ __ohw_sections: sectionsJson }, true);
|
|
6745
|
-
}
|
|
6746
5751
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
6747
5752
|
};
|
|
6748
5753
|
window.addEventListener("message", handleHydrate);
|
|
@@ -6795,63 +5800,7 @@ function OhhwellsBridge() {
|
|
|
6795
5800
|
};
|
|
6796
5801
|
const handleSave = (e) => {
|
|
6797
5802
|
if (e.data?.type !== "ow:save") return;
|
|
6798
|
-
|
|
6799
|
-
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
6800
|
-
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
6801
|
-
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
6802
|
-
};
|
|
6803
|
-
const handleInsertSection = (e) => {
|
|
6804
|
-
if (e.data?.type !== "ow:insert-section") return;
|
|
6805
|
-
const { widgetType, insertAfter, insertBefore } = e.data;
|
|
6806
|
-
if (widgetType !== "scheduling") return;
|
|
6807
|
-
const inserted = mountSchedulingWidget(insertAfter, true, void 0, insertBefore ?? null);
|
|
6808
|
-
if (inserted) {
|
|
6809
|
-
const tracker = getSectionsTracker();
|
|
6810
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
|
|
6811
|
-
const h = document.documentElement.scrollHeight;
|
|
6812
|
-
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
6813
|
-
}
|
|
6814
|
-
};
|
|
6815
|
-
const handleSwitchSchedule = (e) => {
|
|
6816
|
-
if (e.data?.type !== "ow:switch-schedule") return;
|
|
6817
|
-
const scheduleId = e.data.scheduleId;
|
|
6818
|
-
const insertAfter = e.data.insertAfter;
|
|
6819
|
-
if (!scheduleId || !insertAfter) return;
|
|
6820
|
-
const text = updateSectionScheduleId(insertAfter, scheduleId);
|
|
6821
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text }] });
|
|
6822
|
-
};
|
|
6823
|
-
const handleScheduleLinked = (e) => {
|
|
6824
|
-
if (e.data?.type !== "ow:schedule-linked") return;
|
|
6825
|
-
const scheduleId = e.data.scheduleId;
|
|
6826
|
-
const insertAfter = e.data.insertAfter;
|
|
6827
|
-
if (!scheduleId || !insertAfter) return;
|
|
6828
|
-
const text = updateSectionScheduleId(insertAfter, scheduleId);
|
|
6829
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text }] });
|
|
6830
|
-
};
|
|
6831
|
-
const handleClearSchedulingWidget = (e) => {
|
|
6832
|
-
if (e.data?.type !== "ow:clear-scheduling-widget") return;
|
|
6833
|
-
const insertAfter = e.data.insertAfter;
|
|
6834
|
-
if (!insertAfter) return;
|
|
6835
|
-
const text = updateSectionScheduleId(insertAfter, null);
|
|
6836
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text }] });
|
|
6837
|
-
};
|
|
6838
|
-
const handleRemoveSchedulingSection = (e) => {
|
|
6839
|
-
if (e.data?.type !== "ow:remove-scheduling-section") return;
|
|
6840
|
-
document.querySelectorAll('[data-ohw-section-container="scheduling"]').forEach((el) => {
|
|
6841
|
-
el.remove();
|
|
6842
|
-
});
|
|
6843
|
-
const tracker = getSectionsTracker();
|
|
6844
|
-
let sections = [];
|
|
6845
|
-
try {
|
|
6846
|
-
sections = JSON.parse(tracker.textContent || "[]");
|
|
6847
|
-
} catch {
|
|
6848
|
-
}
|
|
6849
|
-
const currentPath = window.location.pathname;
|
|
6850
|
-
const updated = sections.filter((s) => !(s.type === "scheduling" && s.pagePath === currentPath));
|
|
6851
|
-
tracker.textContent = JSON.stringify(updated);
|
|
6852
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
|
|
6853
|
-
const h = document.documentElement.scrollHeight;
|
|
6854
|
-
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
5803
|
+
postToParentRef.current({ type: "ow:save-result", nodes: collectEditableNodes() });
|
|
6855
5804
|
};
|
|
6856
5805
|
const handleSelectionChange = () => {
|
|
6857
5806
|
if (!activeElRef.current) return;
|
|
@@ -6956,11 +5905,6 @@ function OhhwellsBridge() {
|
|
|
6956
5905
|
deactivateRef.current();
|
|
6957
5906
|
};
|
|
6958
5907
|
window.addEventListener("message", handleSave);
|
|
6959
|
-
window.addEventListener("message", handleInsertSection);
|
|
6960
|
-
window.addEventListener("message", handleSwitchSchedule);
|
|
6961
|
-
window.addEventListener("message", handleScheduleLinked);
|
|
6962
|
-
window.addEventListener("message", handleClearSchedulingWidget);
|
|
6963
|
-
window.addEventListener("message", handleRemoveSchedulingSection);
|
|
6964
5908
|
window.addEventListener("message", handleImageUrl);
|
|
6965
5909
|
window.addEventListener("message", handleAnimLock);
|
|
6966
5910
|
window.addEventListener("message", handleCanvasHeight);
|
|
@@ -6995,11 +5939,6 @@ function OhhwellsBridge() {
|
|
|
6995
5939
|
document.removeEventListener("selectionchange", handleSelectionChange);
|
|
6996
5940
|
window.removeEventListener("scroll", handleScroll, true);
|
|
6997
5941
|
window.removeEventListener("message", handleSave);
|
|
6998
|
-
window.removeEventListener("message", handleInsertSection);
|
|
6999
|
-
window.removeEventListener("message", handleSwitchSchedule);
|
|
7000
|
-
window.removeEventListener("message", handleScheduleLinked);
|
|
7001
|
-
window.removeEventListener("message", handleClearSchedulingWidget);
|
|
7002
|
-
window.removeEventListener("message", handleRemoveSchedulingSection);
|
|
7003
5942
|
window.removeEventListener("message", handleImageUrl);
|
|
7004
5943
|
window.removeEventListener("message", handleAnimLock);
|
|
7005
5944
|
window.removeEventListener("message", handleCanvasHeight);
|
|
@@ -7014,7 +5953,7 @@ function OhhwellsBridge() {
|
|
|
7014
5953
|
if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
|
|
7015
5954
|
};
|
|
7016
5955
|
}, [isEditMode, refreshStateRules]);
|
|
7017
|
-
(0,
|
|
5956
|
+
(0, import_react3.useEffect)(() => {
|
|
7018
5957
|
if (!isEditMode) return;
|
|
7019
5958
|
document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
|
|
7020
5959
|
el.removeAttribute("data-ohw-active-state");
|
|
@@ -7043,19 +5982,19 @@ function OhhwellsBridge() {
|
|
|
7043
5982
|
clearTimeout(timer);
|
|
7044
5983
|
};
|
|
7045
5984
|
}, [pathname, isEditMode, refreshStateRules, postToParent]);
|
|
7046
|
-
(0,
|
|
5985
|
+
(0, import_react3.useEffect)(() => {
|
|
7047
5986
|
scrollToHashSectionWhenReady();
|
|
7048
5987
|
const onHashChange = () => scrollToHashSectionWhenReady();
|
|
7049
5988
|
window.addEventListener("hashchange", onHashChange);
|
|
7050
5989
|
return () => window.removeEventListener("hashchange", onHashChange);
|
|
7051
5990
|
}, [pathname]);
|
|
7052
|
-
const handleCommand = (0,
|
|
5991
|
+
const handleCommand = (0, import_react3.useCallback)((cmd) => {
|
|
7053
5992
|
document.execCommand(cmd, false);
|
|
7054
5993
|
activeElRef.current?.focus();
|
|
7055
5994
|
if (activeElRef.current) setToolbarRect(activeElRef.current.getBoundingClientRect());
|
|
7056
5995
|
refreshActiveCommandsRef.current();
|
|
7057
5996
|
}, []);
|
|
7058
|
-
const handleStateChange = (0,
|
|
5997
|
+
const handleStateChange = (0, import_react3.useCallback)((state) => {
|
|
7059
5998
|
if (!activeStateElRef.current) return;
|
|
7060
5999
|
const el = activeStateElRef.current;
|
|
7061
6000
|
if (state === "Default") {
|
|
@@ -7068,8 +6007,8 @@ function OhhwellsBridge() {
|
|
|
7068
6007
|
}
|
|
7069
6008
|
setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
|
|
7070
6009
|
}, [deactivate]);
|
|
7071
|
-
const closeLinkPopover = (0,
|
|
7072
|
-
const openLinkPopoverForActive = (0,
|
|
6010
|
+
const closeLinkPopover = (0, import_react3.useCallback)(() => setLinkPopover(null), []);
|
|
6011
|
+
const openLinkPopoverForActive = (0, import_react3.useCallback)(() => {
|
|
7073
6012
|
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
7074
6013
|
if (!hrefCtx) return;
|
|
7075
6014
|
bumpLinkPopoverGrace();
|
|
@@ -7079,7 +6018,7 @@ function OhhwellsBridge() {
|
|
|
7079
6018
|
rect: hrefCtx.anchor.getBoundingClientRect()
|
|
7080
6019
|
});
|
|
7081
6020
|
}, []);
|
|
7082
|
-
const handleLinkPopoverSubmit = (0,
|
|
6021
|
+
const handleLinkPopoverSubmit = (0, import_react3.useCallback)(
|
|
7083
6022
|
(target) => {
|
|
7084
6023
|
if (!linkPopover) return;
|
|
7085
6024
|
const { key } = linkPopover;
|
|
@@ -7092,11 +6031,11 @@ function OhhwellsBridge() {
|
|
|
7092
6031
|
const showEditLink = toolbarShowEditLink;
|
|
7093
6032
|
const currentSections = sectionsByPath[pathname] ?? [];
|
|
7094
6033
|
linkPopoverOpenRef.current = linkPopover !== null;
|
|
7095
|
-
return bridgeRoot ? (0,
|
|
7096
|
-
/* @__PURE__ */ (0,
|
|
7097
|
-
toolbarRect && /* @__PURE__ */ (0,
|
|
7098
|
-
/* @__PURE__ */ (0,
|
|
7099
|
-
/* @__PURE__ */ (0,
|
|
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)(
|
|
7100
6039
|
FloatingToolbar,
|
|
7101
6040
|
{
|
|
7102
6041
|
rect: toolbarRect,
|
|
@@ -7109,7 +6048,7 @@ function OhhwellsBridge() {
|
|
|
7109
6048
|
}
|
|
7110
6049
|
)
|
|
7111
6050
|
] }),
|
|
7112
|
-
maxBadge && /* @__PURE__ */ (0,
|
|
6051
|
+
maxBadge && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
7113
6052
|
"div",
|
|
7114
6053
|
{
|
|
7115
6054
|
"data-ohw-max-badge": "",
|
|
@@ -7135,7 +6074,7 @@ function OhhwellsBridge() {
|
|
|
7135
6074
|
]
|
|
7136
6075
|
}
|
|
7137
6076
|
),
|
|
7138
|
-
toggleState && /* @__PURE__ */ (0,
|
|
6077
|
+
toggleState && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
7139
6078
|
StateToggle,
|
|
7140
6079
|
{
|
|
7141
6080
|
rect: toggleState.rect,
|
|
@@ -7144,7 +6083,7 @@ function OhhwellsBridge() {
|
|
|
7144
6083
|
onStateChange: handleStateChange
|
|
7145
6084
|
}
|
|
7146
6085
|
),
|
|
7147
|
-
linkPopover ? /* @__PURE__ */ (0,
|
|
6086
|
+
linkPopover ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
7148
6087
|
LinkPopover,
|
|
7149
6088
|
{
|
|
7150
6089
|
rect: linkPopover.rect,
|
|
@@ -7159,32 +6098,7 @@ function OhhwellsBridge() {
|
|
|
7159
6098
|
onClose: closeLinkPopover,
|
|
7160
6099
|
onSubmit: handleLinkPopoverSubmit
|
|
7161
6100
|
}
|
|
7162
|
-
) : null
|
|
7163
|
-
sectionGap && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
7164
|
-
"div",
|
|
7165
|
-
{
|
|
7166
|
-
"data-ohw-section-insert-line": "",
|
|
7167
|
-
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
7168
|
-
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
7169
|
-
children: [
|
|
7170
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
7171
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
7172
|
-
Badge,
|
|
7173
|
-
{
|
|
7174
|
-
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",
|
|
7175
|
-
onClick: () => {
|
|
7176
|
-
window.parent.postMessage(
|
|
7177
|
-
{ type: "ow:add-section", insertAfter: sectionGap.insertAfter, insertBefore: sectionGap.insertBefore },
|
|
7178
|
-
"*"
|
|
7179
|
-
);
|
|
7180
|
-
},
|
|
7181
|
-
children: "Add Section"
|
|
7182
|
-
}
|
|
7183
|
-
),
|
|
7184
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
7185
|
-
]
|
|
7186
|
-
}
|
|
7187
|
-
)
|
|
6101
|
+
) : null
|
|
7188
6102
|
] }),
|
|
7189
6103
|
bridgeRoot
|
|
7190
6104
|
) : null;
|
|
@@ -7194,7 +6108,6 @@ function OhhwellsBridge() {
|
|
|
7194
6108
|
LinkEditorPanel,
|
|
7195
6109
|
LinkPopover,
|
|
7196
6110
|
OhhwellsBridge,
|
|
7197
|
-
SchedulingWidget,
|
|
7198
6111
|
Toggle,
|
|
7199
6112
|
ToggleGroup,
|
|
7200
6113
|
ToggleGroupItem,
|