@ohhwells/bridge 0.1.76 → 0.1.77-next.232
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 +1240 -215
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -5
- package/dist/index.d.ts +21 -5
- package/dist/index.js +1239 -215
- package/dist/index.js.map +1 -1
- package/dist/pages.cjs +141 -0
- package/dist/pages.cjs.map +1 -0
- package/dist/pages.d.cts +45 -0
- package/dist/pages.d.ts +45 -0
- package/dist/pages.js +107 -0
- package/dist/pages.js.map +1 -0
- package/dist/styles.css +58 -0
- package/package.json +8 -3
package/dist/index.js
CHANGED
|
@@ -83,7 +83,12 @@ function parseAiSectionsState(raw) {
|
|
|
83
83
|
media: entry.media && typeof entry.media === "object" ? entry.media : {}
|
|
84
84
|
}));
|
|
85
85
|
const removed = Array.isArray(parsed.removed) ? parsed.removed.filter((id) => typeof id === "string" && id.length > 0) : [];
|
|
86
|
-
return {
|
|
86
|
+
return {
|
|
87
|
+
v: 1,
|
|
88
|
+
sections,
|
|
89
|
+
...removed.length ? { removed } : {},
|
|
90
|
+
...parsed.hideTemplate === true ? { hideTemplate: true } : {}
|
|
91
|
+
};
|
|
87
92
|
} catch {
|
|
88
93
|
return EMPTY_AI_SECTIONS;
|
|
89
94
|
}
|
|
@@ -96,6 +101,7 @@ function applyTreeToState(state, payload) {
|
|
|
96
101
|
const entry = {
|
|
97
102
|
id: payload.id,
|
|
98
103
|
label: payload.label ?? "Generated section",
|
|
104
|
+
...typeof payload.path === "string" && payload.path ? { path: payload.path } : {},
|
|
99
105
|
afterSection: payload.mode === "insert" && !insertBefore ? payload.targetSectionId ?? null : null,
|
|
100
106
|
...insertBefore && payload.targetSectionId ? { beforeSection: payload.targetSectionId } : {},
|
|
101
107
|
...payload.mode === "replace" && payload.targetSectionId ? { replaces: payload.targetSectionId } : {},
|
|
@@ -118,6 +124,317 @@ function deleteSectionFromState(state, sectionId) {
|
|
|
118
124
|
return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
|
|
119
125
|
}
|
|
120
126
|
|
|
127
|
+
// src/lib/brand-chrome.ts
|
|
128
|
+
var BRAND_NAME_KEY = "__ohw_brand_name";
|
|
129
|
+
var BRAND_TITLE_KEY = "__ohw_site_title";
|
|
130
|
+
var BRAND_FAVICON_LETTER_KEY = "__ohw_favicon_letter";
|
|
131
|
+
var BRAND_CHROME_KEYS = /* @__PURE__ */ new Set([
|
|
132
|
+
BRAND_NAME_KEY,
|
|
133
|
+
BRAND_TITLE_KEY,
|
|
134
|
+
BRAND_FAVICON_LETTER_KEY
|
|
135
|
+
]);
|
|
136
|
+
function upsertMeta(selector, attr, token, value) {
|
|
137
|
+
let el = document.head.querySelector(selector);
|
|
138
|
+
if (!el) {
|
|
139
|
+
el = document.createElement("meta");
|
|
140
|
+
el.setAttribute(attr, token);
|
|
141
|
+
document.head.appendChild(el);
|
|
142
|
+
}
|
|
143
|
+
if (el.getAttribute("content") !== value) el.setAttribute("content", value);
|
|
144
|
+
}
|
|
145
|
+
function escapeXml(value) {
|
|
146
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
147
|
+
}
|
|
148
|
+
function applyLetterFavicon(letter) {
|
|
149
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="12" fill="#111827"/><text x="32" y="46" font-family="system-ui,-apple-system,Segoe UI,sans-serif" font-size="40" font-weight="700" text-anchor="middle" fill="#ffffff">${escapeXml(letter)}</text></svg>`;
|
|
150
|
+
const href = `data:image/svg+xml,${encodeURIComponent(svg)}`;
|
|
151
|
+
let link = document.head.querySelector('link[rel="icon"]');
|
|
152
|
+
if (!link) {
|
|
153
|
+
link = document.createElement("link");
|
|
154
|
+
link.rel = "icon";
|
|
155
|
+
document.head.appendChild(link);
|
|
156
|
+
}
|
|
157
|
+
link.type = "image/svg+xml";
|
|
158
|
+
if (link.href !== href) link.href = href;
|
|
159
|
+
}
|
|
160
|
+
function applyBrandChrome(content) {
|
|
161
|
+
const name = content[BRAND_NAME_KEY];
|
|
162
|
+
if (typeof name === "string" && name.length > 0) {
|
|
163
|
+
document.querySelectorAll("[data-ohw-wordmark]").forEach((el) => {
|
|
164
|
+
if (el.textContent !== name) el.textContent = name;
|
|
165
|
+
if (el.getAttribute("title") !== name) el.setAttribute("title", name);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
const title = content[BRAND_TITLE_KEY];
|
|
169
|
+
if (typeof title === "string" && title.length > 0) {
|
|
170
|
+
if (document.title !== title) document.title = title;
|
|
171
|
+
upsertMeta('meta[property="og:title"]', "property", "og:title", title);
|
|
172
|
+
upsertMeta('meta[name="twitter:title"]', "name", "twitter:title", title);
|
|
173
|
+
}
|
|
174
|
+
const letter = content[BRAND_FAVICON_LETTER_KEY];
|
|
175
|
+
if (typeof letter === "string" && letter.length > 0) {
|
|
176
|
+
applyLetterFavicon(letter);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// src/lib/brand-kit.ts
|
|
181
|
+
var BRAND_KIT_KEY = "__ohw_brand";
|
|
182
|
+
var BRAND_VAR_PREFIX = "--ohw-brand-";
|
|
183
|
+
var BRAND_VAR_NAMES = ["primary", "accent", "light", "dark", "surface", "border", "muted"].map(
|
|
184
|
+
(role) => `${BRAND_VAR_PREFIX}${role}`
|
|
185
|
+
);
|
|
186
|
+
var FONT_VARS = {
|
|
187
|
+
heading: ["--font-heading", "--font-display", "--brand-font-heading"],
|
|
188
|
+
body: ["--font-body", "--brand-font-body"]
|
|
189
|
+
};
|
|
190
|
+
var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
|
|
191
|
+
function brandColorVars(kit) {
|
|
192
|
+
const { dark, primary, accent, light } = kit.palette;
|
|
193
|
+
const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
|
|
194
|
+
return {
|
|
195
|
+
[`${BRAND_VAR_PREFIX}primary`]: primary,
|
|
196
|
+
[`${BRAND_VAR_PREFIX}accent`]: accent,
|
|
197
|
+
[`${BRAND_VAR_PREFIX}light`]: light,
|
|
198
|
+
[`${BRAND_VAR_PREFIX}dark`]: dark,
|
|
199
|
+
[`${BRAND_VAR_PREFIX}surface`]: mix(light, 95, dark),
|
|
200
|
+
[`${BRAND_VAR_PREFIX}border`]: mix(light, 85, dark),
|
|
201
|
+
[`${BRAND_VAR_PREFIX}muted`]: mix(dark, 62, light)
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function parseBrandKit(raw) {
|
|
205
|
+
if (!raw) return null;
|
|
206
|
+
try {
|
|
207
|
+
const parsed = JSON.parse(raw);
|
|
208
|
+
const p = parsed?.palette;
|
|
209
|
+
const f = parsed?.fonts;
|
|
210
|
+
if (!p || !f || typeof p.dark !== "string" || typeof p.primary !== "string" || typeof p.accent !== "string" || typeof p.light !== "string" || typeof f.heading !== "string" || typeof f.body !== "string") {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
palette: { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light },
|
|
215
|
+
fonts: { heading: f.heading, body: f.body }
|
|
216
|
+
};
|
|
217
|
+
} catch {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function familyOf(stack) {
|
|
222
|
+
const first = stack.split(",")[0]?.trim() ?? "";
|
|
223
|
+
return first.replace(/^['"]|['"]$/g, "");
|
|
224
|
+
}
|
|
225
|
+
function loadBrandFonts(families) {
|
|
226
|
+
const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
|
|
227
|
+
if (unique.length === 0) return;
|
|
228
|
+
const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
|
|
229
|
+
const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
|
|
230
|
+
let link = document.getElementById(BRAND_FONT_LINK_ID);
|
|
231
|
+
if (!link) {
|
|
232
|
+
link = document.createElement("link");
|
|
233
|
+
link.id = BRAND_FONT_LINK_ID;
|
|
234
|
+
link.rel = "stylesheet";
|
|
235
|
+
document.head.appendChild(link);
|
|
236
|
+
}
|
|
237
|
+
if (link.href !== href) link.href = href;
|
|
238
|
+
}
|
|
239
|
+
function applyBrandToDom(kit) {
|
|
240
|
+
const root = document.documentElement;
|
|
241
|
+
if (!kit) {
|
|
242
|
+
for (const name of BRAND_VAR_NAMES) root.style.removeProperty(name);
|
|
243
|
+
for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
|
|
244
|
+
document.getElementById(BRAND_FONT_LINK_ID)?.remove();
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
for (const [name, value] of Object.entries(brandColorVars(kit))) root.style.setProperty(name, value);
|
|
248
|
+
for (const name of FONT_VARS.heading) root.style.setProperty(name, kit.fonts.heading);
|
|
249
|
+
for (const name of FONT_VARS.body) root.style.setProperty(name, kit.fonts.body);
|
|
250
|
+
loadBrandFonts([familyOf(kit.fonts.heading), familyOf(kit.fonts.body)]);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// src/lib/section-styles.ts
|
|
254
|
+
var STYLE_STORE_KEY = "__ohw_styles";
|
|
255
|
+
var STYLE_SHEET_ID = "ohw-section-styles";
|
|
256
|
+
function parseStyleStore(raw) {
|
|
257
|
+
if (!raw) return null;
|
|
258
|
+
try {
|
|
259
|
+
const parsed = JSON.parse(raw);
|
|
260
|
+
if (parsed?.v !== 1) return null;
|
|
261
|
+
return {
|
|
262
|
+
v: 1,
|
|
263
|
+
sections: typeof parsed.sections === "object" && parsed.sections ? parsed.sections : {},
|
|
264
|
+
nodes: typeof parsed.nodes === "object" && parsed.nodes ? parsed.nodes : {}
|
|
265
|
+
};
|
|
266
|
+
} catch {
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
var BG_VALUES = {
|
|
271
|
+
surface: "color-mix(in srgb, var(--ohw-brand-light, var(--color-light, #ECECEB)) 94%, var(--ohw-brand-dark, var(--color-dark, #0C0A09)))",
|
|
272
|
+
accent: "var(--ohw-brand-primary, var(--color-primary, #0078E5))",
|
|
273
|
+
"accent-soft": "color-mix(in srgb, var(--ohw-brand-primary, var(--color-primary, #0078E5)) 12%, var(--ohw-brand-light, var(--color-light, #FFFFFF)))"
|
|
274
|
+
};
|
|
275
|
+
var HEADLINE_SIZES = { md: 24, lg: 32, xl: 40, display: 56 };
|
|
276
|
+
function styleSheetCss() {
|
|
277
|
+
const rules = [];
|
|
278
|
+
for (const [tone, value] of Object.entries(BG_VALUES)) {
|
|
279
|
+
rules.push(`[data-ohw-style-bg="${tone}"] { background: ${value} !important; }`);
|
|
280
|
+
}
|
|
281
|
+
rules.push(
|
|
282
|
+
`[data-ohw-style-bg="accent"] { color: var(--ohw-brand-light, var(--color-light, #FFFFFF)) !important; }`
|
|
283
|
+
);
|
|
284
|
+
rules.push(
|
|
285
|
+
`[data-ohw-style-distribution="space-between"] { display: flex !important; flex-direction: column; justify-content: space-between; }`,
|
|
286
|
+
`[data-ohw-style-distribution="center"] { display: flex !important; flex-direction: column; justify-content: center; }`
|
|
287
|
+
);
|
|
288
|
+
for (const [scale, size] of Object.entries(HEADLINE_SIZES)) {
|
|
289
|
+
rules.push(
|
|
290
|
+
`[data-ohw-style-headline="${scale}"] :is(h1, h2, h3) { font-size: ${size}px !important; line-height: 1.15 !important; }`
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
rules.push(
|
|
294
|
+
`[data-ohw-style-aspect="fill-height"] img { height: 100% !important; aspect-ratio: auto !important; object-fit: cover; }`
|
|
295
|
+
);
|
|
296
|
+
for (const aspect of ["1:1", "4:5", "3:4", "3:2", "16:9", "2:1", "3:1"]) {
|
|
297
|
+
rules.push(
|
|
298
|
+
`[data-ohw-style-aspect="${aspect.replace(":", "-")}"] img { aspect-ratio: ${aspect.replace(":", " / ")} !important; height: auto !important; object-fit: cover; }`
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
const pad = { tight: 40, balanced: 64, airy: 96 };
|
|
302
|
+
for (const [spacing, px] of Object.entries(pad)) {
|
|
303
|
+
rules.push(
|
|
304
|
+
`[data-ohw-style-spacing="${spacing}"] { padding-top: ${px}px !important; padding-bottom: ${px}px !important; }`
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
return rules.join("\n");
|
|
308
|
+
}
|
|
309
|
+
var STYLE_FONT_LINK_ID = "ohw-style-fonts";
|
|
310
|
+
function loadStyleFonts(families) {
|
|
311
|
+
const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
|
|
312
|
+
const existing = document.getElementById(STYLE_FONT_LINK_ID);
|
|
313
|
+
if (unique.length === 0) {
|
|
314
|
+
existing?.remove();
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
|
|
318
|
+
const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
|
|
319
|
+
let link = existing;
|
|
320
|
+
if (!link) {
|
|
321
|
+
link = document.createElement("link");
|
|
322
|
+
link.id = STYLE_FONT_LINK_ID;
|
|
323
|
+
link.rel = "stylesheet";
|
|
324
|
+
document.head.appendChild(link);
|
|
325
|
+
}
|
|
326
|
+
if (link.href !== href) link.href = href;
|
|
327
|
+
}
|
|
328
|
+
var SECTION_ATTRS = {
|
|
329
|
+
sectionBackground: "data-ohw-style-bg",
|
|
330
|
+
textDistribution: "data-ohw-style-distribution",
|
|
331
|
+
headlineScale: "data-ohw-style-headline",
|
|
332
|
+
imageAspect: "data-ohw-style-aspect",
|
|
333
|
+
spacing: "data-ohw-style-spacing"
|
|
334
|
+
};
|
|
335
|
+
var NODE_WROTE_ATTR = "data-ohw-style-node";
|
|
336
|
+
var NODE_PROPS = ["color", "font-family", "font-size", "background"];
|
|
337
|
+
function saveInline(el, prop) {
|
|
338
|
+
const attr = `data-ohw-style-prev-${prop}`;
|
|
339
|
+
if (!el.hasAttribute(attr)) el.setAttribute(attr, el.style.getPropertyValue(prop));
|
|
340
|
+
}
|
|
341
|
+
function restoreInline(el, prop) {
|
|
342
|
+
const attr = `data-ohw-style-prev-${prop}`;
|
|
343
|
+
if (!el.hasAttribute(attr)) return;
|
|
344
|
+
const prev = el.getAttribute(attr) ?? "";
|
|
345
|
+
if (prev) el.style.setProperty(prop, prev);
|
|
346
|
+
else el.style.removeProperty(prop);
|
|
347
|
+
el.removeAttribute(attr);
|
|
348
|
+
}
|
|
349
|
+
function ensureStyleSheet() {
|
|
350
|
+
let el = document.getElementById(STYLE_SHEET_ID);
|
|
351
|
+
if (!el) {
|
|
352
|
+
el = document.createElement("style");
|
|
353
|
+
el.id = STYLE_SHEET_ID;
|
|
354
|
+
document.head.appendChild(el);
|
|
355
|
+
}
|
|
356
|
+
const css = styleSheetCss();
|
|
357
|
+
if (el.textContent !== css) el.textContent = css;
|
|
358
|
+
}
|
|
359
|
+
function clearSectionAttrs(root) {
|
|
360
|
+
for (const attr of Object.values(SECTION_ATTRS)) {
|
|
361
|
+
for (const el of Array.from(root.querySelectorAll(`[${attr}]`))) el.removeAttribute(attr);
|
|
362
|
+
}
|
|
363
|
+
for (const el of Array.from(root.querySelectorAll("[data-ohw-style-bgcolor]"))) {
|
|
364
|
+
restoreInline(el, "background");
|
|
365
|
+
el.removeAttribute("data-ohw-style-bgcolor");
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
function clearNodeProps(root) {
|
|
369
|
+
for (const el of Array.from(root.querySelectorAll(`[${NODE_WROTE_ATTR}]`))) {
|
|
370
|
+
const h = el;
|
|
371
|
+
for (const prop of NODE_PROPS) restoreInline(h, prop);
|
|
372
|
+
h.removeAttribute(NODE_WROTE_ATTR);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
function buttonSurfaceOf(el) {
|
|
376
|
+
return el.closest("a, button") ?? el;
|
|
377
|
+
}
|
|
378
|
+
function applyStylesToDom(store) {
|
|
379
|
+
ensureStyleSheet();
|
|
380
|
+
clearSectionAttrs(document);
|
|
381
|
+
clearNodeProps(document);
|
|
382
|
+
loadStyleFonts(
|
|
383
|
+
store ? Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []) : []
|
|
384
|
+
);
|
|
385
|
+
if (!store) return;
|
|
386
|
+
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
387
|
+
const sections = document.querySelectorAll(
|
|
388
|
+
`[data-ohw-section="${CSS.escape(sectionId)}"]`
|
|
389
|
+
);
|
|
390
|
+
for (const section of Array.from(sections)) {
|
|
391
|
+
for (const [prop, attr] of Object.entries(SECTION_ATTRS)) {
|
|
392
|
+
const value = override[prop];
|
|
393
|
+
if (value === void 0) continue;
|
|
394
|
+
if (prop === "sectionBackground" && override.sectionBackgroundColor !== void 0) continue;
|
|
395
|
+
section.setAttribute(attr, String(value).replace(":", "-"));
|
|
396
|
+
}
|
|
397
|
+
if (override.sectionBackgroundColor !== void 0) {
|
|
398
|
+
saveInline(section, "background");
|
|
399
|
+
section.style.setProperty("background", override.sectionBackgroundColor, "important");
|
|
400
|
+
section.setAttribute("data-ohw-style-bgcolor", "");
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
for (const [key, override] of Object.entries(store.nodes)) {
|
|
405
|
+
const nodes = document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`);
|
|
406
|
+
for (const el of Array.from(nodes)) {
|
|
407
|
+
if (override.color !== void 0) {
|
|
408
|
+
saveInline(el, "color");
|
|
409
|
+
el.style.setProperty("color", override.color, "important");
|
|
410
|
+
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
411
|
+
}
|
|
412
|
+
if (override.fontFamily !== void 0) {
|
|
413
|
+
saveInline(el, "font-family");
|
|
414
|
+
el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
|
|
415
|
+
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
416
|
+
}
|
|
417
|
+
if (override.fontSize !== void 0) {
|
|
418
|
+
saveInline(el, "font-size");
|
|
419
|
+
el.style.setProperty("font-size", `${override.fontSize}px`, "important");
|
|
420
|
+
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
421
|
+
}
|
|
422
|
+
if (override.buttonBackground !== void 0 || override.buttonText !== void 0) {
|
|
423
|
+
const surface = buttonSurfaceOf(el);
|
|
424
|
+
if (override.buttonBackground !== void 0) {
|
|
425
|
+
saveInline(surface, "background");
|
|
426
|
+
surface.style.setProperty("background", override.buttonBackground, "important");
|
|
427
|
+
}
|
|
428
|
+
if (override.buttonText !== void 0) {
|
|
429
|
+
saveInline(surface, "color");
|
|
430
|
+
surface.style.setProperty("color", override.buttonText, "important");
|
|
431
|
+
}
|
|
432
|
+
surface.setAttribute(NODE_WROTE_ATTR, "");
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
121
438
|
// src/ui/ai-tree/aiSectionsManager.tsx
|
|
122
439
|
import { flushSync } from "react-dom";
|
|
123
440
|
import { createRoot } from "react-dom/client";
|
|
@@ -132,7 +449,8 @@ function lucideByName(name) {
|
|
|
132
449
|
}
|
|
133
450
|
var typeStyle = (spec, font) => ({
|
|
134
451
|
fontFamily: font,
|
|
135
|
-
|
|
452
|
+
// Headings shrink with the viewport (reaching full size around ~900px wide); body copy stays put.
|
|
453
|
+
fontSize: spec.size >= 24 ? `clamp(${Math.max(18, Math.round(spec.size * 0.6))}px, ${(spec.size / 9).toFixed(2)}vw, ${spec.size}px)` : spec.size,
|
|
136
454
|
lineHeight: spec.line,
|
|
137
455
|
fontWeight: spec.weight
|
|
138
456
|
});
|
|
@@ -141,12 +459,58 @@ var featureLines = (value) => value.split(/\n|<br\s*\/?>/i).map((line) => line.t
|
|
|
141
459
|
var CHECK_MASK = `data:image/svg+xml,${encodeURIComponent(
|
|
142
460
|
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>'
|
|
143
461
|
)}`;
|
|
462
|
+
var AI_MOBILE_CSS = [
|
|
463
|
+
"@media (max-width: 768px){",
|
|
464
|
+
"[data-ai-section]{overflow-x:hidden}",
|
|
465
|
+
"[data-ai-container]{padding:0 20px !important}",
|
|
466
|
+
"[data-ai-row]{display:flex !important;flex-direction:column !important;align-items:stretch !important}",
|
|
467
|
+
"[data-ai-cell]{width:100%;min-width:0}",
|
|
468
|
+
"[data-ai-grid]{grid-template-columns:1fr !important}",
|
|
469
|
+
// Group containers flatten to a column on phones; span placements come along for free.
|
|
470
|
+
"[data-ai-group]{display:flex !important;flex-direction:column !important}",
|
|
471
|
+
"[data-ai-group] > *{grid-column:auto !important}",
|
|
472
|
+
"[data-ai-section] img{max-width:100%}",
|
|
473
|
+
"}",
|
|
474
|
+
"@media (min-width: 769px) and (max-width: 1024px){",
|
|
475
|
+
"[data-ai-grid]{grid-template-columns:repeat(2, 1fr) !important}",
|
|
476
|
+
"}"
|
|
477
|
+
].join("");
|
|
144
478
|
var FEATURE_LINE_CSS = [
|
|
145
479
|
"[data-ai-features]>div{position:relative;padding-left:40px;min-height:24px}",
|
|
146
480
|
'[data-ai-features]>div::before{content:"";position:absolute;left:0;top:1px;width:24px;height:24px;',
|
|
147
481
|
`background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
|
|
148
482
|
`mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
|
|
149
483
|
].join("");
|
|
484
|
+
function hexLuminance(color) {
|
|
485
|
+
const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
|
|
486
|
+
if (!m) return null;
|
|
487
|
+
const [r2, g, b] = [0, 2, 4].map((i) => {
|
|
488
|
+
const c = parseInt(m[1].slice(i, i + 2), 16) / 255;
|
|
489
|
+
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
490
|
+
});
|
|
491
|
+
return 0.2126 * r2 + 0.7152 * g + 0.0722 * b;
|
|
492
|
+
}
|
|
493
|
+
function hexContrast(a, b) {
|
|
494
|
+
const la = hexLuminance(a);
|
|
495
|
+
const lb = hexLuminance(b);
|
|
496
|
+
if (la === null || lb === null) return null;
|
|
497
|
+
const [hi, lo] = la > lb ? [la, lb] : [lb, la];
|
|
498
|
+
return (hi + 0.05) / (lo + 0.05);
|
|
499
|
+
}
|
|
500
|
+
function accentBandContext(brand) {
|
|
501
|
+
const p = brand.palette;
|
|
502
|
+
const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
|
|
503
|
+
if (lightWins) {
|
|
504
|
+
return {
|
|
505
|
+
brand: { ...brand, palette: { dark: p.light, primary: p.light, accent: p.light, light: p.primary } },
|
|
506
|
+
buttonLabel: p.primary
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
return {
|
|
510
|
+
brand: { ...brand, palette: { dark: p.dark, primary: p.dark, accent: p.dark, light: p.light } },
|
|
511
|
+
buttonLabel: p.light
|
|
512
|
+
};
|
|
513
|
+
}
|
|
150
514
|
function textAttrs(ctx, path) {
|
|
151
515
|
return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
|
|
152
516
|
}
|
|
@@ -158,7 +522,12 @@ var AI_RESPONSIVE_CSS = [
|
|
|
158
522
|
"@media (max-width: 640px) {",
|
|
159
523
|
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
|
|
160
524
|
" [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
|
|
525
|
+
// Group containers flatten to a column on phones; span placements come along for free.
|
|
526
|
+
" [data-ai-responsive] [data-ai-group] { display: flex !important; flex-direction: column !important; }",
|
|
527
|
+
" [data-ai-responsive] [data-ai-group] > * { grid-column: auto !important; }",
|
|
161
528
|
" [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
|
|
529
|
+
" [data-ai-responsive] { overflow-x: hidden; }",
|
|
530
|
+
" [data-ai-responsive] img { max-width: 100%; }",
|
|
162
531
|
"}"
|
|
163
532
|
].join("\n");
|
|
164
533
|
var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
@@ -236,7 +605,7 @@ function ButtonEl({
|
|
|
236
605
|
}) {
|
|
237
606
|
const secondary = slots.variant === "secondary";
|
|
238
607
|
const href = str(slots.href);
|
|
239
|
-
const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`) } : {};
|
|
608
|
+
const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`), "data-ohw-role": "button" } : {};
|
|
240
609
|
return /* @__PURE__ */ jsx(
|
|
241
610
|
"a",
|
|
242
611
|
{
|
|
@@ -252,7 +621,7 @@ function ButtonEl({
|
|
|
252
621
|
textDecoration: "none",
|
|
253
622
|
cursor: "pointer",
|
|
254
623
|
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body),
|
|
255
|
-
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: AI_TREE_TOKENS.textPrimaryForeground }
|
|
624
|
+
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? AI_TREE_TOKENS.textPrimaryForeground }
|
|
256
625
|
},
|
|
257
626
|
children: /* @__PURE__ */ jsx("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
|
|
258
627
|
}
|
|
@@ -758,7 +1127,24 @@ function CardBlock({ node, ctx, path }) {
|
|
|
758
1127
|
minWidth: 0
|
|
759
1128
|
},
|
|
760
1129
|
children: [
|
|
761
|
-
media && (horizontal ? /* @__PURE__ */ jsx(
|
|
1130
|
+
media && (horizontal ? /* @__PURE__ */ jsx(
|
|
1131
|
+
"div",
|
|
1132
|
+
{
|
|
1133
|
+
style: (
|
|
1134
|
+
// An icon hugs its glyph — flex:1 gave a 48px icon half the card and pushed the
|
|
1135
|
+
// text to the far side. Photos keep the half-and-half split. The inset has no
|
|
1136
|
+
// inner padding (the photo split absorbed that), so the icon carries its own gap.
|
|
1137
|
+
/^(lucide|simple):/.test(mediaRef) ? {
|
|
1138
|
+
flexShrink: 0,
|
|
1139
|
+
display: "flex",
|
|
1140
|
+
alignItems: "center",
|
|
1141
|
+
padding: mediaInset,
|
|
1142
|
+
[mediaPosition === "right" ? "marginLeft" : "marginRight"]: 20
|
|
1143
|
+
} : { flex: 1, minWidth: 0, display: "flex", alignItems: "center", padding: mediaInset }
|
|
1144
|
+
),
|
|
1145
|
+
children: media
|
|
1146
|
+
}
|
|
1147
|
+
) : /* @__PURE__ */ jsx(
|
|
762
1148
|
"div",
|
|
763
1149
|
{
|
|
764
1150
|
style: /^(lucide|simple):/.test(mediaRef) ? { padding: `${AI_TREE_TOKENS.paddingBlock}px ${AI_TREE_TOKENS.paddingBlock}px 0` } : hasBg ? void 0 : { borderRadius: AI_TREE_TOKENS.radiusCard, overflow: "hidden" },
|
|
@@ -849,13 +1235,44 @@ function AccordionBlock({ node, ctx, path }) {
|
|
|
849
1235
|
) })
|
|
850
1236
|
] }, i)) });
|
|
851
1237
|
}
|
|
1238
|
+
function useIsMobile() {
|
|
1239
|
+
const [mobile, setMobile] = React.useState(
|
|
1240
|
+
() => typeof window !== "undefined" && window.matchMedia("(max-width: 768px)").matches
|
|
1241
|
+
);
|
|
1242
|
+
React.useEffect(() => {
|
|
1243
|
+
const mq = window.matchMedia("(max-width: 768px)");
|
|
1244
|
+
const update = () => setMobile(mq.matches);
|
|
1245
|
+
update();
|
|
1246
|
+
mq.addEventListener("change", update);
|
|
1247
|
+
return () => mq.removeEventListener("change", update);
|
|
1248
|
+
}, []);
|
|
1249
|
+
return mobile;
|
|
1250
|
+
}
|
|
852
1251
|
function Carousel({ items, itemsPerRow, ctx }) {
|
|
1252
|
+
const isMobile = useIsMobile();
|
|
1253
|
+
const perPage = isMobile ? 1 : itemsPerRow;
|
|
1254
|
+
const pages = Math.max(1, Math.ceil(items.length / perPage));
|
|
853
1255
|
const [page, setPage] = React.useState(0);
|
|
854
|
-
const pages = Math.max(1, Math.ceil(items.length / itemsPerRow));
|
|
855
1256
|
const current = Math.min(page, pages - 1);
|
|
1257
|
+
if (pages <= 1) {
|
|
1258
|
+
const cols = Math.max(1, Math.min(items.length, itemsPerRow));
|
|
1259
|
+
return /* @__PURE__ */ jsx(
|
|
1260
|
+
"div",
|
|
1261
|
+
{
|
|
1262
|
+
"data-ai-grid": String(cols),
|
|
1263
|
+
style: {
|
|
1264
|
+
display: "grid",
|
|
1265
|
+
gridTemplateColumns: `repeat(${cols}, 1fr)`,
|
|
1266
|
+
gap: AI_TREE_TOKENS.spacing8,
|
|
1267
|
+
alignItems: "start"
|
|
1268
|
+
},
|
|
1269
|
+
children: items
|
|
1270
|
+
}
|
|
1271
|
+
);
|
|
1272
|
+
}
|
|
856
1273
|
const pageGroups = Array.from(
|
|
857
1274
|
{ length: pages },
|
|
858
|
-
(_, p) => items.slice(p *
|
|
1275
|
+
(_, p) => items.slice(p * perPage, (p + 1) * perPage)
|
|
859
1276
|
);
|
|
860
1277
|
const chrome = (enabled) => ({
|
|
861
1278
|
border: `1px solid ${ctx.brand.palette.dark}`,
|
|
@@ -880,55 +1297,69 @@ function Carousel({ items, itemsPerRow, ctx }) {
|
|
|
880
1297
|
cursor: "pointer",
|
|
881
1298
|
padding: 0
|
|
882
1299
|
});
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
children: /* @__PURE__ */ jsx(ArrowLeft, { size: 24, strokeWidth: 1.5, "aria-hidden": true })
|
|
893
|
-
}
|
|
894
|
-
),
|
|
895
|
-
/* @__PURE__ */ jsx("div", { style: { flex: 1, minWidth: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx(
|
|
1300
|
+
const viewport = /* @__PURE__ */ jsx("div", { style: { flex: isMobile ? "0 0 auto" : 1, minWidth: 0, width: "100%", overflow: "hidden" }, children: /* @__PURE__ */ jsx(
|
|
1301
|
+
"div",
|
|
1302
|
+
{
|
|
1303
|
+
style: {
|
|
1304
|
+
display: "flex",
|
|
1305
|
+
transform: `translateX(-${current * 100}%)`,
|
|
1306
|
+
transition: "transform 0.4s ease"
|
|
1307
|
+
},
|
|
1308
|
+
children: pageGroups.map((group, p) => /* @__PURE__ */ jsx(
|
|
896
1309
|
"div",
|
|
897
1310
|
{
|
|
1311
|
+
"data-ai-grid": String(perPage),
|
|
898
1312
|
style: {
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
1313
|
+
flex: "0 0 100%",
|
|
1314
|
+
display: "grid",
|
|
1315
|
+
gridTemplateColumns: `repeat(${perPage}, 1fr)`,
|
|
1316
|
+
gap: AI_TREE_TOKENS.spacing8,
|
|
1317
|
+
alignItems: "start"
|
|
902
1318
|
},
|
|
903
|
-
children:
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1319
|
+
children: group
|
|
1320
|
+
},
|
|
1321
|
+
p
|
|
1322
|
+
))
|
|
1323
|
+
}
|
|
1324
|
+
) });
|
|
1325
|
+
const prevBtn = /* @__PURE__ */ jsx(
|
|
1326
|
+
"button",
|
|
1327
|
+
{
|
|
1328
|
+
type: "button",
|
|
1329
|
+
"aria-label": "Previous",
|
|
1330
|
+
onClick: () => setPage((p) => Math.max(0, p - 1)),
|
|
1331
|
+
style: chrome(current > 0),
|
|
1332
|
+
children: /* @__PURE__ */ jsx(ArrowLeft, { size: 24, strokeWidth: 1.5, "aria-hidden": true })
|
|
1333
|
+
}
|
|
1334
|
+
);
|
|
1335
|
+
const nextBtn = /* @__PURE__ */ jsx(
|
|
1336
|
+
"button",
|
|
1337
|
+
{
|
|
1338
|
+
type: "button",
|
|
1339
|
+
"aria-label": "Next",
|
|
1340
|
+
onClick: () => setPage((p) => Math.min(pages - 1, p + 1)),
|
|
1341
|
+
style: chrome(current < pages - 1),
|
|
1342
|
+
children: /* @__PURE__ */ jsx(ArrowRight, { size: 24, strokeWidth: 1.5, "aria-hidden": true })
|
|
1343
|
+
}
|
|
1344
|
+
);
|
|
1345
|
+
const dots = /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 9, justifyContent: "center" }, children: pageGroups.map((_, p) => /* @__PURE__ */ jsx("button", { type: "button", "aria-label": `Page ${p + 1}`, onClick: () => setPage(p), style: dot(p === current) }, p)) });
|
|
1346
|
+
if (isMobile) {
|
|
1347
|
+
return /* @__PURE__ */ jsxs("div", { "data-ai-carousel": "", style: { display: "flex", flexDirection: "column", gap: AI_TREE_TOKENS.spacing6, alignItems: "center" }, children: [
|
|
1348
|
+
viewport,
|
|
1349
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: AI_TREE_TOKENS.spacing6, justifyContent: "center" }, children: [
|
|
1350
|
+
prevBtn,
|
|
1351
|
+
nextBtn
|
|
1352
|
+
] }),
|
|
1353
|
+
dots
|
|
1354
|
+
] });
|
|
1355
|
+
}
|
|
1356
|
+
return /* @__PURE__ */ jsxs("div", { "data-ai-carousel": "", style: { display: "flex", flexDirection: "column", gap: AI_TREE_TOKENS.spacing8, alignItems: "center" }, children: [
|
|
1357
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: AI_TREE_TOKENS.spacing6, width: "100%" }, children: [
|
|
1358
|
+
prevBtn,
|
|
1359
|
+
viewport,
|
|
1360
|
+
nextBtn
|
|
930
1361
|
] }),
|
|
931
|
-
|
|
1362
|
+
dots
|
|
932
1363
|
] });
|
|
933
1364
|
}
|
|
934
1365
|
function CollectionBlock({ node, ctx, path }) {
|
|
@@ -1022,6 +1453,49 @@ function renderNode(node, ctx, path) {
|
|
|
1022
1453
|
switch (node.type) {
|
|
1023
1454
|
case "text":
|
|
1024
1455
|
return /* @__PURE__ */ jsx(TextBlock, { slots, ctx, path });
|
|
1456
|
+
// Layout container: arranges child blocks, contributes no content of its own. `grid` is a
|
|
1457
|
+
// nested 12-column grid the children span (a collage is 3–5 media on it, bottom-aligned so
|
|
1458
|
+
// mixed aspects read as a composition); `split` is exactly two children at a ratio; `stack`
|
|
1459
|
+
// is a column. Children render through this same dispatcher, so edit markers, media
|
|
1460
|
+
// resolution, and copy paths all work unchanged inside a group.
|
|
1461
|
+
case "group": {
|
|
1462
|
+
const layout = str(slots.layout);
|
|
1463
|
+
const gap = slots.spacing === "tight" ? AI_TREE_TOKENS.spacing3 : slots.spacing === "airy" ? AI_TREE_TOKENS.spacing8 : AI_TREE_TOKENS.spacing6;
|
|
1464
|
+
const kids = (node.children ?? []).map((child, i) => /* @__PURE__ */ jsx(
|
|
1465
|
+
"div",
|
|
1466
|
+
{
|
|
1467
|
+
style: layout === "grid" ? {
|
|
1468
|
+
gridColumn: `span ${typeof child.span === "number" ? Math.min(12, Math.max(1, child.span)) : 12}`,
|
|
1469
|
+
minWidth: 0
|
|
1470
|
+
} : { minWidth: 0 },
|
|
1471
|
+
children: renderNode(child, ctx, `${path}.c${i}`)
|
|
1472
|
+
},
|
|
1473
|
+
i
|
|
1474
|
+
));
|
|
1475
|
+
if (layout === "grid") {
|
|
1476
|
+
return /* @__PURE__ */ jsx(
|
|
1477
|
+
"div",
|
|
1478
|
+
{
|
|
1479
|
+
"data-ai-group": "grid",
|
|
1480
|
+
style: { display: "grid", gridTemplateColumns: "repeat(12, 1fr)", gap, alignItems: "end" },
|
|
1481
|
+
children: kids
|
|
1482
|
+
}
|
|
1483
|
+
);
|
|
1484
|
+
}
|
|
1485
|
+
if (layout === "split") {
|
|
1486
|
+
const ratio = str(slots.ratio);
|
|
1487
|
+
const cols = ratio === "3:5" ? "3fr 5fr" : ratio === "5:3" ? "5fr 3fr" : "1fr 1fr";
|
|
1488
|
+
return /* @__PURE__ */ jsx(
|
|
1489
|
+
"div",
|
|
1490
|
+
{
|
|
1491
|
+
"data-ai-group": "split",
|
|
1492
|
+
style: { display: "grid", gridTemplateColumns: cols, gap, alignItems: "center" },
|
|
1493
|
+
children: kids
|
|
1494
|
+
}
|
|
1495
|
+
);
|
|
1496
|
+
}
|
|
1497
|
+
return /* @__PURE__ */ jsx("div", { "data-ai-group": "stack", style: { display: "flex", flexDirection: "column", gap }, children: kids });
|
|
1498
|
+
}
|
|
1025
1499
|
case "button":
|
|
1026
1500
|
return /* @__PURE__ */ jsx(ButtonEl, { slots, ctx, path });
|
|
1027
1501
|
case "button-row":
|
|
@@ -1102,33 +1576,111 @@ function renderNode(node, ctx, path) {
|
|
|
1102
1576
|
}
|
|
1103
1577
|
);
|
|
1104
1578
|
}
|
|
1105
|
-
case "form":
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1579
|
+
case "form": {
|
|
1580
|
+
const formAttrs = ctx.keyFor ? {
|
|
1581
|
+
"data-ohw-editable": "form",
|
|
1582
|
+
"data-ohw-key": ctx.keyFor(`${path}.form`),
|
|
1583
|
+
"data-ohw-success-text": "Thanks \u2014 we'll be in touch shortly."
|
|
1584
|
+
} : {};
|
|
1585
|
+
const fieldStyle = {
|
|
1586
|
+
width: "100%",
|
|
1587
|
+
boxSizing: "border-box",
|
|
1588
|
+
border: `1px solid color-mix(in srgb, ${ctx.brand.palette.dark} 45%, #ffffff)`,
|
|
1589
|
+
borderRadius: 0,
|
|
1590
|
+
padding: 12,
|
|
1591
|
+
background: "#fff",
|
|
1592
|
+
color: ctx.brand.palette.dark,
|
|
1593
|
+
outline: "none",
|
|
1594
|
+
...typeStyle(AI_TREE_TOKENS.type.bodyM, ctx.brand.fonts.body)
|
|
1595
|
+
};
|
|
1596
|
+
const labelStyle = {
|
|
1597
|
+
...typeStyle(AI_TREE_TOKENS.type.bodyMBold, ctx.brand.fonts.body),
|
|
1598
|
+
color: ctx.brand.palette.dark,
|
|
1599
|
+
textAlign: "left",
|
|
1600
|
+
width: "100%"
|
|
1601
|
+
};
|
|
1602
|
+
const centered = ctx.sectionAlignment === "center";
|
|
1603
|
+
const submitAlign = centered ? "center" : "flex-start";
|
|
1604
|
+
const children = node.children ?? [];
|
|
1605
|
+
return (
|
|
1606
|
+
// 32px between the field group and the submit. In a stacked (centered) section the form is
|
|
1607
|
+
// capped at 780px and centered — the section's 12-col grid would otherwise leave it hugging
|
|
1608
|
+
// the left edge; a split section lets it fill its own column.
|
|
1609
|
+
/* @__PURE__ */ jsxs(
|
|
1610
|
+
"form",
|
|
1611
|
+
{
|
|
1612
|
+
...formAttrs,
|
|
1613
|
+
"data-ai-form": "",
|
|
1614
|
+
style: {
|
|
1615
|
+
display: "flex",
|
|
1616
|
+
flexDirection: "column",
|
|
1617
|
+
gap: 32,
|
|
1618
|
+
width: "100%",
|
|
1619
|
+
...centered ? { maxWidth: 780, marginLeft: "auto", marginRight: "auto" } : {}
|
|
1620
|
+
},
|
|
1621
|
+
children: [
|
|
1622
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: 24, width: "100%", alignItems: "flex-start" }, children: children.map((child, i) => {
|
|
1623
|
+
if (child.type !== "input") return null;
|
|
1624
|
+
const cs = child.slots ?? {};
|
|
1625
|
+
const kind = str(cs.kind);
|
|
1626
|
+
const label = str(cs.label);
|
|
1627
|
+
const placeholder = str(cs.placeholder);
|
|
1628
|
+
const required = cs.required === true;
|
|
1629
|
+
const name = label.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-+|-+$/gu, "") || `field-${i}`;
|
|
1630
|
+
const isTextarea = kind === "textarea";
|
|
1631
|
+
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8, width: "100%" }, children: [
|
|
1632
|
+
/* @__PURE__ */ jsx("label", { ...textAttrs(ctx, `${path}.c${i}.label`), style: labelStyle, children: label }),
|
|
1633
|
+
isTextarea ? /* @__PURE__ */ jsx(
|
|
1634
|
+
"textarea",
|
|
1635
|
+
{
|
|
1636
|
+
name,
|
|
1637
|
+
placeholder,
|
|
1638
|
+
required,
|
|
1639
|
+
style: { ...fieldStyle, height: 180, resize: "vertical" }
|
|
1640
|
+
}
|
|
1641
|
+
) : /* @__PURE__ */ jsx(
|
|
1642
|
+
"input",
|
|
1643
|
+
{
|
|
1644
|
+
name,
|
|
1645
|
+
type: kind === "email" ? "email" : "text",
|
|
1646
|
+
placeholder,
|
|
1647
|
+
required,
|
|
1648
|
+
style: { ...fieldStyle, height: 48 }
|
|
1649
|
+
}
|
|
1650
|
+
)
|
|
1651
|
+
] }, i);
|
|
1652
|
+
}) }),
|
|
1653
|
+
children.map((child, i) => {
|
|
1654
|
+
if (child.type === "input") return null;
|
|
1655
|
+
const cs = child.slots ?? {};
|
|
1656
|
+
return /* @__PURE__ */ jsx(
|
|
1657
|
+
"button",
|
|
1658
|
+
{
|
|
1659
|
+
type: "submit",
|
|
1660
|
+
style: {
|
|
1661
|
+
alignSelf: submitAlign,
|
|
1662
|
+
border: "none",
|
|
1663
|
+
cursor: "pointer",
|
|
1664
|
+
padding: "12px 24px",
|
|
1665
|
+
// Corner radius follows the host template's own buttons (measured from a template
|
|
1666
|
+
// CTA); 8px only when the page has no template button to match.
|
|
1667
|
+
borderRadius: ctx.buttonRadius ?? 8,
|
|
1668
|
+
// Brand-styled: primary fill, brand-derived label colour (not a fixed token) so it
|
|
1669
|
+
// reads correctly on custom palettes.
|
|
1670
|
+
background: ctx.brand.palette.primary,
|
|
1671
|
+
color: ctx.buttonLabel ?? ctx.brand.palette.light,
|
|
1672
|
+
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
1673
|
+
},
|
|
1674
|
+
children: /* @__PURE__ */ jsx("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
|
|
1675
|
+
},
|
|
1676
|
+
i
|
|
1677
|
+
);
|
|
1678
|
+
})
|
|
1679
|
+
]
|
|
1680
|
+
}
|
|
1681
|
+
)
|
|
1682
|
+
);
|
|
1683
|
+
}
|
|
1132
1684
|
case "schedule-widget":
|
|
1133
1685
|
return /* @__PURE__ */ jsx(
|
|
1134
1686
|
"div",
|
|
@@ -1149,16 +1701,27 @@ function renderNode(node, ctx, path) {
|
|
|
1149
1701
|
return null;
|
|
1150
1702
|
}
|
|
1151
1703
|
}
|
|
1152
|
-
function AiTreeRenderer({
|
|
1704
|
+
function AiTreeRenderer({
|
|
1705
|
+
tree,
|
|
1706
|
+
brand,
|
|
1707
|
+
buttonRadius,
|
|
1708
|
+
resolveMedia,
|
|
1709
|
+
editKeyPrefix
|
|
1710
|
+
}) {
|
|
1153
1711
|
if (!isRenderableTree(tree)) {
|
|
1154
1712
|
return null;
|
|
1155
1713
|
}
|
|
1156
1714
|
const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
|
|
1715
|
+
const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
|
|
1716
|
+
const blockBrand = band?.brand ?? resolvedBrand;
|
|
1157
1717
|
const ctx = {
|
|
1158
|
-
brand:
|
|
1718
|
+
brand: blockBrand,
|
|
1159
1719
|
resolveMedia: resolveMedia ?? (() => null),
|
|
1160
|
-
cardSurface:
|
|
1161
|
-
keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null
|
|
1720
|
+
cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
|
|
1721
|
+
keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
|
|
1722
|
+
sectionAlignment: (tree.settings ?? {}).alignment === "center" ? "center" : "left",
|
|
1723
|
+
buttonRadius,
|
|
1724
|
+
...band ? { buttonLabel: band.buttonLabel } : {}
|
|
1162
1725
|
};
|
|
1163
1726
|
const settings = tree.settings ?? {};
|
|
1164
1727
|
const pad = AI_TREE_TOKENS.sectionPadding[settings.spacing ?? "balanced"];
|
|
@@ -1166,6 +1729,20 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
|
|
|
1166
1729
|
const overlayAlpha = { low: 0.25, medium: 0.45, high: 0.65 }[settings.overlayIntensity ?? "medium"];
|
|
1167
1730
|
const backgroundUrl = isOverlay && settings.backgroundMedia ? ctx.resolveMedia(settings.backgroundMedia) : null;
|
|
1168
1731
|
const bgAttrs = ctx.keyFor && isOverlay && settings.backgroundMedia ? { "data-ohw-key": ctx.keyFor("settings.backgroundMedia"), "data-ohw-editable": "bg-image" } : {};
|
|
1732
|
+
const toneBackground = (() => {
|
|
1733
|
+
const { dark, primary, light } = resolvedBrand.palette;
|
|
1734
|
+
switch (settings.sectionBackground) {
|
|
1735
|
+
case "surface":
|
|
1736
|
+
return `color-mix(in srgb, ${light} 94%, ${dark})`;
|
|
1737
|
+
case "accent":
|
|
1738
|
+
return primary;
|
|
1739
|
+
case "accent-soft":
|
|
1740
|
+
return `color-mix(in srgb, ${primary} 12%, ${light})`;
|
|
1741
|
+
default:
|
|
1742
|
+
return void 0;
|
|
1743
|
+
}
|
|
1744
|
+
})();
|
|
1745
|
+
const distributed = !isOverlay && settings.textDistribution;
|
|
1169
1746
|
return /* @__PURE__ */ jsxs(
|
|
1170
1747
|
"section",
|
|
1171
1748
|
{
|
|
@@ -1175,13 +1752,15 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
|
|
|
1175
1752
|
style: {
|
|
1176
1753
|
position: "relative",
|
|
1177
1754
|
padding: `${pad}px 0`,
|
|
1178
|
-
background: isOverlay && !backgroundUrl ? "#DBEAFE" : void 0,
|
|
1755
|
+
background: toneBackground ?? (isOverlay && !backgroundUrl ? "#DBEAFE" : void 0),
|
|
1179
1756
|
backgroundImage: backgroundUrl ? `url(${backgroundUrl})` : void 0,
|
|
1180
1757
|
backgroundSize: "cover",
|
|
1181
|
-
backgroundPosition: "center"
|
|
1758
|
+
backgroundPosition: "center",
|
|
1759
|
+
color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
|
|
1182
1760
|
},
|
|
1183
1761
|
children: [
|
|
1184
1762
|
/* @__PURE__ */ jsx("style", { children: AI_RESPONSIVE_CSS }),
|
|
1763
|
+
/* @__PURE__ */ jsx("style", { children: AI_MOBILE_CSS }),
|
|
1185
1764
|
isOverlay && backgroundUrl && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
|
|
1186
1765
|
/* @__PURE__ */ jsx(
|
|
1187
1766
|
"div",
|
|
@@ -1202,10 +1781,24 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
|
|
|
1202
1781
|
display: "grid",
|
|
1203
1782
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
1204
1783
|
gap: AI_TREE_TOKENS.spacing6,
|
|
1205
|
-
alignItems: settings.verticalPosition === "top" ? "start" : "center",
|
|
1784
|
+
alignItems: distributed === "space-between" ? "stretch" : (distributed ?? settings.verticalPosition) === "top" ? "start" : "center",
|
|
1206
1785
|
marginTop: r2 > 0 ? AI_TREE_TOKENS.spacing8 : 0
|
|
1207
1786
|
},
|
|
1208
|
-
children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ jsx(
|
|
1787
|
+
children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ jsx(
|
|
1788
|
+
"div",
|
|
1789
|
+
{
|
|
1790
|
+
"data-ai-cell": "",
|
|
1791
|
+
style: {
|
|
1792
|
+
gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`,
|
|
1793
|
+
minWidth: 0,
|
|
1794
|
+
// space-between: each column becomes a flex column whose content spreads over
|
|
1795
|
+
// the full row height instead of clumping at the top.
|
|
1796
|
+
...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
|
|
1797
|
+
},
|
|
1798
|
+
children: renderNode(block, ctx, `r${r2}.b${b}`)
|
|
1799
|
+
},
|
|
1800
|
+
b
|
|
1801
|
+
))
|
|
1209
1802
|
},
|
|
1210
1803
|
r2
|
|
1211
1804
|
))
|
|
@@ -1221,17 +1814,36 @@ import { jsx as jsx2 } from "react/jsx-runtime";
|
|
|
1221
1814
|
var CONTAINER_ATTR = "data-ohw-ai-generated";
|
|
1222
1815
|
var REPLACED_ATTR = "data-ohw-ai-replaced-by";
|
|
1223
1816
|
var REMOVED_ATTR = "data-ohw-ai-removed";
|
|
1817
|
+
var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
|
|
1818
|
+
var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
1819
|
+
function readRootVar(name) {
|
|
1820
|
+
if (typeof document === "undefined") return "";
|
|
1821
|
+
return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
1822
|
+
}
|
|
1823
|
+
function deriveBrandOverride() {
|
|
1824
|
+
const dark = readRootVar("--ohw-brand-dark");
|
|
1825
|
+
const primary = readRootVar("--ohw-brand-primary");
|
|
1826
|
+
const light = readRootVar("--ohw-brand-light");
|
|
1827
|
+
if (!dark || !primary || !light) return null;
|
|
1828
|
+
const accent = readRootVar("--ohw-brand-accent");
|
|
1829
|
+
const heading = readRootVar("--font-heading") || readRootVar("--font-display");
|
|
1830
|
+
const body = readRootVar("--font-body");
|
|
1831
|
+
return {
|
|
1832
|
+
palette: { dark, primary, accent: accent || dark, light },
|
|
1833
|
+
fonts: {
|
|
1834
|
+
heading: heading || AI_DEFAULT_BRAND.fonts.heading,
|
|
1835
|
+
body: body || AI_DEFAULT_BRAND.fonts.body
|
|
1836
|
+
}
|
|
1837
|
+
};
|
|
1838
|
+
}
|
|
1224
1839
|
function deriveTemplateBrand() {
|
|
1225
|
-
|
|
1226
|
-
const
|
|
1227
|
-
const
|
|
1228
|
-
const dark = read("--color-dark");
|
|
1229
|
-
const primary = read("--color-primary");
|
|
1230
|
-
const light = read("--color-light");
|
|
1840
|
+
const dark = readRootVar("--color-dark");
|
|
1841
|
+
const primary = readRootVar("--color-primary");
|
|
1842
|
+
const light = readRootVar("--color-light");
|
|
1231
1843
|
if (!dark || !primary || !light) return null;
|
|
1232
|
-
const accent =
|
|
1233
|
-
const heading =
|
|
1234
|
-
const body =
|
|
1844
|
+
const accent = readRootVar("--color-accent");
|
|
1845
|
+
const heading = readRootVar("--font-heading") || readRootVar("--font-display");
|
|
1846
|
+
const body = readRootVar("--font-body");
|
|
1235
1847
|
return {
|
|
1236
1848
|
palette: { dark, primary, accent: accent || dark, light },
|
|
1237
1849
|
fonts: {
|
|
@@ -1240,6 +1852,13 @@ function deriveTemplateBrand() {
|
|
|
1240
1852
|
}
|
|
1241
1853
|
};
|
|
1242
1854
|
}
|
|
1855
|
+
function deriveTemplateButtonRadius() {
|
|
1856
|
+
if (typeof document === "undefined") return null;
|
|
1857
|
+
const btn = document.querySelector('[data-ohw-role="button"]');
|
|
1858
|
+
if (!btn) return null;
|
|
1859
|
+
const radius = getComputedStyle(btn).borderTopLeftRadius;
|
|
1860
|
+
return radius || null;
|
|
1861
|
+
}
|
|
1243
1862
|
var mounted = /* @__PURE__ */ new Map();
|
|
1244
1863
|
function findTemplateSection(id) {
|
|
1245
1864
|
for (const el of document.querySelectorAll(`[data-ohw-section="${CSS.escape(id)}"]`)) {
|
|
@@ -1303,6 +1922,24 @@ function syncRemovedSections(state) {
|
|
|
1303
1922
|
}
|
|
1304
1923
|
}
|
|
1305
1924
|
}
|
|
1925
|
+
function syncTemplateHidden(state, pageHasSections) {
|
|
1926
|
+
const hide = state.hideTemplate === true && pageHasSections;
|
|
1927
|
+
for (const el of Array.from(document.querySelectorAll(`[${TEMPLATE_HIDDEN_ATTR}]`))) {
|
|
1928
|
+
if (!hide) {
|
|
1929
|
+
el.style.removeProperty("display");
|
|
1930
|
+
el.removeAttribute(TEMPLATE_HIDDEN_ATTR);
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
if (!hide) return;
|
|
1934
|
+
for (const el of Array.from(document.querySelectorAll("[data-ohw-section]"))) {
|
|
1935
|
+
if (el.hasAttribute(CONTAINER_ATTR)) continue;
|
|
1936
|
+
if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
|
|
1937
|
+
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
1938
|
+
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR)) continue;
|
|
1939
|
+
el.style.display = "none";
|
|
1940
|
+
el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1306
1943
|
function syncReplacedOriginals(state) {
|
|
1307
1944
|
for (const el of document.querySelectorAll(`[${REPLACED_ATTR}]`)) {
|
|
1308
1945
|
const byId = el.getAttribute(REPLACED_ATTR) ?? "";
|
|
@@ -1321,10 +1958,64 @@ function syncReplacedOriginals(state) {
|
|
|
1321
1958
|
}
|
|
1322
1959
|
}
|
|
1323
1960
|
}
|
|
1961
|
+
var sectionOrderIndex = /* @__PURE__ */ new Map();
|
|
1962
|
+
function setAiSectionOrder(raw, currentPath) {
|
|
1963
|
+
const next = /* @__PURE__ */ new Map();
|
|
1964
|
+
if (raw) {
|
|
1965
|
+
try {
|
|
1966
|
+
const entries = JSON.parse(raw);
|
|
1967
|
+
for (const entry of entries) {
|
|
1968
|
+
if (!entry.pagePath || entry.pagePath === currentPath) next.set(entry.instanceId, entry.order);
|
|
1969
|
+
}
|
|
1970
|
+
} catch {
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
sectionOrderIndex = next;
|
|
1974
|
+
}
|
|
1975
|
+
function applyExplicitOrder(entries) {
|
|
1976
|
+
if (sectionOrderIndex.size === 0) return entries;
|
|
1977
|
+
return entries.map((entry, index) => ({ entry, index, order: sectionOrderIndex.get(entry.id) })).sort((a, b) => {
|
|
1978
|
+
if (a.order === void 0 && b.order === void 0) return a.index - b.index;
|
|
1979
|
+
if (a.order === void 0) return 1;
|
|
1980
|
+
if (b.order === void 0) return -1;
|
|
1981
|
+
return a.order - b.order;
|
|
1982
|
+
}).map((item) => item.entry);
|
|
1983
|
+
}
|
|
1984
|
+
function orderByChain(sections) {
|
|
1985
|
+
const ids = new Set(sections.map((entry) => entry.id));
|
|
1986
|
+
const after = /* @__PURE__ */ new Map();
|
|
1987
|
+
const roots = [];
|
|
1988
|
+
for (const entry of sections) {
|
|
1989
|
+
const anchor = entry.replaces ?? entry.beforeSection ?? entry.afterSection ?? null;
|
|
1990
|
+
if (anchor && ids.has(anchor)) {
|
|
1991
|
+
const bucket = after.get(anchor);
|
|
1992
|
+
if (bucket) bucket.push(entry);
|
|
1993
|
+
else after.set(anchor, [entry]);
|
|
1994
|
+
} else {
|
|
1995
|
+
roots.push(entry);
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
const out = [];
|
|
1999
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2000
|
+
const visit = (entry) => {
|
|
2001
|
+
if (seen.has(entry.id)) return;
|
|
2002
|
+
seen.add(entry.id);
|
|
2003
|
+
out.push(entry);
|
|
2004
|
+
for (const child of after.get(entry.id) ?? []) visit(child);
|
|
2005
|
+
};
|
|
2006
|
+
for (const root of roots) visit(root);
|
|
2007
|
+
return out.length === sections.length ? out : sections;
|
|
2008
|
+
}
|
|
1324
2009
|
function applyAiSectionsToDom(state, options) {
|
|
1325
2010
|
if (typeof document === "undefined") return;
|
|
2011
|
+
const brandOverride = deriveBrandOverride();
|
|
1326
2012
|
const templateBrand = deriveTemplateBrand();
|
|
1327
|
-
const
|
|
2013
|
+
const templateButtonRadius = deriveTemplateButtonRadius();
|
|
2014
|
+
const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
|
|
2015
|
+
const pagePath = window.location.pathname;
|
|
2016
|
+
const pageSections = state.sections.filter((entry) => (entry.path ?? "/") === pagePath);
|
|
2017
|
+
const activeIds = new Set(pageSections.map((entry) => entry.id));
|
|
2018
|
+
const ordered = state.hideTemplate === true ? applyExplicitOrder(orderByChain(pageSections)) : pageSections;
|
|
1328
2019
|
for (const [id, section] of mounted) {
|
|
1329
2020
|
if (!activeIds.has(id)) {
|
|
1330
2021
|
section.root.unmount();
|
|
@@ -1332,8 +2023,8 @@ function applyAiSectionsToDom(state, options) {
|
|
|
1332
2023
|
mounted.delete(id);
|
|
1333
2024
|
}
|
|
1334
2025
|
}
|
|
1335
|
-
for (const entry of
|
|
1336
|
-
const serialized = JSON.stringify(entry);
|
|
2026
|
+
for (const entry of ordered) {
|
|
2027
|
+
const serialized = JSON.stringify(entry) + brandKey;
|
|
1337
2028
|
const existing = mounted.get(entry.id);
|
|
1338
2029
|
if (existing && existing.serialized === serialized && existing.container.isConnected) {
|
|
1339
2030
|
continue;
|
|
@@ -1358,7 +2049,8 @@ function applyAiSectionsToDom(state, options) {
|
|
|
1358
2049
|
AiTreeRenderer,
|
|
1359
2050
|
{
|
|
1360
2051
|
tree: entry.tree,
|
|
1361
|
-
brand: entry.brand ?? options?.brand ?? templateBrand ?? void 0,
|
|
2052
|
+
brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
|
|
2053
|
+
buttonRadius: templateButtonRadius,
|
|
1362
2054
|
resolveMedia,
|
|
1363
2055
|
editKeyPrefix: `ai.${entry.id}`
|
|
1364
2056
|
}
|
|
@@ -1367,8 +2059,20 @@ function applyAiSectionsToDom(state, options) {
|
|
|
1367
2059
|
});
|
|
1368
2060
|
mounted.set(entry.id, { root, container, serialized });
|
|
1369
2061
|
}
|
|
2062
|
+
if (state.hideTemplate === true) {
|
|
2063
|
+
let prev = null;
|
|
2064
|
+
for (const entry of ordered) {
|
|
2065
|
+
const el = mounted.get(entry.id)?.container;
|
|
2066
|
+
if (!el) continue;
|
|
2067
|
+
if (prev && !(prev.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_FOLLOWING)) {
|
|
2068
|
+
prev.insertAdjacentElement("afterend", el);
|
|
2069
|
+
}
|
|
2070
|
+
prev = el;
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
1370
2073
|
syncReplacedOriginals(state);
|
|
1371
2074
|
syncRemovedSections(state);
|
|
2075
|
+
syncTemplateHidden(state, pageSections.length > 0);
|
|
1372
2076
|
}
|
|
1373
2077
|
|
|
1374
2078
|
// src/useLinkHrefGuardian.ts
|
|
@@ -1975,7 +2679,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
1975
2679
|
const autoId = useId();
|
|
1976
2680
|
const insertAfter = insertAfterProp ?? autoId;
|
|
1977
2681
|
const [schedule, setSchedule] = useState2(null);
|
|
1978
|
-
const [loading, setLoading] = useState2(
|
|
2682
|
+
const [loading, setLoading] = useState2(initialScheduleId !== null);
|
|
1979
2683
|
const [inEditor, setInEditor] = useState2(false);
|
|
1980
2684
|
const [isHovered, setIsHovered] = useState2(false);
|
|
1981
2685
|
const [modalState, setModalState] = useState2(null);
|
|
@@ -2149,8 +2853,10 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
2149
2853
|
"*"
|
|
2150
2854
|
);
|
|
2151
2855
|
};
|
|
2152
|
-
if (!inEditor && !loading && !schedule) return null;
|
|
2153
2856
|
const sectionId = `scheduling-${insertAfter}`;
|
|
2857
|
+
if (!inEditor && !loading && !schedule) {
|
|
2858
|
+
return /* @__PURE__ */ jsx4("section", { "data-ohw-section": sectionId, "data-ohw-scheduling-anchor": insertAfter, style: { display: "none" } });
|
|
2859
|
+
}
|
|
2154
2860
|
return /* @__PURE__ */ jsxs3(
|
|
2155
2861
|
"section",
|
|
2156
2862
|
{
|
|
@@ -7067,13 +7773,17 @@ function MediaOverlay({
|
|
|
7067
7773
|
hover,
|
|
7068
7774
|
isUploading,
|
|
7069
7775
|
fadingOut = false,
|
|
7776
|
+
selected = false,
|
|
7777
|
+
hovered = false,
|
|
7070
7778
|
onFadeOutComplete,
|
|
7071
7779
|
onReplace,
|
|
7780
|
+
onSelect,
|
|
7072
7781
|
onVideoSettingsChange
|
|
7073
7782
|
}) {
|
|
7074
7783
|
const { rect } = hover;
|
|
7075
7784
|
const skeletonRef = React8.useRef(null);
|
|
7076
7785
|
const isVideo = hover.elementType === "video";
|
|
7786
|
+
const showChrome = !selected || hovered;
|
|
7077
7787
|
const autoplay = hover.videoAutoplay ?? true;
|
|
7078
7788
|
const muted = hover.videoMuted ?? true;
|
|
7079
7789
|
const probeRef = React8.useRef(null);
|
|
@@ -7087,6 +7797,7 @@ function MediaOverlay({
|
|
|
7087
7797
|
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
7088
7798
|
);
|
|
7089
7799
|
}, [isVideo]);
|
|
7800
|
+
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
7090
7801
|
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
7091
7802
|
const box = {
|
|
7092
7803
|
position: "fixed",
|
|
@@ -7120,7 +7831,7 @@ function MediaOverlay({
|
|
|
7120
7831
|
}
|
|
7121
7832
|
);
|
|
7122
7833
|
}
|
|
7123
|
-
const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ jsxs7(
|
|
7834
|
+
const settingsBar = isVideo && !hover.isDragOver && showChrome ? /* @__PURE__ */ jsxs7(
|
|
7124
7835
|
"div",
|
|
7125
7836
|
{
|
|
7126
7837
|
"data-ohw-bridge": "",
|
|
@@ -7190,10 +7901,12 @@ function MediaOverlay({
|
|
|
7190
7901
|
// in-document, pointer-events does it natively. The button below opts back in, so
|
|
7191
7902
|
// Replace still works.
|
|
7192
7903
|
pointerEvents: hover.hasTextOverlap ? "none" : "auto",
|
|
7193
|
-
|
|
7194
|
-
|
|
7904
|
+
// Selected: a firm component ring with no wash, so the image reads as chosen rather
|
|
7905
|
+
// than hovered. Hover keeps the existing tinted preview.
|
|
7906
|
+
boxShadow: selected ? "inset 0 0 0 2px var(--color-primary)" : "inset 0 0 0 1.5px var(--color-primary)",
|
|
7907
|
+
background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
7195
7908
|
},
|
|
7196
|
-
onClick: () => onReplace(hover.key),
|
|
7909
|
+
onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
|
|
7197
7910
|
children: [
|
|
7198
7911
|
/* @__PURE__ */ jsxs7(
|
|
7199
7912
|
Button,
|
|
@@ -7214,17 +7927,17 @@ function MediaOverlay({
|
|
|
7214
7927
|
},
|
|
7215
7928
|
children: [
|
|
7216
7929
|
isVideo ? /* @__PURE__ */ jsx15(Film, { size: 14 }) : /* @__PURE__ */ jsx15(ImageIcon, { size: 14 }),
|
|
7217
|
-
|
|
7930
|
+
replaceLabel
|
|
7218
7931
|
]
|
|
7219
7932
|
}
|
|
7220
7933
|
),
|
|
7221
|
-
replaceMode
|
|
7934
|
+
showChrome && replaceMode !== "none" && /* @__PURE__ */ jsxs7(
|
|
7222
7935
|
Button,
|
|
7223
7936
|
{
|
|
7224
7937
|
"data-ohw-media-overlay": "",
|
|
7225
7938
|
variant: "outline",
|
|
7226
7939
|
size: "sm",
|
|
7227
|
-
"aria-label":
|
|
7940
|
+
"aria-label": replaceLabel,
|
|
7228
7941
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
7229
7942
|
style: {
|
|
7230
7943
|
...OVERLAY_BUTTON_STYLE,
|
|
@@ -7247,7 +7960,7 @@ function MediaOverlay({
|
|
|
7247
7960
|
},
|
|
7248
7961
|
children: [
|
|
7249
7962
|
isVideo ? /* @__PURE__ */ jsx15(Film, { size: 14 }) : /* @__PURE__ */ jsx15(ImageIcon, { size: 14 }),
|
|
7250
|
-
replaceMode === "full" ?
|
|
7963
|
+
replaceMode === "full" ? replaceLabel : null
|
|
7251
7964
|
]
|
|
7252
7965
|
}
|
|
7253
7966
|
)
|
|
@@ -7331,6 +8044,8 @@ function parseSectionsFromRoot(root) {
|
|
|
7331
8044
|
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
7332
8045
|
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
7333
8046
|
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
8047
|
+
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
8048
|
+
continue;
|
|
7334
8049
|
seen.add(id);
|
|
7335
8050
|
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
7336
8051
|
sections.push({ id, label });
|
|
@@ -7360,6 +8075,10 @@ function topLevelSections() {
|
|
|
7360
8075
|
function instanceIdOf(el) {
|
|
7361
8076
|
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
7362
8077
|
}
|
|
8078
|
+
function findByInstanceId(instanceId) {
|
|
8079
|
+
const escapedId = CSS.escape(instanceId);
|
|
8080
|
+
return document.querySelector(`[data-ohw-instance="${escapedId}"]`) ?? document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
8081
|
+
}
|
|
7363
8082
|
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
7364
8083
|
const sections = topLevelSections();
|
|
7365
8084
|
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
@@ -7395,7 +8114,7 @@ function syncRemovedFlags(entries) {
|
|
|
7395
8114
|
}
|
|
7396
8115
|
});
|
|
7397
8116
|
for (const id of removedIds) {
|
|
7398
|
-
const el =
|
|
8117
|
+
const el = findByInstanceId(id);
|
|
7399
8118
|
if (el) {
|
|
7400
8119
|
el.style.display = "none";
|
|
7401
8120
|
el.setAttribute(REMOVED_ATTR2, "");
|
|
@@ -7423,7 +8142,7 @@ function applyPersistedOrder(entries) {
|
|
|
7423
8142
|
}
|
|
7424
8143
|
}
|
|
7425
8144
|
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
7426
|
-
if (!
|
|
8145
|
+
if (!findByInstanceId(instanceId)) return null;
|
|
7427
8146
|
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
7428
8147
|
const allSections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
7429
8148
|
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
|
|
@@ -7612,6 +8331,7 @@ function AiSectionOverlay({
|
|
|
7612
8331
|
}) {
|
|
7613
8332
|
const [selectedId, setSelectedId] = useState5(null);
|
|
7614
8333
|
const [reviewId, setReviewId] = useState5(null);
|
|
8334
|
+
const [reviewButtonsHidden, setReviewButtonsHidden] = useState5(false);
|
|
7615
8335
|
const reviewIdRef = useRef4(null);
|
|
7616
8336
|
reviewIdRef.current = reviewId;
|
|
7617
8337
|
const selectedIdRef = useRef4(null);
|
|
@@ -7673,6 +8393,7 @@ function AiSectionOverlay({
|
|
|
7673
8393
|
}
|
|
7674
8394
|
const found = readRect(sectionId) != null;
|
|
7675
8395
|
setReviewId(found ? sectionId : null);
|
|
8396
|
+
setReviewButtonsHidden(e.data.hideButtons === true);
|
|
7676
8397
|
postToParent2({ type: "ow:ai-review-started", sectionId, found });
|
|
7677
8398
|
if (found) {
|
|
7678
8399
|
document.querySelector(`[data-ohw-instance="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
|
@@ -7800,13 +8521,16 @@ function AiSectionOverlay({
|
|
|
7800
8521
|
border: `2px solid ${PRIMARY2}`,
|
|
7801
8522
|
borderRadius: edgeAwareRadius(reviewRect),
|
|
7802
8523
|
zIndex: 2147483200,
|
|
7803
|
-
// The veil itself: swallows clicks so the section stays locked until decided.
|
|
8524
|
+
// The veil itself: swallows clicks so the section stays locked until decided. This
|
|
8525
|
+
// stopPropagation only guards the bubble phase; the bridge's capture-phase click
|
|
8526
|
+
// handlers additionally bail on `[data-ohw-ai-review]`, without which a click on
|
|
8527
|
+
// Accept/Discard resolves to the media beneath and opens the file picker.
|
|
7804
8528
|
background: "rgba(8, 133, 254, 0.04)",
|
|
7805
8529
|
pointerEvents: "auto",
|
|
7806
8530
|
cursor: "default"
|
|
7807
8531
|
},
|
|
7808
8532
|
onClick: (e) => e.stopPropagation(),
|
|
7809
|
-
children: /* @__PURE__ */ jsxs9(
|
|
8533
|
+
children: !reviewButtonsHidden && /* @__PURE__ */ jsxs9(
|
|
7810
8534
|
"div",
|
|
7811
8535
|
{
|
|
7812
8536
|
style: {
|
|
@@ -10373,8 +11097,13 @@ function referenceBox(slot) {
|
|
|
10373
11097
|
const neighbour = row ? Array.from(row.querySelectorAll('[data-ohw-editable="icon"]')).find(
|
|
10374
11098
|
(el) => el !== slot && !el.hasAttribute("data-ohw-social-icon-placeholder")
|
|
10375
11099
|
) : null;
|
|
10376
|
-
|
|
10377
|
-
|
|
11100
|
+
if (neighbour) {
|
|
11101
|
+
const box2 = neighbour.querySelector(GLYPH_SELECTOR)?.getBoundingClientRect();
|
|
11102
|
+
if (box2?.width && box2.height) return box2;
|
|
11103
|
+
}
|
|
11104
|
+
const own = slot.getBoundingClientRect();
|
|
11105
|
+
if (own.width && own.height) return own;
|
|
11106
|
+
const box = slot.querySelector(GLYPH_SELECTOR)?.getBoundingClientRect() ?? null;
|
|
10378
11107
|
return box?.width && box.height ? box : null;
|
|
10379
11108
|
}
|
|
10380
11109
|
function iconMarkupSizedFor(slot, markup) {
|
|
@@ -12175,6 +12904,7 @@ function readLogoSizeState(content, placement) {
|
|
|
12175
12904
|
function getLogoElement(el) {
|
|
12176
12905
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
12177
12906
|
if (marked) return marked;
|
|
12907
|
+
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
12178
12908
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
12179
12909
|
if (!root) return null;
|
|
12180
12910
|
const anchor = el.closest("a");
|
|
@@ -13249,6 +13979,7 @@ function useSectionDrag({
|
|
|
13249
13979
|
}
|
|
13250
13980
|
const orderJson = JSON.stringify(entries);
|
|
13251
13981
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
13982
|
+
setAiSectionOrder(orderJson, window.location.pathname);
|
|
13252
13983
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
13253
13984
|
applyPersistedOrder(entries);
|
|
13254
13985
|
clearSectionDragVisuals();
|
|
@@ -14108,21 +14839,10 @@ function parseSchedulingInsertAfter(insertAfter) {
|
|
|
14108
14839
|
insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
|
|
14109
14840
|
};
|
|
14110
14841
|
}
|
|
14111
|
-
function
|
|
14112
|
-
|
|
14113
|
-
const
|
|
14114
|
-
|
|
14115
|
-
return { effectiveInsertAfter, insertBefore };
|
|
14116
|
-
}
|
|
14117
|
-
function getSchedulingMountPoint(insertAfter) {
|
|
14118
|
-
const { anchor } = parseSchedulingInsertAfter(insertAfter);
|
|
14119
|
-
let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
|
|
14120
|
-
if (!anchorEl && anchor === "scheduling") {
|
|
14121
|
-
const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
|
|
14122
|
-
anchorEl = widgets.at(-1) ?? null;
|
|
14123
|
-
}
|
|
14124
|
-
if (!anchorEl) return null;
|
|
14125
|
-
return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
14842
|
+
function resolveEntryAnchor(entry) {
|
|
14843
|
+
if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
|
|
14844
|
+
const parsed = parseSchedulingInsertAfter(entry.insertAfter);
|
|
14845
|
+
return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
|
|
14126
14846
|
}
|
|
14127
14847
|
function schedulingMountDepth(insertAfter) {
|
|
14128
14848
|
if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
|
|
@@ -14139,8 +14859,7 @@ function getPageSchedulingEntries(raw) {
|
|
|
14139
14859
|
}
|
|
14140
14860
|
}
|
|
14141
14861
|
function isSchedulingWidgetMissing(entry) {
|
|
14142
|
-
|
|
14143
|
-
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
|
|
14862
|
+
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
|
|
14144
14863
|
}
|
|
14145
14864
|
function hasMissingSchedulingWidgets(entries) {
|
|
14146
14865
|
return entries.some(isSchedulingWidgetMissing);
|
|
@@ -14170,16 +14889,17 @@ function initSectionsFromContent(content, removeExisting = false) {
|
|
|
14170
14889
|
} catch {
|
|
14171
14890
|
}
|
|
14172
14891
|
}
|
|
14173
|
-
function mountSchedulingWidget(
|
|
14174
|
-
const
|
|
14175
|
-
const sectionId = schedulingSectionId(
|
|
14892
|
+
function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
|
|
14893
|
+
const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
|
|
14894
|
+
const sectionId = schedulingSectionId(widgetId);
|
|
14176
14895
|
if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
|
|
14177
|
-
const
|
|
14178
|
-
if (!
|
|
14896
|
+
const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
|
|
14897
|
+
if (!anchorEl) return false;
|
|
14898
|
+
const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
14179
14899
|
const container = document.createElement("div");
|
|
14180
14900
|
container.dataset.ohwSectionContainer = "scheduling";
|
|
14181
|
-
if (
|
|
14182
|
-
const beforeAnchor = document.querySelector(`[data-ohw-section="${
|
|
14901
|
+
if (beforeId) {
|
|
14902
|
+
const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
|
|
14183
14903
|
const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
|
|
14184
14904
|
if (!beforePoint) return false;
|
|
14185
14905
|
beforePoint.insertAdjacentElement("beforebegin", container);
|
|
@@ -14190,19 +14910,25 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
14190
14910
|
}
|
|
14191
14911
|
tail.insertAdjacentElement("afterend", container);
|
|
14192
14912
|
}
|
|
14193
|
-
|
|
14194
|
-
|
|
14195
|
-
|
|
14196
|
-
|
|
14197
|
-
|
|
14198
|
-
|
|
14199
|
-
|
|
14200
|
-
|
|
14201
|
-
|
|
14202
|
-
|
|
14203
|
-
|
|
14204
|
-
|
|
14205
|
-
|
|
14913
|
+
try {
|
|
14914
|
+
const root = createRoot2(container);
|
|
14915
|
+
flushSync2(() => {
|
|
14916
|
+
root.render(
|
|
14917
|
+
/* @__PURE__ */ jsx33(
|
|
14918
|
+
SchedulingWidget,
|
|
14919
|
+
{
|
|
14920
|
+
notifyOnConnect,
|
|
14921
|
+
initialScheduleId: scheduleId,
|
|
14922
|
+
insertAfter: widgetId
|
|
14923
|
+
}
|
|
14924
|
+
)
|
|
14925
|
+
);
|
|
14926
|
+
});
|
|
14927
|
+
} catch (err) {
|
|
14928
|
+
console.error("[ow:scheduling] render threw", err);
|
|
14929
|
+
container.remove();
|
|
14930
|
+
return false;
|
|
14931
|
+
}
|
|
14206
14932
|
const tracker = getSectionsTracker();
|
|
14207
14933
|
let sections = [];
|
|
14208
14934
|
try {
|
|
@@ -14210,10 +14936,12 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
14210
14936
|
} catch {
|
|
14211
14937
|
}
|
|
14212
14938
|
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
14213
|
-
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter ===
|
|
14939
|
+
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
|
|
14214
14940
|
sections.push({
|
|
14215
14941
|
type: "scheduling",
|
|
14216
|
-
insertAfter:
|
|
14942
|
+
insertAfter: widgetId,
|
|
14943
|
+
anchorId,
|
|
14944
|
+
beforeId: beforeId ?? null,
|
|
14217
14945
|
pagePath: window.location.pathname,
|
|
14218
14946
|
...scheduleId ? { scheduleId } : {}
|
|
14219
14947
|
});
|
|
@@ -14227,7 +14955,8 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
|
14227
14955
|
for (let i = pending.length - 1; i >= 0; i--) {
|
|
14228
14956
|
const entry = pending[i];
|
|
14229
14957
|
const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
|
|
14230
|
-
|
|
14958
|
+
const { anchorId, beforeId } = resolveEntryAnchor(entry);
|
|
14959
|
+
if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
|
|
14231
14960
|
pending.splice(i, 1);
|
|
14232
14961
|
}
|
|
14233
14962
|
}
|
|
@@ -14385,6 +15114,11 @@ function applyLinkByKey(key, val) {
|
|
|
14385
15114
|
hrefAnchors.forEach((el) => applyLinkHref(el, val));
|
|
14386
15115
|
}
|
|
14387
15116
|
}
|
|
15117
|
+
function isInsideLinkEditor(target) {
|
|
15118
|
+
return Boolean(
|
|
15119
|
+
target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest("[data-ohw-footer-container-chrome]") || target.closest("[data-ohw-footer-add-button]") || target.closest("[data-ohw-more-menu]") || target.closest('[data-slot="dropdown-menu-content"]') || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
|
|
15120
|
+
);
|
|
15121
|
+
}
|
|
14388
15122
|
function isInsideFloatingPanel(target) {
|
|
14389
15123
|
return Boolean(target.closest("[data-ohw-floating-panel]"));
|
|
14390
15124
|
}
|
|
@@ -14392,11 +15126,6 @@ function isPointOverFloatingPanel(clientX, clientY) {
|
|
|
14392
15126
|
const el = document.elementFromPoint(clientX, clientY);
|
|
14393
15127
|
return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
|
|
14394
15128
|
}
|
|
14395
|
-
function isInsideLinkEditor(target) {
|
|
14396
|
-
return Boolean(
|
|
14397
|
-
target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest("[data-ohw-footer-container-chrome]") || target.closest("[data-ohw-footer-add-button]") || target.closest("[data-ohw-more-menu]") || target.closest('[data-slot="dropdown-menu-content"]') || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
|
|
14398
|
-
);
|
|
14399
|
-
}
|
|
14400
15129
|
function getHrefKeyFromElement(el) {
|
|
14401
15130
|
if (!el) return null;
|
|
14402
15131
|
const anchor = el.closest("[data-ohw-href-key]");
|
|
@@ -14655,7 +15384,7 @@ function getNavigationSelectionParent(el) {
|
|
|
14655
15384
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
14656
15385
|
return getFooterLinksContainer();
|
|
14657
15386
|
}
|
|
14658
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
15387
|
+
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isFooterLinksContainer(el) || isInferredFooterGroup2(el)) {
|
|
14659
15388
|
return getNavigationRoot(el);
|
|
14660
15389
|
}
|
|
14661
15390
|
return null;
|
|
@@ -14870,7 +15599,6 @@ var ICONS = {
|
|
|
14870
15599
|
insertUnorderedList: '<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>',
|
|
14871
15600
|
insertOrderedList: '<line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/>'
|
|
14872
15601
|
};
|
|
14873
|
-
var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
|
|
14874
15602
|
var SELECTION_CHROME_GAP2 = 4;
|
|
14875
15603
|
var TOOLBAR_STROKE_GAP2 = 4;
|
|
14876
15604
|
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
@@ -15250,6 +15978,7 @@ function StateToggle({
|
|
|
15250
15978
|
);
|
|
15251
15979
|
}
|
|
15252
15980
|
var contentCache = /* @__PURE__ */ new Map();
|
|
15981
|
+
var fetchedContentPaths = /* @__PURE__ */ new Set();
|
|
15253
15982
|
var OHW_LOADER_STYLE = {
|
|
15254
15983
|
position: "fixed",
|
|
15255
15984
|
inset: 0,
|
|
@@ -15368,6 +16097,70 @@ function OhhwellsBridge() {
|
|
|
15368
16097
|
const hoveredImageHasTextOverlapRef = useRef10(false);
|
|
15369
16098
|
const dragOverElRef = useRef10(null);
|
|
15370
16099
|
const [mediaHover, setMediaHover] = useState13(null);
|
|
16100
|
+
const [selectedMedia, setSelectedMedia] = useState13(null);
|
|
16101
|
+
const selectedMediaElRef = useRef10(null);
|
|
16102
|
+
const clearMediaSelection = useCallback8(() => {
|
|
16103
|
+
const prev = selectedMediaElRef.current;
|
|
16104
|
+
selectedMediaElRef.current = null;
|
|
16105
|
+
setSelectedMedia(null);
|
|
16106
|
+
const sectionEl = prev?.closest("[data-ohw-section]") ?? null;
|
|
16107
|
+
if (sectionEl) {
|
|
16108
|
+
postToParentRef.current({
|
|
16109
|
+
type: "ow:section-selected",
|
|
16110
|
+
sectionId: sectionEl.dataset.ohwSection ?? null,
|
|
16111
|
+
sectionLabel: sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? ""),
|
|
16112
|
+
key: null
|
|
16113
|
+
});
|
|
16114
|
+
}
|
|
16115
|
+
}, []);
|
|
16116
|
+
const clearMediaSelectionRef = useRef10(clearMediaSelection);
|
|
16117
|
+
clearMediaSelectionRef.current = clearMediaSelection;
|
|
16118
|
+
const selectMediaElement = useCallback8((el) => {
|
|
16119
|
+
const r2 = el.getBoundingClientRect();
|
|
16120
|
+
const video = el.dataset.ohwEditable === "video" ? el.querySelector("video") : null;
|
|
16121
|
+
selectedMediaElRef.current = el;
|
|
16122
|
+
setSelectedMedia({
|
|
16123
|
+
key: el.dataset.ohwKey ?? "",
|
|
16124
|
+
rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
|
|
16125
|
+
elementType: el.dataset.ohwEditable ?? "image",
|
|
16126
|
+
hasTextOverlap: false,
|
|
16127
|
+
isDragOver: false,
|
|
16128
|
+
...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
|
|
16129
|
+
});
|
|
16130
|
+
const sectionEl = el.closest("[data-ohw-section]");
|
|
16131
|
+
aiSectionApiRef.current?.selectFromElement(el, { report: false });
|
|
16132
|
+
postToParentRef.current({
|
|
16133
|
+
type: "ow:section-selected",
|
|
16134
|
+
sectionId: sectionEl?.dataset.ohwSection ?? null,
|
|
16135
|
+
sectionLabel: sectionEl ? sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? "") : null,
|
|
16136
|
+
key: el.dataset.ohwKey ?? null,
|
|
16137
|
+
// Display name for the pill — the raw key prettifies into fragments ("Img"); the
|
|
16138
|
+
// bridge knows what the node IS, so it names it.
|
|
16139
|
+
keyLabel: el.dataset.ohwEditable === "video" ? "Video" : el.dataset.ohwEditable === "bg-image" ? "Background" : "Image"
|
|
16140
|
+
});
|
|
16141
|
+
}, []);
|
|
16142
|
+
const selectMediaElementRef = useRef10(selectMediaElement);
|
|
16143
|
+
selectMediaElementRef.current = selectMediaElement;
|
|
16144
|
+
useEffect13(() => {
|
|
16145
|
+
if (!selectedMedia) return;
|
|
16146
|
+
const update = () => {
|
|
16147
|
+
const el = selectedMediaElRef.current;
|
|
16148
|
+
if (!el || !el.isConnected) {
|
|
16149
|
+
clearMediaSelection();
|
|
16150
|
+
return;
|
|
16151
|
+
}
|
|
16152
|
+
const r2 = el.getBoundingClientRect();
|
|
16153
|
+
setSelectedMedia(
|
|
16154
|
+
(prev) => prev ? { ...prev, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } } : prev
|
|
16155
|
+
);
|
|
16156
|
+
};
|
|
16157
|
+
window.addEventListener("scroll", update, true);
|
|
16158
|
+
window.addEventListener("resize", update);
|
|
16159
|
+
return () => {
|
|
16160
|
+
window.removeEventListener("scroll", update, true);
|
|
16161
|
+
window.removeEventListener("resize", update);
|
|
16162
|
+
};
|
|
16163
|
+
}, [selectedMedia !== null]);
|
|
15371
16164
|
const [carouselHover, setCarouselHover] = useState13(null);
|
|
15372
16165
|
const [uploadingRects, setUploadingRects] = useState13({});
|
|
15373
16166
|
const hoveredGapRef = useRef10(null);
|
|
@@ -15630,13 +16423,6 @@ function OhhwellsBridge() {
|
|
|
15630
16423
|
const [isItemDragging, setIsItemDragging] = useState13(false);
|
|
15631
16424
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = useState13(false);
|
|
15632
16425
|
isFooterFrameSelectionRef.current = isFooterFrameSelection;
|
|
15633
|
-
const [floatingPanel, setFloatingPanel] = useState13(null);
|
|
15634
|
-
const floatingPanelOpenRef = useRef10(false);
|
|
15635
|
-
floatingPanelOpenRef.current = floatingPanel !== null;
|
|
15636
|
-
const [floatingPanelPos, setFloatingPanelPos] = useState13(null);
|
|
15637
|
-
const [logoSizeDraft, setLogoSizeDraft] = useState13(null);
|
|
15638
|
-
const [editorViewport, setEditorViewport] = useState13("desktop");
|
|
15639
|
-
const [parentScrollSnap, setParentScrollSnap] = useState13(null);
|
|
15640
16426
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState13(null);
|
|
15641
16427
|
const [footerHeadingVisible, setFooterHeadingVisible] = useState13(null);
|
|
15642
16428
|
const footerDragRef = useRef10(null);
|
|
@@ -15651,7 +16437,16 @@ function OhhwellsBridge() {
|
|
|
15651
16437
|
const addNavAfterAnchorRef = useRef10(null);
|
|
15652
16438
|
const editContentRef = useRef10({});
|
|
15653
16439
|
const aiSectionsRef = useRef10("");
|
|
16440
|
+
const brandKitRef = useRef10("");
|
|
16441
|
+
const stylesRef = useRef10("");
|
|
15654
16442
|
const pendingDeleteUndoRef = useRef10(null);
|
|
16443
|
+
const [floatingPanel, setFloatingPanel] = useState13(null);
|
|
16444
|
+
const floatingPanelOpenRef = useRef10(false);
|
|
16445
|
+
const setFloatingPanelRef = useRef10(setFloatingPanel);
|
|
16446
|
+
const [floatingPanelPos, setFloatingPanelPos] = useState13(null);
|
|
16447
|
+
const [logoSizeDraft, setLogoSizeDraft] = useState13(null);
|
|
16448
|
+
const [editorViewport, setEditorViewport] = useState13("desktop");
|
|
16449
|
+
const [parentScrollSnap, setParentScrollSnap] = useState13(null);
|
|
15655
16450
|
const [sitePages, setSitePages] = useState13([]);
|
|
15656
16451
|
const [sectionsByPath, setSectionsByPath] = useState13({});
|
|
15657
16452
|
const sectionsPrefetchGenRef = useRef10(0);
|
|
@@ -15660,7 +16455,18 @@ function OhhwellsBridge() {
|
|
|
15660
16455
|
const linkPopoverOpenRef = useRef10(false);
|
|
15661
16456
|
const linkPopoverGraceUntilRef = useRef10(0);
|
|
15662
16457
|
setLinkPopoverRef.current = setLinkPopover;
|
|
16458
|
+
setFloatingPanelRef.current = setFloatingPanel;
|
|
15663
16459
|
linkPopoverSessionRef.current = linkPopover;
|
|
16460
|
+
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
16461
|
+
useEffect13(() => {
|
|
16462
|
+
const syncViewport = () => {
|
|
16463
|
+
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
16464
|
+
setEditorViewport((prev) => prev === next ? prev : next);
|
|
16465
|
+
};
|
|
16466
|
+
syncViewport();
|
|
16467
|
+
window.addEventListener("resize", syncViewport);
|
|
16468
|
+
return () => window.removeEventListener("resize", syncViewport);
|
|
16469
|
+
}, []);
|
|
15664
16470
|
const {
|
|
15665
16471
|
navDragRef,
|
|
15666
16472
|
navDropSlots,
|
|
@@ -16971,15 +17777,31 @@ function OhhwellsBridge() {
|
|
|
16971
17777
|
}
|
|
16972
17778
|
const applyContent = (content) => {
|
|
16973
17779
|
const imageLoads = [];
|
|
17780
|
+
if (typeof content[BRAND_KIT_KEY] === "string") {
|
|
17781
|
+
brandKitRef.current = content[BRAND_KIT_KEY];
|
|
17782
|
+
applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
|
|
17783
|
+
} else {
|
|
17784
|
+
brandKitRef.current = "";
|
|
17785
|
+
applyBrandToDom(null);
|
|
17786
|
+
}
|
|
16974
17787
|
if (typeof content[AI_SECTIONS_KEY] === "string") {
|
|
16975
17788
|
aiSectionsRef.current = content[AI_SECTIONS_KEY];
|
|
17789
|
+
setAiSectionOrder(content[SECTION_ORDER_KEY], window.location.pathname);
|
|
16976
17790
|
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
16977
17791
|
}
|
|
17792
|
+
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
17793
|
+
stylesRef.current = content[STYLE_STORE_KEY];
|
|
17794
|
+
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
17795
|
+
}
|
|
17796
|
+
applyBrandChrome(content);
|
|
16978
17797
|
for (const [key, val] of Object.entries(content)) {
|
|
16979
17798
|
if (key === "__ohw_sections") continue;
|
|
16980
17799
|
if (key === AI_SECTIONS_KEY) continue;
|
|
16981
17800
|
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
16982
17801
|
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
17802
|
+
if (key === BRAND_KIT_KEY) continue;
|
|
17803
|
+
if (key === STYLE_STORE_KEY) continue;
|
|
17804
|
+
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
16983
17805
|
if (applyVideoSettingNode(key, val)) continue;
|
|
16984
17806
|
if (applyCarouselNode(key, val)) continue;
|
|
16985
17807
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -17045,7 +17867,9 @@ function OhhwellsBridge() {
|
|
|
17045
17867
|
let cancelled = false;
|
|
17046
17868
|
setFetchState("loading");
|
|
17047
17869
|
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
17048
|
-
|
|
17870
|
+
const initialPath = pathname;
|
|
17871
|
+
fetchedContentPaths.add(`${subdomain}::${initialPath}`);
|
|
17872
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
17049
17873
|
if (cancelled) return;
|
|
17050
17874
|
const content = data?.content ?? {};
|
|
17051
17875
|
contentCache.set(subdomain, content);
|
|
@@ -17165,10 +17989,28 @@ function OhhwellsBridge() {
|
|
|
17165
17989
|
initSectionInstancesFromContent(content, window.location.pathname);
|
|
17166
17990
|
observer?.disconnect();
|
|
17167
17991
|
try {
|
|
17992
|
+
applyBrandChrome(content);
|
|
17993
|
+
if (typeof content[BRAND_KIT_KEY] === "string") {
|
|
17994
|
+
applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
|
|
17995
|
+
} else {
|
|
17996
|
+
applyBrandToDom(null);
|
|
17997
|
+
}
|
|
17998
|
+
if (typeof content[AI_SECTIONS_KEY] === "string") {
|
|
17999
|
+
setAiSectionOrder(content[SECTION_ORDER_KEY], window.location.pathname);
|
|
18000
|
+
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
18001
|
+
}
|
|
18002
|
+
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
18003
|
+
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
18004
|
+
}
|
|
17168
18005
|
for (const [key, val] of Object.entries(content)) {
|
|
17169
18006
|
if (key === "__ohw_sections") continue;
|
|
18007
|
+
if (key === AI_SECTIONS_KEY) continue;
|
|
17170
18008
|
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
17171
18009
|
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18010
|
+
if (key === BRAND_KIT_KEY) continue;
|
|
18011
|
+
if (key === STYLE_STORE_KEY) continue;
|
|
18012
|
+
if (key === STYLE_STORE_KEY) continue;
|
|
18013
|
+
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
17172
18014
|
if (applyVideoSettingNode(key, val)) continue;
|
|
17173
18015
|
if (applyCarouselNode(key, val)) continue;
|
|
17174
18016
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -17214,6 +18056,17 @@ function OhhwellsBridge() {
|
|
|
17214
18056
|
debounceTimer = setTimeout(applyFromCache, 150);
|
|
17215
18057
|
};
|
|
17216
18058
|
applyFromCache();
|
|
18059
|
+
const pathCacheKey = `${subdomain}::${pathname}`;
|
|
18060
|
+
if (!fetchedContentPaths.has(pathCacheKey)) {
|
|
18061
|
+
fetchedContentPaths.add(pathCacheKey);
|
|
18062
|
+
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
18063
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
18064
|
+
if (!data?.content) return;
|
|
18065
|
+
contentCache.set(subdomain, data.content);
|
|
18066
|
+
applyFromCache();
|
|
18067
|
+
}).catch(() => {
|
|
18068
|
+
});
|
|
18069
|
+
}
|
|
17217
18070
|
observer = new MutationObserver(scheduleApply);
|
|
17218
18071
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
17219
18072
|
return () => {
|
|
@@ -17309,30 +18162,31 @@ function OhhwellsBridge() {
|
|
|
17309
18162
|
}, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
|
|
17310
18163
|
useEffect13(() => {
|
|
17311
18164
|
if (!isEditMode) return;
|
|
18165
|
+
let lastPosted = 0;
|
|
17312
18166
|
const measure = () => {
|
|
17313
18167
|
const h = document.body.scrollHeight;
|
|
17314
|
-
if (h > 50
|
|
18168
|
+
if (h > 50 && Math.abs(h - lastPosted) > 1) {
|
|
18169
|
+
lastPosted = h;
|
|
18170
|
+
postToParent2({ type: "ow:height", height: h });
|
|
18171
|
+
}
|
|
18172
|
+
};
|
|
18173
|
+
let raf = null;
|
|
18174
|
+
const schedule = () => {
|
|
18175
|
+
if (raf != null) return;
|
|
18176
|
+
raf = requestAnimationFrame(() => {
|
|
18177
|
+
raf = null;
|
|
18178
|
+
measure();
|
|
18179
|
+
});
|
|
17315
18180
|
};
|
|
17316
18181
|
const t1 = setTimeout(measure, 50);
|
|
17317
18182
|
const t2 = setTimeout(measure, 500);
|
|
17318
|
-
|
|
17319
|
-
|
|
17320
|
-
const clearResizeTimers = () => {
|
|
17321
|
-
resizeTimers.forEach(clearTimeout);
|
|
17322
|
-
resizeTimers = [];
|
|
17323
|
-
};
|
|
17324
|
-
const handleResize = () => {
|
|
17325
|
-
if (window.innerWidth === lastWidth) return;
|
|
17326
|
-
lastWidth = window.innerWidth;
|
|
17327
|
-
clearResizeTimers();
|
|
17328
|
-
resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
|
|
17329
|
-
};
|
|
17330
|
-
window.addEventListener("resize", handleResize);
|
|
18183
|
+
const ro = new ResizeObserver(schedule);
|
|
18184
|
+
ro.observe(document.body);
|
|
17331
18185
|
return () => {
|
|
17332
18186
|
clearTimeout(t1);
|
|
17333
18187
|
clearTimeout(t2);
|
|
17334
|
-
|
|
17335
|
-
|
|
18188
|
+
if (raf != null) cancelAnimationFrame(raf);
|
|
18189
|
+
ro.disconnect();
|
|
17336
18190
|
};
|
|
17337
18191
|
}, [pathname, isEditMode, postToParent2]);
|
|
17338
18192
|
useEffect13(() => {
|
|
@@ -17573,6 +18427,7 @@ function OhhwellsBridge() {
|
|
|
17573
18427
|
return;
|
|
17574
18428
|
}
|
|
17575
18429
|
const target = e.target;
|
|
18430
|
+
if (target.closest("[data-ohw-ai-review]")) return;
|
|
17576
18431
|
if (target.closest("[data-ohw-toolbar]")) return;
|
|
17577
18432
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
17578
18433
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
@@ -17584,6 +18439,9 @@ function OhhwellsBridge() {
|
|
|
17584
18439
|
)) {
|
|
17585
18440
|
return;
|
|
17586
18441
|
}
|
|
18442
|
+
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
18443
|
+
clearMediaSelectionRef.current();
|
|
18444
|
+
}
|
|
17587
18445
|
{
|
|
17588
18446
|
const formEl = getFormElement(target);
|
|
17589
18447
|
const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
|
|
@@ -17735,19 +18593,14 @@ function OhhwellsBridge() {
|
|
|
17735
18593
|
}
|
|
17736
18594
|
const clickedButton = findClosestButtonLike(target);
|
|
17737
18595
|
const buttonOnMedia = Boolean(clickedButton && isMediaEditable(editable) && editable.contains(clickedButton));
|
|
17738
|
-
console.log("[click-debug]", {
|
|
17739
|
-
editableType: editable.dataset.ohwEditable,
|
|
17740
|
-
editableTag: editable.tagName,
|
|
17741
|
-
targetTag: target.tagName,
|
|
17742
|
-
clickedButtonTag: clickedButton?.tagName ?? null,
|
|
17743
|
-
buttonOnMedia,
|
|
17744
|
-
isMediaEditableEditable: isMediaEditable(editable)
|
|
17745
|
-
});
|
|
17746
18596
|
if (isMediaEditable(editable) && !buttonOnMedia) {
|
|
17747
18597
|
e.preventDefault();
|
|
17748
18598
|
e.stopPropagation();
|
|
17749
|
-
|
|
17750
|
-
|
|
18599
|
+
if (selectedMediaElRef.current === editable) {
|
|
18600
|
+
postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
|
|
18601
|
+
} else {
|
|
18602
|
+
selectMediaElementRef.current(editable);
|
|
18603
|
+
}
|
|
17751
18604
|
return;
|
|
17752
18605
|
}
|
|
17753
18606
|
const socialItem = getSocialItem(editable);
|
|
@@ -17766,11 +18619,6 @@ function OhhwellsBridge() {
|
|
|
17766
18619
|
const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
|
|
17767
18620
|
const hrefCtx = getHrefKeyFromElement(hrefLookupTarget);
|
|
17768
18621
|
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
17769
|
-
console.log("[click-debug 2]", {
|
|
17770
|
-
hrefLookupTargetTag: hrefLookupTarget.tagName,
|
|
17771
|
-
hrefCtx: hrefCtx ? { key: hrefCtx.key } : null,
|
|
17772
|
-
navAnchorTag: navAnchor?.tagName ?? null
|
|
17773
|
-
});
|
|
17774
18622
|
if (navAnchor) {
|
|
17775
18623
|
e.preventDefault();
|
|
17776
18624
|
e.stopPropagation();
|
|
@@ -17888,6 +18736,7 @@ function OhhwellsBridge() {
|
|
|
17888
18736
|
};
|
|
17889
18737
|
const handleDblClick = (e) => {
|
|
17890
18738
|
const target = e.target;
|
|
18739
|
+
if (target.closest("[data-ohw-ai-review]")) return;
|
|
17891
18740
|
if (target.closest("[data-ohw-toolbar]")) return;
|
|
17892
18741
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
17893
18742
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
@@ -17939,6 +18788,9 @@ function OhhwellsBridge() {
|
|
|
17939
18788
|
setHoveredItemRect(null);
|
|
17940
18789
|
hoveredNavContainerRef.current = null;
|
|
17941
18790
|
setHoveredNavContainerRect(null);
|
|
18791
|
+
siblingHintElRef.current = null;
|
|
18792
|
+
setSiblingHintRect(null);
|
|
18793
|
+
setSiblingHintRects([]);
|
|
17942
18794
|
return;
|
|
17943
18795
|
}
|
|
17944
18796
|
{
|
|
@@ -18057,7 +18909,6 @@ function OhhwellsBridge() {
|
|
|
18057
18909
|
hoveredNavContainerRef.current = null;
|
|
18058
18910
|
setHoveredNavContainerRect(null);
|
|
18059
18911
|
hoveredItemElRef.current = editable;
|
|
18060
|
-
setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
|
|
18061
18912
|
}
|
|
18062
18913
|
}
|
|
18063
18914
|
}
|
|
@@ -18354,7 +19205,7 @@ function OhhwellsBridge() {
|
|
|
18354
19205
|
}
|
|
18355
19206
|
};
|
|
18356
19207
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
18357
|
-
if (linkPopoverOpenRef.current) {
|
|
19208
|
+
if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
18358
19209
|
if (hoveredImageRef.current) {
|
|
18359
19210
|
hoveredImageRef.current = null;
|
|
18360
19211
|
hoveredImageHasTextOverlapRef.current = false;
|
|
@@ -18688,7 +19539,9 @@ function OhhwellsBridge() {
|
|
|
18688
19539
|
return;
|
|
18689
19540
|
}
|
|
18690
19541
|
const { y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
18691
|
-
const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).
|
|
19542
|
+
const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
19543
|
+
(el) => !el.hasAttribute("data-ohw-ai-template-hidden") && !el.hasAttribute("data-ohw-ai-removed") && !el.hasAttribute("data-ohw-ai-replaced-by") && el.getBoundingClientRect().height > 0
|
|
19544
|
+
).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
|
|
18692
19545
|
const ZONE = 20;
|
|
18693
19546
|
for (let i = 0; i < sections.length; i++) {
|
|
18694
19547
|
const a = sections[i];
|
|
@@ -18717,8 +19570,7 @@ function OhhwellsBridge() {
|
|
|
18717
19570
|
};
|
|
18718
19571
|
const handleMouseMove = (e) => {
|
|
18719
19572
|
const { clientX, clientY } = e;
|
|
18720
|
-
if (
|
|
18721
|
-
if (isOverEditorChrome(clientX, clientY)) {
|
|
19573
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
|
|
18722
19574
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
18723
19575
|
formHoverElRef.current = null;
|
|
18724
19576
|
setFormHoverRect(null);
|
|
@@ -18726,6 +19578,12 @@ function OhhwellsBridge() {
|
|
|
18726
19578
|
setHoveredItemRect(null);
|
|
18727
19579
|
hoveredNavContainerRef.current = null;
|
|
18728
19580
|
setHoveredNavContainerRect(null);
|
|
19581
|
+
siblingHintElRef.current = null;
|
|
19582
|
+
setSiblingHintRect(null);
|
|
19583
|
+
setSiblingHintRects([]);
|
|
19584
|
+
dismissImageHover();
|
|
19585
|
+
clearImageHover();
|
|
19586
|
+
setSectionGap(null);
|
|
18729
19587
|
return;
|
|
18730
19588
|
}
|
|
18731
19589
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
@@ -18737,7 +19595,11 @@ function OhhwellsBridge() {
|
|
|
18737
19595
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
18738
19596
|
const { clientX, clientY } = e.data;
|
|
18739
19597
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
18740
|
-
if (
|
|
19598
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
19599
|
+
dismissImageHover();
|
|
19600
|
+
clearImageHover();
|
|
19601
|
+
return;
|
|
19602
|
+
}
|
|
18741
19603
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
18742
19604
|
probeSectionGapAt(clientX, clientY);
|
|
18743
19605
|
probeImageAt(clientX, clientY);
|
|
@@ -19020,10 +19882,23 @@ function OhhwellsBridge() {
|
|
|
19020
19882
|
if (e.data?.type !== "ow:hydrate") return;
|
|
19021
19883
|
const content = e.data.content;
|
|
19022
19884
|
if (!content) return;
|
|
19885
|
+
if (typeof content[BRAND_KIT_KEY] === "string") {
|
|
19886
|
+
brandKitRef.current = content[BRAND_KIT_KEY];
|
|
19887
|
+
applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
|
|
19888
|
+
} else {
|
|
19889
|
+
brandKitRef.current = "";
|
|
19890
|
+
applyBrandToDom(null);
|
|
19891
|
+
}
|
|
19023
19892
|
if (typeof content[AI_SECTIONS_KEY] === "string") {
|
|
19024
19893
|
aiSectionsRef.current = content[AI_SECTIONS_KEY];
|
|
19894
|
+
setAiSectionOrder(content[SECTION_ORDER_KEY], window.location.pathname);
|
|
19025
19895
|
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
19026
19896
|
}
|
|
19897
|
+
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
19898
|
+
stylesRef.current = content[STYLE_STORE_KEY];
|
|
19899
|
+
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
19900
|
+
}
|
|
19901
|
+
applyBrandChrome(content);
|
|
19027
19902
|
let sectionsJson = null;
|
|
19028
19903
|
for (const [key, val] of Object.entries(content)) {
|
|
19029
19904
|
if (key === "__ohw_sections") {
|
|
@@ -19033,6 +19908,9 @@ function OhhwellsBridge() {
|
|
|
19033
19908
|
if (key === AI_SECTIONS_KEY) continue;
|
|
19034
19909
|
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
19035
19910
|
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
19911
|
+
if (key === BRAND_KIT_KEY) continue;
|
|
19912
|
+
if (key === STYLE_STORE_KEY) continue;
|
|
19913
|
+
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
19036
19914
|
if (applyVideoSettingNode(key, val)) continue;
|
|
19037
19915
|
if (applyCarouselNode(key, val)) continue;
|
|
19038
19916
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -19046,6 +19924,8 @@ function OhhwellsBridge() {
|
|
|
19046
19924
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
19047
19925
|
} else if (el.dataset.ohwEditable === "link") {
|
|
19048
19926
|
applyLinkHref(el, val);
|
|
19927
|
+
} else if (el.dataset.ohwEditable === "icon") {
|
|
19928
|
+
applyIconMarkup(el, val);
|
|
19049
19929
|
} else if (isIconMarkupValue(val)) {
|
|
19050
19930
|
} else {
|
|
19051
19931
|
el.innerHTML = val;
|
|
@@ -19130,12 +20010,21 @@ function OhhwellsBridge() {
|
|
|
19130
20010
|
nodes: collectEditableNodes(editContentRef.current)
|
|
19131
20011
|
});
|
|
19132
20012
|
};
|
|
20013
|
+
const clearInteractionChrome = () => {
|
|
20014
|
+
deactivateRef.current();
|
|
20015
|
+
deselectRef.current();
|
|
20016
|
+
clearMediaSelectionRef.current();
|
|
20017
|
+
};
|
|
19133
20018
|
const handleAiApplyTree = (e) => {
|
|
19134
20019
|
if (e.data?.type !== "ow:ai-apply-tree") return;
|
|
19135
20020
|
const payload = e.data.payload;
|
|
19136
20021
|
if (!payload || typeof payload.id !== "string" || !isRenderableTree(payload.tree)) return;
|
|
20022
|
+
clearInteractionChrome();
|
|
19137
20023
|
const previous = aiSectionsRef.current;
|
|
19138
|
-
const nextState = applyTreeToState(parseAiSectionsState(previous),
|
|
20024
|
+
const nextState = applyTreeToState(parseAiSectionsState(previous), {
|
|
20025
|
+
...payload,
|
|
20026
|
+
path: payload.path ?? window.location.pathname
|
|
20027
|
+
});
|
|
19139
20028
|
const nextValue = serializeAiSectionsState(nextState);
|
|
19140
20029
|
aiSectionsRef.current = nextValue;
|
|
19141
20030
|
applyAiSectionsToDom(nextState);
|
|
@@ -19156,6 +20045,7 @@ function OhhwellsBridge() {
|
|
|
19156
20045
|
const exists = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
|
|
19157
20046
|
if (!exists) return;
|
|
19158
20047
|
if (isPageFrameSection(exists)) return;
|
|
20048
|
+
clearInteractionChrome();
|
|
19159
20049
|
const previous = aiSectionsRef.current;
|
|
19160
20050
|
const nextState = deleteSectionFromState(parseAiSectionsState(previous), sectionId);
|
|
19161
20051
|
const nextValue = serializeAiSectionsState(nextState);
|
|
@@ -19171,8 +20061,10 @@ function OhhwellsBridge() {
|
|
|
19171
20061
|
const handleAiSetSections = (e) => {
|
|
19172
20062
|
if (e.data?.type !== "ow:ai-set-sections") return;
|
|
19173
20063
|
const value = typeof e.data.value === "string" ? e.data.value : "";
|
|
20064
|
+
clearInteractionChrome();
|
|
19174
20065
|
aiSectionsRef.current = value;
|
|
19175
20066
|
applyAiSectionsToDom(parseAiSectionsState(value));
|
|
20067
|
+
applyStylesToDom(parseStyleStore(stylesRef.current));
|
|
19176
20068
|
const restoredHeight = document.body.scrollHeight;
|
|
19177
20069
|
if (restoredHeight > 50) postToParentRef.current({ type: "ow:height", height: restoredHeight });
|
|
19178
20070
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: AI_SECTIONS_KEY, text: value }] });
|
|
@@ -19188,10 +20080,40 @@ function OhhwellsBridge() {
|
|
|
19188
20080
|
if (!entries) return;
|
|
19189
20081
|
const orderJson = JSON.stringify(entries);
|
|
19190
20082
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
20083
|
+
setAiSectionOrder(orderJson, window.location.pathname);
|
|
19191
20084
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
19192
20085
|
window.dispatchEvent(new Event("resize"));
|
|
19193
20086
|
};
|
|
19194
20087
|
window.addEventListener("message", handleMoveSection);
|
|
20088
|
+
const handleAiSetBrand = (e) => {
|
|
20089
|
+
if (e.data?.type !== "ow:ai-set-brand") return;
|
|
20090
|
+
const value = typeof e.data.value === "string" ? e.data.value : "";
|
|
20091
|
+
const previous = brandKitRef.current;
|
|
20092
|
+
brandKitRef.current = value;
|
|
20093
|
+
applyBrandToDom(parseBrandKit(value));
|
|
20094
|
+
if (aiSectionsRef.current) applyAiSectionsToDom(parseAiSectionsState(aiSectionsRef.current));
|
|
20095
|
+
applyStylesToDom(parseStyleStore(stylesRef.current));
|
|
20096
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key: BRAND_KIT_KEY, text: value }] });
|
|
20097
|
+
postToParentRef.current({ type: "ow:ai-brand-applied", previous, value });
|
|
20098
|
+
};
|
|
20099
|
+
window.addEventListener("message", handleAiSetBrand);
|
|
20100
|
+
const handleAiSetStyles = (e) => {
|
|
20101
|
+
if (e.data?.type !== "ow:ai-set-styles") return;
|
|
20102
|
+
const value = typeof e.data.value === "string" ? e.data.value : "";
|
|
20103
|
+
const previous = stylesRef.current;
|
|
20104
|
+
stylesRef.current = value;
|
|
20105
|
+
applyStylesToDom(parseStyleStore(value));
|
|
20106
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key: STYLE_STORE_KEY, text: value }] });
|
|
20107
|
+
postToParentRef.current({ type: "ow:ai-styles-applied", previous, value });
|
|
20108
|
+
};
|
|
20109
|
+
window.addEventListener("message", handleAiSetStyles);
|
|
20110
|
+
const handleGetBrand = (e) => {
|
|
20111
|
+
if (e.data?.type !== "ow:get-brand") return;
|
|
20112
|
+
const template = deriveTemplateBrand();
|
|
20113
|
+
const value = brandKitRef.current || (template ? JSON.stringify(template) : "");
|
|
20114
|
+
postToParentRef.current({ type: "ow:brand-value", value });
|
|
20115
|
+
};
|
|
20116
|
+
window.addEventListener("message", handleGetBrand);
|
|
19195
20117
|
const handlePanelDragging = (e) => {
|
|
19196
20118
|
if (e.data?.type !== "ow:panel-dragging") return;
|
|
19197
20119
|
if (e.data.dragging) document.documentElement.setAttribute("data-ohw-panel-dragging", "");
|
|
@@ -19249,8 +20171,15 @@ function OhhwellsBridge() {
|
|
|
19249
20171
|
closeLinkPopoverRef.current();
|
|
19250
20172
|
return;
|
|
19251
20173
|
}
|
|
20174
|
+
if (floatingPanelOpenRef.current) {
|
|
20175
|
+
setFloatingPanelRef.current(null);
|
|
20176
|
+
deselectRef.current();
|
|
20177
|
+
deactivateRef.current();
|
|
20178
|
+
return;
|
|
20179
|
+
}
|
|
19252
20180
|
deselectRef.current();
|
|
19253
20181
|
deactivateRef.current();
|
|
20182
|
+
clearMediaSelectionRef.current();
|
|
19254
20183
|
};
|
|
19255
20184
|
window.addEventListener("message", handleDeactivate);
|
|
19256
20185
|
const handleToastAction = (e) => {
|
|
@@ -19336,6 +20265,10 @@ function OhhwellsBridge() {
|
|
|
19336
20265
|
const handleKeyDown = (e) => {
|
|
19337
20266
|
if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
|
|
19338
20267
|
if (e.key === "Escape" && document.querySelector("[data-ohw-more-menu]")) return;
|
|
20268
|
+
if (e.key === "Escape" && selectedMediaElRef.current) {
|
|
20269
|
+
clearMediaSelectionRef.current();
|
|
20270
|
+
return;
|
|
20271
|
+
}
|
|
19339
20272
|
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
|
|
19340
20273
|
e.preventDefault();
|
|
19341
20274
|
selectAllTextInEditable(activeElRef.current);
|
|
@@ -19495,6 +20428,12 @@ function OhhwellsBridge() {
|
|
|
19495
20428
|
if (aiSectionsRef.current) {
|
|
19496
20429
|
nodes.push({ key: AI_SECTIONS_KEY, type: "sections", text: aiSectionsRef.current });
|
|
19497
20430
|
}
|
|
20431
|
+
if (stylesRef.current) {
|
|
20432
|
+
nodes.push({ key: STYLE_STORE_KEY, type: "styles", text: stylesRef.current });
|
|
20433
|
+
}
|
|
20434
|
+
if (brandKitRef.current) {
|
|
20435
|
+
nodes.push({ key: BRAND_KIT_KEY, type: "brand", text: brandKitRef.current });
|
|
20436
|
+
}
|
|
19498
20437
|
document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
|
|
19499
20438
|
const formKey = formKeyOf(form);
|
|
19500
20439
|
if (!formKey) return;
|
|
@@ -19512,8 +20451,12 @@ function OhhwellsBridge() {
|
|
|
19512
20451
|
if (inserted) {
|
|
19513
20452
|
const tracker = getSectionsTracker();
|
|
19514
20453
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
|
|
19515
|
-
const
|
|
19516
|
-
|
|
20454
|
+
const reportHeight = () => {
|
|
20455
|
+
const h = document.body.scrollHeight;
|
|
20456
|
+
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
20457
|
+
};
|
|
20458
|
+
reportHeight();
|
|
20459
|
+
setTimeout(reportHeight, 500);
|
|
19517
20460
|
}
|
|
19518
20461
|
};
|
|
19519
20462
|
const handleSwitchSchedule = (e) => {
|
|
@@ -19910,13 +20853,16 @@ function OhhwellsBridge() {
|
|
|
19910
20853
|
window.removeEventListener("message", handleAiDeleteSection);
|
|
19911
20854
|
window.removeEventListener("message", handleAiSetSections);
|
|
19912
20855
|
window.removeEventListener("message", handleMoveSection);
|
|
20856
|
+
window.removeEventListener("message", handleAiSetBrand);
|
|
20857
|
+
window.removeEventListener("message", handleAiSetStyles);
|
|
20858
|
+
window.removeEventListener("message", handleGetBrand);
|
|
19913
20859
|
window.removeEventListener("message", handlePanelDragging);
|
|
19914
20860
|
window.removeEventListener("message", handleDeleteSection);
|
|
19915
20861
|
window.removeEventListener("message", handleDeactivate);
|
|
19916
|
-
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
19917
20862
|
window.removeEventListener("message", handleToastAction);
|
|
19918
20863
|
window.removeEventListener("message", handleFormCount);
|
|
19919
20864
|
window.removeEventListener("message", handleUiEscape);
|
|
20865
|
+
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
19920
20866
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
19921
20867
|
autoSaveTimers.current.clear();
|
|
19922
20868
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
@@ -20119,7 +21065,7 @@ function OhhwellsBridge() {
|
|
|
20119
21065
|
postToParent2({
|
|
20120
21066
|
type: "ow:ready",
|
|
20121
21067
|
version: "1",
|
|
20122
|
-
bridgeVersion: "0.1.
|
|
21068
|
+
bridgeVersion: "0.1.77",
|
|
20123
21069
|
path: pathname,
|
|
20124
21070
|
nodes: collectEditableNodes(editContentRef.current),
|
|
20125
21071
|
sections
|
|
@@ -20526,11 +21472,22 @@ function OhhwellsBridge() {
|
|
|
20526
21472
|
const showEditLink = toolbarShowEditLink;
|
|
20527
21473
|
const currentSections = sectionsByPath[pathname] ?? [];
|
|
20528
21474
|
linkPopoverOpenRef.current = linkPopover !== null;
|
|
21475
|
+
const handleMediaSelect = useCallback8((key) => {
|
|
21476
|
+
const el = hoveredImageRef.current?.dataset.ohwKey === key ? hoveredImageRef.current : Array.from(document.querySelectorAll(MEDIA_SELECTOR)).find(
|
|
21477
|
+
(m) => (m.dataset.ohwKey ?? "") === key
|
|
21478
|
+
) ?? null;
|
|
21479
|
+
if (!el) return;
|
|
21480
|
+
selectMediaElementRef.current(el);
|
|
21481
|
+
}, []);
|
|
20529
21482
|
const handleMediaReplace = useCallback8(
|
|
20530
21483
|
(key) => {
|
|
20531
|
-
postToParent2({
|
|
21484
|
+
postToParent2({
|
|
21485
|
+
type: "ow:image-pick",
|
|
21486
|
+
key,
|
|
21487
|
+
elementType: mediaHover?.elementType ?? selectedMedia?.elementType ?? "image"
|
|
21488
|
+
});
|
|
20532
21489
|
},
|
|
20533
|
-
[postToParent2, mediaHover?.elementType]
|
|
21490
|
+
[postToParent2, mediaHover?.elementType, selectedMedia?.elementType]
|
|
20534
21491
|
);
|
|
20535
21492
|
const handleEditCarousel = useCallback8(
|
|
20536
21493
|
(key) => {
|
|
@@ -20602,12 +21559,25 @@ function OhhwellsBridge() {
|
|
|
20602
21559
|
},
|
|
20603
21560
|
`uploading-${key}`
|
|
20604
21561
|
)),
|
|
20605
|
-
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx33(
|
|
21562
|
+
mediaHover && !(mediaHover.key in uploadingRects) && mediaHover.key !== selectedMedia?.key && /* @__PURE__ */ jsx33(
|
|
20606
21563
|
MediaOverlay,
|
|
20607
21564
|
{
|
|
20608
21565
|
hover: mediaHover,
|
|
20609
21566
|
isUploading: false,
|
|
20610
21567
|
onReplace: handleMediaReplace,
|
|
21568
|
+
onSelect: handleMediaSelect,
|
|
21569
|
+
onVideoSettingsChange: handleVideoSettingsChange
|
|
21570
|
+
}
|
|
21571
|
+
),
|
|
21572
|
+
selectedMedia && !(selectedMedia.key in uploadingRects) && !linkPopover && /* @__PURE__ */ jsx33(
|
|
21573
|
+
MediaOverlay,
|
|
21574
|
+
{
|
|
21575
|
+
hover: selectedMedia,
|
|
21576
|
+
selected: true,
|
|
21577
|
+
hovered: mediaHover?.key === selectedMedia.key,
|
|
21578
|
+
isUploading: false,
|
|
21579
|
+
onReplace: handleMediaReplace,
|
|
21580
|
+
onSelect: handleMediaSelect,
|
|
20611
21581
|
onVideoSettingsChange: handleVideoSettingsChange
|
|
20612
21582
|
}
|
|
20613
21583
|
),
|
|
@@ -21013,6 +21983,59 @@ function OhhwellsBridge() {
|
|
|
21013
21983
|
) : null
|
|
21014
21984
|
] });
|
|
21015
21985
|
}
|
|
21986
|
+
|
|
21987
|
+
// src/ui/EmptySection.tsx
|
|
21988
|
+
import Link3 from "next/link";
|
|
21989
|
+
import { Fragment as Fragment9, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
21990
|
+
function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
|
|
21991
|
+
return /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
21992
|
+
/* @__PURE__ */ jsx34(
|
|
21993
|
+
"p",
|
|
21994
|
+
{
|
|
21995
|
+
style: {
|
|
21996
|
+
fontFamily: "var(--brand-font-body)",
|
|
21997
|
+
fontSize: "0.75rem",
|
|
21998
|
+
fontWeight: 500,
|
|
21999
|
+
letterSpacing: "0.15em",
|
|
22000
|
+
textTransform: "uppercase",
|
|
22001
|
+
color: "var(--brand-accent)",
|
|
22002
|
+
marginBottom: "1.5rem"
|
|
22003
|
+
},
|
|
22004
|
+
children: /* @__PURE__ */ jsx34(Link3, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ jsx34("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
|
|
22005
|
+
}
|
|
22006
|
+
),
|
|
22007
|
+
/* @__PURE__ */ jsx34(
|
|
22008
|
+
"h1",
|
|
22009
|
+
{
|
|
22010
|
+
style: {
|
|
22011
|
+
fontFamily: "var(--brand-font-heading)",
|
|
22012
|
+
fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
|
|
22013
|
+
lineHeight: 1.1,
|
|
22014
|
+
letterSpacing: "-0.025em",
|
|
22015
|
+
color: "var(--brand-text)",
|
|
22016
|
+
marginBottom: "1rem"
|
|
22017
|
+
},
|
|
22018
|
+
...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
|
|
22019
|
+
children: title
|
|
22020
|
+
}
|
|
22021
|
+
),
|
|
22022
|
+
/* @__PURE__ */ jsx34(
|
|
22023
|
+
"p",
|
|
22024
|
+
{
|
|
22025
|
+
style: {
|
|
22026
|
+
fontFamily: "var(--brand-font-body)",
|
|
22027
|
+
fontSize: "1rem",
|
|
22028
|
+
lineHeight: 1.7,
|
|
22029
|
+
fontWeight: 300,
|
|
22030
|
+
color: "var(--brand-text-muted)",
|
|
22031
|
+
maxWidth: "340px"
|
|
22032
|
+
},
|
|
22033
|
+
...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
|
|
22034
|
+
children: "This page doesn't have any content yet."
|
|
22035
|
+
}
|
|
22036
|
+
)
|
|
22037
|
+
] });
|
|
22038
|
+
}
|
|
21016
22039
|
export {
|
|
21017
22040
|
AI_DEFAULT_BRAND,
|
|
21018
22041
|
AI_TREE_SCHEMA_VERSIONS,
|
|
@@ -21029,6 +22052,7 @@ export {
|
|
|
21029
22052
|
DropdownMenuItem,
|
|
21030
22053
|
DropdownMenuSeparator,
|
|
21031
22054
|
DropdownMenuTrigger,
|
|
22055
|
+
EmptySection,
|
|
21032
22056
|
ItemActionToolbar,
|
|
21033
22057
|
ItemInteractionLayer,
|
|
21034
22058
|
LinkEditorPanel,
|