@ohhwells/bridge 0.1.17 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +714 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +690 -40
- package/dist/index.js.map +1 -1
- package/dist/styles.css +382 -2
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -32,6 +32,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
32
32
|
var index_exports = {};
|
|
33
33
|
__export(index_exports, {
|
|
34
34
|
OhhwellsBridge: () => OhhwellsBridge,
|
|
35
|
+
SchedulingWidget: () => SchedulingWidget,
|
|
35
36
|
Toggle: () => Toggle,
|
|
36
37
|
ToggleGroup: () => ToggleGroup,
|
|
37
38
|
ToggleGroupItem: () => ToggleGroupItem,
|
|
@@ -40,10 +41,428 @@ __export(index_exports, {
|
|
|
40
41
|
module.exports = __toCommonJS(index_exports);
|
|
41
42
|
|
|
42
43
|
// src/OhhwellsBridge.tsx
|
|
44
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
45
|
+
var import_client = require("react-dom/client");
|
|
46
|
+
|
|
47
|
+
// src/ui/SchedulingWidget.tsx
|
|
43
48
|
var import_react = __toESM(require("react"), 1);
|
|
49
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
50
|
+
var API_URL = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
51
|
+
var DAY_ABBR = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
|
|
52
|
+
function getApiDomain() {
|
|
53
|
+
const h = window.location.hostname;
|
|
54
|
+
for (const base of ["ohhwells.site", "theflowops-staging.com", "theflowops.com"]) {
|
|
55
|
+
if (h.endsWith(`.${base}`)) return h.slice(0, -(base.length + 1));
|
|
56
|
+
}
|
|
57
|
+
return h;
|
|
58
|
+
}
|
|
59
|
+
function classRunsOnDate(cls, date, type) {
|
|
60
|
+
if (type === "FIXED") {
|
|
61
|
+
const d = String(date.getDate()).padStart(2, "0");
|
|
62
|
+
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
63
|
+
return cls.fixedDates?.some((fd) => fd.date === `${d}-${m}-${date.getFullYear()}`) ?? false;
|
|
64
|
+
}
|
|
65
|
+
return cls.weekdays?.some((w) => w.weekday === date.getDay()) ?? false;
|
|
66
|
+
}
|
|
67
|
+
function formatClassTime(cls) {
|
|
68
|
+
let h = parseInt(cls.startTime.hour, 10);
|
|
69
|
+
const m = parseInt(cls.startTime.minutes, 10);
|
|
70
|
+
if (cls.startTime.time === "PM" && h !== 12) h += 12;
|
|
71
|
+
if (cls.startTime.time === "AM" && h === 12) h = 0;
|
|
72
|
+
const endTotal = h * 60 + m + cls.duration;
|
|
73
|
+
const eh = Math.floor(endTotal / 60) % 24;
|
|
74
|
+
const em = endTotal % 60;
|
|
75
|
+
return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
|
|
76
|
+
}
|
|
77
|
+
function getBookingsOnDate(cls, date) {
|
|
78
|
+
if (!cls.bookings?.length) return 0;
|
|
79
|
+
const ds = date.toISOString().split("T")[0];
|
|
80
|
+
return cls.bookings.filter((b) => {
|
|
81
|
+
try {
|
|
82
|
+
return new Date(b.classDate).toISOString().split("T")[0] === ds;
|
|
83
|
+
} catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}).length;
|
|
87
|
+
}
|
|
88
|
+
function buildTimezoneLabel(tz) {
|
|
89
|
+
try {
|
|
90
|
+
const now = /* @__PURE__ */ new Date();
|
|
91
|
+
const timeStr = new Intl.DateTimeFormat("en-US", {
|
|
92
|
+
hour: "2-digit",
|
|
93
|
+
minute: "2-digit",
|
|
94
|
+
hour12: false,
|
|
95
|
+
timeZone: tz
|
|
96
|
+
}).format(now);
|
|
97
|
+
const offsetPart = new Intl.DateTimeFormat("en-US", { timeZoneName: "short", timeZone: tz }).formatToParts(now).find((p) => p.type === "timeZoneName")?.value ?? "";
|
|
98
|
+
const city = tz.split("/").pop()?.replace(/_/g, " ") ?? tz;
|
|
99
|
+
return `${timeStr} (${offsetPart}) ${city} time`;
|
|
100
|
+
} catch {
|
|
101
|
+
return tz;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function EmptyState({ inEditor }) {
|
|
105
|
+
const handleAddSchedule = () => {
|
|
106
|
+
if (inEditor) {
|
|
107
|
+
window.parent.postMessage({ type: "ow:scheduling-not-connected" }, "*");
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.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: [
|
|
111
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-10 h-10 bg-[#F5F5F4] rounded-[10px] flex items-center justify-center shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
112
|
+
"svg",
|
|
113
|
+
{
|
|
114
|
+
width: "20",
|
|
115
|
+
height: "20",
|
|
116
|
+
viewBox: "0 0 24 24",
|
|
117
|
+
fill: "none",
|
|
118
|
+
stroke: "var(--color-accent, #A89B83)",
|
|
119
|
+
strokeWidth: "1.5",
|
|
120
|
+
strokeLinecap: "round",
|
|
121
|
+
strokeLinejoin: "round",
|
|
122
|
+
children: [
|
|
123
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
|
|
124
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "16", y1: "2", x2: "16", y2: "6" }),
|
|
125
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "8", y1: "2", x2: "8", y2: "6" }),
|
|
126
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "3", y1: "10", x2: "21", y2: "10" }),
|
|
127
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", y1: "14", x2: "12", y2: "18" }),
|
|
128
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "10", y1: "16", x2: "14", y2: "16" })
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
) }),
|
|
132
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col items-center gap-2", children: [
|
|
133
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "font-body text-lg font-medium text-center text-[#0A0A0A] m-0", children: "No schedule yet" }),
|
|
134
|
+
/* @__PURE__ */ (0, import_jsx_runtime.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." })
|
|
135
|
+
] }),
|
|
136
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
137
|
+
"button",
|
|
138
|
+
{
|
|
139
|
+
onClick: handleAddSchedule,
|
|
140
|
+
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",
|
|
141
|
+
children: "Add Schedule"
|
|
142
|
+
}
|
|
143
|
+
)
|
|
144
|
+
] });
|
|
145
|
+
}
|
|
146
|
+
function LoadingSkeleton() {
|
|
147
|
+
const shimmer = {
|
|
148
|
+
background: "linear-gradient(90deg,#f0f0f0 25%,#e8e8e8 50%,#f0f0f0 75%)",
|
|
149
|
+
backgroundSize: "200% 100%",
|
|
150
|
+
animation: "ohw-shimmer 1.5s infinite"
|
|
151
|
+
};
|
|
152
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "w-full flex flex-col gap-10", children: [
|
|
153
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `@keyframes ohw-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}` }),
|
|
154
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex h-[70px] items-stretch", children: Array.from({ length: 7 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex-1 flex flex-col justify-between items-center px-1", children: [
|
|
155
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...shimmer, width: "32px", height: "14px", borderRadius: "4px" } }),
|
|
156
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...shimmer, width: "40px", height: "40px", borderRadius: "50%" } })
|
|
157
|
+
] }, i)) }),
|
|
158
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
159
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-[60px] py-4", children: [
|
|
160
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...shimmer, width: "120px", height: "16px", borderRadius: "4px", flexShrink: 0 } }),
|
|
161
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex-1 flex flex-col gap-2", children: [
|
|
162
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...shimmer, width: "55%", height: "16px", borderRadius: "4px" } }),
|
|
163
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...shimmer, width: "38%", height: "14px", borderRadius: "4px" } })
|
|
164
|
+
] }),
|
|
165
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...shimmer, width: "56px", height: "32px", borderRadius: "4px", flexShrink: 0 } }),
|
|
166
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...shimmer, width: "200px", height: "44px", borderRadius: "8px", flexShrink: 0 } })
|
|
167
|
+
] }),
|
|
168
|
+
i < 2 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-px bg-black/20" })
|
|
169
|
+
] }, i))
|
|
170
|
+
] });
|
|
171
|
+
}
|
|
172
|
+
function ScheduleView({ schedule, dates, selectedIdx, onSelectDate }) {
|
|
173
|
+
const todayMs = (0, import_react.useMemo)(() => {
|
|
174
|
+
const d = /* @__PURE__ */ new Date();
|
|
175
|
+
d.setHours(0, 0, 0, 0);
|
|
176
|
+
return d.getTime();
|
|
177
|
+
}, []);
|
|
178
|
+
const datesWithClasses = (0, import_react.useMemo)(
|
|
179
|
+
() => new Set(dates.map(
|
|
180
|
+
(d, i) => schedule.classes?.some((c) => classRunsOnDate(c, d, schedule.type)) ? i : -1
|
|
181
|
+
).filter((i) => i >= 0)),
|
|
182
|
+
[dates, schedule]
|
|
183
|
+
);
|
|
184
|
+
const selectedDate = dates[selectedIdx];
|
|
185
|
+
const selectedClasses = (0, import_react.useMemo)(
|
|
186
|
+
() => (schedule.classes ?? []).filter((c) => selectedDate && classRunsOnDate(c, selectedDate, schedule.type)),
|
|
187
|
+
[schedule, selectedDate]
|
|
188
|
+
);
|
|
189
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "w-full flex flex-col gap-10", children: [
|
|
190
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "overflow-x-auto w-full", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex min-w-max", children: dates.map((date, i) => {
|
|
191
|
+
const isToday = date.getTime() === todayMs;
|
|
192
|
+
const isSelected = i === selectedIdx;
|
|
193
|
+
const clickable = datesWithClasses.has(i);
|
|
194
|
+
const label = isToday ? "TODAY" : DAY_ABBR[date.getDay()];
|
|
195
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
196
|
+
"div",
|
|
197
|
+
{
|
|
198
|
+
onClick: () => clickable && onSelectDate(i),
|
|
199
|
+
className: `flex-none w-[72px] h-[70px] flex flex-col justify-between items-center ${clickable ? "cursor-pointer opacity-100" : "cursor-default opacity-50"}`,
|
|
200
|
+
children: [
|
|
201
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-body text-base font-normal text-center text-(--color-dark,#200C02)", children: label }),
|
|
202
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
203
|
+
"div",
|
|
204
|
+
{
|
|
205
|
+
className: "w-10 h-10 rounded-full flex items-center justify-center",
|
|
206
|
+
style: { background: isSelected ? "var(--color-primary, #3D312B)" : "transparent" },
|
|
207
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
208
|
+
"span",
|
|
209
|
+
{
|
|
210
|
+
className: "font-body text-xl font-bold text-center tracking-display-tight",
|
|
211
|
+
style: { color: isSelected ? "var(--color-light, #FEFFF0)" : "var(--color-dark, #200C02)" },
|
|
212
|
+
children: date.getDate()
|
|
213
|
+
}
|
|
214
|
+
)
|
|
215
|
+
}
|
|
216
|
+
)
|
|
217
|
+
]
|
|
218
|
+
},
|
|
219
|
+
i
|
|
220
|
+
);
|
|
221
|
+
}) }) }),
|
|
222
|
+
selectedClasses.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.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_runtime.jsx)("div", { className: "flex flex-col", children: selectedClasses.map((cls, i) => {
|
|
223
|
+
const booked = getBookingsOnDate(cls, selectedDate);
|
|
224
|
+
const available = cls.maxParticipants - booked;
|
|
225
|
+
const isFull = available <= 0;
|
|
226
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
227
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-[60px] py-4 box-border", children: [
|
|
228
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-[120px] shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block", children: formatClassTime(cls) }) }),
|
|
229
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex-1 flex flex-col gap-3 min-w-0", children: [
|
|
230
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block truncate", children: cls.name }),
|
|
231
|
+
cls.hostName && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName })
|
|
232
|
+
] }),
|
|
233
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-14 shrink-0 flex flex-col gap-px", children: isFull ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
234
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
235
|
+
available,
|
|
236
|
+
"/",
|
|
237
|
+
cls.maxParticipants
|
|
238
|
+
] }),
|
|
239
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "available" })
|
|
240
|
+
] }) }),
|
|
241
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
242
|
+
"button",
|
|
243
|
+
{
|
|
244
|
+
className: "shrink-0 w-[200px] px-5 py-[10px] flex items-center justify-center rounded-lg font-body text-base font-bold cursor-pointer box-border",
|
|
245
|
+
style: isFull ? {
|
|
246
|
+
background: "transparent",
|
|
247
|
+
border: "1px solid var(--color-dark, #200C02)",
|
|
248
|
+
color: "var(--color-dark, #200C02)"
|
|
249
|
+
} : {
|
|
250
|
+
background: "var(--color-primary, #3D312B)",
|
|
251
|
+
border: "none",
|
|
252
|
+
color: "var(--color-light, #FEFFF0)"
|
|
253
|
+
},
|
|
254
|
+
children: isFull ? "Join Waitlist" : "Book Now"
|
|
255
|
+
}
|
|
256
|
+
)
|
|
257
|
+
] }),
|
|
258
|
+
i < selectedClasses.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-px bg-black/20" })
|
|
259
|
+
] }, cls.id ?? i);
|
|
260
|
+
}) })
|
|
261
|
+
] });
|
|
262
|
+
}
|
|
263
|
+
function CalendarFoldIcon() {
|
|
264
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
265
|
+
"svg",
|
|
266
|
+
{
|
|
267
|
+
width: "16",
|
|
268
|
+
height: "16",
|
|
269
|
+
viewBox: "0 0 24 24",
|
|
270
|
+
fill: "none",
|
|
271
|
+
stroke: "currentColor",
|
|
272
|
+
strokeWidth: "2",
|
|
273
|
+
strokeLinecap: "round",
|
|
274
|
+
strokeLinejoin: "round",
|
|
275
|
+
style: { flexShrink: 0 },
|
|
276
|
+
children: [
|
|
277
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 2v4" }),
|
|
278
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M16 2v4" }),
|
|
279
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 17V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h11Z" }),
|
|
280
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 10h18" }),
|
|
281
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M15 22v-4a2 2 0 0 1 2-2h4" })
|
|
282
|
+
]
|
|
283
|
+
}
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
function SchedulingWidget({ notifyOnConnect = false, initialScheduleId }) {
|
|
287
|
+
const [schedule, setSchedule] = (0, import_react.useState)(null);
|
|
288
|
+
const [loading, setLoading] = (0, import_react.useState)(true);
|
|
289
|
+
const [inEditor, setInEditor] = (0, import_react.useState)(false);
|
|
290
|
+
const [isHovered, setIsHovered] = (0, import_react.useState)(false);
|
|
291
|
+
const switchScheduleIdRef = import_react.default.useRef(null);
|
|
292
|
+
const dates = (0, import_react.useMemo)(() => {
|
|
293
|
+
const today = /* @__PURE__ */ new Date();
|
|
294
|
+
today.setHours(0, 0, 0, 0);
|
|
295
|
+
return Array.from({ length: 14 }, (_, i) => {
|
|
296
|
+
const d = new Date(today);
|
|
297
|
+
d.setDate(today.getDate() + i);
|
|
298
|
+
return d;
|
|
299
|
+
});
|
|
300
|
+
}, []);
|
|
301
|
+
const [selectedIdx, setSelectedIdx] = (0, import_react.useState)(0);
|
|
302
|
+
(0, import_react.useEffect)(() => {
|
|
303
|
+
if (!schedule?.classes) return;
|
|
304
|
+
for (let i = 0; i < dates.length; i++) {
|
|
305
|
+
if (schedule.classes.some((c) => classRunsOnDate(c, dates[i], schedule.type))) {
|
|
306
|
+
setSelectedIdx(i);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}, [schedule, dates]);
|
|
311
|
+
(0, import_react.useEffect)(() => {
|
|
312
|
+
if (typeof window === "undefined") return;
|
|
313
|
+
const isInEditor = window.self !== window.top;
|
|
314
|
+
setInEditor(isInEditor);
|
|
315
|
+
if (isInEditor) {
|
|
316
|
+
const startEmpty = initialScheduleId === null;
|
|
317
|
+
if (startEmpty) setLoading(false);
|
|
318
|
+
let initialized = startEmpty;
|
|
319
|
+
const timer = !startEmpty ? setTimeout(() => {
|
|
320
|
+
if (!initialized) {
|
|
321
|
+
initialized = true;
|
|
322
|
+
setLoading(false);
|
|
323
|
+
}
|
|
324
|
+
}, 5e3) : null;
|
|
325
|
+
const handler = (e) => {
|
|
326
|
+
if (e.data?.type === "ow:clear-scheduling-widget") {
|
|
327
|
+
setSchedule(null);
|
|
328
|
+
setLoading(false);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
if (e.data?.type === "ow:switch-schedule") {
|
|
332
|
+
switchScheduleIdRef.current = e.data.scheduleId ?? null;
|
|
333
|
+
initialized = false;
|
|
334
|
+
setLoading(true);
|
|
335
|
+
window.parent.postMessage({ type: "ow:request-user-schedules" }, "*");
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (e.data?.type !== "ow:user-schedules-response") return;
|
|
339
|
+
if (initialized && switchScheduleIdRef.current === null) return;
|
|
340
|
+
initialized = true;
|
|
341
|
+
if (timer) clearTimeout(timer);
|
|
342
|
+
const schedules = e.data.schedules ?? [];
|
|
343
|
+
const isSwitching = switchScheduleIdRef.current !== null;
|
|
344
|
+
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;
|
|
345
|
+
switchScheduleIdRef.current = null;
|
|
346
|
+
setSchedule(target);
|
|
347
|
+
setLoading(false);
|
|
348
|
+
if (notifyOnConnect && target && !isSwitching) {
|
|
349
|
+
window.parent.postMessage({ type: "ow:schedule-connected", schedule: { id: target.id, name: target.name } }, "*");
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
window.addEventListener("message", handler);
|
|
353
|
+
if (!startEmpty) window.parent.postMessage({ type: "ow:request-user-schedules" }, "*");
|
|
354
|
+
return () => {
|
|
355
|
+
window.removeEventListener("message", handler);
|
|
356
|
+
if (timer) clearTimeout(timer);
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
if (initialScheduleId === null) {
|
|
360
|
+
setLoading(false);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
;
|
|
364
|
+
(async () => {
|
|
365
|
+
try {
|
|
366
|
+
if (initialScheduleId) {
|
|
367
|
+
const res = await fetch(`${API_URL}/api/schedule/id/${initialScheduleId}`);
|
|
368
|
+
const data = await res.json();
|
|
369
|
+
setSchedule(data?.id ? data : null);
|
|
370
|
+
} else {
|
|
371
|
+
const domain = getApiDomain();
|
|
372
|
+
const sitemapRes = await fetch(`${API_URL}/api/schedule/sitemap/${domain}`);
|
|
373
|
+
const slugs = await sitemapRes.json();
|
|
374
|
+
if (!Array.isArray(slugs) || !slugs.length) {
|
|
375
|
+
setLoading(false);
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
const { slug } = [...slugs].sort(
|
|
379
|
+
(a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()
|
|
380
|
+
)[0];
|
|
381
|
+
const res = await fetch(`${API_URL}/api/schedule/${domain}/${slug}`);
|
|
382
|
+
const data = await res.json();
|
|
383
|
+
setSchedule(data?.id ? data : null);
|
|
384
|
+
}
|
|
385
|
+
} catch {
|
|
386
|
+
}
|
|
387
|
+
setLoading(false);
|
|
388
|
+
})();
|
|
389
|
+
}, []);
|
|
390
|
+
const timezoneLabel = schedule?.timezone ? (() => {
|
|
391
|
+
try {
|
|
392
|
+
return buildTimezoneLabel(schedule.timezone);
|
|
393
|
+
} catch {
|
|
394
|
+
return void 0;
|
|
395
|
+
}
|
|
396
|
+
})() : void 0;
|
|
397
|
+
const handleReplaceSchedule = () => {
|
|
398
|
+
setIsHovered(false);
|
|
399
|
+
if (schedule) {
|
|
400
|
+
window.parent.postMessage({ type: "ow:schedule-connected", schedule: { id: schedule.id, name: schedule.name } }, "*");
|
|
401
|
+
} else {
|
|
402
|
+
window.parent.postMessage({ type: "ow:scheduling-not-connected" }, "*");
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
406
|
+
"section",
|
|
407
|
+
{
|
|
408
|
+
"data-ohw-section": "scheduling",
|
|
409
|
+
className: "w-full box-border py-20 px-16 font-body bg-(--color-light,#FEFFF0) relative",
|
|
410
|
+
onMouseEnter: () => inEditor && setIsHovered(true),
|
|
411
|
+
onMouseLeave: () => setIsHovered(false),
|
|
412
|
+
children: [
|
|
413
|
+
inEditor && isHovered && !!schedule && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
414
|
+
"div",
|
|
415
|
+
{
|
|
416
|
+
className: "absolute inset-0 z-10 pointer-events-auto cursor-pointer",
|
|
417
|
+
onClick: handleReplaceSchedule,
|
|
418
|
+
children: [
|
|
419
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0", style: { background: "#0885FE", opacity: 0.18 } }),
|
|
420
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0", style: { boxShadow: "inset 0 0 0 1.5px #0885FE" } }),
|
|
421
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
422
|
+
"div",
|
|
423
|
+
{
|
|
424
|
+
className: "bg-white border border-[#E7E5E4] rounded-md px-3 py-1.5 flex items-center gap-1.5",
|
|
425
|
+
style: {
|
|
426
|
+
fontSize: 14,
|
|
427
|
+
lineHeight: "24px",
|
|
428
|
+
fontFamily: "'Figtree', system-ui, sans-serif",
|
|
429
|
+
fontWeight: 500,
|
|
430
|
+
color: "#0C0A09"
|
|
431
|
+
},
|
|
432
|
+
children: [
|
|
433
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CalendarFoldIcon, {}),
|
|
434
|
+
"Replace schedule"
|
|
435
|
+
]
|
|
436
|
+
}
|
|
437
|
+
) })
|
|
438
|
+
]
|
|
439
|
+
}
|
|
440
|
+
),
|
|
441
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
|
|
442
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
|
|
443
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "font-display text-5xl font-bold text-center m-0 text-(--color-dark,#200C02)", children: schedule?.name ?? "Book an appointment" }),
|
|
444
|
+
schedule?.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
|
|
445
|
+
] }),
|
|
446
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "w-full flex flex-col items-end gap-3", children: [
|
|
447
|
+
timezoneLabel && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-body text-sm font-normal text-(--color-accent,#A89B83)", children: timezoneLabel }),
|
|
448
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-full p-10 box-border", children: loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoadingSkeleton, {}) : !schedule ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EmptyState, { inEditor }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
449
|
+
ScheduleView,
|
|
450
|
+
{
|
|
451
|
+
schedule,
|
|
452
|
+
dates,
|
|
453
|
+
selectedIdx,
|
|
454
|
+
onSelectDate: setSelectedIdx
|
|
455
|
+
}
|
|
456
|
+
) })
|
|
457
|
+
] })
|
|
458
|
+
] })
|
|
459
|
+
]
|
|
460
|
+
}
|
|
461
|
+
);
|
|
462
|
+
}
|
|
44
463
|
|
|
45
464
|
// src/ui/toggle-group.tsx
|
|
46
|
-
var
|
|
465
|
+
var React2 = __toESM(require("react"), 1);
|
|
47
466
|
|
|
48
467
|
// node_modules/clsx/dist/clsx.mjs
|
|
49
468
|
function r(e) {
|
|
@@ -3363,7 +3782,7 @@ var cva = (base, config) => (props) => {
|
|
|
3363
3782
|
|
|
3364
3783
|
// src/ui/toggle.tsx
|
|
3365
3784
|
var import_radix_ui = require("radix-ui");
|
|
3366
|
-
var
|
|
3785
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
3367
3786
|
var toggleVariants = cva(
|
|
3368
3787
|
"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",
|
|
3369
3788
|
{
|
|
@@ -3390,7 +3809,7 @@ function Toggle({
|
|
|
3390
3809
|
size,
|
|
3391
3810
|
...props
|
|
3392
3811
|
}) {
|
|
3393
|
-
return /* @__PURE__ */ (0,
|
|
3812
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
3394
3813
|
import_radix_ui.Toggle.Root,
|
|
3395
3814
|
{
|
|
3396
3815
|
"data-slot": "toggle",
|
|
@@ -3401,8 +3820,8 @@ function Toggle({
|
|
|
3401
3820
|
}
|
|
3402
3821
|
|
|
3403
3822
|
// src/ui/toggle-group.tsx
|
|
3404
|
-
var
|
|
3405
|
-
var ToggleGroupContext =
|
|
3823
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
3824
|
+
var ToggleGroupContext = React2.createContext({
|
|
3406
3825
|
value: "",
|
|
3407
3826
|
onValueChange: () => {
|
|
3408
3827
|
}
|
|
@@ -3414,13 +3833,13 @@ function ToggleGroup({
|
|
|
3414
3833
|
children,
|
|
3415
3834
|
...props
|
|
3416
3835
|
}) {
|
|
3417
|
-
return /* @__PURE__ */ (0,
|
|
3836
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3418
3837
|
"div",
|
|
3419
3838
|
{
|
|
3420
3839
|
role: "group",
|
|
3421
3840
|
className: cn("flex items-center gap-1 p-1 bg-muted rounded-md", className),
|
|
3422
3841
|
...props,
|
|
3423
|
-
children: /* @__PURE__ */ (0,
|
|
3842
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleGroupContext.Provider, { value: { value, onValueChange }, children })
|
|
3424
3843
|
}
|
|
3425
3844
|
);
|
|
3426
3845
|
}
|
|
@@ -3430,8 +3849,8 @@ function ToggleGroupItem({
|
|
|
3430
3849
|
children,
|
|
3431
3850
|
...props
|
|
3432
3851
|
}) {
|
|
3433
|
-
const { value: groupValue, onValueChange } =
|
|
3434
|
-
return /* @__PURE__ */ (0,
|
|
3852
|
+
const { value: groupValue, onValueChange } = React2.useContext(ToggleGroupContext);
|
|
3853
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3435
3854
|
Toggle,
|
|
3436
3855
|
{
|
|
3437
3856
|
pressed: groupValue === value,
|
|
@@ -3472,8 +3891,30 @@ function isEditSessionActive() {
|
|
|
3472
3891
|
return new URLSearchParams(q).get("mode") === "edit";
|
|
3473
3892
|
}
|
|
3474
3893
|
|
|
3894
|
+
// src/ui/badge.tsx
|
|
3895
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
3896
|
+
var badgeVariants = cva(
|
|
3897
|
+
"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",
|
|
3898
|
+
{
|
|
3899
|
+
variants: {
|
|
3900
|
+
variant: {
|
|
3901
|
+
default: "border-transparent bg-primary text-primary-foreground",
|
|
3902
|
+
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
3903
|
+
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
3904
|
+
outline: "text-foreground"
|
|
3905
|
+
}
|
|
3906
|
+
},
|
|
3907
|
+
defaultVariants: {
|
|
3908
|
+
variant: "default"
|
|
3909
|
+
}
|
|
3910
|
+
}
|
|
3911
|
+
);
|
|
3912
|
+
function Badge({ className, variant, ...props }) {
|
|
3913
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
3914
|
+
}
|
|
3915
|
+
|
|
3475
3916
|
// src/OhhwellsBridge.tsx
|
|
3476
|
-
var
|
|
3917
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
3477
3918
|
var PRIMARY = "#0885FE";
|
|
3478
3919
|
var IMAGE_FADE_MS = 300;
|
|
3479
3920
|
function runOpacityFade(el, onDone) {
|
|
@@ -3524,6 +3965,41 @@ function fadeInBgImage(el, url, onReady) {
|
|
|
3524
3965
|
if (!prevPos || prevPos === "static") el.style.position = prevPos;
|
|
3525
3966
|
});
|
|
3526
3967
|
}
|
|
3968
|
+
function getSectionsTracker() {
|
|
3969
|
+
let el = document.querySelector("[data-ohw-sections-tracker]");
|
|
3970
|
+
if (!el) {
|
|
3971
|
+
el = document.createElement("div");
|
|
3972
|
+
el.setAttribute("data-ohw-sections-tracker", "");
|
|
3973
|
+
el.style.display = "none";
|
|
3974
|
+
document.body.appendChild(el);
|
|
3975
|
+
}
|
|
3976
|
+
return el;
|
|
3977
|
+
}
|
|
3978
|
+
function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId) {
|
|
3979
|
+
const anchor = document.querySelector(`[data-ohw-section="${insertAfter}"]`);
|
|
3980
|
+
if (!anchor) return false;
|
|
3981
|
+
if (anchor.nextElementSibling?.dataset.ohwSectionContainer) return false;
|
|
3982
|
+
const container = document.createElement("div");
|
|
3983
|
+
container.dataset.ohwSectionContainer = "scheduling";
|
|
3984
|
+
anchor.insertAdjacentElement("afterend", container);
|
|
3985
|
+
(0, import_client.createRoot)(container).render(/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SchedulingWidget, { notifyOnConnect, initialScheduleId: scheduleId }));
|
|
3986
|
+
const tracker = getSectionsTracker();
|
|
3987
|
+
let sections = [];
|
|
3988
|
+
try {
|
|
3989
|
+
sections = JSON.parse(tracker.textContent || "[]");
|
|
3990
|
+
} catch {
|
|
3991
|
+
}
|
|
3992
|
+
if (!sections.find((s) => s.type === "scheduling" && s.insertAfter === insertAfter)) {
|
|
3993
|
+
sections.push({
|
|
3994
|
+
type: "scheduling",
|
|
3995
|
+
insertAfter,
|
|
3996
|
+
pagePath: window.location.pathname,
|
|
3997
|
+
...scheduleId ? { scheduleId } : {}
|
|
3998
|
+
});
|
|
3999
|
+
tracker.textContent = JSON.stringify(sections);
|
|
4000
|
+
}
|
|
4001
|
+
return true;
|
|
4002
|
+
}
|
|
3527
4003
|
function collectEditableNodes() {
|
|
3528
4004
|
return Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
|
|
3529
4005
|
if (el.dataset.ohwEditable === "image") {
|
|
@@ -3681,7 +4157,7 @@ var TOOLBAR_GROUPS = [
|
|
|
3681
4157
|
];
|
|
3682
4158
|
function GlowFrame({ rect, elRef }) {
|
|
3683
4159
|
const GAP = 6;
|
|
3684
|
-
return /* @__PURE__ */ (0,
|
|
4160
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3685
4161
|
"div",
|
|
3686
4162
|
{
|
|
3687
4163
|
ref: elRef,
|
|
@@ -3732,7 +4208,7 @@ function FloatingToolbar({
|
|
|
3732
4208
|
activeCommands
|
|
3733
4209
|
}) {
|
|
3734
4210
|
const { top, left, transform } = calcToolbarPos(rect, parentScroll);
|
|
3735
|
-
return /* @__PURE__ */ (0,
|
|
4211
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3736
4212
|
"div",
|
|
3737
4213
|
{
|
|
3738
4214
|
ref: elRef,
|
|
@@ -3755,11 +4231,11 @@ function FloatingToolbar({
|
|
|
3755
4231
|
pointerEvents: "auto",
|
|
3756
4232
|
whiteSpace: "nowrap"
|
|
3757
4233
|
},
|
|
3758
|
-
children: TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0,
|
|
3759
|
-
gi > 0 && /* @__PURE__ */ (0,
|
|
4234
|
+
children: TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react2.default.Fragment, { children: [
|
|
4235
|
+
gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
|
|
3760
4236
|
btns.map((btn) => {
|
|
3761
4237
|
const isActive = activeCommands.has(btn.cmd);
|
|
3762
|
-
return /* @__PURE__ */ (0,
|
|
4238
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3763
4239
|
"button",
|
|
3764
4240
|
{
|
|
3765
4241
|
title: btn.title,
|
|
@@ -3785,7 +4261,7 @@ function FloatingToolbar({
|
|
|
3785
4261
|
flexShrink: 0,
|
|
3786
4262
|
padding: 6
|
|
3787
4263
|
},
|
|
3788
|
-
children: /* @__PURE__ */ (0,
|
|
4264
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3789
4265
|
"svg",
|
|
3790
4266
|
{
|
|
3791
4267
|
width: "16",
|
|
@@ -3818,7 +4294,7 @@ function StateToggle({
|
|
|
3818
4294
|
states,
|
|
3819
4295
|
onStateChange
|
|
3820
4296
|
}) {
|
|
3821
|
-
return /* @__PURE__ */ (0,
|
|
4297
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3822
4298
|
ToggleGroup,
|
|
3823
4299
|
{
|
|
3824
4300
|
"data-ohw-state-toggle": "",
|
|
@@ -3832,7 +4308,7 @@ function StateToggle({
|
|
|
3832
4308
|
left: rect.right - 8,
|
|
3833
4309
|
transform: "translateX(-100%)"
|
|
3834
4310
|
},
|
|
3835
|
-
children: states.map((state) => /* @__PURE__ */ (0,
|
|
4311
|
+
children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
3836
4312
|
}
|
|
3837
4313
|
);
|
|
3838
4314
|
}
|
|
@@ -3842,8 +4318,8 @@ function OhhwellsBridge() {
|
|
|
3842
4318
|
const router = (0, import_navigation.useRouter)();
|
|
3843
4319
|
const searchParams = (0, import_navigation.useSearchParams)();
|
|
3844
4320
|
const isEditMode = isEditSessionActive();
|
|
3845
|
-
const [bridgeRoot, setBridgeRoot] = (0,
|
|
3846
|
-
(0,
|
|
4321
|
+
const [bridgeRoot, setBridgeRoot] = (0, import_react2.useState)(null);
|
|
4322
|
+
(0, import_react2.useEffect)(() => {
|
|
3847
4323
|
const figtreeFontId = "ohw-figtree-font";
|
|
3848
4324
|
if (!document.getElementById(figtreeFontId)) {
|
|
3849
4325
|
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
@@ -3871,37 +4347,39 @@ function OhhwellsBridge() {
|
|
|
3871
4347
|
const parts = window.location.hostname.split(".");
|
|
3872
4348
|
return parts.length >= 3 && parts[0] !== "www" ? parts[0] : "";
|
|
3873
4349
|
})();
|
|
3874
|
-
const postToParent = (0,
|
|
4350
|
+
const postToParent = (0, import_react2.useCallback)((data) => {
|
|
3875
4351
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
3876
4352
|
window.parent.postMessage(data, "*");
|
|
3877
4353
|
}
|
|
3878
4354
|
}, []);
|
|
3879
|
-
const [fetchState, setFetchState] = (0,
|
|
3880
|
-
const autoSaveTimers = (0,
|
|
3881
|
-
const activeElRef = (0,
|
|
3882
|
-
const originalContentRef = (0,
|
|
3883
|
-
const activeStateElRef = (0,
|
|
3884
|
-
const parentScrollRef = (0,
|
|
3885
|
-
const toolbarElRef = (0,
|
|
3886
|
-
const glowElRef = (0,
|
|
3887
|
-
const hoveredImageRef = (0,
|
|
3888
|
-
const hoveredImageHasTextOverlapRef = (0,
|
|
3889
|
-
const
|
|
3890
|
-
const
|
|
3891
|
-
const
|
|
3892
|
-
const
|
|
4355
|
+
const [fetchState, setFetchState] = (0, import_react2.useState)("idle");
|
|
4356
|
+
const autoSaveTimers = (0, import_react2.useRef)(/* @__PURE__ */ new Map());
|
|
4357
|
+
const activeElRef = (0, import_react2.useRef)(null);
|
|
4358
|
+
const originalContentRef = (0, import_react2.useRef)(null);
|
|
4359
|
+
const activeStateElRef = (0, import_react2.useRef)(null);
|
|
4360
|
+
const parentScrollRef = (0, import_react2.useRef)(null);
|
|
4361
|
+
const toolbarElRef = (0, import_react2.useRef)(null);
|
|
4362
|
+
const glowElRef = (0, import_react2.useRef)(null);
|
|
4363
|
+
const hoveredImageRef = (0, import_react2.useRef)(null);
|
|
4364
|
+
const hoveredImageHasTextOverlapRef = (0, import_react2.useRef)(false);
|
|
4365
|
+
const hoveredGapRef = (0, import_react2.useRef)(null);
|
|
4366
|
+
const imageUnhoverTimerRef = (0, import_react2.useRef)(null);
|
|
4367
|
+
const imageShowTimerRef = (0, import_react2.useRef)(null);
|
|
4368
|
+
const editStylesRef = (0, import_react2.useRef)(null);
|
|
4369
|
+
const activateRef = (0, import_react2.useRef)(() => {
|
|
3893
4370
|
});
|
|
3894
|
-
const deactivateRef = (0,
|
|
4371
|
+
const deactivateRef = (0, import_react2.useRef)(() => {
|
|
3895
4372
|
});
|
|
3896
|
-
const refreshActiveCommandsRef = (0,
|
|
4373
|
+
const refreshActiveCommandsRef = (0, import_react2.useRef)(() => {
|
|
3897
4374
|
});
|
|
3898
|
-
const postToParentRef = (0,
|
|
4375
|
+
const postToParentRef = (0, import_react2.useRef)(postToParent);
|
|
3899
4376
|
postToParentRef.current = postToParent;
|
|
3900
|
-
const [toolbarRect, setToolbarRect] = (0,
|
|
3901
|
-
const [toggleState, setToggleState] = (0,
|
|
3902
|
-
const [maxBadge, setMaxBadge] = (0,
|
|
3903
|
-
const [activeCommands, setActiveCommands] = (0,
|
|
3904
|
-
(0,
|
|
4377
|
+
const [toolbarRect, setToolbarRect] = (0, import_react2.useState)(null);
|
|
4378
|
+
const [toggleState, setToggleState] = (0, import_react2.useState)(null);
|
|
4379
|
+
const [maxBadge, setMaxBadge] = (0, import_react2.useState)(null);
|
|
4380
|
+
const [activeCommands, setActiveCommands] = (0, import_react2.useState)(/* @__PURE__ */ new Set());
|
|
4381
|
+
const [sectionGap, setSectionGap] = (0, import_react2.useState)(null);
|
|
4382
|
+
(0, import_react2.useEffect)(() => {
|
|
3905
4383
|
const update = () => {
|
|
3906
4384
|
const el = activeElRef.current;
|
|
3907
4385
|
if (el) setToolbarRect(el.getBoundingClientRect());
|
|
@@ -3909,6 +4387,12 @@ function OhhwellsBridge() {
|
|
|
3909
4387
|
if (!prev || !activeStateElRef.current) return prev;
|
|
3910
4388
|
return { ...prev, rect: activeStateElRef.current.getBoundingClientRect() };
|
|
3911
4389
|
});
|
|
4390
|
+
setSectionGap((prev) => {
|
|
4391
|
+
if (!prev) return prev;
|
|
4392
|
+
const anchor = document.querySelector(`[data-ohw-section="${prev.insertAfter}"]`);
|
|
4393
|
+
if (!anchor) return prev;
|
|
4394
|
+
return { ...prev, y: anchor.getBoundingClientRect().bottom };
|
|
4395
|
+
});
|
|
3912
4396
|
};
|
|
3913
4397
|
const vvp = window.visualViewport;
|
|
3914
4398
|
if (!vvp) return;
|
|
@@ -3919,10 +4403,10 @@ function OhhwellsBridge() {
|
|
|
3919
4403
|
vvp.removeEventListener("resize", update);
|
|
3920
4404
|
};
|
|
3921
4405
|
}, []);
|
|
3922
|
-
const refreshStateRules = (0,
|
|
4406
|
+
const refreshStateRules = (0, import_react2.useCallback)(() => {
|
|
3923
4407
|
editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
|
|
3924
4408
|
}, []);
|
|
3925
|
-
const deactivate = (0,
|
|
4409
|
+
const deactivate = (0, import_react2.useCallback)(() => {
|
|
3926
4410
|
const el = activeElRef.current;
|
|
3927
4411
|
if (!el) return;
|
|
3928
4412
|
const key = el.dataset.ohwKey;
|
|
@@ -3947,7 +4431,7 @@ function OhhwellsBridge() {
|
|
|
3947
4431
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
3948
4432
|
postToParent({ type: "ow:exit-edit" });
|
|
3949
4433
|
}, [postToParent]);
|
|
3950
|
-
const activate = (0,
|
|
4434
|
+
const activate = (0, import_react2.useCallback)((el) => {
|
|
3951
4435
|
if (activeElRef.current === el) return;
|
|
3952
4436
|
deactivate();
|
|
3953
4437
|
if (hoveredImageRef.current) {
|
|
@@ -3965,14 +4449,27 @@ function OhhwellsBridge() {
|
|
|
3965
4449
|
}, [deactivate, postToParent]);
|
|
3966
4450
|
activateRef.current = activate;
|
|
3967
4451
|
deactivateRef.current = deactivate;
|
|
3968
|
-
(0,
|
|
4452
|
+
(0, import_react2.useLayoutEffect)(() => {
|
|
3969
4453
|
if (!subdomain || isEditMode) {
|
|
3970
4454
|
setFetchState("done");
|
|
3971
4455
|
return;
|
|
3972
4456
|
}
|
|
3973
4457
|
const applyContent = (content) => {
|
|
3974
4458
|
const imageLoads = [];
|
|
4459
|
+
document.querySelectorAll("[data-ohw-section-container]").forEach((el) => el.remove());
|
|
4460
|
+
if (content["__ohw_sections"]) {
|
|
4461
|
+
try {
|
|
4462
|
+
const entries = JSON.parse(content["__ohw_sections"]);
|
|
4463
|
+
const currentPath = window.location.pathname;
|
|
4464
|
+
entries.forEach(({ type, insertAfter, scheduleId, pagePath }) => {
|
|
4465
|
+
if (pagePath && pagePath !== currentPath) return;
|
|
4466
|
+
if (type === "scheduling") mountSchedulingWidget(insertAfter, false, scheduleId);
|
|
4467
|
+
});
|
|
4468
|
+
} catch {
|
|
4469
|
+
}
|
|
4470
|
+
}
|
|
3975
4471
|
for (const [key, val] of Object.entries(content)) {
|
|
4472
|
+
if (key === "__ohw_sections") continue;
|
|
3976
4473
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
3977
4474
|
if (el.dataset.ohwEditable === "image") {
|
|
3978
4475
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -4015,12 +4512,24 @@ function OhhwellsBridge() {
|
|
|
4015
4512
|
cancelled = true;
|
|
4016
4513
|
};
|
|
4017
4514
|
}, [subdomain, isEditMode, pathname]);
|
|
4018
|
-
(0,
|
|
4515
|
+
(0, import_react2.useEffect)(() => {
|
|
4019
4516
|
if (!subdomain || isEditMode) return;
|
|
4020
4517
|
const applyFromCache = () => {
|
|
4021
4518
|
const content = contentCache.get(subdomain);
|
|
4022
4519
|
if (!content) return;
|
|
4520
|
+
if (content["__ohw_sections"]) {
|
|
4521
|
+
try {
|
|
4522
|
+
const entries = JSON.parse(content["__ohw_sections"]);
|
|
4523
|
+
const currentPath = window.location.pathname;
|
|
4524
|
+
entries.forEach(({ type, insertAfter, scheduleId, pagePath }) => {
|
|
4525
|
+
if (pagePath && pagePath !== currentPath) return;
|
|
4526
|
+
if (type === "scheduling") mountSchedulingWidget(insertAfter, false, scheduleId);
|
|
4527
|
+
});
|
|
4528
|
+
} catch {
|
|
4529
|
+
}
|
|
4530
|
+
}
|
|
4023
4531
|
for (const [key, val] of Object.entries(content)) {
|
|
4532
|
+
if (key === "__ohw_sections") continue;
|
|
4024
4533
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
4025
4534
|
if (el.dataset.ohwEditable === "image") {
|
|
4026
4535
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -4039,16 +4548,16 @@ function OhhwellsBridge() {
|
|
|
4039
4548
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
4040
4549
|
return () => observer.disconnect();
|
|
4041
4550
|
}, [subdomain, isEditMode]);
|
|
4042
|
-
(0,
|
|
4551
|
+
(0, import_react2.useLayoutEffect)(() => {
|
|
4043
4552
|
const el = document.getElementById("ohw-loader");
|
|
4044
4553
|
if (!el) return;
|
|
4045
4554
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
4046
4555
|
el.style.display = visible ? "flex" : "none";
|
|
4047
4556
|
}, [subdomain, fetchState]);
|
|
4048
|
-
(0,
|
|
4557
|
+
(0, import_react2.useEffect)(() => {
|
|
4049
4558
|
postToParent({ type: "ow:navigation", path: pathname });
|
|
4050
4559
|
}, [pathname, postToParent]);
|
|
4051
|
-
(0,
|
|
4560
|
+
(0, import_react2.useEffect)(() => {
|
|
4052
4561
|
if (!isEditMode) return;
|
|
4053
4562
|
const measure = () => {
|
|
4054
4563
|
const h = document.body.scrollHeight;
|
|
@@ -4072,7 +4581,7 @@ function OhhwellsBridge() {
|
|
|
4072
4581
|
window.removeEventListener("resize", handleResize);
|
|
4073
4582
|
};
|
|
4074
4583
|
}, [pathname, isEditMode, postToParent]);
|
|
4075
|
-
(0,
|
|
4584
|
+
(0, import_react2.useEffect)(() => {
|
|
4076
4585
|
if (!subdomainFromQuery || isEditMode) return;
|
|
4077
4586
|
const handleClick = (e) => {
|
|
4078
4587
|
const anchor = e.target.closest("a");
|
|
@@ -4088,7 +4597,7 @@ function OhhwellsBridge() {
|
|
|
4088
4597
|
document.addEventListener("click", handleClick, true);
|
|
4089
4598
|
return () => document.removeEventListener("click", handleClick, true);
|
|
4090
4599
|
}, [subdomainFromQuery, isEditMode, router]);
|
|
4091
|
-
(0,
|
|
4600
|
+
(0, import_react2.useEffect)(() => {
|
|
4092
4601
|
if (!isEditMode) {
|
|
4093
4602
|
editStylesRef.current?.base.remove();
|
|
4094
4603
|
editStylesRef.current?.forceHover.remove();
|
|
@@ -4348,6 +4857,15 @@ function OhhwellsBridge() {
|
|
|
4348
4857
|
textEditable.setAttribute("data-ohw-hovered", "");
|
|
4349
4858
|
return;
|
|
4350
4859
|
}
|
|
4860
|
+
if (hoveredGapRef.current) {
|
|
4861
|
+
if (hoveredImageRef.current) {
|
|
4862
|
+
hoveredImageRef.current = null;
|
|
4863
|
+
resumeAnimTracks();
|
|
4864
|
+
postToParentRef.current({ type: "ow:image-unhover" });
|
|
4865
|
+
}
|
|
4866
|
+
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
4867
|
+
return;
|
|
4868
|
+
}
|
|
4351
4869
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
4352
4870
|
if (imgEl !== hoveredImageRef.current || hoveredImageHasTextOverlapRef.current) {
|
|
4353
4871
|
hoveredImageRef.current = imgEl;
|
|
@@ -4413,8 +4931,30 @@ function OhhwellsBridge() {
|
|
|
4413
4931
|
}
|
|
4414
4932
|
}
|
|
4415
4933
|
};
|
|
4934
|
+
const probeSectionGapAt = (clientX, clientY, fromParentViewport = false) => {
|
|
4935
|
+
const { y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
4936
|
+
const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
|
|
4937
|
+
const ZONE = 20;
|
|
4938
|
+
for (let i = 0; i < sections.length; i++) {
|
|
4939
|
+
const a = sections[i];
|
|
4940
|
+
const b = sections[i + 1] ?? null;
|
|
4941
|
+
const boundaryY = a.getBoundingClientRect().bottom;
|
|
4942
|
+
if (Math.abs(y - boundaryY) <= ZONE) {
|
|
4943
|
+
const insertAfter = a.dataset.ohwSection ?? "";
|
|
4944
|
+
const insertBefore = b?.dataset.ohwSection ?? null;
|
|
4945
|
+
hoveredGapRef.current = { insertAfter, insertBefore };
|
|
4946
|
+
setSectionGap({ insertAfter, insertBefore, y: boundaryY });
|
|
4947
|
+
return;
|
|
4948
|
+
}
|
|
4949
|
+
}
|
|
4950
|
+
if (hoveredGapRef.current) {
|
|
4951
|
+
hoveredGapRef.current = null;
|
|
4952
|
+
setSectionGap(null);
|
|
4953
|
+
}
|
|
4954
|
+
};
|
|
4416
4955
|
const handleMouseMove = (e) => {
|
|
4417
4956
|
const { clientX, clientY } = e;
|
|
4957
|
+
probeSectionGapAt(clientX, clientY);
|
|
4418
4958
|
probeImageAt(clientX, clientY);
|
|
4419
4959
|
probeHoverCardsAt(clientX, clientY);
|
|
4420
4960
|
};
|
|
@@ -4422,6 +4962,7 @@ function OhhwellsBridge() {
|
|
|
4422
4962
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
4423
4963
|
const { clientX, clientY } = e.data;
|
|
4424
4964
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
4965
|
+
probeSectionGapAt(clientX, clientY);
|
|
4425
4966
|
probeImageAt(clientX, clientY);
|
|
4426
4967
|
probeHoverCardsAt(clientX, clientY);
|
|
4427
4968
|
};
|
|
@@ -4580,6 +5121,18 @@ function OhhwellsBridge() {
|
|
|
4580
5121
|
const content = e.data.content;
|
|
4581
5122
|
if (!content) return;
|
|
4582
5123
|
for (const [key, val] of Object.entries(content)) {
|
|
5124
|
+
if (key === "__ohw_sections") {
|
|
5125
|
+
try {
|
|
5126
|
+
const entries = JSON.parse(val);
|
|
5127
|
+
const tracker = getSectionsTracker();
|
|
5128
|
+
tracker.textContent = val;
|
|
5129
|
+
entries.forEach(({ type, insertAfter, scheduleId }) => {
|
|
5130
|
+
if (type === "scheduling") mountSchedulingWidget(insertAfter, false, scheduleId);
|
|
5131
|
+
});
|
|
5132
|
+
} catch {
|
|
5133
|
+
}
|
|
5134
|
+
continue;
|
|
5135
|
+
}
|
|
4583
5136
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
4584
5137
|
if (el.dataset.ohwEditable === "image") {
|
|
4585
5138
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -4634,7 +5187,71 @@ function OhhwellsBridge() {
|
|
|
4634
5187
|
};
|
|
4635
5188
|
const handleSave = (e) => {
|
|
4636
5189
|
if (e.data?.type !== "ow:save") return;
|
|
4637
|
-
|
|
5190
|
+
const nodes = collectEditableNodes();
|
|
5191
|
+
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
5192
|
+
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
5193
|
+
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
5194
|
+
};
|
|
5195
|
+
const handleInsertSection = (e) => {
|
|
5196
|
+
if (e.data?.type !== "ow:insert-section") return;
|
|
5197
|
+
const { widgetType, insertAfter } = e.data;
|
|
5198
|
+
if (widgetType !== "scheduling") return;
|
|
5199
|
+
const inserted = mountSchedulingWidget(insertAfter, true);
|
|
5200
|
+
if (inserted) {
|
|
5201
|
+
const tracker = getSectionsTracker();
|
|
5202
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
|
|
5203
|
+
const h = document.documentElement.scrollHeight;
|
|
5204
|
+
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
5205
|
+
}
|
|
5206
|
+
};
|
|
5207
|
+
const handleSwitchSchedule = (e) => {
|
|
5208
|
+
if (e.data?.type !== "ow:switch-schedule") return;
|
|
5209
|
+
const scheduleId = e.data.scheduleId;
|
|
5210
|
+
if (!scheduleId) return;
|
|
5211
|
+
const tracker = getSectionsTracker();
|
|
5212
|
+
let sections = [];
|
|
5213
|
+
try {
|
|
5214
|
+
sections = JSON.parse(tracker.textContent || "[]");
|
|
5215
|
+
} catch {
|
|
5216
|
+
}
|
|
5217
|
+
const currentPath = window.location.pathname;
|
|
5218
|
+
const updated = sections.map(
|
|
5219
|
+
(s) => s.type === "scheduling" && s.pagePath === currentPath ? { ...s, scheduleId } : s
|
|
5220
|
+
);
|
|
5221
|
+
tracker.textContent = JSON.stringify(updated);
|
|
5222
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
|
|
5223
|
+
};
|
|
5224
|
+
const handleClearSchedulingWidget = (e) => {
|
|
5225
|
+
if (e.data?.type !== "ow:clear-scheduling-widget") return;
|
|
5226
|
+
const tracker = getSectionsTracker();
|
|
5227
|
+
let sections = [];
|
|
5228
|
+
try {
|
|
5229
|
+
sections = JSON.parse(tracker.textContent || "[]");
|
|
5230
|
+
} catch {
|
|
5231
|
+
}
|
|
5232
|
+
const currentPath = window.location.pathname;
|
|
5233
|
+
const updated = sections.map(
|
|
5234
|
+
(s) => s.type === "scheduling" && s.pagePath === currentPath ? { ...s, scheduleId: null } : s
|
|
5235
|
+
);
|
|
5236
|
+
tracker.textContent = JSON.stringify(updated);
|
|
5237
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
|
|
5238
|
+
};
|
|
5239
|
+
const handleRemoveSchedulingSection = (e) => {
|
|
5240
|
+
if (e.data?.type !== "ow:remove-scheduling-section") return;
|
|
5241
|
+
const els = document.querySelectorAll('[data-ohw-section="scheduling"]');
|
|
5242
|
+
els.forEach((el) => el.parentElement?.removeChild(el));
|
|
5243
|
+
const tracker = getSectionsTracker();
|
|
5244
|
+
let sections = [];
|
|
5245
|
+
try {
|
|
5246
|
+
sections = JSON.parse(tracker.textContent || "[]");
|
|
5247
|
+
} catch {
|
|
5248
|
+
}
|
|
5249
|
+
const currentPath = window.location.pathname;
|
|
5250
|
+
const updated = sections.filter((s) => !(s.type === "scheduling" && s.pagePath === currentPath));
|
|
5251
|
+
tracker.textContent = JSON.stringify(updated);
|
|
5252
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
|
|
5253
|
+
const h = document.documentElement.scrollHeight;
|
|
5254
|
+
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
4638
5255
|
};
|
|
4639
5256
|
const handleSelectionChange = () => {
|
|
4640
5257
|
if (!activeElRef.current) return;
|
|
@@ -4739,6 +5356,10 @@ function OhhwellsBridge() {
|
|
|
4739
5356
|
deactivateRef.current();
|
|
4740
5357
|
};
|
|
4741
5358
|
window.addEventListener("message", handleSave);
|
|
5359
|
+
window.addEventListener("message", handleInsertSection);
|
|
5360
|
+
window.addEventListener("message", handleSwitchSchedule);
|
|
5361
|
+
window.addEventListener("message", handleClearSchedulingWidget);
|
|
5362
|
+
window.addEventListener("message", handleRemoveSchedulingSection);
|
|
4742
5363
|
window.addEventListener("message", handleImageUrl);
|
|
4743
5364
|
window.addEventListener("message", handleAnimLock);
|
|
4744
5365
|
window.addEventListener("message", handleCanvasHeight);
|
|
@@ -4773,6 +5394,10 @@ function OhhwellsBridge() {
|
|
|
4773
5394
|
document.removeEventListener("selectionchange", handleSelectionChange);
|
|
4774
5395
|
window.removeEventListener("scroll", handleScroll, true);
|
|
4775
5396
|
window.removeEventListener("message", handleSave);
|
|
5397
|
+
window.removeEventListener("message", handleInsertSection);
|
|
5398
|
+
window.removeEventListener("message", handleSwitchSchedule);
|
|
5399
|
+
window.removeEventListener("message", handleClearSchedulingWidget);
|
|
5400
|
+
window.removeEventListener("message", handleRemoveSchedulingSection);
|
|
4776
5401
|
window.removeEventListener("message", handleImageUrl);
|
|
4777
5402
|
window.removeEventListener("message", handleAnimLock);
|
|
4778
5403
|
window.removeEventListener("message", handleCanvasHeight);
|
|
@@ -4787,7 +5412,7 @@ function OhhwellsBridge() {
|
|
|
4787
5412
|
if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
|
|
4788
5413
|
};
|
|
4789
5414
|
}, [isEditMode, refreshStateRules]);
|
|
4790
|
-
(0,
|
|
5415
|
+
(0, import_react2.useEffect)(() => {
|
|
4791
5416
|
if (!isEditMode) return;
|
|
4792
5417
|
document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
|
|
4793
5418
|
el.removeAttribute("data-ohw-active-state");
|
|
@@ -4809,13 +5434,13 @@ function OhhwellsBridge() {
|
|
|
4809
5434
|
clearTimeout(timer);
|
|
4810
5435
|
};
|
|
4811
5436
|
}, [pathname, isEditMode, refreshStateRules, postToParent]);
|
|
4812
|
-
const handleCommand = (0,
|
|
5437
|
+
const handleCommand = (0, import_react2.useCallback)((cmd) => {
|
|
4813
5438
|
document.execCommand(cmd, false);
|
|
4814
5439
|
activeElRef.current?.focus();
|
|
4815
5440
|
if (activeElRef.current) setToolbarRect(activeElRef.current.getBoundingClientRect());
|
|
4816
5441
|
refreshActiveCommandsRef.current();
|
|
4817
5442
|
}, []);
|
|
4818
|
-
const handleStateChange = (0,
|
|
5443
|
+
const handleStateChange = (0, import_react2.useCallback)((state) => {
|
|
4819
5444
|
if (!activeStateElRef.current) return;
|
|
4820
5445
|
const el = activeStateElRef.current;
|
|
4821
5446
|
if (state === "Default") {
|
|
@@ -4829,12 +5454,12 @@ function OhhwellsBridge() {
|
|
|
4829
5454
|
setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
|
|
4830
5455
|
}, [deactivate]);
|
|
4831
5456
|
return bridgeRoot ? (0, import_react_dom.createPortal)(
|
|
4832
|
-
/* @__PURE__ */ (0,
|
|
4833
|
-
toolbarRect && /* @__PURE__ */ (0,
|
|
4834
|
-
/* @__PURE__ */ (0,
|
|
4835
|
-
/* @__PURE__ */ (0,
|
|
5457
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
5458
|
+
toolbarRect && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
5459
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GlowFrame, { rect: toolbarRect, elRef: glowElRef }),
|
|
5460
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FloatingToolbar, { rect: toolbarRect, parentScroll: parentScrollRef.current, elRef: toolbarElRef, onCommand: handleCommand, activeCommands })
|
|
4836
5461
|
] }),
|
|
4837
|
-
maxBadge && /* @__PURE__ */ (0,
|
|
5462
|
+
maxBadge && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
4838
5463
|
"div",
|
|
4839
5464
|
{
|
|
4840
5465
|
"data-ohw-max-badge": "",
|
|
@@ -4860,7 +5485,7 @@ function OhhwellsBridge() {
|
|
|
4860
5485
|
]
|
|
4861
5486
|
}
|
|
4862
5487
|
),
|
|
4863
|
-
toggleState && /* @__PURE__ */ (0,
|
|
5488
|
+
toggleState && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
4864
5489
|
StateToggle,
|
|
4865
5490
|
{
|
|
4866
5491
|
rect: toggleState.rect,
|
|
@@ -4868,6 +5493,31 @@ function OhhwellsBridge() {
|
|
|
4868
5493
|
states: toggleState.states,
|
|
4869
5494
|
onStateChange: handleStateChange
|
|
4870
5495
|
}
|
|
5496
|
+
),
|
|
5497
|
+
sectionGap && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
5498
|
+
"div",
|
|
5499
|
+
{
|
|
5500
|
+
"data-ohw-section-insert-line": "",
|
|
5501
|
+
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
5502
|
+
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
5503
|
+
children: [
|
|
5504
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
5505
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
5506
|
+
Badge,
|
|
5507
|
+
{
|
|
5508
|
+
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",
|
|
5509
|
+
onClick: () => {
|
|
5510
|
+
window.parent.postMessage(
|
|
5511
|
+
{ type: "ow:add-section", insertAfter: sectionGap.insertAfter, insertBefore: sectionGap.insertBefore },
|
|
5512
|
+
"*"
|
|
5513
|
+
);
|
|
5514
|
+
},
|
|
5515
|
+
children: "Add Section"
|
|
5516
|
+
}
|
|
5517
|
+
),
|
|
5518
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
5519
|
+
]
|
|
5520
|
+
}
|
|
4871
5521
|
)
|
|
4872
5522
|
] }),
|
|
4873
5523
|
bridgeRoot
|
|
@@ -4876,6 +5526,7 @@ function OhhwellsBridge() {
|
|
|
4876
5526
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4877
5527
|
0 && (module.exports = {
|
|
4878
5528
|
OhhwellsBridge,
|
|
5529
|
+
SchedulingWidget,
|
|
4879
5530
|
Toggle,
|
|
4880
5531
|
ToggleGroup,
|
|
4881
5532
|
ToggleGroupItem,
|