@ohhwells/bridge 0.1.92 → 0.1.93-next.281
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 +1602 -520
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -4
- package/dist/index.d.ts +55 -4
- package/dist/index.js +1601 -520
- 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 +149 -76
- package/package.json +8 -3
package/dist/index.js
CHANGED
|
@@ -70,6 +70,9 @@ function isRenderableTree(value) {
|
|
|
70
70
|
// src/lib/ai-sections-store.ts
|
|
71
71
|
var AI_SECTIONS_KEY = "__ohw_ai_sections";
|
|
72
72
|
var AI_SLOT_KEY_PREFIX = "ai.";
|
|
73
|
+
function aiSlotKeyPrefixFor(sectionId) {
|
|
74
|
+
return `${AI_SLOT_KEY_PREFIX}${sectionId}.`;
|
|
75
|
+
}
|
|
73
76
|
var EMPTY_AI_SECTIONS = { v: 1, sections: [] };
|
|
74
77
|
function parseAiSectionsState(raw) {
|
|
75
78
|
if (!raw) return EMPTY_AI_SECTIONS;
|
|
@@ -181,6 +184,33 @@ function deleteSectionFromState(state, sectionId) {
|
|
|
181
184
|
if (removed.includes(sectionId)) return state;
|
|
182
185
|
return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
|
|
183
186
|
}
|
|
187
|
+
function reapRemovedAiSections(state, store, removedIds, excludeIds = /* @__PURE__ */ new Set()) {
|
|
188
|
+
const generated = new Set(state.sections.map((entry) => entry.id));
|
|
189
|
+
const reapedIds = [...new Set(removedIds)].filter((id) => generated.has(id) && !excludeIds.has(id));
|
|
190
|
+
if (reapedIds.length === 0) {
|
|
191
|
+
return { state, store, reapedIds: [], slotPrefixes: [], changed: false };
|
|
192
|
+
}
|
|
193
|
+
const reaped = new Set(reapedIds);
|
|
194
|
+
const slotPrefixes = reapedIds.map(aiSlotKeyPrefixFor);
|
|
195
|
+
const nextState = {
|
|
196
|
+
...state,
|
|
197
|
+
v: 1,
|
|
198
|
+
sections: state.sections.filter((entry) => !reaped.has(entry.id))
|
|
199
|
+
};
|
|
200
|
+
let nextStore = store;
|
|
201
|
+
if (store) {
|
|
202
|
+
const sections = {};
|
|
203
|
+
for (const [key, override] of Object.entries(store.sections)) {
|
|
204
|
+
if (!reaped.has(key)) sections[key] = override;
|
|
205
|
+
}
|
|
206
|
+
const nodes = {};
|
|
207
|
+
for (const [key, override] of Object.entries(store.nodes)) {
|
|
208
|
+
if (!slotPrefixes.some((prefix) => key.startsWith(prefix))) nodes[key] = override;
|
|
209
|
+
}
|
|
210
|
+
nextStore = { v: 1, sections, nodes };
|
|
211
|
+
}
|
|
212
|
+
return { state: nextState, store: nextStore, reapedIds, slotPrefixes, changed: true };
|
|
213
|
+
}
|
|
184
214
|
|
|
185
215
|
// src/lib/brand-chrome.ts
|
|
186
216
|
var BRAND_NAME_KEY = "__ohw_brand_name";
|
|
@@ -249,16 +279,17 @@ var LEGACY_BRAND_VAR_NAMES = [
|
|
|
249
279
|
"text-muted",
|
|
250
280
|
"surface",
|
|
251
281
|
"border",
|
|
252
|
-
"on-primary"
|
|
253
|
-
"navbar-background"
|
|
282
|
+
"on-primary"
|
|
254
283
|
].map((role) => `--brand-${role}`);
|
|
255
284
|
var FONT_VARS = {
|
|
256
285
|
heading: ["--font-heading", "--font-display", "--brand-font-heading"],
|
|
257
286
|
body: ["--font-body", "--brand-font-body"]
|
|
258
287
|
};
|
|
259
288
|
var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
|
|
260
|
-
|
|
261
|
-
|
|
289
|
+
var CUSTOM_FONT_STYLE_ID = "ohw-brand-custom-fonts";
|
|
290
|
+
var CUSTOM_FONT_FORMATS = /* @__PURE__ */ new Set(["woff2", "woff", "truetype", "opentype"]);
|
|
291
|
+
function brandColorVars(palette) {
|
|
292
|
+
const { dark, primary, accent, light } = palette;
|
|
262
293
|
const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
|
|
263
294
|
const surface = mix(light, 95, dark);
|
|
264
295
|
const border = mix(light, 85, dark);
|
|
@@ -281,22 +312,42 @@ function brandColorVars(kit) {
|
|
|
281
312
|
"--brand-border": border,
|
|
282
313
|
// Buttons/bands painted in the primary colour assume it's dark/saturated enough to need
|
|
283
314
|
// light text on top — the same assumption LOGO_IMAGE's light-on-dark navbar mark makes.
|
|
284
|
-
"--brand-on-primary": light
|
|
285
|
-
"--brand-navbar-background": dark
|
|
315
|
+
"--brand-on-primary": light
|
|
286
316
|
};
|
|
287
317
|
}
|
|
318
|
+
function parseCustomFontWeight(raw) {
|
|
319
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
320
|
+
const w = raw;
|
|
321
|
+
if (typeof w.weight !== "number" || !Number.isFinite(w.weight)) return null;
|
|
322
|
+
if (typeof w.url !== "string" || !w.url) return null;
|
|
323
|
+
if (typeof w.format !== "string" || !CUSTOM_FONT_FORMATS.has(w.format)) return null;
|
|
324
|
+
const weightEnd = typeof w.weightEnd === "number" && Number.isFinite(w.weightEnd) && w.weightEnd > w.weight ? w.weightEnd : void 0;
|
|
325
|
+
return { weight: w.weight, ...weightEnd !== void 0 ? { weightEnd } : {}, url: w.url, format: w.format };
|
|
326
|
+
}
|
|
327
|
+
function parseCustomFont(raw) {
|
|
328
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
329
|
+
const f = raw;
|
|
330
|
+
if (typeof f.family !== "string" || !f.family) return null;
|
|
331
|
+
if (typeof f.label !== "string" || !f.label) return null;
|
|
332
|
+
if (!Array.isArray(f.weights)) return null;
|
|
333
|
+
const weights = f.weights.map(parseCustomFontWeight).filter((w) => w !== null);
|
|
334
|
+
if (weights.length === 0) return null;
|
|
335
|
+
return { family: f.family, label: f.label, weights };
|
|
336
|
+
}
|
|
288
337
|
function parseBrandKit(raw) {
|
|
289
338
|
if (!raw) return null;
|
|
290
339
|
try {
|
|
291
340
|
const parsed = JSON.parse(raw);
|
|
292
341
|
const p = parsed?.palette;
|
|
293
342
|
const f = parsed?.fonts;
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
343
|
+
const palette = p && typeof p.dark === "string" && typeof p.primary === "string" && typeof p.accent === "string" && typeof p.light === "string" ? { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light } : void 0;
|
|
344
|
+
const fonts = f && typeof f.heading === "string" && typeof f.body === "string" ? { heading: f.heading, body: f.body } : void 0;
|
|
345
|
+
const customFonts = Array.isArray(parsed?.customFonts) ? parsed.customFonts.map(parseCustomFont).filter((c) => c !== null) : void 0;
|
|
346
|
+
if (!palette && !fonts && !customFonts) return null;
|
|
297
347
|
return {
|
|
298
|
-
palette
|
|
299
|
-
fonts
|
|
348
|
+
...palette ? { palette } : {},
|
|
349
|
+
...fonts ? { fonts } : {},
|
|
350
|
+
...customFonts ? { customFonts } : {}
|
|
300
351
|
};
|
|
301
352
|
} catch {
|
|
302
353
|
return null;
|
|
@@ -306,11 +357,16 @@ function familyOf(stack) {
|
|
|
306
357
|
const first = stack.split(",")[0]?.trim() ?? "";
|
|
307
358
|
return first.replace(/^['"]|['"]$/g, "");
|
|
308
359
|
}
|
|
360
|
+
function quoteFamily(family) {
|
|
361
|
+
return `'${family.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
362
|
+
}
|
|
363
|
+
var WEIGHT_SCALE = [100, 200, 300, 400, 500, 600, 700, 800, 900];
|
|
309
364
|
function loadBrandFonts(families) {
|
|
310
365
|
const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
|
|
311
366
|
if (unique.length === 0) return;
|
|
312
|
-
const
|
|
313
|
-
const
|
|
367
|
+
const weights = WEIGHT_SCALE.join(";");
|
|
368
|
+
const spec = unique.map((f) => `family=${f.replace(/ /g, "+")}:wght@${weights}`).join("&");
|
|
369
|
+
const href = `https://fonts.googleapis.com/css2?${spec}&display=swap`;
|
|
314
370
|
let link = document.getElementById(BRAND_FONT_LINK_ID);
|
|
315
371
|
if (!link) {
|
|
316
372
|
link = document.createElement("link");
|
|
@@ -320,18 +376,54 @@ function loadBrandFonts(families) {
|
|
|
320
376
|
}
|
|
321
377
|
if (link.href !== href) link.href = href;
|
|
322
378
|
}
|
|
379
|
+
function escapeCssString(value) {
|
|
380
|
+
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
381
|
+
}
|
|
382
|
+
function loadCustomFonts(fonts) {
|
|
383
|
+
const list = fonts ?? [];
|
|
384
|
+
let style = document.getElementById(CUSTOM_FONT_STYLE_ID);
|
|
385
|
+
if (list.length === 0) {
|
|
386
|
+
style?.remove();
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
if (!style) {
|
|
390
|
+
style = document.createElement("style");
|
|
391
|
+
style.id = CUSTOM_FONT_STYLE_ID;
|
|
392
|
+
document.head.appendChild(style);
|
|
393
|
+
}
|
|
394
|
+
style.textContent = list.flatMap(
|
|
395
|
+
(font) => font.weights.map((w) => {
|
|
396
|
+
const weightDescriptor = w.weightEnd ? `${w.weight} ${w.weightEnd}` : `${w.weight}`;
|
|
397
|
+
return `@font-face { font-family: '${escapeCssString(font.family)}'; src: url('${escapeCssString(w.url)}') format('${w.format}'); font-weight: ${weightDescriptor}; font-display: swap; }`;
|
|
398
|
+
})
|
|
399
|
+
).join("\n");
|
|
400
|
+
}
|
|
323
401
|
function applyBrandToDom(kit) {
|
|
324
402
|
const root = document.documentElement;
|
|
325
403
|
if (!kit) {
|
|
326
404
|
for (const name of [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES]) root.style.removeProperty(name);
|
|
327
405
|
for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
|
|
328
406
|
document.getElementById(BRAND_FONT_LINK_ID)?.remove();
|
|
407
|
+
document.getElementById(CUSTOM_FONT_STYLE_ID)?.remove();
|
|
329
408
|
return;
|
|
330
409
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
410
|
+
if (kit.palette) {
|
|
411
|
+
for (const [name, value] of Object.entries(brandColorVars(kit.palette))) root.style.setProperty(name, value);
|
|
412
|
+
}
|
|
413
|
+
if (kit.customFonts) {
|
|
414
|
+
loadCustomFonts(kit.customFonts);
|
|
415
|
+
}
|
|
416
|
+
if (kit.fonts) {
|
|
417
|
+
const heading = quoteFamily(kit.fonts.heading);
|
|
418
|
+
const body = quoteFamily(kit.fonts.body);
|
|
419
|
+
for (const name of FONT_VARS.heading) root.style.setProperty(name, heading);
|
|
420
|
+
for (const name of FONT_VARS.body) root.style.setProperty(name, body);
|
|
421
|
+
const customFamilies = new Set((kit.customFonts ?? []).map((f) => f.family));
|
|
422
|
+
const googleFamilies = [familyOf(kit.fonts.heading), familyOf(kit.fonts.body)].filter(
|
|
423
|
+
(f) => !customFamilies.has(f)
|
|
424
|
+
);
|
|
425
|
+
loadBrandFonts(googleFamilies);
|
|
426
|
+
}
|
|
335
427
|
}
|
|
336
428
|
|
|
337
429
|
// src/lib/section-styles.ts
|
|
@@ -388,6 +480,12 @@ function styleSheetCss() {
|
|
|
388
480
|
`[data-ohw-style-spacing="${spacing}"] { padding-top: ${px}px !important; padding-bottom: ${px}px !important; }`
|
|
389
481
|
);
|
|
390
482
|
}
|
|
483
|
+
rules.push(
|
|
484
|
+
`[data-ohw-style-corners="sharp"] :is(.card, [data-ohw-card], img, picture, figure, [data-ohw-editable="bg-image"]) { border-radius: 0 !important; }`,
|
|
485
|
+
`[data-ohw-style-corners="sharp"] :has(> img) { border-radius: 0 !important; }`,
|
|
486
|
+
`[data-ohw-style-corners="rounded"] :is(.card, [data-ohw-card], img, picture, figure, [data-ohw-editable="bg-image"]) { border-radius: max(0.75rem, var(--radius, 0px)) !important; }`,
|
|
487
|
+
`[data-ohw-style-corners="rounded"] :has(> img) { border-radius: max(0.75rem, var(--radius, 0px)) !important; }`
|
|
488
|
+
);
|
|
391
489
|
for (const align of ["left", "center", "right"]) {
|
|
392
490
|
rules.push(`[data-ohw-style-align="${align}"] { text-align: ${align} !important; }`);
|
|
393
491
|
}
|
|
@@ -418,6 +516,7 @@ var SECTION_ATTRS = {
|
|
|
418
516
|
headlineScale: "data-ohw-style-headline",
|
|
419
517
|
imageAspect: "data-ohw-style-aspect",
|
|
420
518
|
spacing: "data-ohw-style-spacing",
|
|
519
|
+
cornerStyle: "data-ohw-style-corners",
|
|
421
520
|
align: "data-ohw-style-align"
|
|
422
521
|
};
|
|
423
522
|
var NODE_WROTE_ATTR = "data-ohw-style-node";
|
|
@@ -480,14 +579,39 @@ function buttonSurfaceOf(el) {
|
|
|
480
579
|
}
|
|
481
580
|
function alignSubjectOf(el) {
|
|
482
581
|
const button = el.closest('[data-ohw-role="button"]');
|
|
483
|
-
|
|
582
|
+
if (button?.parentElement) return button.parentElement;
|
|
583
|
+
let subject = el;
|
|
584
|
+
while (subject.parentElement && !subject.parentElement.hasAttribute("data-ohw-section") && /^inline/.test(getComputedStyle(subject).display)) {
|
|
585
|
+
subject = subject.parentElement;
|
|
586
|
+
}
|
|
587
|
+
const TEXT_ROW = /^(P|LI|H[1-6]|BLOCKQUOTE|FIGCAPTION|DT|DD)$/;
|
|
588
|
+
const parent = subject.parentElement;
|
|
589
|
+
if (parent && TEXT_ROW.test(parent.tagName) && /^(inline-)?flex$/.test(getComputedStyle(parent).display)) {
|
|
590
|
+
return parent;
|
|
591
|
+
}
|
|
592
|
+
if (parent && !parent.hasAttribute("data-ohw-section")) {
|
|
593
|
+
const pcs = getComputedStyle(parent);
|
|
594
|
+
const children = Array.from(parent.children);
|
|
595
|
+
const textRowChild = (c) => c.hasAttribute("data-ohw-editable") || (c.textContent ?? "").trim().length === 0 || c.getAttribute("aria-hidden") === "true";
|
|
596
|
+
if (/^(inline-)?flex$/.test(pcs.display) && pcs.flexDirection.startsWith("row") && children.length > 0 && children.some((c) => c.hasAttribute("data-ohw-editable")) && children.every(textRowChild)) {
|
|
597
|
+
return parent;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
const row = subject.closest("li");
|
|
601
|
+
if (row && row !== subject && /^(inline-)?flex$/.test(getComputedStyle(row).display)) {
|
|
602
|
+
return row;
|
|
603
|
+
}
|
|
604
|
+
return subject;
|
|
484
605
|
}
|
|
485
606
|
function applyStylesToDom(store) {
|
|
486
607
|
ensureStyleSheet();
|
|
487
608
|
clearSectionAttrs(document);
|
|
488
609
|
clearNodeProps(document);
|
|
489
610
|
loadStyleFonts(
|
|
490
|
-
store ?
|
|
611
|
+
store ? [
|
|
612
|
+
...Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []),
|
|
613
|
+
...Object.values(store.sections).flatMap((s) => s.fontFamily ? [s.fontFamily] : [])
|
|
614
|
+
] : []
|
|
491
615
|
);
|
|
492
616
|
if (!store) return;
|
|
493
617
|
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
@@ -507,6 +631,23 @@ function applyStylesToDom(store) {
|
|
|
507
631
|
section.style.setProperty("background", override.sectionBackgroundColor, "important");
|
|
508
632
|
section.setAttribute("data-ohw-style-bgcolor", "");
|
|
509
633
|
}
|
|
634
|
+
if (override.textColor !== void 0 || override.fontFamily !== void 0) {
|
|
635
|
+
const textEls = marker.querySelectorAll(
|
|
636
|
+
'[data-ohw-editable="text"], [data-ohw-editable="plain"], [data-ohw-field-label]'
|
|
637
|
+
);
|
|
638
|
+
for (const el of Array.from(textEls)) {
|
|
639
|
+
if (override.textColor !== void 0) {
|
|
640
|
+
saveInline(el, "color");
|
|
641
|
+
el.style.setProperty("color", override.textColor, "important");
|
|
642
|
+
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
643
|
+
}
|
|
644
|
+
if (override.fontFamily !== void 0) {
|
|
645
|
+
saveInline(el, "font-family");
|
|
646
|
+
el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
|
|
647
|
+
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
510
651
|
}
|
|
511
652
|
}
|
|
512
653
|
for (const [key, override] of Object.entries(store.nodes)) {
|
|
@@ -553,15 +694,557 @@ function applyStylesToDom(store) {
|
|
|
553
694
|
}
|
|
554
695
|
}
|
|
555
696
|
}
|
|
697
|
+
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
698
|
+
if (override.headingColor === void 0) continue;
|
|
699
|
+
const escaped = CSS.escape(sectionId);
|
|
700
|
+
const byInstance = document.querySelectorAll(`[data-ohw-instance="${escaped}"]`);
|
|
701
|
+
const sections = byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`);
|
|
702
|
+
for (const marker of Array.from(sections)) {
|
|
703
|
+
const headings = marker.querySelectorAll(
|
|
704
|
+
":is(h1, h2, h3, h4, h5, h6)[data-ohw-editable], :is(h1, h2, h3, h4, h5, h6) > [data-ohw-editable]"
|
|
705
|
+
);
|
|
706
|
+
for (const el of Array.from(headings)) {
|
|
707
|
+
saveInline(el, "color");
|
|
708
|
+
el.style.setProperty("color", override.headingColor, "important");
|
|
709
|
+
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
556
713
|
}
|
|
557
714
|
|
|
558
715
|
// src/ui/ai-tree/aiSectionsManager.tsx
|
|
559
716
|
import { flushSync } from "react-dom";
|
|
560
717
|
import { createRoot } from "react-dom/client";
|
|
561
718
|
|
|
719
|
+
// src/lib/sections.ts
|
|
720
|
+
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
721
|
+
function isChromeSection(el) {
|
|
722
|
+
return el.matches("header, nav, footer, aside");
|
|
723
|
+
}
|
|
724
|
+
function titleCaseSectionId(id) {
|
|
725
|
+
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
726
|
+
}
|
|
727
|
+
function parseSectionsFromRoot(root) {
|
|
728
|
+
const seen = /* @__PURE__ */ new Set();
|
|
729
|
+
const sections = [];
|
|
730
|
+
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
731
|
+
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
732
|
+
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
733
|
+
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
734
|
+
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
735
|
+
continue;
|
|
736
|
+
seen.add(id);
|
|
737
|
+
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
738
|
+
sections.push({ id, label });
|
|
739
|
+
}
|
|
740
|
+
return sections;
|
|
741
|
+
}
|
|
742
|
+
function collectSectionsFromDom() {
|
|
743
|
+
if (typeof document === "undefined") return [];
|
|
744
|
+
return parseSectionsFromRoot(document);
|
|
745
|
+
}
|
|
746
|
+
function parseSectionsFromHtml(html) {
|
|
747
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
748
|
+
return parseSectionsFromRoot(doc);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// src/lib/section-instances.ts
|
|
752
|
+
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
753
|
+
var REMOVED_ATTR = "data-ohw-section-removed";
|
|
754
|
+
function isRemovedSection(el) {
|
|
755
|
+
return el.hasAttribute(REMOVED_ATTR);
|
|
756
|
+
}
|
|
757
|
+
function movableUnit(el) {
|
|
758
|
+
return el.closest("[data-ohw-section-container]") ?? el;
|
|
759
|
+
}
|
|
760
|
+
function sectionTypeOf(el) {
|
|
761
|
+
return el.getAttribute("data-ohw-section") ?? el.querySelector("[data-ohw-section]")?.getAttribute("data-ohw-section") ?? "";
|
|
762
|
+
}
|
|
763
|
+
function sectionElementOf(el) {
|
|
764
|
+
return el.hasAttribute("data-ohw-section") ? el : el.querySelector("[data-ohw-section]") ?? el;
|
|
765
|
+
}
|
|
766
|
+
function collectTopLevelUnits(predicate) {
|
|
767
|
+
const seen = /* @__PURE__ */ new Set();
|
|
768
|
+
const result = [];
|
|
769
|
+
document.querySelectorAll("[data-ohw-section]").forEach((el) => {
|
|
770
|
+
if (!predicate(el)) return;
|
|
771
|
+
const unit = movableUnit(el);
|
|
772
|
+
if (unit.parentElement?.closest("[data-ohw-section],[data-ohw-section-container]")) return;
|
|
773
|
+
if (seen.has(unit)) return;
|
|
774
|
+
seen.add(unit);
|
|
775
|
+
result.push(unit);
|
|
776
|
+
});
|
|
777
|
+
return result;
|
|
778
|
+
}
|
|
779
|
+
function topLevelSections() {
|
|
780
|
+
return collectTopLevelUnits((el) => !isChromeSection(el) && !isRemovedSection(movableUnit(el)));
|
|
781
|
+
}
|
|
782
|
+
function instanceIdOf(el) {
|
|
783
|
+
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
784
|
+
}
|
|
785
|
+
function findByInstanceId(instanceId) {
|
|
786
|
+
const escapedId = CSS.escape(instanceId);
|
|
787
|
+
const direct = document.querySelector(`[data-ohw-instance="${escapedId}"]`);
|
|
788
|
+
if (direct) return movableUnit(direct);
|
|
789
|
+
const bare = document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
790
|
+
return bare ? movableUnit(bare) : null;
|
|
791
|
+
}
|
|
792
|
+
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
793
|
+
const sections = topLevelSections();
|
|
794
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
795
|
+
if (index === -1) return null;
|
|
796
|
+
const dragged = sections[index];
|
|
797
|
+
const others = sections.filter((_, i) => i !== index);
|
|
798
|
+
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
799
|
+
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
800
|
+
return reordered.map((el, order) => ({
|
|
801
|
+
instanceId: instanceIdOf(el),
|
|
802
|
+
type: sectionTypeOf(el),
|
|
803
|
+
order,
|
|
804
|
+
pagePath: currentPath
|
|
805
|
+
}));
|
|
806
|
+
}
|
|
807
|
+
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
808
|
+
const sections = topLevelSections();
|
|
809
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
810
|
+
if (index === -1) return null;
|
|
811
|
+
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
812
|
+
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
813
|
+
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
814
|
+
if (!entries) return null;
|
|
815
|
+
applyPersistedOrder(entries);
|
|
816
|
+
return entries;
|
|
817
|
+
}
|
|
818
|
+
function syncRemovedFlags(entries) {
|
|
819
|
+
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
820
|
+
document.querySelectorAll(`[${REMOVED_ATTR}]`).forEach((el) => {
|
|
821
|
+
if (!removedIds.has(instanceIdOf(el))) {
|
|
822
|
+
el.style.removeProperty("display");
|
|
823
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
824
|
+
}
|
|
825
|
+
});
|
|
826
|
+
for (const id of removedIds) {
|
|
827
|
+
const el = findByInstanceId(id);
|
|
828
|
+
if (el) {
|
|
829
|
+
el.style.display = "none";
|
|
830
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
function applyPersistedOrder(entries) {
|
|
835
|
+
syncRemovedFlags(entries);
|
|
836
|
+
if (entries.length === 0) return;
|
|
837
|
+
const sections = topLevelSections();
|
|
838
|
+
if (sections.length === 0) return;
|
|
839
|
+
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
840
|
+
const ordered = [...sections].sort((a, b) => {
|
|
841
|
+
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
842
|
+
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
843
|
+
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
844
|
+
if (aOrder === void 0) return 1;
|
|
845
|
+
if (bOrder === void 0) return -1;
|
|
846
|
+
return aOrder - bOrder;
|
|
847
|
+
});
|
|
848
|
+
let prev = null;
|
|
849
|
+
for (const el of ordered) {
|
|
850
|
+
if (prev) prev.after(el);
|
|
851
|
+
prev = el;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
855
|
+
if (!findByInstanceId(instanceId)) return null;
|
|
856
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
857
|
+
const allSections = collectTopLevelUnits((el) => !isChromeSection(el));
|
|
858
|
+
allSections.forEach((el, order) => {
|
|
859
|
+
const id = instanceIdOf(el);
|
|
860
|
+
if (!byId.has(id)) {
|
|
861
|
+
byId.set(id, { instanceId: id, type: sectionTypeOf(el), order, pagePath: currentPath });
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
const target = byId.get(instanceId);
|
|
865
|
+
if (!target) return null;
|
|
866
|
+
byId.set(instanceId, { ...target, removed });
|
|
867
|
+
const entries = Array.from(byId.values());
|
|
868
|
+
applyPersistedOrder(entries);
|
|
869
|
+
return entries;
|
|
870
|
+
}
|
|
871
|
+
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
872
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
873
|
+
}
|
|
874
|
+
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
875
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
876
|
+
}
|
|
877
|
+
function duplicateSectionInstance(instanceId, newId, currentPath, existingEntries) {
|
|
878
|
+
const original = findByInstanceId(instanceId);
|
|
879
|
+
if (!original) return null;
|
|
880
|
+
const clone = original.cloneNode(true);
|
|
881
|
+
clone.setAttribute("data-ohw-instance", newId);
|
|
882
|
+
const keyRekeys = rekeySectionSubtree(clone, newId);
|
|
883
|
+
original.insertAdjacentElement("afterend", clone);
|
|
884
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
885
|
+
const entries = topLevelSections().map((el, order) => {
|
|
886
|
+
const id = instanceIdOf(el);
|
|
887
|
+
return {
|
|
888
|
+
instanceId: id,
|
|
889
|
+
type: sectionTypeOf(el),
|
|
890
|
+
order,
|
|
891
|
+
pagePath: currentPath,
|
|
892
|
+
...byId.get(id)?.removed ? { removed: true } : {}
|
|
893
|
+
};
|
|
894
|
+
});
|
|
895
|
+
applyPersistedOrder(entries);
|
|
896
|
+
return { entries, keyRekeys };
|
|
897
|
+
}
|
|
898
|
+
function newInstanceId() {
|
|
899
|
+
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
900
|
+
}
|
|
901
|
+
function getPageSectionOrderEntries(raw, currentPath) {
|
|
902
|
+
if (!raw) return [];
|
|
903
|
+
try {
|
|
904
|
+
const entries = JSON.parse(raw);
|
|
905
|
+
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
906
|
+
} catch {
|
|
907
|
+
return [];
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
function mergePageSectionOrder(raw, currentPath, pageEntries) {
|
|
911
|
+
let all = [];
|
|
912
|
+
if (raw) {
|
|
913
|
+
try {
|
|
914
|
+
const parsed = JSON.parse(raw);
|
|
915
|
+
if (Array.isArray(parsed)) all = parsed;
|
|
916
|
+
} catch {
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
const otherPages = all.filter((e) => e && e.pagePath && e.pagePath !== currentPath);
|
|
920
|
+
const pageIds = new Set(pageEntries.map((e) => e.instanceId));
|
|
921
|
+
const removedHere = all.filter(
|
|
922
|
+
(e) => e && (!e.pagePath || e.pagePath === currentPath) && e.removed && !pageIds.has(e.instanceId)
|
|
923
|
+
);
|
|
924
|
+
return [...otherPages, ...removedHere, ...pageEntries];
|
|
925
|
+
}
|
|
926
|
+
function rekeySectionSubtree(root, instanceId) {
|
|
927
|
+
const suffix = `::${instanceId}`;
|
|
928
|
+
const pairs = [];
|
|
929
|
+
const rekey = (el, attr) => {
|
|
930
|
+
const current = el.getAttribute(attr);
|
|
931
|
+
if (!current) return;
|
|
932
|
+
const base = current.includes("::") ? current.slice(0, current.indexOf("::")) : current;
|
|
933
|
+
const next = `${base}${suffix}`;
|
|
934
|
+
el.setAttribute(attr, next);
|
|
935
|
+
pairs.push({ from: current, to: next });
|
|
936
|
+
};
|
|
937
|
+
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
938
|
+
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
939
|
+
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
940
|
+
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
941
|
+
return pairs;
|
|
942
|
+
}
|
|
943
|
+
function initSectionInstancesFromContent(content, currentPath) {
|
|
944
|
+
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
945
|
+
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
946
|
+
});
|
|
947
|
+
document.querySelectorAll("[data-ohw-section-container]:not([data-ohw-instance])").forEach((el) => {
|
|
948
|
+
const type = sectionTypeOf(el);
|
|
949
|
+
if (type) el.setAttribute("data-ohw-instance", type);
|
|
950
|
+
});
|
|
951
|
+
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
952
|
+
for (const entry of entries) {
|
|
953
|
+
if (entry.instanceId === entry.type) continue;
|
|
954
|
+
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
955
|
+
const original = document.querySelector(
|
|
956
|
+
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
957
|
+
);
|
|
958
|
+
if (!original) continue;
|
|
959
|
+
const clone = original.cloneNode(true);
|
|
960
|
+
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
961
|
+
rekeySectionSubtree(clone, entry.instanceId);
|
|
962
|
+
original.insertAdjacentElement("afterend", clone);
|
|
963
|
+
}
|
|
964
|
+
applyPersistedOrder(entries);
|
|
965
|
+
}
|
|
966
|
+
|
|
562
967
|
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
563
968
|
import React from "react";
|
|
564
969
|
import { ArrowLeft, ArrowRight, ChevronDown, icons as lucideIcons } from "lucide-react";
|
|
970
|
+
|
|
971
|
+
// src/lib/placeholder-imagery.ts
|
|
972
|
+
var U = (id) => `https://images.unsplash.com/photo-${id}?auto=format&fit=crop&w=1600&q=80`;
|
|
973
|
+
var GENERIC = [
|
|
974
|
+
U("1441986300917-64674bd600d8"),
|
|
975
|
+
U("1486406146926-c627a92ad1ab"),
|
|
976
|
+
U("1497032628192-86f99bcd76bc"),
|
|
977
|
+
U("1521737604893-d14cc237f11d"),
|
|
978
|
+
U("1522071820081-009f0129c71c"),
|
|
979
|
+
U("1519389950473-47ba0277781c"),
|
|
980
|
+
U("1460925895917-afdab827c52f"),
|
|
981
|
+
U("1504384308090-c894fdcc538d")
|
|
982
|
+
];
|
|
983
|
+
var PEOPLE = [
|
|
984
|
+
U("1500648767791-00dcc994a43e"),
|
|
985
|
+
U("1494790108377-be9c29b29330"),
|
|
986
|
+
U("1507003211169-0a1dd7228f2d"),
|
|
987
|
+
U("1438761681033-6461ffad8d80"),
|
|
988
|
+
U("1544005313-94ddf0286df2"),
|
|
989
|
+
U("1472099645785-5658abf4ff4e"),
|
|
990
|
+
U("1519085360753-af0119f7cbe7"),
|
|
991
|
+
U("1534528741775-53994a69daeb")
|
|
992
|
+
];
|
|
993
|
+
var THEMED = [
|
|
994
|
+
{
|
|
995
|
+
keywords: ["portrait", "headshot", "person", "people", "team", "staff", "avatar", "founder", "face"],
|
|
996
|
+
pool: PEOPLE
|
|
997
|
+
},
|
|
998
|
+
{
|
|
999
|
+
keywords: ["pet", "dog", "cat", "puppy", "kitten", "vet", "animal"],
|
|
1000
|
+
pool: [
|
|
1001
|
+
U("1548199973-03cce0bbc87b"),
|
|
1002
|
+
U("1450778869180-41d0601e046e"),
|
|
1003
|
+
U("1583511655857-d19b40a7a54e"),
|
|
1004
|
+
U("1587300003388-59208cc962cb"),
|
|
1005
|
+
U("1517849845537-4d257902454a"),
|
|
1006
|
+
U("1601758228041-f3b2795255f1")
|
|
1007
|
+
]
|
|
1008
|
+
},
|
|
1009
|
+
{
|
|
1010
|
+
keywords: [
|
|
1011
|
+
"baker",
|
|
1012
|
+
"bakery",
|
|
1013
|
+
"cafe",
|
|
1014
|
+
"coffee",
|
|
1015
|
+
"latte",
|
|
1016
|
+
"restaurant",
|
|
1017
|
+
"pastr",
|
|
1018
|
+
"bread",
|
|
1019
|
+
"cake",
|
|
1020
|
+
"cater",
|
|
1021
|
+
"chef",
|
|
1022
|
+
"kitchen",
|
|
1023
|
+
"food",
|
|
1024
|
+
"pizza",
|
|
1025
|
+
"dessert",
|
|
1026
|
+
"brunch",
|
|
1027
|
+
"bistro",
|
|
1028
|
+
"deli",
|
|
1029
|
+
"dish",
|
|
1030
|
+
"menu"
|
|
1031
|
+
],
|
|
1032
|
+
pool: [
|
|
1033
|
+
U("1509440159596-0249088772ff"),
|
|
1034
|
+
U("1555507036-ab1f4038808a"),
|
|
1035
|
+
U("1517433670267-08bbd4be890f"),
|
|
1036
|
+
U("1486427944299-d1955d23e34d"),
|
|
1037
|
+
U("1504754524776-8f4f37790ca0"),
|
|
1038
|
+
U("1495474472287-4d71bcdd2085"),
|
|
1039
|
+
U("1521017432531-fbd92d768814"),
|
|
1040
|
+
U("1556909114-f6e7ad7d3136")
|
|
1041
|
+
]
|
|
1042
|
+
},
|
|
1043
|
+
{
|
|
1044
|
+
keywords: [
|
|
1045
|
+
"shop",
|
|
1046
|
+
"store",
|
|
1047
|
+
"boutique",
|
|
1048
|
+
"retail",
|
|
1049
|
+
"clothing",
|
|
1050
|
+
"fashion",
|
|
1051
|
+
"jewel",
|
|
1052
|
+
"gift",
|
|
1053
|
+
"florist",
|
|
1054
|
+
"market",
|
|
1055
|
+
"grocer",
|
|
1056
|
+
"product",
|
|
1057
|
+
"storefront"
|
|
1058
|
+
],
|
|
1059
|
+
pool: [
|
|
1060
|
+
U("1441984904996-e0b6ba687e04"),
|
|
1061
|
+
U("1472851294608-062f824d29cc"),
|
|
1062
|
+
U("1523381210434-271e8be1f52b"),
|
|
1063
|
+
U("1534452203293-494d7ddbf7e0"),
|
|
1064
|
+
U("1445205170230-053b83016050"),
|
|
1065
|
+
U("1560243563-062bfc001d68")
|
|
1066
|
+
]
|
|
1067
|
+
},
|
|
1068
|
+
{
|
|
1069
|
+
keywords: [
|
|
1070
|
+
"yoga",
|
|
1071
|
+
"pilates",
|
|
1072
|
+
"fitness",
|
|
1073
|
+
"gym",
|
|
1074
|
+
"workout",
|
|
1075
|
+
"trainer",
|
|
1076
|
+
"wellness",
|
|
1077
|
+
"meditat",
|
|
1078
|
+
"massage",
|
|
1079
|
+
"therap",
|
|
1080
|
+
"physio",
|
|
1081
|
+
"chiro",
|
|
1082
|
+
"nutrition",
|
|
1083
|
+
"spa",
|
|
1084
|
+
"studio"
|
|
1085
|
+
],
|
|
1086
|
+
pool: [
|
|
1087
|
+
U("1544367567-0f2fcb009e0b"),
|
|
1088
|
+
U("1506126613408-eca07ce68773"),
|
|
1089
|
+
U("1545205597-3d9d02c29597"),
|
|
1090
|
+
U("1552196563-55cd4e45efb3"),
|
|
1091
|
+
U("1518611012118-696072aa579a"),
|
|
1092
|
+
U("1571019613454-1cb2f99b2d8b"),
|
|
1093
|
+
U("1540555700478-4be289fbecef"),
|
|
1094
|
+
U("1519824145371-296894a0daa9")
|
|
1095
|
+
]
|
|
1096
|
+
},
|
|
1097
|
+
{
|
|
1098
|
+
keywords: [
|
|
1099
|
+
"salon",
|
|
1100
|
+
"hairdress",
|
|
1101
|
+
"haircut",
|
|
1102
|
+
"barber",
|
|
1103
|
+
"manicure",
|
|
1104
|
+
"pedicure",
|
|
1105
|
+
"nails",
|
|
1106
|
+
"beauty",
|
|
1107
|
+
"makeup",
|
|
1108
|
+
"cosmetic",
|
|
1109
|
+
"eyelash",
|
|
1110
|
+
"eyebrow",
|
|
1111
|
+
"skincare",
|
|
1112
|
+
"esthetic",
|
|
1113
|
+
"waxing",
|
|
1114
|
+
"hair"
|
|
1115
|
+
],
|
|
1116
|
+
pool: [
|
|
1117
|
+
U("1560066984-138dadb4c035"),
|
|
1118
|
+
U("1522337660859-02fbefca4702"),
|
|
1119
|
+
U("1562322140-8baeececf3df"),
|
|
1120
|
+
U("1521590832167-7bcbfaa6381f"),
|
|
1121
|
+
U("1487412947147-5cebf100ffc2"),
|
|
1122
|
+
U("1526045478516-99145907023c")
|
|
1123
|
+
]
|
|
1124
|
+
},
|
|
1125
|
+
{
|
|
1126
|
+
keywords: [
|
|
1127
|
+
"cleaning",
|
|
1128
|
+
"plumb",
|
|
1129
|
+
"electric",
|
|
1130
|
+
"landscap",
|
|
1131
|
+
"contractor",
|
|
1132
|
+
"handyman",
|
|
1133
|
+
"renov",
|
|
1134
|
+
"hvac",
|
|
1135
|
+
"roofing",
|
|
1136
|
+
"painting",
|
|
1137
|
+
"carpentry",
|
|
1138
|
+
"flooring",
|
|
1139
|
+
"movers",
|
|
1140
|
+
"construction",
|
|
1141
|
+
"tools"
|
|
1142
|
+
],
|
|
1143
|
+
pool: [
|
|
1144
|
+
U("1581578731548-c64695cc6952"),
|
|
1145
|
+
U("1504307651254-35680f356dfd"),
|
|
1146
|
+
U("1581092160562-40aa08e78837"),
|
|
1147
|
+
U("1621905251189-08b45d6a269e"),
|
|
1148
|
+
U("1558618666-fcd25c85cd64"),
|
|
1149
|
+
U("1585128792020-803d29415281")
|
|
1150
|
+
]
|
|
1151
|
+
},
|
|
1152
|
+
{
|
|
1153
|
+
keywords: [
|
|
1154
|
+
"legal",
|
|
1155
|
+
"attorney",
|
|
1156
|
+
"lawyer",
|
|
1157
|
+
"account",
|
|
1158
|
+
"bookkeep",
|
|
1159
|
+
"consult",
|
|
1160
|
+
"coaching",
|
|
1161
|
+
"financ",
|
|
1162
|
+
"insurance",
|
|
1163
|
+
"realtor",
|
|
1164
|
+
"estate",
|
|
1165
|
+
"marketing",
|
|
1166
|
+
"agency",
|
|
1167
|
+
"office",
|
|
1168
|
+
"business",
|
|
1169
|
+
"desk"
|
|
1170
|
+
],
|
|
1171
|
+
pool: [
|
|
1172
|
+
U("1497366216548-37526070297c"),
|
|
1173
|
+
U("1497366811353-6870744d04b2"),
|
|
1174
|
+
U("1454165804606-c3d57bc86b40"),
|
|
1175
|
+
U("1521791136064-7986c2920216"),
|
|
1176
|
+
U("1556761175-b413da4baf72"),
|
|
1177
|
+
U("1542744173-8e7e53415bb0")
|
|
1178
|
+
]
|
|
1179
|
+
},
|
|
1180
|
+
{
|
|
1181
|
+
keywords: [
|
|
1182
|
+
"wedding",
|
|
1183
|
+
"event",
|
|
1184
|
+
"party",
|
|
1185
|
+
"celebrat",
|
|
1186
|
+
"venue",
|
|
1187
|
+
"community",
|
|
1188
|
+
"nonprofit",
|
|
1189
|
+
"charity",
|
|
1190
|
+
"workshop",
|
|
1191
|
+
"photograph",
|
|
1192
|
+
"concert"
|
|
1193
|
+
],
|
|
1194
|
+
pool: [
|
|
1195
|
+
U("1511578314322-379afb476865"),
|
|
1196
|
+
U("1501281668745-f7f57925c3b4"),
|
|
1197
|
+
U("1523580494863-6f3031224c94"),
|
|
1198
|
+
U("1540575467063-178a50c2df87"),
|
|
1199
|
+
U("1505236858219-8359eb29e329"),
|
|
1200
|
+
U("1528605248644-14dd04022da1")
|
|
1201
|
+
]
|
|
1202
|
+
}
|
|
1203
|
+
];
|
|
1204
|
+
function poolForSubject(subject) {
|
|
1205
|
+
for (const theme of THEMED) {
|
|
1206
|
+
if (theme.keywords.some((k) => subject.includes(k))) {
|
|
1207
|
+
return theme.pool;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
return GENERIC;
|
|
1211
|
+
}
|
|
1212
|
+
function mixedHash(text) {
|
|
1213
|
+
let hash = 2166136261;
|
|
1214
|
+
for (let i = 0; i < text.length; i++) {
|
|
1215
|
+
hash ^= text.charCodeAt(i);
|
|
1216
|
+
hash = Math.imul(hash, 16777619);
|
|
1217
|
+
}
|
|
1218
|
+
return hash >>> 16 & 65535;
|
|
1219
|
+
}
|
|
1220
|
+
function resolvePlaceholderRef(ref) {
|
|
1221
|
+
const match = /^placeholder:([a-z0-9-]+)$/.exec(ref);
|
|
1222
|
+
if (!match) return null;
|
|
1223
|
+
const subject = match[1];
|
|
1224
|
+
const pool = poolForSubject(subject.replace(/-\d+$/, ""));
|
|
1225
|
+
return pool[mixedHash(ref) % pool.length];
|
|
1226
|
+
}
|
|
1227
|
+
function collectPlaceholderRefs(tree) {
|
|
1228
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1229
|
+
for (const match of JSON.stringify(tree ?? null).matchAll(/"(placeholder:[a-z0-9-]+)"/gu)) {
|
|
1230
|
+
seen.add(match[1]);
|
|
1231
|
+
}
|
|
1232
|
+
return [...seen];
|
|
1233
|
+
}
|
|
1234
|
+
function buildPlaceholderMap(tree) {
|
|
1235
|
+
const map = {};
|
|
1236
|
+
const cursor = /* @__PURE__ */ new Map();
|
|
1237
|
+
for (const ref of collectPlaceholderRefs(tree)) {
|
|
1238
|
+
const subject = ref.slice("placeholder:".length).replace(/-\d+$/, "");
|
|
1239
|
+
const pool = poolForSubject(subject);
|
|
1240
|
+
const start = cursor.get(pool) ?? mixedHash(ref) % pool.length;
|
|
1241
|
+
map[ref] = pool[start % pool.length];
|
|
1242
|
+
cursor.set(pool, start + 1);
|
|
1243
|
+
}
|
|
1244
|
+
return map;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
565
1248
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
566
1249
|
function lucideByName(name) {
|
|
567
1250
|
const pascal = name.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
@@ -575,6 +1258,7 @@ var typeStyle = (spec, font) => ({
|
|
|
575
1258
|
fontWeight: spec.weight
|
|
576
1259
|
});
|
|
577
1260
|
var str = (value) => typeof value === "string" ? value : "";
|
|
1261
|
+
var cardRadius = (slots) => slots.cornerStyle === "sharp" ? 0 : AI_TREE_TOKENS.radiusCard;
|
|
578
1262
|
var featureLines = (value) => value.split(/\n|<br\s*\/?>/i).map((line) => line.trim()).filter(Boolean);
|
|
579
1263
|
var CHECK_MASK = `data:image/svg+xml,${encodeURIComponent(
|
|
580
1264
|
'<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>'
|
|
@@ -601,6 +1285,25 @@ var FEATURE_LINE_CSS = [
|
|
|
601
1285
|
`background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
|
|
602
1286
|
`mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
|
|
603
1287
|
].join("");
|
|
1288
|
+
function buttonShellStyle(ctx, fullWidth) {
|
|
1289
|
+
const bs = ctx.buttonStyle;
|
|
1290
|
+
if (bs) {
|
|
1291
|
+
return {
|
|
1292
|
+
borderRadius: bs.radius,
|
|
1293
|
+
...bs.padding ? { padding: bs.padding } : {},
|
|
1294
|
+
...bs.fontFamily ? { fontFamily: bs.fontFamily } : { fontFamily: ctx.brand.fonts.body },
|
|
1295
|
+
...bs.fontSize ? { fontSize: bs.fontSize } : {},
|
|
1296
|
+
...bs.fontWeight ? { fontWeight: bs.fontWeight } : {},
|
|
1297
|
+
...bs.letterSpacing && bs.letterSpacing !== "normal" ? { letterSpacing: bs.letterSpacing } : {},
|
|
1298
|
+
...bs.textTransform && bs.textTransform !== "none" ? { textTransform: bs.textTransform } : {}
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
return {
|
|
1302
|
+
borderRadius: AI_TREE_TOKENS.radiusButton,
|
|
1303
|
+
padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
|
|
1304
|
+
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
604
1307
|
function hexLuminance(color) {
|
|
605
1308
|
const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
|
|
606
1309
|
if (!m) return null;
|
|
@@ -617,6 +1320,12 @@ function hexContrast(a, b) {
|
|
|
617
1320
|
const [hi, lo] = la > lb ? [la, lb] : [lb, la];
|
|
618
1321
|
return (hi + 0.05) / (lo + 0.05);
|
|
619
1322
|
}
|
|
1323
|
+
function primaryButtonLabel(brand) {
|
|
1324
|
+
const darkC = hexContrast(brand.palette.primary, brand.palette.dark);
|
|
1325
|
+
const lightC = hexContrast(brand.palette.primary, AI_TREE_TOKENS.textPrimaryForeground);
|
|
1326
|
+
if (darkC === null || lightC === null) return AI_TREE_TOKENS.textPrimaryForeground;
|
|
1327
|
+
return darkC > lightC ? brand.palette.dark : AI_TREE_TOKENS.textPrimaryForeground;
|
|
1328
|
+
}
|
|
620
1329
|
function accentBandContext(brand) {
|
|
621
1330
|
const p = brand.palette;
|
|
622
1331
|
const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
|
|
@@ -634,6 +1343,22 @@ function accentBandContext(brand) {
|
|
|
634
1343
|
function textAttrs(ctx, path) {
|
|
635
1344
|
return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
|
|
636
1345
|
}
|
|
1346
|
+
var AI_RESPONSIVE_CSS = [
|
|
1347
|
+
"@media (max-width: 960px) {",
|
|
1348
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
|
|
1349
|
+
' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
|
|
1350
|
+
"}",
|
|
1351
|
+
"@media (max-width: 640px) {",
|
|
1352
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
|
|
1353
|
+
" [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
|
|
1354
|
+
// Group containers flatten to a column on phones; span placements come along for free.
|
|
1355
|
+
" [data-ai-responsive] [data-ai-group] { display: flex !important; flex-direction: column !important; }",
|
|
1356
|
+
" [data-ai-responsive] [data-ai-group] > * { grid-column: auto !important; }",
|
|
1357
|
+
" [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
|
|
1358
|
+
" [data-ai-responsive] { overflow-x: hidden; }",
|
|
1359
|
+
" [data-ai-responsive] img { max-width: 100%; }",
|
|
1360
|
+
"}"
|
|
1361
|
+
].join("\n");
|
|
637
1362
|
var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
638
1363
|
function MediaBox({
|
|
639
1364
|
refValue,
|
|
@@ -646,13 +1371,17 @@ function MediaBox({
|
|
|
646
1371
|
const url = refValue ? ctx.resolveMedia(refValue) : null;
|
|
647
1372
|
const isIcon = /^(lucide|simple):/.test(refValue);
|
|
648
1373
|
const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
|
|
649
|
-
const editAttrs = ctx.keyFor && editPath
|
|
1374
|
+
const editAttrs = ctx.keyFor && editPath ? {
|
|
1375
|
+
"data-ohw-key": ctx.keyFor(editPath),
|
|
1376
|
+
"data-ohw-editable": isIcon ? "icon" : "image"
|
|
1377
|
+
} : {};
|
|
650
1378
|
if (isIcon) {
|
|
651
1379
|
const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
|
|
652
1380
|
return /* @__PURE__ */ jsx(
|
|
653
1381
|
"span",
|
|
654
1382
|
{
|
|
655
1383
|
"data-ai-icon": refValue,
|
|
1384
|
+
...editAttrs,
|
|
656
1385
|
style: {
|
|
657
1386
|
display: "inline-flex",
|
|
658
1387
|
width: 48,
|
|
@@ -716,12 +1445,15 @@ function ButtonEl({
|
|
|
716
1445
|
width: fullWidth ? "100%" : void 0,
|
|
717
1446
|
alignItems: "center",
|
|
718
1447
|
justifyContent: "center",
|
|
719
|
-
padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
|
|
720
|
-
borderRadius: AI_TREE_TOKENS.radiusButton,
|
|
721
1448
|
textDecoration: "none",
|
|
722
1449
|
cursor: "pointer",
|
|
723
|
-
...
|
|
724
|
-
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } :
|
|
1450
|
+
...buttonShellStyle(ctx, fullWidth),
|
|
1451
|
+
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : (
|
|
1452
|
+
// Off-band, prefer the template button's measured fill/label pair — a template may
|
|
1453
|
+
// fill its CTAs with any token (hvac: accent bg, primary text). On an accent band
|
|
1454
|
+
// the flipped palette keeps contrast, so the brand-driven colours stay.
|
|
1455
|
+
!ctx.buttonLabel && ctx.buttonStyle?.background ? { background: ctx.buttonStyle.background, color: ctx.buttonStyle.color } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand) }
|
|
1456
|
+
)
|
|
725
1457
|
},
|
|
726
1458
|
children: /* @__PURE__ */ jsx("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
|
|
727
1459
|
}
|
|
@@ -897,10 +1629,11 @@ function PricingCard({ node, ctx, path }) {
|
|
|
897
1629
|
return /* @__PURE__ */ jsxs(
|
|
898
1630
|
"div",
|
|
899
1631
|
{
|
|
1632
|
+
"data-ohw-card": "",
|
|
900
1633
|
style: {
|
|
901
1634
|
background: hasBg ? ctx.brand.palette.light : "transparent",
|
|
902
1635
|
border: `1px solid ${dark}`,
|
|
903
|
-
borderRadius:
|
|
1636
|
+
borderRadius: cardRadius(slots),
|
|
904
1637
|
padding: AI_TREE_TOKENS.paddingBlock,
|
|
905
1638
|
display: "flex",
|
|
906
1639
|
flexDirection: "column",
|
|
@@ -1005,10 +1738,11 @@ function TestimonialCard({ node, ctx, path }) {
|
|
|
1005
1738
|
return /* @__PURE__ */ jsx(
|
|
1006
1739
|
"div",
|
|
1007
1740
|
{
|
|
1741
|
+
"data-ohw-card": "",
|
|
1008
1742
|
"data-ai-avatar-pos": avatarPos ?? void 0,
|
|
1009
1743
|
style: {
|
|
1010
1744
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1011
|
-
borderRadius: hasBg ?
|
|
1745
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1012
1746
|
overflow: "hidden",
|
|
1013
1747
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1014
1748
|
minWidth: 0
|
|
@@ -1043,10 +1777,11 @@ function TeamCard({ node, ctx, path }) {
|
|
|
1043
1777
|
return /* @__PURE__ */ jsxs(
|
|
1044
1778
|
"div",
|
|
1045
1779
|
{
|
|
1780
|
+
"data-ohw-card": "",
|
|
1046
1781
|
"data-ai-avatar-pos": avatarPos ?? void 0,
|
|
1047
1782
|
style: {
|
|
1048
1783
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1049
|
-
borderRadius: hasBg ?
|
|
1784
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1050
1785
|
overflow: "hidden",
|
|
1051
1786
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1052
1787
|
minWidth: 0,
|
|
@@ -1217,9 +1952,10 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1217
1952
|
return /* @__PURE__ */ jsxs(
|
|
1218
1953
|
"div",
|
|
1219
1954
|
{
|
|
1955
|
+
"data-ohw-card": "",
|
|
1220
1956
|
style: {
|
|
1221
1957
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1222
|
-
borderRadius: hasBg ?
|
|
1958
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1223
1959
|
overflow: "hidden",
|
|
1224
1960
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1225
1961
|
display: horizontal ? "flex" : "block",
|
|
@@ -1247,7 +1983,7 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1247
1983
|
) : /* @__PURE__ */ jsx(
|
|
1248
1984
|
"div",
|
|
1249
1985
|
{
|
|
1250
|
-
style: /^(lucide|simple):/.test(mediaRef) ? { padding: `${AI_TREE_TOKENS.paddingBlock}px ${AI_TREE_TOKENS.paddingBlock}px 0` } : hasBg ? void 0 : { borderRadius:
|
|
1986
|
+
style: /^(lucide|simple):/.test(mediaRef) ? { padding: `${AI_TREE_TOKENS.paddingBlock}px ${AI_TREE_TOKENS.paddingBlock}px 0` } : hasBg ? void 0 : { borderRadius: cardRadius(slots), overflow: "hidden" },
|
|
1251
1987
|
children: media
|
|
1252
1988
|
}
|
|
1253
1989
|
)),
|
|
@@ -1538,7 +2274,7 @@ function CollectionBlock({ node, ctx, path }) {
|
|
|
1538
2274
|
return /* @__PURE__ */ jsx(
|
|
1539
2275
|
"div",
|
|
1540
2276
|
{
|
|
1541
|
-
"data-ai-grid":
|
|
2277
|
+
"data-ai-grid": String(itemsPerRow),
|
|
1542
2278
|
style: {
|
|
1543
2279
|
display: "grid",
|
|
1544
2280
|
gridTemplateColumns: `repeat(${itemsPerRow}, 1fr)`,
|
|
@@ -1658,6 +2394,32 @@ function renderNode(node, ctx, path) {
|
|
|
1658
2394
|
if (child) {
|
|
1659
2395
|
return renderNode(child, ctx, `${path}.c0`);
|
|
1660
2396
|
}
|
|
2397
|
+
if (str(slots.provider) === "map" && str(slots.query)) {
|
|
2398
|
+
const query = str(slots.query);
|
|
2399
|
+
const mapAttrs = ctx.keyFor ? {
|
|
2400
|
+
"data-ohw-key": ctx.keyFor(`${path}.query`),
|
|
2401
|
+
"data-ohw-editable": "map",
|
|
2402
|
+
"data-ohw-map-query": query
|
|
2403
|
+
} : {};
|
|
2404
|
+
return /* @__PURE__ */ jsx(
|
|
2405
|
+
"iframe",
|
|
2406
|
+
{
|
|
2407
|
+
...mapAttrs,
|
|
2408
|
+
"data-ai-embed": "map",
|
|
2409
|
+
title: str(slots.title) || "Map",
|
|
2410
|
+
src: `https://www.google.com/maps?q=${encodeURIComponent(query)}&output=embed`,
|
|
2411
|
+
loading: "lazy",
|
|
2412
|
+
referrerPolicy: "no-referrer-when-downgrade",
|
|
2413
|
+
style: {
|
|
2414
|
+
width: "100%",
|
|
2415
|
+
minHeight: 320,
|
|
2416
|
+
border: 0,
|
|
2417
|
+
borderRadius: AI_TREE_TOKENS.radiusCard,
|
|
2418
|
+
display: "block"
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
);
|
|
2422
|
+
}
|
|
1661
2423
|
return /* @__PURE__ */ jsx(
|
|
1662
2424
|
"div",
|
|
1663
2425
|
{
|
|
@@ -1761,15 +2523,14 @@ function renderNode(node, ctx, path) {
|
|
|
1761
2523
|
alignSelf: submitAlign,
|
|
1762
2524
|
border: "none",
|
|
1763
2525
|
cursor: "pointer",
|
|
1764
|
-
padding
|
|
1765
|
-
|
|
1766
|
-
//
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
2526
|
+
// Shape/padding/typography follow the host template's own buttons.
|
|
2527
|
+
...buttonShellStyle(ctx),
|
|
2528
|
+
// Brand-styled: the template button's measured fill/label pair off-band, else
|
|
2529
|
+
// primary fill with a brand-derived label so it reads on custom palettes.
|
|
2530
|
+
...!ctx.buttonLabel && ctx.buttonStyle?.background ? { background: ctx.buttonStyle.background, color: ctx.buttonStyle.color } : {
|
|
2531
|
+
background: ctx.brand.palette.primary,
|
|
2532
|
+
color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand)
|
|
2533
|
+
}
|
|
1773
2534
|
},
|
|
1774
2535
|
children: /* @__PURE__ */ jsx("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
|
|
1775
2536
|
},
|
|
@@ -1804,7 +2565,7 @@ function renderNode(node, ctx, path) {
|
|
|
1804
2565
|
function AiTreeRenderer({
|
|
1805
2566
|
tree,
|
|
1806
2567
|
brand,
|
|
1807
|
-
|
|
2568
|
+
buttonStyle,
|
|
1808
2569
|
resolveMedia,
|
|
1809
2570
|
editKeyPrefix
|
|
1810
2571
|
}) {
|
|
@@ -1814,13 +2575,18 @@ function AiTreeRenderer({
|
|
|
1814
2575
|
const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
|
|
1815
2576
|
const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
|
|
1816
2577
|
const blockBrand = band?.brand ?? resolvedBrand;
|
|
2578
|
+
const placeholderMap = buildPlaceholderMap(tree);
|
|
1817
2579
|
const ctx = {
|
|
1818
2580
|
brand: blockBrand,
|
|
1819
|
-
|
|
2581
|
+
// An owner/library ref resolves through the host resolver; a `placeholder:<subject>` ref the
|
|
2582
|
+
// host cannot resolve falls back to real stock photography (the per-section map first, then a
|
|
2583
|
+
// standalone resolve), so generated galleries, image rows, and overlay backgrounds arrive with
|
|
2584
|
+
// photos instead of grey boxes.
|
|
2585
|
+
resolveMedia: (ref) => resolveMedia?.(ref) ?? placeholderMap[ref] ?? resolvePlaceholderRef(ref),
|
|
1820
2586
|
cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
|
|
1821
2587
|
keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
|
|
1822
2588
|
sectionAlignment: (tree.settings ?? {}).alignment === "center" ? "center" : "left",
|
|
1823
|
-
|
|
2589
|
+
buttonStyle,
|
|
1824
2590
|
...band ? { buttonLabel: band.buttonLabel } : {}
|
|
1825
2591
|
};
|
|
1826
2592
|
const settings = tree.settings ?? {};
|
|
@@ -1861,6 +2627,7 @@ function AiTreeRenderer({
|
|
|
1861
2627
|
{
|
|
1862
2628
|
"data-ai-section": tree.tag ?? "",
|
|
1863
2629
|
...bgAttrs,
|
|
2630
|
+
"data-ai-responsive": "",
|
|
1864
2631
|
style: {
|
|
1865
2632
|
position: "relative",
|
|
1866
2633
|
padding: `${pad}px 0`,
|
|
@@ -1871,12 +2638,13 @@ function AiTreeRenderer({
|
|
|
1871
2638
|
color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
|
|
1872
2639
|
},
|
|
1873
2640
|
children: [
|
|
1874
|
-
|
|
2641
|
+
/* @__PURE__ */ jsx("style", { children: AI_RESPONSIVE_CSS }),
|
|
1875
2642
|
/* @__PURE__ */ jsx("style", { children: AI_MOBILE_CSS }),
|
|
2643
|
+
isOverlay && backgroundUrl && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
|
|
1876
2644
|
/* @__PURE__ */ jsx(
|
|
1877
2645
|
"div",
|
|
1878
2646
|
{
|
|
1879
|
-
"data-ai-
|
|
2647
|
+
"data-ai-section-inner": "",
|
|
1880
2648
|
style: {
|
|
1881
2649
|
position: "relative",
|
|
1882
2650
|
maxWidth: AI_TREE_TOKENS.sectionMaxWidth,
|
|
@@ -1887,7 +2655,7 @@ function AiTreeRenderer({
|
|
|
1887
2655
|
children: tree.rows.map((row, r2) => /* @__PURE__ */ jsx(
|
|
1888
2656
|
"div",
|
|
1889
2657
|
{
|
|
1890
|
-
"data-ai-
|
|
2658
|
+
"data-ai-columns": "",
|
|
1891
2659
|
style: {
|
|
1892
2660
|
display: "grid",
|
|
1893
2661
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
@@ -1926,21 +2694,63 @@ function AiTreeRenderer({
|
|
|
1926
2694
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1927
2695
|
var CONTAINER_ATTR = "data-ohw-ai-generated";
|
|
1928
2696
|
var REPLACED_ATTR = "data-ohw-ai-replaced-by";
|
|
1929
|
-
var
|
|
2697
|
+
var REMOVED_ATTR2 = "data-ohw-ai-removed";
|
|
1930
2698
|
var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
|
|
1931
2699
|
var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
2700
|
+
function isChromeSection2(el) {
|
|
2701
|
+
if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) return true;
|
|
2702
|
+
return el.tagName === "HEADER" || el.tagName === "FOOTER";
|
|
2703
|
+
}
|
|
1932
2704
|
function readRootVar(name) {
|
|
1933
2705
|
if (typeof document === "undefined") return "";
|
|
1934
2706
|
return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
1935
2707
|
}
|
|
2708
|
+
function normalizeColorToHex(value) {
|
|
2709
|
+
if (!value || typeof document === "undefined") return value;
|
|
2710
|
+
const canvas = document.createElement("canvas");
|
|
2711
|
+
canvas.width = 1;
|
|
2712
|
+
canvas.height = 1;
|
|
2713
|
+
const ctx = canvas.getContext("2d");
|
|
2714
|
+
if (!ctx) return value;
|
|
2715
|
+
ctx.fillStyle = value;
|
|
2716
|
+
ctx.fillRect(0, 0, 1, 1);
|
|
2717
|
+
const [r2, g, b] = ctx.getImageData(0, 0, 1, 1).data;
|
|
2718
|
+
const toHex = (n) => n.toString(16).padStart(2, "0");
|
|
2719
|
+
return `#${toHex(r2)}${toHex(g)}${toHex(b)}`;
|
|
2720
|
+
}
|
|
2721
|
+
var GENERIC_FONT_KEYWORDS = /* @__PURE__ */ new Set([
|
|
2722
|
+
"serif",
|
|
2723
|
+
"sans-serif",
|
|
2724
|
+
"monospace",
|
|
2725
|
+
"cursive",
|
|
2726
|
+
"fantasy",
|
|
2727
|
+
"system-ui",
|
|
2728
|
+
"ui-serif",
|
|
2729
|
+
"ui-sans-serif",
|
|
2730
|
+
"ui-monospace",
|
|
2731
|
+
"ui-rounded",
|
|
2732
|
+
"math",
|
|
2733
|
+
"emoji",
|
|
2734
|
+
"fangsong"
|
|
2735
|
+
]);
|
|
2736
|
+
function primaryFontFamily(stack) {
|
|
2737
|
+
const first = stack.split(",").map((part) => part.trim().replace(/^["']|["']$/g, "")).find((part) => part && !GENERIC_FONT_KEYWORDS.has(part.toLowerCase()));
|
|
2738
|
+
return first ?? "";
|
|
2739
|
+
}
|
|
2740
|
+
function humanizeFontFamily(name) {
|
|
2741
|
+
return name.replace(/^__/, "").replace(/_[0-9a-f]{6}$/i, "").replace(/_/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").trim().replace(/\s+/g, " ").replace(/(^|\s)([a-z])/g, (_, sep, c) => sep + c.toUpperCase());
|
|
2742
|
+
}
|
|
2743
|
+
function readFontVar(name) {
|
|
2744
|
+
return humanizeFontFamily(primaryFontFamily(readRootVar(name)));
|
|
2745
|
+
}
|
|
1936
2746
|
function deriveBrandOverride() {
|
|
1937
2747
|
const dark = readRootVar("--ohw-brand-dark");
|
|
1938
2748
|
const primary = readRootVar("--ohw-brand-primary");
|
|
1939
2749
|
const light = readRootVar("--ohw-brand-light");
|
|
1940
2750
|
if (!dark || !primary || !light) return null;
|
|
1941
2751
|
const accent = readRootVar("--ohw-brand-accent");
|
|
1942
|
-
const heading =
|
|
1943
|
-
const body =
|
|
2752
|
+
const heading = readFontVar("--font-heading") || readFontVar("--font-display");
|
|
2753
|
+
const body = readFontVar("--font-body");
|
|
1944
2754
|
return {
|
|
1945
2755
|
palette: { dark, primary, accent: accent || dark, light },
|
|
1946
2756
|
fonts: {
|
|
@@ -1949,28 +2759,98 @@ function deriveBrandOverride() {
|
|
|
1949
2759
|
}
|
|
1950
2760
|
};
|
|
1951
2761
|
}
|
|
1952
|
-
function
|
|
1953
|
-
const dark = readRootVar("--color-dark");
|
|
1954
|
-
const primary = readRootVar("--color-primary");
|
|
1955
|
-
const light = readRootVar("--color-light");
|
|
2762
|
+
function deriveTemplateBrandLive() {
|
|
2763
|
+
const dark = readRootVar("--color-dark") || readRootVar("--brand-text");
|
|
2764
|
+
const primary = readRootVar("--color-primary") || readRootVar("--brand-primary");
|
|
2765
|
+
const light = readRootVar("--color-light") || readRootVar("--brand-background");
|
|
1956
2766
|
if (!dark || !primary || !light) return null;
|
|
1957
|
-
const accent = readRootVar("--color-accent");
|
|
1958
|
-
const heading =
|
|
1959
|
-
const body =
|
|
2767
|
+
const accent = readRootVar("--color-accent") || readRootVar("--brand-accent");
|
|
2768
|
+
const heading = readFontVar("--brand-font-heading") || readFontVar("--font-heading") || readFontVar("--font-display");
|
|
2769
|
+
const body = readFontVar("--brand-font-body") || readFontVar("--font-body");
|
|
1960
2770
|
return {
|
|
1961
|
-
palette: {
|
|
2771
|
+
palette: {
|
|
2772
|
+
dark: normalizeColorToHex(dark),
|
|
2773
|
+
primary: normalizeColorToHex(primary),
|
|
2774
|
+
accent: normalizeColorToHex(accent || dark),
|
|
2775
|
+
light: normalizeColorToHex(light)
|
|
2776
|
+
},
|
|
1962
2777
|
fonts: {
|
|
1963
2778
|
heading: heading || AI_DEFAULT_BRAND.fonts.heading,
|
|
1964
2779
|
body: body || AI_DEFAULT_BRAND.fonts.body
|
|
1965
2780
|
}
|
|
1966
2781
|
};
|
|
1967
2782
|
}
|
|
1968
|
-
function
|
|
2783
|
+
function deriveTemplateFontsLive() {
|
|
2784
|
+
const heading = readFontVar("--brand-font-heading") || readFontVar("--font-heading") || readFontVar("--font-display");
|
|
2785
|
+
const body = readFontVar("--brand-font-body") || readFontVar("--font-body");
|
|
2786
|
+
if (!heading && !body) return null;
|
|
2787
|
+
return {
|
|
2788
|
+
heading: heading || AI_DEFAULT_BRAND.fonts.heading,
|
|
2789
|
+
body: body || AI_DEFAULT_BRAND.fonts.body
|
|
2790
|
+
};
|
|
2791
|
+
}
|
|
2792
|
+
var OVERRIDE_VAR_NAMES = [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES, ...FONT_VARS.heading, ...FONT_VARS.body];
|
|
2793
|
+
function withOverrideStripped(read) {
|
|
2794
|
+
const root = document.documentElement;
|
|
2795
|
+
const restore = OVERRIDE_VAR_NAMES.map((name) => [name, root.style.getPropertyValue(name)]);
|
|
2796
|
+
for (const name of OVERRIDE_VAR_NAMES) root.style.removeProperty(name);
|
|
2797
|
+
try {
|
|
2798
|
+
return read();
|
|
2799
|
+
} finally {
|
|
2800
|
+
for (const [name, value] of restore) if (value) root.style.setProperty(name, value);
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
var TEMPLATE_BRAND_SNAPSHOT = typeof document === "undefined" ? null : withOverrideStripped(deriveTemplateBrandLive);
|
|
2804
|
+
var TEMPLATE_FONTS_SNAPSHOT = typeof document === "undefined" ? null : withOverrideStripped(deriveTemplateFontsLive);
|
|
2805
|
+
function deriveTemplateBrand() {
|
|
2806
|
+
return TEMPLATE_BRAND_SNAPSHOT;
|
|
2807
|
+
}
|
|
2808
|
+
function deriveTemplateFonts() {
|
|
2809
|
+
return TEMPLATE_FONTS_SNAPSHOT;
|
|
2810
|
+
}
|
|
2811
|
+
function deriveTemplateButtonStyle() {
|
|
1969
2812
|
if (typeof document === "undefined") return null;
|
|
1970
|
-
const
|
|
2813
|
+
const candidates = Array.from(
|
|
2814
|
+
document.querySelectorAll('[data-ohw-role="button"]')
|
|
2815
|
+
).filter(
|
|
2816
|
+
(el) => !el.closest(`[${CONTAINER_ATTR}]`) && // Whole-card links legitimately carry the button role (serene's clickable treatment
|
|
2817
|
+
// cards) but must never donate the "button look" — a real button holds at most its
|
|
2818
|
+
// one editable label, a card holds a headline, copy and prices.
|
|
2819
|
+
el.querySelectorAll("[data-ohw-editable]").length <= 1
|
|
2820
|
+
);
|
|
2821
|
+
const isFilled = (el) => {
|
|
2822
|
+
const bg = getComputedStyle(el).backgroundColor;
|
|
2823
|
+
if (!bg || bg === "transparent") return false;
|
|
2824
|
+
const alpha = bg.match(/rgba?\([^)]*,\s*([\d.]+)\)$/);
|
|
2825
|
+
return !alpha || parseFloat(alpha[1]) > 0;
|
|
2826
|
+
};
|
|
2827
|
+
const btn = candidates.find(isFilled) ?? candidates[0];
|
|
1971
2828
|
if (!btn) return null;
|
|
1972
|
-
const
|
|
1973
|
-
|
|
2829
|
+
const cs = getComputedStyle(btn);
|
|
2830
|
+
const filled = isFilled(btn);
|
|
2831
|
+
const corners = [
|
|
2832
|
+
cs.borderTopLeftRadius,
|
|
2833
|
+
cs.borderTopRightRadius,
|
|
2834
|
+
cs.borderBottomRightRadius,
|
|
2835
|
+
cs.borderBottomLeftRadius
|
|
2836
|
+
].map((v) => v || "0px");
|
|
2837
|
+
const radius = corners.every((v) => v === corners[0]) ? corners[0] : corners.join(" ");
|
|
2838
|
+
const px = (v) => parseFloat(v) || 0;
|
|
2839
|
+
const lineHeight = px(cs.lineHeight) || px(cs.fontSize) * 1.2;
|
|
2840
|
+
const contentH = btn.getBoundingClientRect().height - px(cs.borderTopWidth) - px(cs.borderBottomWidth);
|
|
2841
|
+
const impliedY = Math.round(Math.max(0, (contentH - lineHeight) / 2));
|
|
2842
|
+
const padY = Math.max(px(cs.paddingTop), px(cs.paddingBottom), impliedY);
|
|
2843
|
+
const padX = Math.max(px(cs.paddingLeft), px(cs.paddingRight));
|
|
2844
|
+
return {
|
|
2845
|
+
radius: radius || "10px",
|
|
2846
|
+
padding: `${padY}px ${padX}px`,
|
|
2847
|
+
...filled ? { background: cs.backgroundColor, color: cs.color } : {},
|
|
2848
|
+
fontFamily: cs.fontFamily || "",
|
|
2849
|
+
fontSize: cs.fontSize || "",
|
|
2850
|
+
fontWeight: cs.fontWeight || "",
|
|
2851
|
+
letterSpacing: cs.letterSpacing || "",
|
|
2852
|
+
textTransform: cs.textTransform || ""
|
|
2853
|
+
};
|
|
1974
2854
|
}
|
|
1975
2855
|
var mounted = /* @__PURE__ */ new Map();
|
|
1976
2856
|
function findTemplateSection(id) {
|
|
@@ -1986,6 +2866,19 @@ function findPlacementAnchor(id, exclude) {
|
|
|
1986
2866
|
for (const el of document.querySelectorAll(`[data-ohw-section="${CSS.escape(id)}"]`)) {
|
|
1987
2867
|
if (el === exclude) continue;
|
|
1988
2868
|
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
2869
|
+
if (isChromeSection2(el)) return null;
|
|
2870
|
+
return el;
|
|
2871
|
+
}
|
|
2872
|
+
return null;
|
|
2873
|
+
}
|
|
2874
|
+
function findFooterSection() {
|
|
2875
|
+
const byId = findTemplateSection("footer");
|
|
2876
|
+
if (byId) return byId;
|
|
2877
|
+
for (const el of Array.from(
|
|
2878
|
+
document.querySelectorAll("footer[data-ohw-section]")
|
|
2879
|
+
).reverse()) {
|
|
2880
|
+
if (el.hasAttribute(CONTAINER_ATTR)) continue;
|
|
2881
|
+
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
1989
2882
|
return el;
|
|
1990
2883
|
}
|
|
1991
2884
|
return null;
|
|
@@ -2012,7 +2905,7 @@ function placeContainer(container, entry) {
|
|
|
2012
2905
|
return;
|
|
2013
2906
|
}
|
|
2014
2907
|
}
|
|
2015
|
-
const footer =
|
|
2908
|
+
const footer = findFooterSection();
|
|
2016
2909
|
if (footer) {
|
|
2017
2910
|
footer.insertAdjacentElement("beforebegin", container);
|
|
2018
2911
|
} else {
|
|
@@ -2021,18 +2914,18 @@ function placeContainer(container, entry) {
|
|
|
2021
2914
|
}
|
|
2022
2915
|
function syncRemovedSections(state) {
|
|
2023
2916
|
const removed = new Set(state.removed ?? []);
|
|
2024
|
-
for (const el of document.querySelectorAll(`[${
|
|
2917
|
+
for (const el of document.querySelectorAll(`[${REMOVED_ATTR2}]`)) {
|
|
2025
2918
|
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
2026
2919
|
if (!removed.has(id)) {
|
|
2027
2920
|
el.style.removeProperty("display");
|
|
2028
|
-
el.removeAttribute(
|
|
2921
|
+
el.removeAttribute(REMOVED_ATTR2);
|
|
2029
2922
|
}
|
|
2030
2923
|
}
|
|
2031
2924
|
for (const id of removed) {
|
|
2032
2925
|
const section = findTemplateSection(id);
|
|
2033
2926
|
if (section && !section.hasAttribute(REPLACED_ATTR)) {
|
|
2034
2927
|
section.style.display = "none";
|
|
2035
|
-
section.setAttribute(
|
|
2928
|
+
section.setAttribute(REMOVED_ATTR2, "");
|
|
2036
2929
|
}
|
|
2037
2930
|
}
|
|
2038
2931
|
}
|
|
@@ -2047,9 +2940,9 @@ function syncTemplateHidden(state, pageHasSections) {
|
|
|
2047
2940
|
if (!hide) return;
|
|
2048
2941
|
for (const el of Array.from(document.querySelectorAll("[data-ohw-section]"))) {
|
|
2049
2942
|
if (el.hasAttribute(CONTAINER_ATTR)) continue;
|
|
2050
|
-
if (
|
|
2943
|
+
if (isChromeSection2(el)) continue;
|
|
2051
2944
|
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
2052
|
-
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(
|
|
2945
|
+
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR2)) continue;
|
|
2053
2946
|
el.style.display = "none";
|
|
2054
2947
|
el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
|
|
2055
2948
|
}
|
|
@@ -2073,18 +2966,23 @@ function syncReplacedOriginals(state) {
|
|
|
2073
2966
|
}
|
|
2074
2967
|
}
|
|
2075
2968
|
var sectionOrderIndex = /* @__PURE__ */ new Map();
|
|
2969
|
+
var removedSectionIds = /* @__PURE__ */ new Set();
|
|
2076
2970
|
function setAiSectionOrder(raw, currentPath) {
|
|
2077
2971
|
const next = /* @__PURE__ */ new Map();
|
|
2972
|
+
const removed = /* @__PURE__ */ new Set();
|
|
2078
2973
|
if (raw) {
|
|
2079
2974
|
try {
|
|
2080
2975
|
const entries = JSON.parse(raw);
|
|
2081
2976
|
for (const entry of entries) {
|
|
2082
|
-
if (
|
|
2977
|
+
if (entry.pagePath && entry.pagePath !== currentPath) continue;
|
|
2978
|
+
next.set(entry.instanceId, entry.order);
|
|
2979
|
+
if (entry.removed) removed.add(entry.instanceId);
|
|
2083
2980
|
}
|
|
2084
2981
|
} catch {
|
|
2085
2982
|
}
|
|
2086
2983
|
}
|
|
2087
2984
|
sectionOrderIndex = next;
|
|
2985
|
+
removedSectionIds = removed;
|
|
2088
2986
|
}
|
|
2089
2987
|
function applyExplicitOrder(entries) {
|
|
2090
2988
|
if (sectionOrderIndex.size === 0) return entries;
|
|
@@ -2120,11 +3018,23 @@ function orderByChain(sections) {
|
|
|
2120
3018
|
for (const root of roots) visit(root);
|
|
2121
3019
|
return out.length === sections.length ? out : sections;
|
|
2122
3020
|
}
|
|
3021
|
+
function syncSoftRemovedGenerated() {
|
|
3022
|
+
for (const [id, section] of mounted) {
|
|
3023
|
+
const el = section.container;
|
|
3024
|
+
if (removedSectionIds.has(id)) {
|
|
3025
|
+
el.style.display = "none";
|
|
3026
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
3027
|
+
} else if (el.hasAttribute(REMOVED_ATTR)) {
|
|
3028
|
+
el.style.removeProperty("display");
|
|
3029
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
3030
|
+
}
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
2123
3033
|
function applyAiSectionsToDom(state, options) {
|
|
2124
3034
|
if (typeof document === "undefined") return;
|
|
2125
3035
|
const brandOverride = deriveBrandOverride();
|
|
2126
3036
|
const templateBrand = deriveTemplateBrand();
|
|
2127
|
-
const
|
|
3037
|
+
const templateButtonStyle = deriveTemplateButtonStyle();
|
|
2128
3038
|
const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
|
|
2129
3039
|
const pagePath = window.location.pathname;
|
|
2130
3040
|
const pageSections = state.sections.filter((entry) => (entry.path ?? "/") === pagePath);
|
|
@@ -2164,7 +3074,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2164
3074
|
{
|
|
2165
3075
|
tree: entry.tree,
|
|
2166
3076
|
brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
|
|
2167
|
-
|
|
3077
|
+
buttonStyle: templateButtonStyle,
|
|
2168
3078
|
resolveMedia,
|
|
2169
3079
|
editKeyPrefix: `ai.${entry.id}`
|
|
2170
3080
|
}
|
|
@@ -2187,6 +3097,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2187
3097
|
syncReplacedOriginals(state);
|
|
2188
3098
|
syncRemovedSections(state);
|
|
2189
3099
|
syncTemplateHidden(state, pageSections.length > 0);
|
|
3100
|
+
syncSoftRemovedGenerated();
|
|
2190
3101
|
}
|
|
2191
3102
|
|
|
2192
3103
|
// src/useLinkHrefGuardian.ts
|
|
@@ -6378,12 +7289,12 @@ var cva = (base, config) => (props) => {
|
|
|
6378
7289
|
import { Toggle as TogglePrimitive } from "radix-ui";
|
|
6379
7290
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
6380
7291
|
var toggleVariants = cva(
|
|
6381
|
-
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
7292
|
+
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-bridge-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
6382
7293
|
{
|
|
6383
7294
|
variants: {
|
|
6384
7295
|
variant: {
|
|
6385
7296
|
default: "bg-transparent border-0",
|
|
6386
|
-
outline: "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground"
|
|
7297
|
+
outline: "border border-input bg-transparent shadow-xs hover:bg-bridge-accent hover:text-accent-foreground"
|
|
6387
7298
|
},
|
|
6388
7299
|
size: {
|
|
6389
7300
|
default: "px-2 py-1",
|
|
@@ -6476,10 +7387,10 @@ var DragHandle = React4.forwardRef(
|
|
|
6476
7387
|
type,
|
|
6477
7388
|
"data-slot": "drag-handle",
|
|
6478
7389
|
className: cn(
|
|
6479
|
-
"inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-
|
|
7390
|
+
"inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-7.5",
|
|
6480
7391
|
"bg-white border border-transparent text-stone-500 shadow-md cursor-grab",
|
|
6481
7392
|
"enabled:hover:border enabled:hover:border-stone-200 enabled:hover:text-stone-950",
|
|
6482
|
-
"enabled:active:border enabled:active:border-primary enabled:active:bg-primary-50 enabled:active:text-stone-950 enabled:active:shadow enabled:active:cursor-grabbing",
|
|
7393
|
+
"enabled:active:border enabled:active:border-bridge-primary enabled:active:bg-primary-50 enabled:active:text-stone-950 enabled:active:shadow enabled:active:cursor-grabbing",
|
|
6483
7394
|
"disabled:cursor-not-allowed disabled:opacity-40 disabled:text-stone-950 disabled:pointer-events-none",
|
|
6484
7395
|
className
|
|
6485
7396
|
),
|
|
@@ -6501,7 +7412,7 @@ var CustomToolbar = React5.forwardRef(({ className, onMouseDown, ...props }, ref
|
|
|
6501
7412
|
"data-ohw-toolbar": "",
|
|
6502
7413
|
className: cn(
|
|
6503
7414
|
// Figma: bg background, radius 8, gap-1, p-0.5, shadow-md — no border
|
|
6504
|
-
"inline-flex h-8 items-center gap-1 rounded-
|
|
7415
|
+
"inline-flex h-8 items-center gap-1 rounded-(--radius,0.5rem) bg-background p-0.5 font-sans whitespace-nowrap shadow-md",
|
|
6505
7416
|
className
|
|
6506
7417
|
),
|
|
6507
7418
|
onMouseDown: (e) => {
|
|
@@ -6530,7 +7441,7 @@ var CustomToolbarButton = React5.forwardRef(
|
|
|
6530
7441
|
type,
|
|
6531
7442
|
className: cn(
|
|
6532
7443
|
"inline-flex size-7 shrink-0 items-center justify-center rounded-[calc(var(--radius,0.5rem)-2px)] text-foreground transition-colors",
|
|
6533
|
-
active ? "bg-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
|
|
7444
|
+
active ? "bg-bridge-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
|
|
6534
7445
|
className
|
|
6535
7446
|
),
|
|
6536
7447
|
...props
|
|
@@ -6735,9 +7646,7 @@ function ItemActionToolbar({
|
|
|
6735
7646
|
ToggleGroup,
|
|
6736
7647
|
{
|
|
6737
7648
|
value: dropdownOpen ? "open" : "closed",
|
|
6738
|
-
onValueChange: (
|
|
6739
|
-
if (value !== "open" && value !== "closed") return;
|
|
6740
|
-
onDropdownOpenChange?.(value === "open");
|
|
7649
|
+
onValueChange: () => {
|
|
6741
7650
|
},
|
|
6742
7651
|
className: "h-7 gap-0.5 rounded-[calc(var(--radius,0.5rem)-2px)] bg-muted p-0.5",
|
|
6743
7652
|
onMouseDown: (e) => {
|
|
@@ -6752,6 +7661,11 @@ function ItemActionToolbar({
|
|
|
6752
7661
|
size: "sm",
|
|
6753
7662
|
"aria-label": "Closed",
|
|
6754
7663
|
className: "h-6 min-w-0 px-2 text-xs font-medium",
|
|
7664
|
+
onMouseDown: (e) => {
|
|
7665
|
+
e.preventDefault();
|
|
7666
|
+
e.stopPropagation();
|
|
7667
|
+
if (dropdownOpen !== false) onDropdownOpenChange?.(false);
|
|
7668
|
+
},
|
|
6755
7669
|
children: "Closed"
|
|
6756
7670
|
}
|
|
6757
7671
|
),
|
|
@@ -6762,6 +7676,11 @@ function ItemActionToolbar({
|
|
|
6762
7676
|
size: "sm",
|
|
6763
7677
|
"aria-label": "Open",
|
|
6764
7678
|
className: "h-6 min-w-0 px-2 text-xs font-medium",
|
|
7679
|
+
onMouseDown: (e) => {
|
|
7680
|
+
e.preventDefault();
|
|
7681
|
+
e.stopPropagation();
|
|
7682
|
+
if (dropdownOpen !== true) onDropdownOpenChange?.(true);
|
|
7683
|
+
},
|
|
6765
7684
|
children: "Open"
|
|
6766
7685
|
}
|
|
6767
7686
|
)
|
|
@@ -7724,13 +8643,13 @@ function FormFieldToolbar({
|
|
|
7724
8643
|
]
|
|
7725
8644
|
}
|
|
7726
8645
|
) }),
|
|
7727
|
-
/* @__PURE__ */ jsx13(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-
|
|
8646
|
+
/* @__PURE__ */ jsx13(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-47.5 p-1", children: FIELD_TYPES.map((entry) => {
|
|
7728
8647
|
const Icon = TYPE_ICONS[entry.type];
|
|
7729
8648
|
return /* @__PURE__ */ jsxs6(
|
|
7730
8649
|
DropdownMenuItem,
|
|
7731
8650
|
{
|
|
7732
8651
|
onSelect: () => onTypeChange(entry.type),
|
|
7733
|
-
className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-primary/10" : ""),
|
|
8652
|
+
className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-bridge-primary/10" : ""),
|
|
7734
8653
|
children: [
|
|
7735
8654
|
/* @__PURE__ */ jsx13(Icon, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
|
|
7736
8655
|
entry.label
|
|
@@ -7747,7 +8666,7 @@ function FormFieldToolbar({
|
|
|
7747
8666
|
type: "button",
|
|
7748
8667
|
"aria-pressed": required,
|
|
7749
8668
|
onClick: onRequiredToggle,
|
|
7750
|
-
className: "flex h-7 items-center gap-1.5 whitespace-nowrap rounded-md px-2 text-[13px] font-medium transition-colors " + (required ? "bg-primary/10 text-primary" : "text-foreground hover:bg-muted/70"),
|
|
8669
|
+
className: "flex h-7 items-center gap-1.5 whitespace-nowrap rounded-md px-2 text-[13px] font-medium transition-colors " + (required ? "bg-bridge-primary/10 text-bridge-primary" : "text-foreground hover:bg-muted/70"),
|
|
7751
8670
|
"data-ohw-field-required-toggle": "",
|
|
7752
8671
|
children: [
|
|
7753
8672
|
/* @__PURE__ */ jsx13(Asterisk, { size: 14, strokeWidth: 2, "aria-hidden": true }),
|
|
@@ -7767,7 +8686,7 @@ function FormFieldToolbar({
|
|
|
7767
8686
|
children: /* @__PURE__ */ jsx13(MoreHorizontal2, { size: 15, "aria-hidden": true })
|
|
7768
8687
|
}
|
|
7769
8688
|
) }),
|
|
7770
|
-
/* @__PURE__ */ jsxs6(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-
|
|
8689
|
+
/* @__PURE__ */ jsxs6(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-42.5 p-1", children: [
|
|
7771
8690
|
/* @__PURE__ */ jsxs6(DropdownMenuItem, { onSelect: onDuplicate, className: "rounded-md py-2 text-[13px]", children: [
|
|
7772
8691
|
/* @__PURE__ */ jsx13(Copy2, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
|
|
7773
8692
|
"Duplicate"
|
|
@@ -7787,7 +8706,7 @@ function FieldTypePicker({ onPick }) {
|
|
|
7787
8706
|
"div",
|
|
7788
8707
|
{
|
|
7789
8708
|
"data-ohw-field-type-picker": "",
|
|
7790
|
-
className: "pointer-events-auto grid w-
|
|
8709
|
+
className: "pointer-events-auto grid w-105 grid-cols-3 gap-3 rounded-xl border border-border bg-background p-4 shadow-lg",
|
|
7791
8710
|
children: FIELD_TYPES.map((entry) => {
|
|
7792
8711
|
const Icon = TYPE_ICONS[entry.type];
|
|
7793
8712
|
return /* @__PURE__ */ jsxs6(
|
|
@@ -7795,7 +8714,7 @@ function FieldTypePicker({ onPick }) {
|
|
|
7795
8714
|
{
|
|
7796
8715
|
type: "button",
|
|
7797
8716
|
onClick: () => onPick(entry.type),
|
|
7798
|
-
className: "flex h-
|
|
8717
|
+
className: "flex h-26 flex-col items-center justify-center gap-3 rounded-xl border border-border text-[15px] font-medium text-foreground transition-colors hover:border-bridge-primary hover:bg-bridge-primary/5",
|
|
7799
8718
|
children: [
|
|
7800
8719
|
/* @__PURE__ */ jsx13(Icon, { size: 26, strokeWidth: 1.5, "aria-hidden": true }),
|
|
7801
8720
|
entry.label
|
|
@@ -7821,7 +8740,7 @@ var buttonVariants = cva(
|
|
|
7821
8740
|
{
|
|
7822
8741
|
variants: {
|
|
7823
8742
|
variant: {
|
|
7824
|
-
default: "bg-primary text-primary-foreground hover:opacity-90",
|
|
8743
|
+
default: "bg-bridge-primary text-primary-foreground hover:opacity-90",
|
|
7825
8744
|
outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
|
|
7826
8745
|
ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
|
|
7827
8746
|
},
|
|
@@ -7916,6 +8835,7 @@ function MediaOverlay({
|
|
|
7916
8835
|
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
7917
8836
|
);
|
|
7918
8837
|
}, [isVideo]);
|
|
8838
|
+
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
7919
8839
|
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
7920
8840
|
const box = {
|
|
7921
8841
|
position: "fixed",
|
|
@@ -8021,8 +8941,8 @@ function MediaOverlay({
|
|
|
8021
8941
|
pointerEvents: hover.hasTextOverlap ? "none" : "auto",
|
|
8022
8942
|
// Selected: a firm component ring with no wash, so the image reads as chosen rather
|
|
8023
8943
|
// than hovered. Hover keeps the existing tinted preview.
|
|
8024
|
-
boxShadow: selected ? "inset 0 0 0 2px var(--color-primary)" : "inset 0 0 0 1.5px var(--color-primary)",
|
|
8025
|
-
background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
8944
|
+
boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
8945
|
+
background: selected ? "transparent" : "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
|
|
8026
8946
|
},
|
|
8027
8947
|
onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
|
|
8028
8948
|
children: [
|
|
@@ -8045,17 +8965,17 @@ function MediaOverlay({
|
|
|
8045
8965
|
},
|
|
8046
8966
|
children: [
|
|
8047
8967
|
isVideo ? /* @__PURE__ */ jsx15(Film, { size: 14 }) : /* @__PURE__ */ jsx15(ImageIcon, { size: 14 }),
|
|
8048
|
-
|
|
8968
|
+
replaceLabel
|
|
8049
8969
|
]
|
|
8050
8970
|
}
|
|
8051
8971
|
),
|
|
8052
|
-
replaceMode
|
|
8972
|
+
showChrome && replaceMode !== "none" && /* @__PURE__ */ jsxs7(
|
|
8053
8973
|
Button,
|
|
8054
8974
|
{
|
|
8055
8975
|
"data-ohw-media-overlay": "",
|
|
8056
8976
|
variant: "outline",
|
|
8057
8977
|
size: "sm",
|
|
8058
|
-
"aria-label":
|
|
8978
|
+
"aria-label": replaceLabel,
|
|
8059
8979
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
8060
8980
|
style: {
|
|
8061
8981
|
...OVERLAY_BUTTON_STYLE,
|
|
@@ -8078,7 +8998,7 @@ function MediaOverlay({
|
|
|
8078
8998
|
},
|
|
8079
8999
|
children: [
|
|
8080
9000
|
isVideo ? /* @__PURE__ */ jsx15(Film, { size: 14 }) : /* @__PURE__ */ jsx15(ImageIcon, { size: 14 }),
|
|
8081
|
-
replaceMode === "full" ?
|
|
9001
|
+
replaceMode === "full" ? replaceLabel : null
|
|
8082
9002
|
]
|
|
8083
9003
|
}
|
|
8084
9004
|
)
|
|
@@ -8116,8 +9036,8 @@ function CarouselOverlay({
|
|
|
8116
9036
|
height: rect.height,
|
|
8117
9037
|
zIndex: 2147483646,
|
|
8118
9038
|
pointerEvents: "auto",
|
|
8119
|
-
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
8120
|
-
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
9039
|
+
boxShadow: "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
9040
|
+
background: "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
|
|
8121
9041
|
},
|
|
8122
9042
|
onClick: () => onEdit(hover.key),
|
|
8123
9043
|
children: /* @__PURE__ */ jsxs8(
|
|
@@ -8137,229 +9057,17 @@ function CarouselOverlay({
|
|
|
8137
9057
|
/* @__PURE__ */ jsx16(GalleryHorizontal, { size: 14 }),
|
|
8138
9058
|
"Edit gallery"
|
|
8139
9059
|
]
|
|
8140
|
-
}
|
|
8141
|
-
)
|
|
8142
|
-
}
|
|
8143
|
-
);
|
|
8144
|
-
}
|
|
8145
|
-
|
|
8146
|
-
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
8147
|
-
import { useCallback as useCallback2, useEffect as useEffect4, useRef as useRef4, useState as useState5 } from "react";
|
|
8148
|
-
import { Check, X } from "lucide-react";
|
|
8149
|
-
|
|
8150
|
-
// src/lib/sections.ts
|
|
8151
|
-
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
8152
|
-
function isChromeSection(el) {
|
|
8153
|
-
return el.matches("header, nav, footer, aside");
|
|
8154
|
-
}
|
|
8155
|
-
function titleCaseSectionId(id) {
|
|
8156
|
-
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
8157
|
-
}
|
|
8158
|
-
function parseSectionsFromRoot(root) {
|
|
8159
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8160
|
-
const sections = [];
|
|
8161
|
-
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
8162
|
-
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
8163
|
-
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
8164
|
-
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
8165
|
-
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
8166
|
-
continue;
|
|
8167
|
-
seen.add(id);
|
|
8168
|
-
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
8169
|
-
sections.push({ id, label });
|
|
8170
|
-
}
|
|
8171
|
-
return sections;
|
|
8172
|
-
}
|
|
8173
|
-
function collectSectionsFromDom() {
|
|
8174
|
-
if (typeof document === "undefined") return [];
|
|
8175
|
-
return parseSectionsFromRoot(document);
|
|
8176
|
-
}
|
|
8177
|
-
function parseSectionsFromHtml(html) {
|
|
8178
|
-
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
8179
|
-
return parseSectionsFromRoot(doc);
|
|
8180
|
-
}
|
|
8181
|
-
|
|
8182
|
-
// src/lib/section-instances.ts
|
|
8183
|
-
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
8184
|
-
var REMOVED_ATTR2 = "data-ohw-section-removed";
|
|
8185
|
-
function isRemovedSection(el) {
|
|
8186
|
-
return el.hasAttribute(REMOVED_ATTR2);
|
|
8187
|
-
}
|
|
8188
|
-
function topLevelSections() {
|
|
8189
|
-
return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
8190
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el) && !isRemovedSection(el)
|
|
8191
|
-
);
|
|
8192
|
-
}
|
|
8193
|
-
function instanceIdOf(el) {
|
|
8194
|
-
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
8195
|
-
}
|
|
8196
|
-
function findByInstanceId(instanceId) {
|
|
8197
|
-
const escapedId = CSS.escape(instanceId);
|
|
8198
|
-
return document.querySelector(`[data-ohw-instance="${escapedId}"]`) ?? document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
8199
|
-
}
|
|
8200
|
-
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
8201
|
-
const sections = topLevelSections();
|
|
8202
|
-
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8203
|
-
if (index === -1) return null;
|
|
8204
|
-
const dragged = sections[index];
|
|
8205
|
-
const others = sections.filter((_, i) => i !== index);
|
|
8206
|
-
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
8207
|
-
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
8208
|
-
return reordered.map((el, order) => ({
|
|
8209
|
-
instanceId: instanceIdOf(el),
|
|
8210
|
-
type: el.getAttribute("data-ohw-section") ?? "",
|
|
8211
|
-
order,
|
|
8212
|
-
pagePath: currentPath
|
|
8213
|
-
}));
|
|
8214
|
-
}
|
|
8215
|
-
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
8216
|
-
const sections = topLevelSections();
|
|
8217
|
-
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8218
|
-
if (index === -1) return null;
|
|
8219
|
-
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
8220
|
-
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
8221
|
-
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
8222
|
-
if (!entries) return null;
|
|
8223
|
-
applyPersistedOrder(entries);
|
|
8224
|
-
return entries;
|
|
8225
|
-
}
|
|
8226
|
-
function syncRemovedFlags(entries) {
|
|
8227
|
-
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
8228
|
-
document.querySelectorAll(`[${REMOVED_ATTR2}]`).forEach((el) => {
|
|
8229
|
-
if (!removedIds.has(instanceIdOf(el))) {
|
|
8230
|
-
el.style.removeProperty("display");
|
|
8231
|
-
el.removeAttribute(REMOVED_ATTR2);
|
|
8232
|
-
}
|
|
8233
|
-
});
|
|
8234
|
-
for (const id of removedIds) {
|
|
8235
|
-
const el = findByInstanceId(id);
|
|
8236
|
-
if (el) {
|
|
8237
|
-
el.style.display = "none";
|
|
8238
|
-
el.setAttribute(REMOVED_ATTR2, "");
|
|
8239
|
-
}
|
|
8240
|
-
}
|
|
8241
|
-
}
|
|
8242
|
-
function applyPersistedOrder(entries) {
|
|
8243
|
-
syncRemovedFlags(entries);
|
|
8244
|
-
if (entries.length === 0) return;
|
|
8245
|
-
const sections = topLevelSections();
|
|
8246
|
-
if (sections.length === 0) return;
|
|
8247
|
-
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
8248
|
-
const ordered = [...sections].sort((a, b) => {
|
|
8249
|
-
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
8250
|
-
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
8251
|
-
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
8252
|
-
if (aOrder === void 0) return 1;
|
|
8253
|
-
if (bOrder === void 0) return -1;
|
|
8254
|
-
return aOrder - bOrder;
|
|
8255
|
-
});
|
|
8256
|
-
let prev = null;
|
|
8257
|
-
for (const el of ordered) {
|
|
8258
|
-
if (prev) prev.after(el);
|
|
8259
|
-
prev = el;
|
|
8260
|
-
}
|
|
8261
|
-
}
|
|
8262
|
-
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
8263
|
-
if (!findByInstanceId(instanceId)) return null;
|
|
8264
|
-
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
8265
|
-
const allSections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
8266
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
|
|
8267
|
-
);
|
|
8268
|
-
allSections.forEach((el, order) => {
|
|
8269
|
-
const id = instanceIdOf(el);
|
|
8270
|
-
if (!byId.has(id)) {
|
|
8271
|
-
byId.set(id, { instanceId: id, type: el.getAttribute("data-ohw-section") ?? "", order, pagePath: currentPath });
|
|
8272
|
-
}
|
|
8273
|
-
});
|
|
8274
|
-
const target = byId.get(instanceId);
|
|
8275
|
-
if (!target) return null;
|
|
8276
|
-
byId.set(instanceId, { ...target, removed });
|
|
8277
|
-
const entries = Array.from(byId.values());
|
|
8278
|
-
applyPersistedOrder(entries);
|
|
8279
|
-
return entries;
|
|
8280
|
-
}
|
|
8281
|
-
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
8282
|
-
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
8283
|
-
}
|
|
8284
|
-
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
8285
|
-
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
8286
|
-
}
|
|
8287
|
-
function duplicateSectionInstance(instanceId, newId, currentPath, existingEntries) {
|
|
8288
|
-
const original = findByInstanceId(instanceId);
|
|
8289
|
-
if (!original) return null;
|
|
8290
|
-
const clone = original.cloneNode(true);
|
|
8291
|
-
clone.setAttribute("data-ohw-instance", newId);
|
|
8292
|
-
const keyRekeys = rekeySectionSubtree(clone, newId);
|
|
8293
|
-
original.insertAdjacentElement("afterend", clone);
|
|
8294
|
-
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
8295
|
-
const entries = topLevelSections().map((el, order) => {
|
|
8296
|
-
const id = instanceIdOf(el);
|
|
8297
|
-
return {
|
|
8298
|
-
instanceId: id,
|
|
8299
|
-
type: el.getAttribute("data-ohw-section") ?? "",
|
|
8300
|
-
order,
|
|
8301
|
-
pagePath: currentPath,
|
|
8302
|
-
...byId.get(id)?.removed ? { removed: true } : {}
|
|
8303
|
-
};
|
|
8304
|
-
});
|
|
8305
|
-
applyPersistedOrder(entries);
|
|
8306
|
-
return { entries, keyRekeys };
|
|
8307
|
-
}
|
|
8308
|
-
function newInstanceId() {
|
|
8309
|
-
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
8310
|
-
}
|
|
8311
|
-
function getPageSectionOrderEntries(raw, currentPath) {
|
|
8312
|
-
if (!raw) return [];
|
|
8313
|
-
try {
|
|
8314
|
-
const entries = JSON.parse(raw);
|
|
8315
|
-
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
8316
|
-
} catch {
|
|
8317
|
-
return [];
|
|
8318
|
-
}
|
|
8319
|
-
}
|
|
8320
|
-
function rekeySectionSubtree(root, instanceId) {
|
|
8321
|
-
const suffix = `::${instanceId}`;
|
|
8322
|
-
const pairs = [];
|
|
8323
|
-
const rekey = (el, attr) => {
|
|
8324
|
-
const current = el.getAttribute(attr);
|
|
8325
|
-
if (!current) return;
|
|
8326
|
-
const base = current.includes("::") ? current.slice(0, current.indexOf("::")) : current;
|
|
8327
|
-
const next = `${base}${suffix}`;
|
|
8328
|
-
el.setAttribute(attr, next);
|
|
8329
|
-
pairs.push({ from: current, to: next });
|
|
8330
|
-
};
|
|
8331
|
-
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
8332
|
-
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
8333
|
-
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
8334
|
-
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
8335
|
-
return pairs;
|
|
8336
|
-
}
|
|
8337
|
-
function initSectionInstancesFromContent(content, currentPath) {
|
|
8338
|
-
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
8339
|
-
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
8340
|
-
});
|
|
8341
|
-
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
8342
|
-
for (const entry of entries) {
|
|
8343
|
-
if (entry.instanceId === entry.type) continue;
|
|
8344
|
-
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
8345
|
-
const original = document.querySelector(
|
|
8346
|
-
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
8347
|
-
);
|
|
8348
|
-
if (!original) continue;
|
|
8349
|
-
const clone = original.cloneNode(true);
|
|
8350
|
-
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
8351
|
-
rekeySectionSubtree(clone, entry.instanceId);
|
|
8352
|
-
original.insertAdjacentElement("afterend", clone);
|
|
8353
|
-
}
|
|
8354
|
-
applyPersistedOrder(entries);
|
|
9060
|
+
}
|
|
9061
|
+
)
|
|
9062
|
+
}
|
|
9063
|
+
);
|
|
8355
9064
|
}
|
|
8356
9065
|
|
|
8357
9066
|
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
9067
|
+
import { useCallback as useCallback2, useEffect as useEffect4, useRef as useRef4, useState as useState5 } from "react";
|
|
9068
|
+
import { Check, X } from "lucide-react";
|
|
8358
9069
|
import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
8359
|
-
|
|
8360
|
-
const escaped = CSS.escape(instanceId);
|
|
8361
|
-
return document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]:not([data-ohw-instance])`);
|
|
8362
|
-
}
|
|
9070
|
+
var findSectionElement = findByInstanceId;
|
|
8363
9071
|
function readRect(instanceId) {
|
|
8364
9072
|
const el = findSectionElement(instanceId);
|
|
8365
9073
|
if (!el) return null;
|
|
@@ -8399,7 +9107,7 @@ function useLiveSectionRect(sectionId) {
|
|
|
8399
9107
|
}
|
|
8400
9108
|
function computeSectionBoundaryFlags(instanceId) {
|
|
8401
9109
|
const topLevel = topLevelSections();
|
|
8402
|
-
const index = topLevel.findIndex((el) => (el
|
|
9110
|
+
const index = topLevel.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8403
9111
|
if (index === -1) return { isFirst: true, isLast: true };
|
|
8404
9112
|
return { isFirst: index === 0, isLast: index === topLevel.length - 1 };
|
|
8405
9113
|
}
|
|
@@ -8483,18 +9191,20 @@ function AiSectionOverlay({
|
|
|
8483
9191
|
selectedIdRef.current = selectedId;
|
|
8484
9192
|
const report = useCallback2(
|
|
8485
9193
|
(el) => {
|
|
9194
|
+
const labelSrc = el ? sectionElementOf(el) : null;
|
|
8486
9195
|
postToParent2({
|
|
8487
9196
|
type: "ow:section-selected",
|
|
8488
|
-
sectionId: el ? el
|
|
8489
|
-
sectionLabel:
|
|
9197
|
+
sectionId: el ? instanceIdOf(el) || null : null,
|
|
9198
|
+
sectionLabel: labelSrc ? labelSrc.dataset.ohwSectionLabel ?? titleCaseSectionId(labelSrc.dataset.ohwSection ?? "") : null
|
|
8490
9199
|
});
|
|
8491
9200
|
},
|
|
8492
9201
|
[postToParent2]
|
|
8493
9202
|
);
|
|
8494
9203
|
const selectFromElement = useCallback2(
|
|
8495
9204
|
(el, options) => {
|
|
8496
|
-
const
|
|
8497
|
-
const
|
|
9205
|
+
const inner = el?.closest("[data-ohw-section]") ?? null;
|
|
9206
|
+
const sectionEl = inner ? movableUnit(inner) : null;
|
|
9207
|
+
const id = sectionEl ? instanceIdOf(sectionEl) || null : null;
|
|
8498
9208
|
if (id === selectedIdRef.current) return;
|
|
8499
9209
|
setSelectedId(id);
|
|
8500
9210
|
if (options?.report !== false) report(sectionEl);
|
|
@@ -8560,7 +9270,8 @@ function AiSectionOverlay({
|
|
|
8560
9270
|
return;
|
|
8561
9271
|
}
|
|
8562
9272
|
const sec = t.closest("[data-ohw-section]");
|
|
8563
|
-
|
|
9273
|
+
const unit = sec ? movableUnit(sec) : null;
|
|
9274
|
+
setHoveredId(unit ? instanceIdOf(unit) || null : null);
|
|
8564
9275
|
};
|
|
8565
9276
|
const onLeave = () => setHoveredId(null);
|
|
8566
9277
|
document.addEventListener("mousemove", onMove, { passive: true });
|
|
@@ -9164,7 +9875,7 @@ function SectionTreeItem({
|
|
|
9164
9875
|
/* @__PURE__ */ jsx20(
|
|
9165
9876
|
"div",
|
|
9166
9877
|
{
|
|
9167
|
-
className: "mr-
|
|
9878
|
+
className: "-mr-px h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
|
|
9168
9879
|
"aria-hidden": true
|
|
9169
9880
|
}
|
|
9170
9881
|
),
|
|
@@ -9183,7 +9894,7 @@ function SectionTreeItem({
|
|
|
9183
9894
|
className: cn(
|
|
9184
9895
|
"flex h-9 min-w-0 flex-1 items-center gap-2 rounded-md border border-border bg-background p-3",
|
|
9185
9896
|
interactive && "cursor-pointer hover:bg-muted/30",
|
|
9186
|
-
interactive && selected && "border-primary"
|
|
9897
|
+
interactive && selected && "border-bridge-primary"
|
|
9187
9898
|
),
|
|
9188
9899
|
children: [
|
|
9189
9900
|
/* @__PURE__ */ jsx20(
|
|
@@ -9313,7 +10024,7 @@ function UrlOrPageInput({
|
|
|
9313
10024
|
};
|
|
9314
10025
|
const fieldClassName = cn(
|
|
9315
10026
|
"data-ohw-link-field flex h-[36px] w-full items-center overflow-hidden rounded-md border bg-background pl-3 pr-3 py-2 outline-none transition-[border-color,box-shadow]",
|
|
9316
|
-
urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
|
|
10027
|
+
urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-bridge-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
|
|
9317
10028
|
);
|
|
9318
10029
|
return /* @__PURE__ */ jsxs13("div", { className: "flex w-full flex-col gap-2 p-0", children: [
|
|
9319
10030
|
/* @__PURE__ */ jsx23(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
|
|
@@ -10357,6 +11068,32 @@ function getNavbarDesktopContainer() {
|
|
|
10357
11068
|
function getNavbarDrawerContainer() {
|
|
10358
11069
|
return document.querySelector("[data-ohw-nav-drawer]");
|
|
10359
11070
|
}
|
|
11071
|
+
function isNavbarListContainerVisible(el) {
|
|
11072
|
+
if (el.hasAttribute("hidden")) return false;
|
|
11073
|
+
if (el.getClientRects().length === 0) return false;
|
|
11074
|
+
const style = window.getComputedStyle(el);
|
|
11075
|
+
return style.display !== "none" && style.visibility !== "hidden";
|
|
11076
|
+
}
|
|
11077
|
+
function getActiveNavbarListContainer(draggedEl) {
|
|
11078
|
+
const desktop = getNavbarDesktopContainer();
|
|
11079
|
+
const drawer = getNavbarDrawerContainer();
|
|
11080
|
+
if (draggedEl) {
|
|
11081
|
+
if (drawer?.contains(draggedEl)) return drawer;
|
|
11082
|
+
if (desktop?.contains(draggedEl)) return desktop;
|
|
11083
|
+
}
|
|
11084
|
+
if (desktop && isNavbarListContainerVisible(desktop)) return desktop;
|
|
11085
|
+
if (drawer && isNavbarListContainerVisible(drawer)) return drawer;
|
|
11086
|
+
return desktop ?? drawer;
|
|
11087
|
+
}
|
|
11088
|
+
function listActiveNavbarItems(draggedEl) {
|
|
11089
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
11090
|
+
if (container) {
|
|
11091
|
+
return Array.from(container.querySelectorAll("[data-ohw-href-key]")).filter(
|
|
11092
|
+
isNavbarLinkItem
|
|
11093
|
+
);
|
|
11094
|
+
}
|
|
11095
|
+
return listNavbarItems();
|
|
11096
|
+
}
|
|
10360
11097
|
function listNavbarItems() {
|
|
10361
11098
|
const desktop = getNavbarDesktopContainer();
|
|
10362
11099
|
if (desktop) {
|
|
@@ -11469,20 +12206,23 @@ function isEmptyLabelValue(value) {
|
|
|
11469
12206
|
function applyStoredValues(item, content) {
|
|
11470
12207
|
const hrefKey = socialHrefKey(item);
|
|
11471
12208
|
const iconKey = socialIconKey(item);
|
|
12209
|
+
const baseKey = hrefKey?.replace(/-href$/, "");
|
|
11472
12210
|
if (hrefKey && content[hrefKey] !== void 0) item.setAttribute("href", content[hrefKey]);
|
|
11473
|
-
|
|
12211
|
+
const glyphKey = iconKey ?? baseKey ?? null;
|
|
12212
|
+
const glyphStored = glyphKey ? content[glyphKey]?.trim() : void 0;
|
|
12213
|
+
if (glyphStored) {
|
|
12214
|
+
ensureIconSlot(item);
|
|
11474
12215
|
const glyph = item.querySelector(ICON_SELECTOR);
|
|
11475
|
-
if (glyph
|
|
11476
|
-
applyIconMarkup(glyph,
|
|
12216
|
+
if (glyph) {
|
|
12217
|
+
applyIconMarkup(glyph, glyphStored);
|
|
11477
12218
|
glyph.removeAttribute(SOCIALS_ICON_PLACEHOLDER_ATTR);
|
|
11478
12219
|
}
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
|
|
11484
|
-
|
|
11485
|
-
}
|
|
12220
|
+
}
|
|
12221
|
+
const label = socialLabelElement(item);
|
|
12222
|
+
const labelKey = label?.getAttribute("data-ohw-key");
|
|
12223
|
+
if (label && labelKey && content[labelKey] !== void 0) {
|
|
12224
|
+
const words = isEmptyLabelValue(content[labelKey]) ? "" : content[labelKey];
|
|
12225
|
+
if (label.innerHTML !== words) label.innerHTML = words;
|
|
11486
12226
|
}
|
|
11487
12227
|
}
|
|
11488
12228
|
function socialPlatformKey(iconKey) {
|
|
@@ -11571,6 +12311,9 @@ function insertSocialItem(row, after, content = {}, { placeholder = true, keys }
|
|
|
11571
12311
|
if (placeholder) {
|
|
11572
12312
|
const label = socialLabelElement(item);
|
|
11573
12313
|
if (label) label.textContent = PLACEHOLDER_SOCIAL_LABEL;
|
|
12314
|
+
} else if (keys) {
|
|
12315
|
+
const label = socialLabelElement(item);
|
|
12316
|
+
if (label) label.textContent = "";
|
|
11574
12317
|
}
|
|
11575
12318
|
applySocialsDisplayToRow(row, display);
|
|
11576
12319
|
return { item, hrefKey, iconKey, order: getSocialsOrderFromDom(row.ownerDocument) };
|
|
@@ -13071,6 +13814,7 @@ function readLogoSizeState(content, placement) {
|
|
|
13071
13814
|
function getLogoElement(el) {
|
|
13072
13815
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
13073
13816
|
if (marked) return marked;
|
|
13817
|
+
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
13074
13818
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
13075
13819
|
if (!root) return null;
|
|
13076
13820
|
const anchor = el.closest("a");
|
|
@@ -13364,7 +14108,7 @@ function DisplaySwitch({
|
|
|
13364
14108
|
onClick: () => onChange(!checked),
|
|
13365
14109
|
className: cn(
|
|
13366
14110
|
"relative h-5 w-9 shrink-0 rounded-full transition-colors",
|
|
13367
|
-
checked ? "bg-primary" : "bg-primary-50",
|
|
14111
|
+
checked ? "bg-bridge-primary" : "bg-primary-50",
|
|
13368
14112
|
disabled ? "cursor-default opacity-50" : "cursor-pointer"
|
|
13369
14113
|
),
|
|
13370
14114
|
children: /* @__PURE__ */ jsx28(
|
|
@@ -13372,7 +14116,7 @@ function DisplaySwitch({
|
|
|
13372
14116
|
{
|
|
13373
14117
|
className: cn(
|
|
13374
14118
|
"absolute top-0.5 h-4 w-4 rounded-full bg-white transition-all",
|
|
13375
|
-
checked ? "left-
|
|
14119
|
+
checked ? "left-4.5" : "left-0.5"
|
|
13376
14120
|
)
|
|
13377
14121
|
}
|
|
13378
14122
|
)
|
|
@@ -13433,8 +14177,8 @@ var lockFooterDuringDrag = lockItemDuringDrag;
|
|
|
13433
14177
|
var unlockFooterDragInteraction = unlockItemDragInteraction;
|
|
13434
14178
|
|
|
13435
14179
|
// src/lib/nav-dnd.ts
|
|
13436
|
-
function listReorderableNavItems() {
|
|
13437
|
-
return
|
|
14180
|
+
function listReorderableNavItems(draggedEl) {
|
|
14181
|
+
return listActiveNavbarItems(draggedEl).filter((el) => {
|
|
13438
14182
|
const key = el.getAttribute("data-ohw-href-key");
|
|
13439
14183
|
return isNavbarHrefKey(key) && !isNestedNavChild(el);
|
|
13440
14184
|
});
|
|
@@ -13449,8 +14193,8 @@ function resolveParentNavHrefKey(child) {
|
|
|
13449
14193
|
const key = trigger?.getAttribute("data-ohw-href-key");
|
|
13450
14194
|
return key && isNavbarHrefKey(key) ? key : null;
|
|
13451
14195
|
}
|
|
13452
|
-
function listNavChildren(parentHrefKey) {
|
|
13453
|
-
const items =
|
|
14196
|
+
function listNavChildren(parentHrefKey, draggedEl) {
|
|
14197
|
+
const items = listActiveNavbarItems(draggedEl);
|
|
13454
14198
|
const parent = items.find((el) => el.getAttribute("data-ohw-href-key") === parentHrefKey);
|
|
13455
14199
|
if (!parent) return [];
|
|
13456
14200
|
const group = parent.closest("[data-ohw-nav-group]");
|
|
@@ -13460,20 +14204,83 @@ function listNavChildren(parentHrefKey) {
|
|
|
13460
14204
|
(el) => isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))
|
|
13461
14205
|
);
|
|
13462
14206
|
}
|
|
13463
|
-
function
|
|
13464
|
-
const
|
|
13465
|
-
if (
|
|
13466
|
-
const
|
|
13467
|
-
|
|
14207
|
+
function isVerticalNavLayout(items, draggedEl) {
|
|
14208
|
+
const visible = items.filter((el) => el.getClientRects().length > 0);
|
|
14209
|
+
if (visible.length >= 2) {
|
|
14210
|
+
const a = visible[0].getBoundingClientRect();
|
|
14211
|
+
const b = visible[1].getBoundingClientRect();
|
|
14212
|
+
const verticalGap = b.top - a.bottom;
|
|
14213
|
+
const horizontalGap = b.left - a.right;
|
|
14214
|
+
return verticalGap > horizontalGap;
|
|
14215
|
+
}
|
|
14216
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
14217
|
+
if (!container) return false;
|
|
14218
|
+
const style = window.getComputedStyle(container);
|
|
14219
|
+
return style.flexDirection === "column" || style.flexDirection === "column-reverse";
|
|
14220
|
+
}
|
|
14221
|
+
function buildVerticalRootNavDropSlots(items, draggedEl) {
|
|
14222
|
+
const slots = [];
|
|
14223
|
+
const barThickness = 3;
|
|
14224
|
+
if (items.length === 0) {
|
|
14225
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
14226
|
+
if (!container) return slots;
|
|
14227
|
+
const rect = container.getBoundingClientRect();
|
|
14228
|
+
slots.push({
|
|
14229
|
+
insertIndex: 0,
|
|
14230
|
+
parentId: null,
|
|
14231
|
+
left: rect.left,
|
|
14232
|
+
top: rect.top + rect.height / 2 - barThickness / 2,
|
|
14233
|
+
width: Math.max(rect.width, 40),
|
|
14234
|
+
height: barThickness,
|
|
14235
|
+
direction: "horizontal"
|
|
14236
|
+
});
|
|
14237
|
+
return slots;
|
|
14238
|
+
}
|
|
14239
|
+
const edgeGap = (() => {
|
|
14240
|
+
if (items.length < 2) return 16;
|
|
14241
|
+
const a = items[0].getBoundingClientRect();
|
|
14242
|
+
const b = items[1].getBoundingClientRect();
|
|
14243
|
+
return Math.max(0, b.top - a.bottom);
|
|
14244
|
+
})();
|
|
14245
|
+
for (let i = 0; i <= items.length; i++) {
|
|
14246
|
+
let top;
|
|
14247
|
+
let width;
|
|
14248
|
+
let left;
|
|
14249
|
+
if (i === 0) {
|
|
14250
|
+
const first = items[0].getBoundingClientRect();
|
|
14251
|
+
top = first.top - edgeGap / 2 - barThickness / 2;
|
|
14252
|
+
left = first.left;
|
|
14253
|
+
width = first.width;
|
|
14254
|
+
} else if (i === items.length) {
|
|
14255
|
+
const last = items[items.length - 1].getBoundingClientRect();
|
|
14256
|
+
const lastGap = items.length >= 2 ? Math.max(0, last.top - items[items.length - 2].getBoundingClientRect().bottom) : edgeGap;
|
|
14257
|
+
top = last.bottom + lastGap / 2 - barThickness / 2;
|
|
14258
|
+
left = last.left;
|
|
14259
|
+
width = last.width;
|
|
14260
|
+
} else {
|
|
14261
|
+
const prev = items[i - 1].getBoundingClientRect();
|
|
14262
|
+
const next = items[i].getBoundingClientRect();
|
|
14263
|
+
top = (prev.bottom + next.top) / 2 - barThickness / 2;
|
|
14264
|
+
left = Math.min(prev.left, next.left);
|
|
14265
|
+
width = Math.max(prev.right, next.right) - left;
|
|
14266
|
+
}
|
|
14267
|
+
slots.push({
|
|
14268
|
+
insertIndex: i,
|
|
14269
|
+
parentId: null,
|
|
14270
|
+
left,
|
|
14271
|
+
top,
|
|
14272
|
+
width: Math.max(width, 40),
|
|
14273
|
+
height: barThickness,
|
|
14274
|
+
direction: "horizontal"
|
|
14275
|
+
});
|
|
13468
14276
|
}
|
|
13469
|
-
return
|
|
14277
|
+
return slots;
|
|
13470
14278
|
}
|
|
13471
|
-
function
|
|
13472
|
-
const items = listReorderableNavItems();
|
|
14279
|
+
function buildHorizontalRootNavDropSlots(items, draggedEl) {
|
|
13473
14280
|
const slots = [];
|
|
13474
14281
|
const barThickness = 3;
|
|
13475
14282
|
if (items.length === 0) {
|
|
13476
|
-
const container =
|
|
14283
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
13477
14284
|
if (!container) return slots;
|
|
13478
14285
|
const rect = container.getBoundingClientRect();
|
|
13479
14286
|
slots.push({
|
|
@@ -13504,10 +14311,7 @@ function buildRootNavDropSlots() {
|
|
|
13504
14311
|
height = first.height;
|
|
13505
14312
|
} else if (i === items.length) {
|
|
13506
14313
|
const last = items[items.length - 1].getBoundingClientRect();
|
|
13507
|
-
const lastGap = items.length >= 2 ? Math.max(
|
|
13508
|
-
0,
|
|
13509
|
-
last.left - items[items.length - 2].getBoundingClientRect().right
|
|
13510
|
-
) : edgeGap;
|
|
14314
|
+
const lastGap = items.length >= 2 ? Math.max(0, last.left - items[items.length - 2].getBoundingClientRect().right) : edgeGap;
|
|
13511
14315
|
left = last.right + lastGap / 2 - barThickness / 2;
|
|
13512
14316
|
top = last.top;
|
|
13513
14317
|
height = last.height;
|
|
@@ -13530,8 +14334,15 @@ function buildRootNavDropSlots() {
|
|
|
13530
14334
|
}
|
|
13531
14335
|
return slots;
|
|
13532
14336
|
}
|
|
13533
|
-
function
|
|
13534
|
-
const
|
|
14337
|
+
function buildRootNavDropSlots(draggedEl) {
|
|
14338
|
+
const items = listReorderableNavItems(draggedEl);
|
|
14339
|
+
if (isVerticalNavLayout(items, draggedEl)) {
|
|
14340
|
+
return buildVerticalRootNavDropSlots(items, draggedEl);
|
|
14341
|
+
}
|
|
14342
|
+
return buildHorizontalRootNavDropSlots(items, draggedEl);
|
|
14343
|
+
}
|
|
14344
|
+
function buildChildNavDropSlots(parentHrefKey, draggedEl) {
|
|
14345
|
+
const children = listNavChildren(parentHrefKey, draggedEl);
|
|
13535
14346
|
const slots = [];
|
|
13536
14347
|
const barThickness = 3;
|
|
13537
14348
|
if (children.length === 0) return slots;
|
|
@@ -13552,10 +14363,7 @@ function buildChildNavDropSlots(parentHrefKey) {
|
|
|
13552
14363
|
width = first.width;
|
|
13553
14364
|
} else if (i === children.length) {
|
|
13554
14365
|
const last = children[children.length - 1].getBoundingClientRect();
|
|
13555
|
-
const lastGap = children.length >= 2 ? Math.max(
|
|
13556
|
-
0,
|
|
13557
|
-
last.top - children[children.length - 2].getBoundingClientRect().bottom
|
|
13558
|
-
) : edgeGap;
|
|
14366
|
+
const lastGap = children.length >= 2 ? Math.max(0, last.top - children[children.length - 2].getBoundingClientRect().bottom) : edgeGap;
|
|
13559
14367
|
top = last.bottom + lastGap / 2 - barThickness / 2;
|
|
13560
14368
|
left = last.left;
|
|
13561
14369
|
width = last.width;
|
|
@@ -13578,18 +14386,19 @@ function buildChildNavDropSlots(parentHrefKey) {
|
|
|
13578
14386
|
}
|
|
13579
14387
|
return slots;
|
|
13580
14388
|
}
|
|
13581
|
-
function buildAllNavDropSlots(draggedHrefKey) {
|
|
13582
|
-
const
|
|
13583
|
-
|
|
14389
|
+
function buildAllNavDropSlots(draggedHrefKey, draggedEl) {
|
|
14390
|
+
const activeItems = listActiveNavbarItems(draggedEl);
|
|
14391
|
+
const dragged = (draggedEl && activeItems.includes(draggedEl) ? draggedEl : null) ?? activeItems.find((el) => el.getAttribute("data-ohw-href-key") === draggedHrefKey) ?? listNavbarItems().find((el) => el.getAttribute("data-ohw-href-key") === draggedHrefKey);
|
|
14392
|
+
if (!dragged) return buildRootNavDropSlots(draggedEl);
|
|
13584
14393
|
if (isNestedNavChild(dragged)) {
|
|
13585
14394
|
const parentKey = resolveParentNavHrefKey(dragged);
|
|
13586
14395
|
if (!parentKey) return [];
|
|
13587
|
-
return buildChildNavDropSlots(parentKey);
|
|
14396
|
+
return buildChildNavDropSlots(parentKey, draggedEl);
|
|
13588
14397
|
}
|
|
13589
|
-
return buildRootNavDropSlots();
|
|
14398
|
+
return buildRootNavDropSlots(draggedEl);
|
|
13590
14399
|
}
|
|
13591
|
-
function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
|
|
13592
|
-
const slots = buildAllNavDropSlots(draggedHrefKey);
|
|
14400
|
+
function hitTestNavDropSlot(clientX, clientY, draggedHrefKey, draggedEl) {
|
|
14401
|
+
const slots = buildAllNavDropSlots(draggedHrefKey, draggedEl);
|
|
13593
14402
|
let best = null;
|
|
13594
14403
|
for (const slot of slots) {
|
|
13595
14404
|
const cx2 = slot.left + slot.width / 2;
|
|
@@ -13640,6 +14449,12 @@ function useNavItemDrag({
|
|
|
13640
14449
|
setIsItemDragging(false);
|
|
13641
14450
|
if (keepOpenEl?.isConnected) {
|
|
13642
14451
|
setNavGroupForceOpen(keepOpenEl, true);
|
|
14452
|
+
requestAnimationFrame(() => {
|
|
14453
|
+
if (keepOpenEl.isConnected) setNavGroupForceOpen(keepOpenEl, true);
|
|
14454
|
+
requestAnimationFrame(() => {
|
|
14455
|
+
if (keepOpenEl.isConnected) setNavGroupForceOpen(keepOpenEl, true);
|
|
14456
|
+
});
|
|
14457
|
+
});
|
|
13643
14458
|
} else {
|
|
13644
14459
|
setNavGroupForceOpen(null, false);
|
|
13645
14460
|
}
|
|
@@ -13655,7 +14470,7 @@ function useNavItemDrag({
|
|
|
13655
14470
|
}
|
|
13656
14471
|
session.activeSlot = activeSlot;
|
|
13657
14472
|
setSiblingHintRects([]);
|
|
13658
|
-
const slots = buildAllNavDropSlots(session.hrefKey);
|
|
14473
|
+
const slots = buildAllNavDropSlots(session.hrefKey, session.draggedEl);
|
|
13659
14474
|
setNavDropSlots(slots);
|
|
13660
14475
|
const activeIdx = activeSlot ? slots.findIndex(
|
|
13661
14476
|
(s) => s.parentId === activeSlot.parentId && s.insertIndex === activeSlot.insertIndex
|
|
@@ -13691,7 +14506,12 @@ function useNavItemDrag({
|
|
|
13691
14506
|
if (session.wasSelected && selectedElRef.current === session.draggedEl) {
|
|
13692
14507
|
setToolbarRect(rect);
|
|
13693
14508
|
}
|
|
13694
|
-
const initialSlot = hitTestNavDropSlot(
|
|
14509
|
+
const initialSlot = hitTestNavDropSlot(
|
|
14510
|
+
session.lastClientX,
|
|
14511
|
+
session.lastClientY,
|
|
14512
|
+
session.hrefKey,
|
|
14513
|
+
session.draggedEl
|
|
14514
|
+
);
|
|
13695
14515
|
refreshNavDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
|
|
13696
14516
|
},
|
|
13697
14517
|
[
|
|
@@ -13713,10 +14533,11 @@ function useNavItemDrag({
|
|
|
13713
14533
|
}
|
|
13714
14534
|
const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
|
|
13715
14535
|
const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
|
|
13716
|
-
const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey);
|
|
14536
|
+
const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey, session.draggedEl);
|
|
13717
14537
|
const planned = slot != null ? planNavItemMove(session.hrefKey, slot.parentId, slot.insertIndex) : null;
|
|
13718
14538
|
const wasSelected = session.wasSelected;
|
|
13719
14539
|
const hrefKey = session.hrefKey;
|
|
14540
|
+
const keepDropdownOpen = Boolean(session.draggedEl.closest("[data-ohw-nav-children]"));
|
|
13720
14541
|
const applySelectionAfterDrop = () => {
|
|
13721
14542
|
if (!wasSelected) {
|
|
13722
14543
|
deselectRef.current();
|
|
@@ -13750,6 +14571,14 @@ function useNavItemDrag({
|
|
|
13750
14571
|
});
|
|
13751
14572
|
applySelectionAfterDrop();
|
|
13752
14573
|
clearNavDragVisuals();
|
|
14574
|
+
if (keepDropdownOpen) {
|
|
14575
|
+
requestAnimationFrame(() => {
|
|
14576
|
+
const desktop = document.querySelector("[data-ohw-nav-container]");
|
|
14577
|
+
const drawer = document.querySelector("[data-ohw-nav-drawer]");
|
|
14578
|
+
const link = desktop?.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`) ?? drawer?.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`) ?? document.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
|
|
14579
|
+
if (link) setNavGroupForceOpen(link, true);
|
|
14580
|
+
});
|
|
14581
|
+
}
|
|
13753
14582
|
requestAnimationFrame(() => {
|
|
13754
14583
|
if (editContentRef.current[NAV_ORDER_KEY] === planned.orderJson) {
|
|
13755
14584
|
applyNavForest(planned.forest);
|
|
@@ -13789,7 +14618,7 @@ function useNavItemDrag({
|
|
|
13789
14618
|
if (!session) return false;
|
|
13790
14619
|
e.preventDefault();
|
|
13791
14620
|
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
13792
|
-
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
14621
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey, session.draggedEl);
|
|
13793
14622
|
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
13794
14623
|
return true;
|
|
13795
14624
|
},
|
|
@@ -13835,7 +14664,7 @@ function useNavItemDrag({
|
|
|
13835
14664
|
clearTextSelection();
|
|
13836
14665
|
const session = navDragRef.current;
|
|
13837
14666
|
if (!session) return;
|
|
13838
|
-
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
14667
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey, session.draggedEl);
|
|
13839
14668
|
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
13840
14669
|
return;
|
|
13841
14670
|
}
|
|
@@ -13851,7 +14680,8 @@ function useNavItemDrag({
|
|
|
13851
14680
|
} catch {
|
|
13852
14681
|
}
|
|
13853
14682
|
if (linkPopoverOpenRef.current) setLinkPopover(null);
|
|
13854
|
-
|
|
14683
|
+
const isNestedDrag = Boolean(pending.el.closest("[data-ohw-nav-children]"));
|
|
14684
|
+
if (activeElRef.current && !isNestedDrag) deactivateRef.current();
|
|
13855
14685
|
const key = pending.el.getAttribute("data-ohw-href-key");
|
|
13856
14686
|
if (!key) return;
|
|
13857
14687
|
beginNavDragRef.current({
|
|
@@ -13862,6 +14692,9 @@ function useNavItemDrag({
|
|
|
13862
14692
|
lastClientY: e.clientY,
|
|
13863
14693
|
activeSlot: null
|
|
13864
14694
|
});
|
|
14695
|
+
if (activeElRef.current && isNestedDrag) {
|
|
14696
|
+
deactivateRef.current();
|
|
14697
|
+
}
|
|
13865
14698
|
};
|
|
13866
14699
|
const endPointerDrag = (e) => {
|
|
13867
14700
|
const pending = navPointerDragRef.current;
|
|
@@ -13939,6 +14772,7 @@ function useNavItemDrag({
|
|
|
13939
14772
|
);
|
|
13940
14773
|
return {
|
|
13941
14774
|
navDragRef,
|
|
14775
|
+
navPointerDragRef,
|
|
13942
14776
|
navDropSlots,
|
|
13943
14777
|
activeNavDropIndex,
|
|
13944
14778
|
startNavLinkDrag,
|
|
@@ -14143,15 +14977,17 @@ function useSectionDrag({
|
|
|
14143
14977
|
clearSectionDragVisuals();
|
|
14144
14978
|
return;
|
|
14145
14979
|
}
|
|
14146
|
-
const orderJson = JSON.stringify(
|
|
14980
|
+
const orderJson = JSON.stringify(
|
|
14981
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
14982
|
+
);
|
|
14147
14983
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
14148
14984
|
setAiSectionOrder(orderJson, window.location.pathname);
|
|
14149
14985
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
14150
|
-
applyPersistedOrder(
|
|
14986
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
14151
14987
|
clearSectionDragVisuals();
|
|
14152
14988
|
requestAnimationFrame(() => {
|
|
14153
14989
|
if (editContentRef.current[SECTION_ORDER_KEY] === orderJson) {
|
|
14154
|
-
applyPersistedOrder(
|
|
14990
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
14155
14991
|
}
|
|
14156
14992
|
requestAnimationFrame(() => {
|
|
14157
14993
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -14184,8 +15020,9 @@ function useSectionDrag({
|
|
|
14184
15020
|
const target = e.target;
|
|
14185
15021
|
if (!(target instanceof HTMLElement)) return;
|
|
14186
15022
|
if (target.closest(SECTION_DRAG_EXCLUDED_SELECTOR)) return;
|
|
14187
|
-
const
|
|
14188
|
-
if (!
|
|
15023
|
+
const inner = target.closest("[data-ohw-section]");
|
|
15024
|
+
if (!inner || isChromeSection(inner) || inner.dataset.ohwSection === "footer") return;
|
|
15025
|
+
const sectionEl = movableUnit(inner);
|
|
14189
15026
|
if (!topLevelSections().includes(sectionEl)) return;
|
|
14190
15027
|
startSectionPressDrag(sectionEl, e.clientX, e.clientY, e.pointerId);
|
|
14191
15028
|
};
|
|
@@ -14452,10 +15289,15 @@ function collectEditableNodes(extraContent, root = document) {
|
|
|
14452
15289
|
if (el.dataset.ohwEditable === "link") {
|
|
14453
15290
|
return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref3(el) };
|
|
14454
15291
|
}
|
|
15292
|
+
if (el.dataset.ohwEditable === "map") {
|
|
15293
|
+
return { key: el.dataset.ohwKey ?? "", type: "map", text: el.dataset.ohwMapQuery ?? "" };
|
|
15294
|
+
}
|
|
14455
15295
|
return {
|
|
14456
15296
|
key: el.dataset.ohwKey ?? "",
|
|
14457
15297
|
type: el.dataset.ohwEditable ?? "text",
|
|
14458
|
-
|
|
15298
|
+
// innerText does not exist on SVG elements (a circular-badge <textPath> is a legitimate
|
|
15299
|
+
// plain editable) — textContent is the value there.
|
|
15300
|
+
text: el.dataset.ohwEditable === "plain" ? el.innerText ?? el.textContent ?? "" : el.innerHTML
|
|
14459
15301
|
};
|
|
14460
15302
|
});
|
|
14461
15303
|
const hrefEls = Array.from(root.querySelectorAll("[data-ohw-href-key]"));
|
|
@@ -14892,7 +15734,7 @@ var badgeVariants = cva(
|
|
|
14892
15734
|
{
|
|
14893
15735
|
variants: {
|
|
14894
15736
|
variant: {
|
|
14895
|
-
default: "border-transparent bg-primary text-primary-foreground",
|
|
15737
|
+
default: "border-transparent bg-bridge-primary text-primary-foreground",
|
|
14896
15738
|
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
14897
15739
|
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
14898
15740
|
outline: "text-foreground"
|
|
@@ -15014,21 +15856,10 @@ function parseSchedulingInsertAfter(insertAfter) {
|
|
|
15014
15856
|
insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
|
|
15015
15857
|
};
|
|
15016
15858
|
}
|
|
15017
|
-
function
|
|
15018
|
-
|
|
15019
|
-
const
|
|
15020
|
-
|
|
15021
|
-
return { effectiveInsertAfter, insertBefore };
|
|
15022
|
-
}
|
|
15023
|
-
function getSchedulingMountPoint(insertAfter) {
|
|
15024
|
-
const { anchor } = parseSchedulingInsertAfter(insertAfter);
|
|
15025
|
-
let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
|
|
15026
|
-
if (!anchorEl && anchor === "scheduling") {
|
|
15027
|
-
const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
|
|
15028
|
-
anchorEl = widgets.at(-1) ?? null;
|
|
15029
|
-
}
|
|
15030
|
-
if (!anchorEl) return null;
|
|
15031
|
-
return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
15859
|
+
function resolveEntryAnchor(entry) {
|
|
15860
|
+
if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
|
|
15861
|
+
const parsed = parseSchedulingInsertAfter(entry.insertAfter);
|
|
15862
|
+
return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
|
|
15032
15863
|
}
|
|
15033
15864
|
function schedulingMountDepth(insertAfter) {
|
|
15034
15865
|
if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
|
|
@@ -15045,8 +15876,7 @@ function getPageSchedulingEntries(raw) {
|
|
|
15045
15876
|
}
|
|
15046
15877
|
}
|
|
15047
15878
|
function isSchedulingWidgetMissing(entry) {
|
|
15048
|
-
|
|
15049
|
-
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
|
|
15879
|
+
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
|
|
15050
15880
|
}
|
|
15051
15881
|
function hasMissingSchedulingWidgets(entries) {
|
|
15052
15882
|
return entries.some(isSchedulingWidgetMissing);
|
|
@@ -15084,18 +15914,18 @@ function initSectionsFromContent(content, removeExisting = false, currentPath =
|
|
|
15084
15914
|
} catch {
|
|
15085
15915
|
}
|
|
15086
15916
|
}
|
|
15087
|
-
function mountSchedulingWidget(
|
|
15088
|
-
const
|
|
15089
|
-
const sectionId = schedulingSectionId(
|
|
15917
|
+
function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
|
|
15918
|
+
const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
|
|
15919
|
+
const sectionId = schedulingSectionId(widgetId);
|
|
15090
15920
|
if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
|
|
15091
|
-
const
|
|
15092
|
-
if (!
|
|
15921
|
+
const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
|
|
15922
|
+
if (!anchorEl) return false;
|
|
15923
|
+
const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
15093
15924
|
const container = document.createElement("div");
|
|
15094
15925
|
container.dataset.ohwSectionContainer = "scheduling";
|
|
15095
|
-
container.dataset.ohwSection = sectionId;
|
|
15096
15926
|
container.dataset.ohwInstance = sectionId;
|
|
15097
|
-
if (
|
|
15098
|
-
const beforeAnchor = document.querySelector(`[data-ohw-section="${
|
|
15927
|
+
if (beforeId) {
|
|
15928
|
+
const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
|
|
15099
15929
|
const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
|
|
15100
15930
|
if (!beforePoint) return false;
|
|
15101
15931
|
beforePoint.insertAdjacentElement("beforebegin", container);
|
|
@@ -15106,20 +15936,26 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
15106
15936
|
}
|
|
15107
15937
|
tail.insertAdjacentElement("afterend", container);
|
|
15108
15938
|
}
|
|
15109
|
-
|
|
15110
|
-
|
|
15111
|
-
|
|
15112
|
-
|
|
15113
|
-
|
|
15114
|
-
|
|
15115
|
-
|
|
15116
|
-
|
|
15117
|
-
|
|
15118
|
-
|
|
15119
|
-
|
|
15120
|
-
|
|
15121
|
-
|
|
15122
|
-
|
|
15939
|
+
try {
|
|
15940
|
+
const root = createRoot2(container);
|
|
15941
|
+
schedulingRoots.set(container, root);
|
|
15942
|
+
flushSync2(() => {
|
|
15943
|
+
root.render(
|
|
15944
|
+
/* @__PURE__ */ jsx33(
|
|
15945
|
+
SchedulingWidget,
|
|
15946
|
+
{
|
|
15947
|
+
notifyOnConnect,
|
|
15948
|
+
initialScheduleId: scheduleId,
|
|
15949
|
+
insertAfter: widgetId
|
|
15950
|
+
}
|
|
15951
|
+
)
|
|
15952
|
+
);
|
|
15953
|
+
});
|
|
15954
|
+
} catch (err) {
|
|
15955
|
+
console.error("[ow:scheduling] render threw", err);
|
|
15956
|
+
container.remove();
|
|
15957
|
+
return false;
|
|
15958
|
+
}
|
|
15123
15959
|
const tracker = getSectionsTracker();
|
|
15124
15960
|
let sections = [];
|
|
15125
15961
|
try {
|
|
@@ -15127,10 +15963,12 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
15127
15963
|
} catch {
|
|
15128
15964
|
}
|
|
15129
15965
|
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
15130
|
-
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter ===
|
|
15966
|
+
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
|
|
15131
15967
|
sections.push({
|
|
15132
15968
|
type: "scheduling",
|
|
15133
|
-
insertAfter:
|
|
15969
|
+
insertAfter: widgetId,
|
|
15970
|
+
anchorId,
|
|
15971
|
+
beforeId: beforeId ?? null,
|
|
15134
15972
|
pagePath: window.location.pathname,
|
|
15135
15973
|
...scheduleId ? { scheduleId } : {}
|
|
15136
15974
|
});
|
|
@@ -15144,7 +15982,8 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
|
15144
15982
|
for (let i = pending.length - 1; i >= 0; i--) {
|
|
15145
15983
|
const entry = pending[i];
|
|
15146
15984
|
const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
|
|
15147
|
-
|
|
15985
|
+
const { anchorId, beforeId } = resolveEntryAnchor(entry);
|
|
15986
|
+
if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
|
|
15148
15987
|
pending.splice(i, 1);
|
|
15149
15988
|
}
|
|
15150
15989
|
}
|
|
@@ -15236,7 +16075,7 @@ var EDITOR_CHROME_SELECTOR = '[data-ohw-toolbar], [data-ohw-form-toolbar], [data
|
|
|
15236
16075
|
function isOverEditorChrome(x, y) {
|
|
15237
16076
|
return document.elementsFromPoint(x, y).some((el) => el instanceof HTMLElement && el.matches(EDITOR_CHROME_SELECTOR));
|
|
15238
16077
|
}
|
|
15239
|
-
var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]):not([data-ohw-editable="icon"]):not([data-ohw-editable="form"])';
|
|
16078
|
+
var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]):not([data-ohw-editable="icon"]):not([data-ohw-editable="form"]):not([data-ohw-editable="map"])';
|
|
15240
16079
|
function getVideoEl2(el) {
|
|
15241
16080
|
return el instanceof HTMLVideoElement ? el : el.querySelector("video");
|
|
15242
16081
|
}
|
|
@@ -15292,6 +16131,12 @@ function applyVideoSettingNode(key, val) {
|
|
|
15292
16131
|
});
|
|
15293
16132
|
return true;
|
|
15294
16133
|
}
|
|
16134
|
+
function applyMapQuery(el, val) {
|
|
16135
|
+
if (!(el instanceof HTMLIFrameElement)) return;
|
|
16136
|
+
const nextSrc = `https://www.google.com/maps?q=${encodeURIComponent(val)}&output=embed`;
|
|
16137
|
+
if (el.src !== nextSrc) el.src = nextSrc;
|
|
16138
|
+
el.setAttribute("data-ohw-map-query", val);
|
|
16139
|
+
}
|
|
15295
16140
|
function applyLinkByKey(key, val) {
|
|
15296
16141
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
15297
16142
|
if (el.dataset.ohwEditable === "link") applyLinkHref(el, val);
|
|
@@ -15302,6 +16147,11 @@ function applyLinkByKey(key, val) {
|
|
|
15302
16147
|
hrefAnchors.forEach((el) => applyLinkHref(el, val));
|
|
15303
16148
|
}
|
|
15304
16149
|
}
|
|
16150
|
+
function isInsideLinkEditor(target) {
|
|
16151
|
+
return Boolean(
|
|
16152
|
+
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"]')
|
|
16153
|
+
);
|
|
16154
|
+
}
|
|
15305
16155
|
function isInsideFloatingPanel(target) {
|
|
15306
16156
|
return Boolean(target.closest("[data-ohw-floating-panel]"));
|
|
15307
16157
|
}
|
|
@@ -15309,11 +16159,6 @@ function isPointOverFloatingPanel(clientX, clientY) {
|
|
|
15309
16159
|
const el = document.elementFromPoint(clientX, clientY);
|
|
15310
16160
|
return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
|
|
15311
16161
|
}
|
|
15312
|
-
function isInsideLinkEditor(target) {
|
|
15313
|
-
return Boolean(
|
|
15314
|
-
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"]')
|
|
15315
|
-
);
|
|
15316
|
-
}
|
|
15317
16162
|
function getHrefKeyFromElement(el) {
|
|
15318
16163
|
if (!el) return null;
|
|
15319
16164
|
const anchor = el.closest("[data-ohw-href-key]");
|
|
@@ -15326,6 +16171,7 @@ function isNavDropdownPanelOpen(childrenRoot) {
|
|
|
15326
16171
|
if (childrenRoot.closest("[data-ohw-nav-drawer]")) return true;
|
|
15327
16172
|
const group = childrenRoot.closest("[data-ohw-nav-group]");
|
|
15328
16173
|
if (group?.hasAttribute("data-ohw-nav-force-open")) return true;
|
|
16174
|
+
if (navDropdownsOpenOnClick()) return false;
|
|
15329
16175
|
if (childrenRoot.clientHeight < 2 || childrenRoot.clientWidth < 2) return false;
|
|
15330
16176
|
const style = window.getComputedStyle(childrenRoot);
|
|
15331
16177
|
if (style.display === "none" || style.visibility === "hidden") return false;
|
|
@@ -15369,6 +16215,11 @@ function getNavigationItemAnchor(el) {
|
|
|
15369
16215
|
function isNavigationItem2(el) {
|
|
15370
16216
|
return getNavigationItemAnchor(el) !== null;
|
|
15371
16217
|
}
|
|
16218
|
+
function isNavFooterScopedNavigationItem(el) {
|
|
16219
|
+
return Boolean(
|
|
16220
|
+
el.closest("nav, footer, [data-ohw-nav-container], [data-ohw-nav-drawer]")
|
|
16221
|
+
);
|
|
16222
|
+
}
|
|
15372
16223
|
function socialWordsClicked(target, item) {
|
|
15373
16224
|
const text = target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
|
|
15374
16225
|
return Boolean(text && item.contains(text));
|
|
@@ -15572,13 +16423,14 @@ function getNavigationSelectionParent(el) {
|
|
|
15572
16423
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
15573
16424
|
return getFooterLinksContainer();
|
|
15574
16425
|
}
|
|
15575
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
16426
|
+
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)) {
|
|
15576
16427
|
return getNavigationRoot(el);
|
|
15577
16428
|
}
|
|
15578
16429
|
return null;
|
|
15579
16430
|
}
|
|
15580
16431
|
function collectNavigationItemSiblingHintRects(selected) {
|
|
15581
16432
|
if (!isNavigationItem2(selected)) return [];
|
|
16433
|
+
if (!isNavFooterScopedNavigationItem(selected)) return [];
|
|
15582
16434
|
const socialsRow = findSocialsRow(selected);
|
|
15583
16435
|
if (socialsRow) {
|
|
15584
16436
|
return listSocialItems(socialsRow).filter((item) => item !== selected).map((item) => item.getBoundingClientRect());
|
|
@@ -15787,7 +16639,6 @@ var ICONS = {
|
|
|
15787
16639
|
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"/>',
|
|
15788
16640
|
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"/>'
|
|
15789
16641
|
};
|
|
15790
|
-
var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
|
|
15791
16642
|
var SELECTION_CHROME_GAP2 = 4;
|
|
15792
16643
|
var TOOLBAR_STROKE_GAP2 = 4;
|
|
15793
16644
|
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
@@ -16167,6 +17018,7 @@ function StateToggle({
|
|
|
16167
17018
|
);
|
|
16168
17019
|
}
|
|
16169
17020
|
var contentCache = /* @__PURE__ */ new Map();
|
|
17021
|
+
var fetchedContentPaths = /* @__PURE__ */ new Set();
|
|
16170
17022
|
var brandingCache = /* @__PURE__ */ new Map();
|
|
16171
17023
|
var OHW_LOADER_STYLE = {
|
|
16172
17024
|
position: "fixed",
|
|
@@ -16696,13 +17548,6 @@ function OhhwellsBridge() {
|
|
|
16696
17548
|
const [isItemDragging, setIsItemDragging] = useState13(false);
|
|
16697
17549
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = useState13(false);
|
|
16698
17550
|
isFooterFrameSelectionRef.current = isFooterFrameSelection;
|
|
16699
|
-
const [floatingPanel, setFloatingPanel] = useState13(null);
|
|
16700
|
-
const floatingPanelOpenRef = useRef10(false);
|
|
16701
|
-
floatingPanelOpenRef.current = floatingPanel !== null;
|
|
16702
|
-
const [floatingPanelPos, setFloatingPanelPos] = useState13(null);
|
|
16703
|
-
const [logoSizeDraft, setLogoSizeDraft] = useState13(null);
|
|
16704
|
-
const [editorViewport, setEditorViewport] = useState13("desktop");
|
|
16705
|
-
const [parentScrollSnap, setParentScrollSnap] = useState13(null);
|
|
16706
17551
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState13(null);
|
|
16707
17552
|
const [footerHeadingVisible, setFooterHeadingVisible] = useState13(null);
|
|
16708
17553
|
const footerDragRef = useRef10(null);
|
|
@@ -16720,6 +17565,13 @@ function OhhwellsBridge() {
|
|
|
16720
17565
|
const brandKitRef = useRef10("");
|
|
16721
17566
|
const stylesRef = useRef10("");
|
|
16722
17567
|
const pendingDeleteUndoRef = useRef10(null);
|
|
17568
|
+
const [floatingPanel, setFloatingPanel] = useState13(null);
|
|
17569
|
+
const floatingPanelOpenRef = useRef10(false);
|
|
17570
|
+
const setFloatingPanelRef = useRef10(setFloatingPanel);
|
|
17571
|
+
const [floatingPanelPos, setFloatingPanelPos] = useState13(null);
|
|
17572
|
+
const [logoSizeDraft, setLogoSizeDraft] = useState13(null);
|
|
17573
|
+
const [editorViewport, setEditorViewport] = useState13("desktop");
|
|
17574
|
+
const [parentScrollSnap, setParentScrollSnap] = useState13(null);
|
|
16723
17575
|
const [sitePages, setSitePages] = useState13([]);
|
|
16724
17576
|
const [sectionsByPath, setSectionsByPath] = useState13({});
|
|
16725
17577
|
const sectionsPrefetchGenRef = useRef10(0);
|
|
@@ -16728,9 +17580,21 @@ function OhhwellsBridge() {
|
|
|
16728
17580
|
const linkPopoverOpenRef = useRef10(false);
|
|
16729
17581
|
const linkPopoverGraceUntilRef = useRef10(0);
|
|
16730
17582
|
setLinkPopoverRef.current = setLinkPopover;
|
|
17583
|
+
setFloatingPanelRef.current = setFloatingPanel;
|
|
16731
17584
|
linkPopoverSessionRef.current = linkPopover;
|
|
17585
|
+
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
17586
|
+
useEffect13(() => {
|
|
17587
|
+
const syncViewport = () => {
|
|
17588
|
+
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
17589
|
+
setEditorViewport((prev) => prev === next ? prev : next);
|
|
17590
|
+
};
|
|
17591
|
+
syncViewport();
|
|
17592
|
+
window.addEventListener("resize", syncViewport);
|
|
17593
|
+
return () => window.removeEventListener("resize", syncViewport);
|
|
17594
|
+
}, []);
|
|
16732
17595
|
const {
|
|
16733
17596
|
navDragRef,
|
|
17597
|
+
navPointerDragRef,
|
|
16734
17598
|
navDropSlots,
|
|
16735
17599
|
activeNavDropIndex,
|
|
16736
17600
|
startNavLinkDrag,
|
|
@@ -16933,7 +17797,12 @@ function OhhwellsBridge() {
|
|
|
16933
17797
|
if (owner) persistFieldsRef.current(owner);
|
|
16934
17798
|
}
|
|
16935
17799
|
activeElRef.current = null;
|
|
16936
|
-
|
|
17800
|
+
const preserveNavDropdown = Boolean(navPointerDragRef.current?.el?.closest("[data-ohw-nav-children]")) || Boolean(navDragRef.current?.draggedEl?.closest("[data-ohw-nav-children]")) || Boolean(
|
|
17801
|
+
selectedElRef.current?.closest("[data-ohw-nav-children]") && selectedElRef.current?.closest("[data-ohw-nav-group]")?.hasAttribute("data-ohw-nav-force-open")
|
|
17802
|
+
);
|
|
17803
|
+
if (!preserveNavDropdown) {
|
|
17804
|
+
setNavGroupForceOpen(null, false);
|
|
17805
|
+
}
|
|
16937
17806
|
setReorderHrefKey(null);
|
|
16938
17807
|
setReorderDragDisabled(false);
|
|
16939
17808
|
if (!selectedElRef.current) {
|
|
@@ -17055,7 +17924,10 @@ function OhhwellsBridge() {
|
|
|
17055
17924
|
setSelectedIsSocialsRow(false);
|
|
17056
17925
|
const isDropdownTrigger = !isNestedNavChild(navAnchor) && (navItemHasDropdownChildren(navAnchor) || navItemOwnsDropdownPanel(navAnchor));
|
|
17057
17926
|
if (isNestedNavChild(navAnchor)) {
|
|
17058
|
-
|
|
17927
|
+
const group = navAnchor.closest("[data-ohw-nav-group]");
|
|
17928
|
+
if (group?.hasAttribute("data-ohw-nav-force-open")) {
|
|
17929
|
+
setNavGroupForceOpen(navAnchor, true);
|
|
17930
|
+
}
|
|
17059
17931
|
setNavDropdownPreviewOpen(null);
|
|
17060
17932
|
} else if (isDropdownTrigger) {
|
|
17061
17933
|
const group = navAnchor.closest("[data-ohw-nav-group]");
|
|
@@ -17137,6 +18009,10 @@ function OhhwellsBridge() {
|
|
|
17137
18009
|
const handleNavDropdownOpenChange = useCallback8((open) => {
|
|
17138
18010
|
const selected = selectedElRef.current;
|
|
17139
18011
|
if (!selected || !isNavigationItem2(selected)) return;
|
|
18012
|
+
if (isNestedNavChild(selected)) return;
|
|
18013
|
+
const group = selected.closest("[data-ohw-nav-group]");
|
|
18014
|
+
const domOpen = Boolean(group?.hasAttribute("data-ohw-nav-force-open"));
|
|
18015
|
+
if (open === domOpen) return;
|
|
17140
18016
|
setNavGroupForceOpen(selected, open);
|
|
17141
18017
|
setNavDropdownPreviewOpen(open);
|
|
17142
18018
|
requestAnimationFrame(() => {
|
|
@@ -17666,7 +18542,10 @@ function OhhwellsBridge() {
|
|
|
17666
18542
|
clearHrefKeyHover(anchor);
|
|
17667
18543
|
const isDropdownTrigger = !isNestedNavChild(anchor) && (navItemHasDropdownChildren(anchor) || navItemOwnsDropdownPanel(anchor));
|
|
17668
18544
|
if (isNestedNavChild(anchor)) {
|
|
17669
|
-
|
|
18545
|
+
const group = anchor.closest("[data-ohw-nav-group]");
|
|
18546
|
+
if (group?.hasAttribute("data-ohw-nav-force-open")) {
|
|
18547
|
+
setNavGroupForceOpen(anchor, true);
|
|
18548
|
+
}
|
|
17670
18549
|
setNavDropdownPreviewOpen(null);
|
|
17671
18550
|
} else if (isDropdownTrigger) {
|
|
17672
18551
|
setNavGroupForceOpen(null, false);
|
|
@@ -18053,6 +18932,7 @@ function OhhwellsBridge() {
|
|
|
18053
18932
|
}
|
|
18054
18933
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
18055
18934
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
18935
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
18056
18936
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
18057
18937
|
}
|
|
18058
18938
|
applyBrandChrome(content);
|
|
@@ -18060,11 +18940,11 @@ function OhhwellsBridge() {
|
|
|
18060
18940
|
for (const [key, val] of Object.entries(content)) {
|
|
18061
18941
|
if (key === "__ohw_sections") continue;
|
|
18062
18942
|
if (key === AI_SECTIONS_KEY) continue;
|
|
18943
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18944
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18063
18945
|
if (key === BRAND_KIT_KEY) continue;
|
|
18064
18946
|
if (key === STYLE_STORE_KEY) continue;
|
|
18065
18947
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
18066
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18067
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18068
18948
|
if (applyVideoSettingNode(key, val)) continue;
|
|
18069
18949
|
if (applyCarouselNode(key, val)) continue;
|
|
18070
18950
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -18092,6 +18972,8 @@ function OhhwellsBridge() {
|
|
|
18092
18972
|
}
|
|
18093
18973
|
} else if (el.dataset.ohwEditable === "link") {
|
|
18094
18974
|
applyLinkHref(el, val);
|
|
18975
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
18976
|
+
applyMapQuery(el, val);
|
|
18095
18977
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
18096
18978
|
applyIconMarkup(el, val);
|
|
18097
18979
|
} else if (el.dataset.ohwEditable === "form") {
|
|
@@ -18110,6 +18992,9 @@ function OhhwellsBridge() {
|
|
|
18110
18992
|
applySocialsDisplayFromContent(content);
|
|
18111
18993
|
applySocialsLabelsFromContent(content, document, { fillEmptyOnly: isEditModeRef.current });
|
|
18112
18994
|
if (isEditModeRef.current) requestMissingSocialIconsRef.current();
|
|
18995
|
+
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
18996
|
+
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
18997
|
+
}
|
|
18113
18998
|
enforceLinkHrefs();
|
|
18114
18999
|
initSectionsFromContent(content, true);
|
|
18115
19000
|
sectionsLoadedRef.current = true;
|
|
@@ -18130,7 +19015,9 @@ function OhhwellsBridge() {
|
|
|
18130
19015
|
let cancelled = false;
|
|
18131
19016
|
setFetchState("loading");
|
|
18132
19017
|
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
18133
|
-
|
|
19018
|
+
const initialPath = pathname;
|
|
19019
|
+
fetchedContentPaths.add(`${subdomain}::${initialPath}`);
|
|
19020
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
18134
19021
|
if (cancelled) return;
|
|
18135
19022
|
const content = data?.content ?? {};
|
|
18136
19023
|
const branding = Boolean(data?.showBranding);
|
|
@@ -18239,7 +19126,9 @@ function OhhwellsBridge() {
|
|
|
18239
19126
|
}, [isEditMode]);
|
|
18240
19127
|
useEffect13(() => {
|
|
18241
19128
|
if (isEditMode || fetchState !== "done") return;
|
|
19129
|
+
console.log("env", process.env.NEXT_PUBLIC_FLOWOPS_API_URL);
|
|
18242
19130
|
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
19131
|
+
console.log({ apiUrl, subdomain });
|
|
18243
19132
|
bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
|
|
18244
19133
|
}, [isEditMode, fetchState, subdomain]);
|
|
18245
19134
|
useEffect13(() => {
|
|
@@ -18249,10 +19138,10 @@ function OhhwellsBridge() {
|
|
|
18249
19138
|
const applyFromCache = () => {
|
|
18250
19139
|
const content = contentCache.get(subdomain);
|
|
18251
19140
|
if (!content) return;
|
|
18252
|
-
retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
|
|
18253
|
-
initSectionInstancesFromContent(content, window.location.pathname);
|
|
18254
19141
|
observer?.disconnect();
|
|
18255
19142
|
try {
|
|
19143
|
+
retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
|
|
19144
|
+
initSectionInstancesFromContent(content, window.location.pathname);
|
|
18256
19145
|
applyBrandChrome(content);
|
|
18257
19146
|
if (typeof content[BRAND_KIT_KEY] === "string") {
|
|
18258
19147
|
applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
|
|
@@ -18264,16 +19153,17 @@ function OhhwellsBridge() {
|
|
|
18264
19153
|
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
18265
19154
|
}
|
|
18266
19155
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
19156
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
18267
19157
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
18268
19158
|
}
|
|
18269
19159
|
for (const [key, val] of Object.entries(content)) {
|
|
18270
19160
|
if (key === "__ohw_sections") continue;
|
|
18271
19161
|
if (key === AI_SECTIONS_KEY) continue;
|
|
19162
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
19163
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18272
19164
|
if (key === BRAND_KIT_KEY) continue;
|
|
18273
19165
|
if (key === STYLE_STORE_KEY) continue;
|
|
18274
19166
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
18275
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18276
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18277
19167
|
if (applyVideoSettingNode(key, val)) continue;
|
|
18278
19168
|
if (applyCarouselNode(key, val)) continue;
|
|
18279
19169
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -18288,6 +19178,8 @@ function OhhwellsBridge() {
|
|
|
18288
19178
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
18289
19179
|
} else if (el.dataset.ohwEditable === "link") {
|
|
18290
19180
|
applyLinkHref(el, val);
|
|
19181
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
19182
|
+
applyMapQuery(el, val);
|
|
18291
19183
|
} else if (el.dataset.ohwEditable === "form") {
|
|
18292
19184
|
} else if (isIconMarkupValue(val)) {
|
|
18293
19185
|
} else if (el.innerHTML !== val) {
|
|
@@ -18303,6 +19195,9 @@ function OhhwellsBridge() {
|
|
|
18303
19195
|
applySocialsDisplayFromContent(content);
|
|
18304
19196
|
applySocialsLabelsFromContent(content, document, { fillEmptyOnly: isEditModeRef.current });
|
|
18305
19197
|
if (isEditModeRef.current) requestMissingSocialIconsRef.current();
|
|
19198
|
+
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
19199
|
+
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
19200
|
+
}
|
|
18306
19201
|
document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
|
|
18307
19202
|
if (!form.querySelector("[data-ohw-form-success]")) {
|
|
18308
19203
|
reconcileFieldsFromContent(form, content);
|
|
@@ -18319,6 +19214,17 @@ function OhhwellsBridge() {
|
|
|
18319
19214
|
debounceTimer = setTimeout(applyFromCache, 150);
|
|
18320
19215
|
};
|
|
18321
19216
|
applyFromCache();
|
|
19217
|
+
const pathCacheKey = `${subdomain}::${pathname}`;
|
|
19218
|
+
if (!fetchedContentPaths.has(pathCacheKey)) {
|
|
19219
|
+
fetchedContentPaths.add(pathCacheKey);
|
|
19220
|
+
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
19221
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
19222
|
+
if (!data?.content) return;
|
|
19223
|
+
contentCache.set(subdomain, data.content);
|
|
19224
|
+
applyFromCache();
|
|
19225
|
+
}).catch(() => {
|
|
19226
|
+
});
|
|
19227
|
+
}
|
|
18322
19228
|
observer = new MutationObserver(scheduleApply);
|
|
18323
19229
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
18324
19230
|
return () => {
|
|
@@ -18343,6 +19249,10 @@ function OhhwellsBridge() {
|
|
|
18343
19249
|
deselectRef.current();
|
|
18344
19250
|
deactivateRef.current();
|
|
18345
19251
|
}, [pathname, isEditMode]);
|
|
19252
|
+
useEffect13(() => {
|
|
19253
|
+
if (!isEditMode) return;
|
|
19254
|
+
initSectionInstancesFromContent(editContentRef.current, pathname);
|
|
19255
|
+
}, [pathname, isEditMode]);
|
|
18346
19256
|
useEffect13(() => {
|
|
18347
19257
|
const contentForNav = () => {
|
|
18348
19258
|
if (isEditMode) return editContentRef.current;
|
|
@@ -18434,26 +19344,11 @@ function OhhwellsBridge() {
|
|
|
18434
19344
|
const t2 = setTimeout(measure, 500);
|
|
18435
19345
|
const ro = new ResizeObserver(schedule);
|
|
18436
19346
|
ro.observe(document.body);
|
|
18437
|
-
let lastWidth = window.innerWidth;
|
|
18438
|
-
let resizeTimers = [];
|
|
18439
|
-
const clearResizeTimers = () => {
|
|
18440
|
-
resizeTimers.forEach(clearTimeout);
|
|
18441
|
-
resizeTimers = [];
|
|
18442
|
-
};
|
|
18443
|
-
const handleResize = () => {
|
|
18444
|
-
if (window.innerWidth === lastWidth) return;
|
|
18445
|
-
lastWidth = window.innerWidth;
|
|
18446
|
-
clearResizeTimers();
|
|
18447
|
-
resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
|
|
18448
|
-
};
|
|
18449
|
-
window.addEventListener("resize", handleResize);
|
|
18450
19347
|
return () => {
|
|
18451
19348
|
clearTimeout(t1);
|
|
18452
19349
|
clearTimeout(t2);
|
|
18453
19350
|
if (raf != null) cancelAnimationFrame(raf);
|
|
18454
19351
|
ro.disconnect();
|
|
18455
|
-
clearResizeTimers();
|
|
18456
|
-
window.removeEventListener("resize", handleResize);
|
|
18457
19352
|
};
|
|
18458
19353
|
}, [pathname, isEditMode, postToParent2]);
|
|
18459
19354
|
useEffect13(() => {
|
|
@@ -18484,28 +19379,19 @@ function OhhwellsBridge() {
|
|
|
18484
19379
|
return;
|
|
18485
19380
|
}
|
|
18486
19381
|
const existing = editStylesRef.current;
|
|
18487
|
-
|
|
18488
|
-
if (existing?.base.textContent) {
|
|
18489
|
-
const match = existing.base.textContent.match(/\.min-h-screen[^{]*\{[^}]*min-height:\s*(\d+)px/);
|
|
18490
|
-
if (match) initialVh = parseInt(match[1], 10);
|
|
18491
|
-
}
|
|
19382
|
+
const canvasHeight = "var(--ohw-canvas-h, 852px)";
|
|
18492
19383
|
const baseCss = `
|
|
18493
19384
|
html { height: auto !important; }
|
|
18494
19385
|
body { height: auto !important; min-height: 0 !important; overflow: hidden !important; }
|
|
18495
|
-
.min-h-screen, .min-h-svh, .min-h-dvh { min-height: ${
|
|
18496
|
-
.h-screen, .h-svh, .h-dvh { height: ${
|
|
18497
|
-
|
|
18498
|
-
|
|
18499
|
-
[style*="
|
|
18500
|
-
|
|
18501
|
-
|
|
18502
|
-
|
|
18503
|
-
|
|
18504
|
-
so content taller than one screen (a long mobile hero, say) overflows a centered flex
|
|
18505
|
-
column upward, under whatever sits above it. Only the min-height half belongs to it. */
|
|
18506
|
-
[style*="min-height"][style*="100vh"],
|
|
18507
|
-
[style*="min-height"][style*="100svh"],
|
|
18508
|
-
[style*="min-height"][style*="100dvh"] { height: auto !important; }
|
|
19386
|
+
.min-h-screen, .min-h-svh, .min-h-dvh { min-height: ${canvasHeight} !important; }
|
|
19387
|
+
.h-screen, .h-svh, .h-dvh { height: ${canvasHeight} !important; }
|
|
19388
|
+
/* Literal inline viewport units only \u2014 skip R11 sections that already reference --ohw-canvas-h
|
|
19389
|
+
(their style attribute contains "100svh" only as a var() fallback string). */
|
|
19390
|
+
[style*="100vh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
|
|
19391
|
+
[style*="100svh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
|
|
19392
|
+
[style*="100dvh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
|
|
19393
|
+
/* R11: min-height via --ohw-canvas-h; height must grow with content taller than one screen. */
|
|
19394
|
+
[style*="min-height"][style*="--ohw-canvas-h"] { height: auto !important; }
|
|
18509
19395
|
/* Emptied text keeps somewhere to click. A label typed down to nothing collapses to a
|
|
18510
19396
|
couple of pixels, and getting back into it meant hunting for the caret with the mouse.
|
|
18511
19397
|
Edit mode only \u2014 the published page shows nothing where there is nothing (OHH-736). */
|
|
@@ -18652,6 +19538,10 @@ function OhhwellsBridge() {
|
|
|
18652
19538
|
outline-offset: 0 !important;
|
|
18653
19539
|
box-shadow: none !important;
|
|
18654
19540
|
}
|
|
19541
|
+
/* Open nav dropdown panels paint above AI section selection chrome (2147483000). */
|
|
19542
|
+
[data-ohw-nav-group][data-ohw-nav-force-open] > [data-ohw-nav-children] {
|
|
19543
|
+
z-index: 2147483100 !important;
|
|
19544
|
+
}
|
|
18655
19545
|
/* Text edit wins over grab/default (must beat [data-ohw-can-drag] *). */
|
|
18656
19546
|
[data-ohw-editing],
|
|
18657
19547
|
[data-ohw-editing] *,
|
|
@@ -18670,6 +19560,10 @@ function OhhwellsBridge() {
|
|
|
18670
19560
|
[data-ohw-editable-state], [data-ohw-editable-state] * { pointer-events: none !important; }
|
|
18671
19561
|
[data-ohw-editable-state][data-ohw-active-state] [data-ohw-editable] { pointer-events: auto !important; }
|
|
18672
19562
|
[data-ohw-editable-state][data-ohw-active-state][data-ohw-editable] { pointer-events: auto !important; }
|
|
19563
|
+
/* SVG hit-tests painted glyphs only, so an editable curved-text badge answered clicks
|
|
19564
|
+
on its letter strokes alone (and a spinning one barely at all). In edit mode the
|
|
19565
|
+
whole box takes the click; the handler resolves it to the editable inside. */
|
|
19566
|
+
svg:has([data-ohw-editable]) { pointer-events: bounding-box !important; }
|
|
18673
19567
|
`;
|
|
18674
19568
|
if (!existing) {
|
|
18675
19569
|
const base = document.createElement("style");
|
|
@@ -18708,9 +19602,6 @@ function OhhwellsBridge() {
|
|
|
18708
19602
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
18709
19603
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
18710
19604
|
if (isInsideLinkEditor(target)) return;
|
|
18711
|
-
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
18712
|
-
clearMediaSelectionRef.current();
|
|
18713
|
-
}
|
|
18714
19605
|
if (isInsideFloatingPanel(target)) return;
|
|
18715
19606
|
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
18716
19607
|
if (target.closest(
|
|
@@ -18718,6 +19609,9 @@ function OhhwellsBridge() {
|
|
|
18718
19609
|
)) {
|
|
18719
19610
|
return;
|
|
18720
19611
|
}
|
|
19612
|
+
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
19613
|
+
clearMediaSelectionRef.current();
|
|
19614
|
+
}
|
|
18721
19615
|
{
|
|
18722
19616
|
const formEl = getFormElement(target);
|
|
18723
19617
|
const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
|
|
@@ -18840,7 +19734,19 @@ function OhhwellsBridge() {
|
|
|
18840
19734
|
openLogoSizePanelRef.current(logoEl);
|
|
18841
19735
|
return;
|
|
18842
19736
|
}
|
|
18843
|
-
|
|
19737
|
+
let editable = target.closest("[data-ohw-editable]");
|
|
19738
|
+
if (!editable && target instanceof SVGElement) {
|
|
19739
|
+
const inner = target.closest("svg")?.querySelectorAll("[data-ohw-editable]");
|
|
19740
|
+
if (inner && inner.length === 1) editable = inner[0];
|
|
19741
|
+
}
|
|
19742
|
+
if (editable && !(editable instanceof HTMLElement)) {
|
|
19743
|
+
e.preventDefault();
|
|
19744
|
+
e.stopPropagation();
|
|
19745
|
+
deselectRef.current();
|
|
19746
|
+
deactivateRef.current();
|
|
19747
|
+
aiSectionApiRef.current?.selectFromElement(editable);
|
|
19748
|
+
return;
|
|
19749
|
+
}
|
|
18844
19750
|
if (editable) {
|
|
18845
19751
|
if (editable.dataset.ohwEditable === "link") {
|
|
18846
19752
|
e.preventDefault();
|
|
@@ -18869,14 +19775,6 @@ function OhhwellsBridge() {
|
|
|
18869
19775
|
}
|
|
18870
19776
|
const clickedButton = findClosestButtonLike(target);
|
|
18871
19777
|
const buttonOnMedia = Boolean(clickedButton && isMediaEditable(editable) && editable.contains(clickedButton));
|
|
18872
|
-
console.log("[click-debug]", {
|
|
18873
|
-
editableType: editable.dataset.ohwEditable,
|
|
18874
|
-
editableTag: editable.tagName,
|
|
18875
|
-
targetTag: target.tagName,
|
|
18876
|
-
clickedButtonTag: clickedButton?.tagName ?? null,
|
|
18877
|
-
buttonOnMedia,
|
|
18878
|
-
isMediaEditableEditable: isMediaEditable(editable)
|
|
18879
|
-
});
|
|
18880
19778
|
if (isMediaEditable(editable) && !buttonOnMedia) {
|
|
18881
19779
|
e.preventDefault();
|
|
18882
19780
|
e.stopPropagation();
|
|
@@ -18903,11 +19801,6 @@ function OhhwellsBridge() {
|
|
|
18903
19801
|
const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
|
|
18904
19802
|
const hrefCtx = getHrefKeyFromElement(hrefLookupTarget);
|
|
18905
19803
|
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
18906
|
-
console.log("[click-debug 2]", {
|
|
18907
|
-
hrefLookupTargetTag: hrefLookupTarget.tagName,
|
|
18908
|
-
hrefCtx: hrefCtx ? { key: hrefCtx.key } : null,
|
|
18909
|
-
navAnchorTag: navAnchor?.tagName ?? null
|
|
18910
|
-
});
|
|
18911
19804
|
if (navAnchor) {
|
|
18912
19805
|
e.preventDefault();
|
|
18913
19806
|
e.stopPropagation();
|
|
@@ -19077,6 +19970,9 @@ function OhhwellsBridge() {
|
|
|
19077
19970
|
setHoveredItemRect(null);
|
|
19078
19971
|
hoveredNavContainerRef.current = null;
|
|
19079
19972
|
setHoveredNavContainerRect(null);
|
|
19973
|
+
siblingHintElRef.current = null;
|
|
19974
|
+
setSiblingHintRect(null);
|
|
19975
|
+
setSiblingHintRects([]);
|
|
19080
19976
|
return;
|
|
19081
19977
|
}
|
|
19082
19978
|
{
|
|
@@ -19195,7 +20091,6 @@ function OhhwellsBridge() {
|
|
|
19195
20091
|
hoveredNavContainerRef.current = null;
|
|
19196
20092
|
setHoveredNavContainerRect(null);
|
|
19197
20093
|
hoveredItemElRef.current = editable;
|
|
19198
|
-
setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
|
|
19199
20094
|
}
|
|
19200
20095
|
}
|
|
19201
20096
|
}
|
|
@@ -19492,7 +20387,7 @@ function OhhwellsBridge() {
|
|
|
19492
20387
|
}
|
|
19493
20388
|
};
|
|
19494
20389
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
19495
|
-
if (linkPopoverOpenRef.current) {
|
|
20390
|
+
if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
19496
20391
|
if (hoveredImageRef.current) {
|
|
19497
20392
|
hoveredImageRef.current = null;
|
|
19498
20393
|
hoveredImageHasTextOverlapRef.current = false;
|
|
@@ -19581,6 +20476,15 @@ function OhhwellsBridge() {
|
|
|
19581
20476
|
}
|
|
19582
20477
|
return;
|
|
19583
20478
|
}
|
|
20479
|
+
const cardHit = !isDragOver && Array.from(document.querySelectorAll(".card, [data-ohw-card]")).some((card) => {
|
|
20480
|
+
if (card.contains(imgEl)) return false;
|
|
20481
|
+
const r2 = card.getBoundingClientRect();
|
|
20482
|
+
return x2 >= r2.left && x2 <= r2.right && y2 >= r2.top && y2 <= r2.bottom;
|
|
20483
|
+
});
|
|
20484
|
+
if (cardHit) {
|
|
20485
|
+
dismissImageHover();
|
|
20486
|
+
return;
|
|
20487
|
+
}
|
|
19584
20488
|
const topEl = document.elementFromPoint(x2, y2);
|
|
19585
20489
|
if (topEl?.closest('[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"], [data-ohw-more-menu], [data-slot="dropdown-menu-content"], [data-slot="dropdown-menu-item"]')) {
|
|
19586
20490
|
if (hoveredImageRef.current) {
|
|
@@ -19857,8 +20761,7 @@ function OhhwellsBridge() {
|
|
|
19857
20761
|
};
|
|
19858
20762
|
const handleMouseMove = (e) => {
|
|
19859
20763
|
const { clientX, clientY } = e;
|
|
19860
|
-
if (
|
|
19861
|
-
if (isOverEditorChrome(clientX, clientY)) {
|
|
20764
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
|
|
19862
20765
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
19863
20766
|
formHoverElRef.current = null;
|
|
19864
20767
|
setFormHoverRect(null);
|
|
@@ -19866,6 +20769,12 @@ function OhhwellsBridge() {
|
|
|
19866
20769
|
setHoveredItemRect(null);
|
|
19867
20770
|
hoveredNavContainerRef.current = null;
|
|
19868
20771
|
setHoveredNavContainerRect(null);
|
|
20772
|
+
siblingHintElRef.current = null;
|
|
20773
|
+
setSiblingHintRect(null);
|
|
20774
|
+
setSiblingHintRects([]);
|
|
20775
|
+
dismissImageHover();
|
|
20776
|
+
clearImageHover();
|
|
20777
|
+
setSectionGap(null);
|
|
19869
20778
|
return;
|
|
19870
20779
|
}
|
|
19871
20780
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
@@ -19877,7 +20786,11 @@ function OhhwellsBridge() {
|
|
|
19877
20786
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
19878
20787
|
const { clientX, clientY } = e.data;
|
|
19879
20788
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
19880
|
-
if (
|
|
20789
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
20790
|
+
dismissImageHover();
|
|
20791
|
+
clearImageHover();
|
|
20792
|
+
return;
|
|
20793
|
+
}
|
|
19881
20794
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
19882
20795
|
probeSectionGapAt(clientX, clientY);
|
|
19883
20796
|
probeImageAt(clientX, clientY);
|
|
@@ -19991,7 +20904,11 @@ function OhhwellsBridge() {
|
|
|
19991
20904
|
const slotFromItem = hrefKey ? findSocialByHrefKey(hrefKey)?.querySelector('[data-ohw-editable="icon"]') : null;
|
|
19992
20905
|
const requestedIsIconSlot = Boolean(requestedIconKey) && Boolean(document.querySelector(`[data-ohw-key="${requestedIconKey}"][data-ohw-editable="icon"]`));
|
|
19993
20906
|
const requestedIsFree = Boolean(requestedIconKey) && !document.querySelector(`[data-ohw-key="${requestedIconKey}"]`);
|
|
19994
|
-
|
|
20907
|
+
let iconKey = requestedIsIconSlot ? requestedIconKey : slotFromItem?.dataset.ohwKey ?? (requestedIsFree ? requestedIconKey : void 0);
|
|
20908
|
+
const item = hrefKey ? findSocialByHrefKey(hrefKey) : null;
|
|
20909
|
+
if (item && typeof iconMarkup === "string" && iconMarkup) {
|
|
20910
|
+
iconKey = ensureIconSlot(item) ?? iconKey;
|
|
20911
|
+
}
|
|
19995
20912
|
if (iconKey && typeof iconMarkup === "string" && iconMarkup) {
|
|
19996
20913
|
document.querySelectorAll(`[data-ohw-key="${iconKey}"][data-ohw-editable="icon"]`).forEach((el) => {
|
|
19997
20914
|
applyIconMarkup(el, iconMarkup);
|
|
@@ -20001,7 +20918,7 @@ function OhhwellsBridge() {
|
|
|
20001
20918
|
}
|
|
20002
20919
|
if (iconKey && platformId) nodes.push({ key: socialPlatformKey(iconKey), text: platformId });
|
|
20003
20920
|
if (iconKey && label) {
|
|
20004
|
-
const labelKey = socialLabelKey(iconKey);
|
|
20921
|
+
const labelKey = (item ? socialLabelElement(item)?.getAttribute("data-ohw-key") : null) ?? socialLabelKey(iconKey);
|
|
20005
20922
|
document.querySelectorAll(`[data-ohw-key="${labelKey}"]`).forEach((el) => {
|
|
20006
20923
|
if (keepLabel && el.textContent?.trim()) return;
|
|
20007
20924
|
el.textContent = label;
|
|
@@ -20156,6 +21073,44 @@ function OhhwellsBridge() {
|
|
|
20156
21073
|
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
20157
21074
|
}, 400));
|
|
20158
21075
|
};
|
|
21076
|
+
const reapCommittedAiSections = (excludeIds) => {
|
|
21077
|
+
const aiState = parseAiSectionsState(aiSectionsRef.current);
|
|
21078
|
+
if (aiState.sections.length === 0) return [];
|
|
21079
|
+
let orderEntries = [];
|
|
21080
|
+
try {
|
|
21081
|
+
const parsed = JSON.parse(editContentRef.current[SECTION_ORDER_KEY] ?? "[]");
|
|
21082
|
+
if (Array.isArray(parsed)) orderEntries = parsed;
|
|
21083
|
+
} catch {
|
|
21084
|
+
return [];
|
|
21085
|
+
}
|
|
21086
|
+
const removedIds = orderEntries.filter((entry) => entry && typeof entry.instanceId === "string" && entry.removed).map((entry) => entry.instanceId);
|
|
21087
|
+
if (removedIds.length === 0) return [];
|
|
21088
|
+
const result = reapRemovedAiSections(aiState, parseStyleStore(stylesRef.current), removedIds, excludeIds);
|
|
21089
|
+
if (!result.changed) return [];
|
|
21090
|
+
const nodes = [];
|
|
21091
|
+
aiSectionsRef.current = serializeAiSectionsState(result.state);
|
|
21092
|
+
nodes.push({ key: AI_SECTIONS_KEY, text: aiSectionsRef.current });
|
|
21093
|
+
const reaped = new Set(result.reapedIds);
|
|
21094
|
+
const nextOrderJson = JSON.stringify(orderEntries.filter((entry) => !reaped.has(entry.instanceId)));
|
|
21095
|
+
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: nextOrderJson };
|
|
21096
|
+
setAiSectionOrder(nextOrderJson, window.location.pathname);
|
|
21097
|
+
nodes.push({ key: SECTION_ORDER_KEY, text: nextOrderJson });
|
|
21098
|
+
if (result.store) {
|
|
21099
|
+
stylesRef.current = JSON.stringify(result.store);
|
|
21100
|
+
nodes.push({ key: STYLE_STORE_KEY, text: stylesRef.current });
|
|
21101
|
+
}
|
|
21102
|
+
const nextContent = { ...editContentRef.current };
|
|
21103
|
+
for (const key of Object.keys(nextContent)) {
|
|
21104
|
+
if (key.startsWith(AI_SLOT_KEY_PREFIX) && result.slotPrefixes.some((prefix) => key.startsWith(prefix)) && nextContent[key] !== "") {
|
|
21105
|
+
nextContent[key] = "";
|
|
21106
|
+
nodes.push({ key, text: "" });
|
|
21107
|
+
}
|
|
21108
|
+
}
|
|
21109
|
+
editContentRef.current = nextContent;
|
|
21110
|
+
applyAiSectionsToDom(result.state);
|
|
21111
|
+
applyStylesToDom(parseStyleStore(stylesRef.current));
|
|
21112
|
+
return nodes;
|
|
21113
|
+
};
|
|
20159
21114
|
const handleHydrate = (e) => {
|
|
20160
21115
|
if (e.data?.type !== "ow:hydrate") return;
|
|
20161
21116
|
const content = e.data.content;
|
|
@@ -20174,6 +21129,7 @@ function OhhwellsBridge() {
|
|
|
20174
21129
|
}
|
|
20175
21130
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
20176
21131
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
21132
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
20177
21133
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
20178
21134
|
}
|
|
20179
21135
|
applyBrandChrome(content);
|
|
@@ -20185,11 +21141,11 @@ function OhhwellsBridge() {
|
|
|
20185
21141
|
continue;
|
|
20186
21142
|
}
|
|
20187
21143
|
if (key === AI_SECTIONS_KEY) continue;
|
|
21144
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
21145
|
+
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
20188
21146
|
if (key === BRAND_KIT_KEY) continue;
|
|
20189
21147
|
if (key === STYLE_STORE_KEY) continue;
|
|
20190
21148
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
20191
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
20192
|
-
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
20193
21149
|
if (applyVideoSettingNode(key, val)) continue;
|
|
20194
21150
|
if (applyCarouselNode(key, val)) continue;
|
|
20195
21151
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -20203,6 +21159,8 @@ function OhhwellsBridge() {
|
|
|
20203
21159
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
20204
21160
|
} else if (el.dataset.ohwEditable === "link") {
|
|
20205
21161
|
applyLinkHref(el, val);
|
|
21162
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
21163
|
+
applyMapQuery(el, val);
|
|
20206
21164
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
20207
21165
|
applyIconMarkup(el, val);
|
|
20208
21166
|
} else if (isIconMarkupValue(val)) {
|
|
@@ -20223,9 +21181,20 @@ function OhhwellsBridge() {
|
|
|
20223
21181
|
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
20224
21182
|
reconcileFooterOrderFromContent(editContentRef.current);
|
|
20225
21183
|
syncNavigationDragCursorAttrs();
|
|
21184
|
+
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
21185
|
+
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
21186
|
+
}
|
|
20226
21187
|
enforceLinkHrefs();
|
|
21188
|
+
const hydrateReapExclude = /* @__PURE__ */ new Set();
|
|
21189
|
+
const hydratePendingUndo = pendingDeleteUndoRef.current;
|
|
21190
|
+
if (hydratePendingUndo?.sectionInstanceId) hydrateReapExclude.add(hydratePendingUndo.sectionInstanceId);
|
|
21191
|
+
const reapNodes = reapCommittedAiSections(hydrateReapExclude);
|
|
21192
|
+
if (reapNodes.length > 0) postToParentRef.current({ type: "ow:change", nodes: reapNodes });
|
|
20227
21193
|
const hydratedHeight = document.body.scrollHeight;
|
|
20228
21194
|
if (hydratedHeight > 50) postToParentRef.current({ type: "ow:height", height: hydratedHeight });
|
|
21195
|
+
if (parseAiSectionsState(aiSectionsRef.current).sections.length > 0) {
|
|
21196
|
+
postAiSectionsChanged();
|
|
21197
|
+
}
|
|
20229
21198
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
20230
21199
|
};
|
|
20231
21200
|
const handleUpdateLogoIdentity = (e) => {
|
|
@@ -20397,10 +21366,26 @@ function OhhwellsBridge() {
|
|
|
20397
21366
|
const handleGetBrand = (e) => {
|
|
20398
21367
|
if (e.data?.type !== "ow:get-brand") return;
|
|
20399
21368
|
const template = deriveTemplateBrand();
|
|
20400
|
-
const
|
|
21369
|
+
const fallback = template ?? (() => {
|
|
21370
|
+
const fonts = deriveTemplateFonts();
|
|
21371
|
+
return fonts ? { palette: AI_DEFAULT_BRAND.palette, fonts } : null;
|
|
21372
|
+
})();
|
|
21373
|
+
const value = brandKitRef.current || (fallback ? JSON.stringify(fallback) : "");
|
|
20401
21374
|
postToParentRef.current({ type: "ow:brand-value", value });
|
|
20402
21375
|
};
|
|
20403
21376
|
window.addEventListener("message", handleGetBrand);
|
|
21377
|
+
const handleGetTemplateFonts = (e) => {
|
|
21378
|
+
if (e.data?.type !== "ow:get-template-fonts") return;
|
|
21379
|
+
const fonts = deriveTemplateFonts();
|
|
21380
|
+
postToParentRef.current({ type: "ow:template-fonts-value", value: fonts ? JSON.stringify(fonts) : "" });
|
|
21381
|
+
};
|
|
21382
|
+
window.addEventListener("message", handleGetTemplateFonts);
|
|
21383
|
+
const handleGetTemplateBrand = (e) => {
|
|
21384
|
+
if (e.data?.type !== "ow:get-template-brand") return;
|
|
21385
|
+
const brand = deriveTemplateBrand();
|
|
21386
|
+
postToParentRef.current({ type: "ow:template-brand-value", value: brand ? JSON.stringify(brand) : "" });
|
|
21387
|
+
};
|
|
21388
|
+
window.addEventListener("message", handleGetTemplateBrand);
|
|
20404
21389
|
const handleMoveSection = (e) => {
|
|
20405
21390
|
if (e.data?.type !== "ow:move-section") return;
|
|
20406
21391
|
const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
|
|
@@ -20408,8 +21393,11 @@ function OhhwellsBridge() {
|
|
|
20408
21393
|
if (!instanceId || !direction) return;
|
|
20409
21394
|
const entries = moveSectionInstance(instanceId, direction, window.location.pathname);
|
|
20410
21395
|
if (!entries) return;
|
|
20411
|
-
const orderJson = JSON.stringify(
|
|
21396
|
+
const orderJson = JSON.stringify(
|
|
21397
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
21398
|
+
);
|
|
20412
21399
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
21400
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
20413
21401
|
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20414
21402
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
20415
21403
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20455,8 +21443,11 @@ function OhhwellsBridge() {
|
|
|
20455
21443
|
const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname);
|
|
20456
21444
|
const entries = deleteSectionInstance(instanceId, window.location.pathname, currentEntries);
|
|
20457
21445
|
if (!entries) return;
|
|
20458
|
-
const orderJson = JSON.stringify(
|
|
21446
|
+
const orderJson = JSON.stringify(
|
|
21447
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
21448
|
+
);
|
|
20459
21449
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
21450
|
+
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20460
21451
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
20461
21452
|
aiSectionApiRef.current?.clear();
|
|
20462
21453
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20465,6 +21456,7 @@ function OhhwellsBridge() {
|
|
|
20465
21456
|
const actionId = newInstanceId();
|
|
20466
21457
|
pendingDeleteUndoRef.current = {
|
|
20467
21458
|
actionId,
|
|
21459
|
+
sectionInstanceId: instanceId,
|
|
20468
21460
|
restore: () => {
|
|
20469
21461
|
const restoredEntries = getPageSectionOrderEntries(
|
|
20470
21462
|
editContentRef.current[SECTION_ORDER_KEY],
|
|
@@ -20472,8 +21464,11 @@ function OhhwellsBridge() {
|
|
|
20472
21464
|
);
|
|
20473
21465
|
const restored = restoreSectionInstance(instanceId, window.location.pathname, restoredEntries);
|
|
20474
21466
|
if (!restored) return;
|
|
20475
|
-
const restoredJson = JSON.stringify(
|
|
21467
|
+
const restoredJson = JSON.stringify(
|
|
21468
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, restored)
|
|
21469
|
+
);
|
|
20476
21470
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: restoredJson };
|
|
21471
|
+
setAiSectionOrder(restoredJson, window.location.pathname);
|
|
20477
21472
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: restoredJson }] });
|
|
20478
21473
|
window.dispatchEvent(new Event("resize"));
|
|
20479
21474
|
const restoreHeight = document.body.scrollHeight;
|
|
@@ -20499,7 +21494,9 @@ function OhhwellsBridge() {
|
|
|
20499
21494
|
const result = duplicateSectionInstance(instanceId, newId, window.location.pathname, currentEntries);
|
|
20500
21495
|
if (!result) return;
|
|
20501
21496
|
const { entries, keyRekeys } = result;
|
|
20502
|
-
const orderJson = JSON.stringify(
|
|
21497
|
+
const orderJson = JSON.stringify(
|
|
21498
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
21499
|
+
);
|
|
20503
21500
|
const nodes = [{ key: SECTION_ORDER_KEY, text: orderJson }];
|
|
20504
21501
|
for (const { from, to } of keyRekeys) {
|
|
20505
21502
|
const inherited = editContentRef.current[from];
|
|
@@ -20509,6 +21506,7 @@ function OhhwellsBridge() {
|
|
|
20509
21506
|
...editContentRef.current,
|
|
20510
21507
|
...Object.fromEntries(nodes.map(({ key, text }) => [key, text]))
|
|
20511
21508
|
};
|
|
21509
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
20512
21510
|
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20513
21511
|
postToParentRef.current({ type: "ow:change", nodes });
|
|
20514
21512
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20527,6 +21525,12 @@ function OhhwellsBridge() {
|
|
|
20527
21525
|
closeLinkPopoverRef.current();
|
|
20528
21526
|
return;
|
|
20529
21527
|
}
|
|
21528
|
+
if (floatingPanelOpenRef.current) {
|
|
21529
|
+
setFloatingPanelRef.current(null);
|
|
21530
|
+
deselectRef.current();
|
|
21531
|
+
deactivateRef.current();
|
|
21532
|
+
return;
|
|
21533
|
+
}
|
|
20530
21534
|
deselectRef.current();
|
|
20531
21535
|
deactivateRef.current();
|
|
20532
21536
|
clearMediaSelectionRef.current();
|
|
@@ -20759,7 +21763,12 @@ function OhhwellsBridge() {
|
|
|
20759
21763
|
}
|
|
20760
21764
|
if (navDragRef.current) {
|
|
20761
21765
|
const session = navDragRef.current;
|
|
20762
|
-
const slot = hitTestNavDropSlot(
|
|
21766
|
+
const slot = hitTestNavDropSlot(
|
|
21767
|
+
session.lastClientX,
|
|
21768
|
+
session.lastClientY,
|
|
21769
|
+
session.hrefKey,
|
|
21770
|
+
session.draggedEl
|
|
21771
|
+
);
|
|
20763
21772
|
refreshNavDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
|
|
20764
21773
|
}
|
|
20765
21774
|
if (hoveredImageRef.current) {
|
|
@@ -20772,6 +21781,10 @@ function OhhwellsBridge() {
|
|
|
20772
21781
|
};
|
|
20773
21782
|
const handleSave = (e) => {
|
|
20774
21783
|
if (e.data?.type !== "ow:save") return;
|
|
21784
|
+
const pendingUndo = pendingDeleteUndoRef.current;
|
|
21785
|
+
const reapExclude = /* @__PURE__ */ new Set();
|
|
21786
|
+
if (pendingUndo?.sectionInstanceId) reapExclude.add(pendingUndo.sectionInstanceId);
|
|
21787
|
+
const reapNodes = reapCommittedAiSections(reapExclude);
|
|
20775
21788
|
const nodes = collectEditableNodes(editContentRef.current);
|
|
20776
21789
|
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
20777
21790
|
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
@@ -20791,6 +21804,11 @@ function OhhwellsBridge() {
|
|
|
20791
21804
|
const text = specs.length ? JSON.stringify(specs) : editContentRef.current[fieldsKey(formKey)];
|
|
20792
21805
|
if (text) nodes.push({ key: fieldsKey(formKey), type: "text", text });
|
|
20793
21806
|
});
|
|
21807
|
+
for (const reapNode of reapNodes) {
|
|
21808
|
+
if (reapNode.key.startsWith(AI_SLOT_KEY_PREFIX) && !nodes.some((n) => n.key === reapNode.key)) {
|
|
21809
|
+
nodes.push({ key: reapNode.key, type: "text", text: reapNode.text });
|
|
21810
|
+
}
|
|
21811
|
+
}
|
|
20794
21812
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
20795
21813
|
};
|
|
20796
21814
|
const handleInsertSection = (e) => {
|
|
@@ -20801,8 +21819,12 @@ function OhhwellsBridge() {
|
|
|
20801
21819
|
if (inserted) {
|
|
20802
21820
|
const tracker = getSectionsTracker();
|
|
20803
21821
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
|
|
20804
|
-
const
|
|
20805
|
-
|
|
21822
|
+
const reportHeight = () => {
|
|
21823
|
+
const h = document.body.scrollHeight;
|
|
21824
|
+
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
21825
|
+
};
|
|
21826
|
+
reportHeight();
|
|
21827
|
+
setTimeout(reportHeight, 500);
|
|
20806
21828
|
}
|
|
20807
21829
|
};
|
|
20808
21830
|
const handleSwitchSchedule = (e) => {
|
|
@@ -20952,18 +21974,21 @@ function OhhwellsBridge() {
|
|
|
20952
21974
|
}
|
|
20953
21975
|
return null;
|
|
20954
21976
|
};
|
|
21977
|
+
const isPointInRect = (el, clientX, clientY) => {
|
|
21978
|
+
const r2 = el.getBoundingClientRect();
|
|
21979
|
+
return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
|
|
21980
|
+
};
|
|
20955
21981
|
const isPointOverEditable = (scope, clientX, clientY) => {
|
|
20956
21982
|
const editables = scope.querySelectorAll("[data-ohw-editable], [data-ohw-href-key]");
|
|
20957
21983
|
for (const el of editables) {
|
|
20958
|
-
|
|
20959
|
-
if (clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom) return true;
|
|
21984
|
+
if (isPointInRect(el, clientX, clientY)) return true;
|
|
20960
21985
|
}
|
|
20961
21986
|
return false;
|
|
20962
21987
|
};
|
|
20963
21988
|
const handleCarouselHover = (e) => {
|
|
20964
21989
|
const container = findCarouselAtPoint(e.clientX, e.clientY);
|
|
20965
21990
|
const scope = container?.closest("[data-ohw-section]") ?? container?.parentElement ?? null;
|
|
20966
|
-
if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY)) {
|
|
21991
|
+
if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY) || isPointOverNavigation(e.clientX, e.clientY) || isPointOverBridgeChrome(e.clientX, e.clientY)) {
|
|
20967
21992
|
setCarouselHover((prev) => prev ? null : prev);
|
|
20968
21993
|
return;
|
|
20969
21994
|
}
|
|
@@ -21201,15 +22226,17 @@ function OhhwellsBridge() {
|
|
|
21201
22226
|
window.removeEventListener("message", handleAiSetBrand);
|
|
21202
22227
|
window.removeEventListener("message", handleAiSetStyles);
|
|
21203
22228
|
window.removeEventListener("message", handleGetBrand);
|
|
22229
|
+
window.removeEventListener("message", handleGetTemplateFonts);
|
|
22230
|
+
window.removeEventListener("message", handleGetTemplateBrand);
|
|
21204
22231
|
window.removeEventListener("message", handleMoveSection);
|
|
21205
22232
|
window.removeEventListener("message", handlePanelDragging);
|
|
21206
22233
|
window.removeEventListener("message", handleDeleteSection);
|
|
21207
22234
|
window.removeEventListener("message", handleDuplicateSection);
|
|
21208
22235
|
window.removeEventListener("message", handleDeactivate);
|
|
21209
|
-
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
21210
22236
|
window.removeEventListener("message", handleToastAction);
|
|
21211
22237
|
window.removeEventListener("message", handleFormCount);
|
|
21212
22238
|
window.removeEventListener("message", handleUiEscape);
|
|
22239
|
+
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
21213
22240
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
21214
22241
|
autoSaveTimers.current.clear();
|
|
21215
22242
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
@@ -21412,7 +22439,7 @@ function OhhwellsBridge() {
|
|
|
21412
22439
|
postToParent2({
|
|
21413
22440
|
type: "ow:ready",
|
|
21414
22441
|
version: "1",
|
|
21415
|
-
bridgeVersion: "0.1.
|
|
22442
|
+
bridgeVersion: "0.1.93",
|
|
21416
22443
|
path: pathname,
|
|
21417
22444
|
nodes: collectEditableNodes(editContentRef.current),
|
|
21418
22445
|
sections
|
|
@@ -22028,7 +23055,7 @@ function OhhwellsBridge() {
|
|
|
22028
23055
|
"span",
|
|
22029
23056
|
{
|
|
22030
23057
|
"data-ohw-form-count": "",
|
|
22031
|
-
className: "ml-0.5 inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-primary px-1.5 text-[11px] font-semibold text-primary-foreground",
|
|
23058
|
+
className: "ml-0.5 inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-bridge-primary px-1.5 text-[11px] font-semibold text-primary-foreground",
|
|
22032
23059
|
children: formPickCount
|
|
22033
23060
|
}
|
|
22034
23061
|
)
|
|
@@ -22265,11 +23292,11 @@ function OhhwellsBridge() {
|
|
|
22265
23292
|
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
22266
23293
|
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
22267
23294
|
children: [
|
|
22268
|
-
/* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
23295
|
+
/* @__PURE__ */ jsx33("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } }),
|
|
22269
23296
|
/* @__PURE__ */ jsx33(
|
|
22270
23297
|
Badge,
|
|
22271
23298
|
{
|
|
22272
|
-
className: "px-8 py-1 bg-primary hover:bg-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
|
|
23299
|
+
className: "px-8 py-1 bg-bridge-primary hover:bg-bridge-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
|
|
22273
23300
|
onClick: () => {
|
|
22274
23301
|
window.parent.postMessage(
|
|
22275
23302
|
{
|
|
@@ -22283,7 +23310,7 @@ function OhhwellsBridge() {
|
|
|
22283
23310
|
children: "Add Section"
|
|
22284
23311
|
}
|
|
22285
23312
|
),
|
|
22286
|
-
/* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
23313
|
+
/* @__PURE__ */ jsx33("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } })
|
|
22287
23314
|
]
|
|
22288
23315
|
}
|
|
22289
23316
|
),
|
|
@@ -22331,6 +23358,59 @@ function OhhwellsBridge() {
|
|
|
22331
23358
|
) : null
|
|
22332
23359
|
] });
|
|
22333
23360
|
}
|
|
23361
|
+
|
|
23362
|
+
// src/ui/EmptySection.tsx
|
|
23363
|
+
import Link3 from "next/link";
|
|
23364
|
+
import { Fragment as Fragment9, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
23365
|
+
function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
|
|
23366
|
+
return /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
23367
|
+
/* @__PURE__ */ jsx34(
|
|
23368
|
+
"p",
|
|
23369
|
+
{
|
|
23370
|
+
style: {
|
|
23371
|
+
fontFamily: "var(--brand-font-body)",
|
|
23372
|
+
fontSize: "0.75rem",
|
|
23373
|
+
fontWeight: 500,
|
|
23374
|
+
letterSpacing: "0.15em",
|
|
23375
|
+
textTransform: "uppercase",
|
|
23376
|
+
color: "var(--brand-accent)",
|
|
23377
|
+
marginBottom: "1.5rem"
|
|
23378
|
+
},
|
|
23379
|
+
children: /* @__PURE__ */ jsx34(Link3, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ jsx34("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
|
|
23380
|
+
}
|
|
23381
|
+
),
|
|
23382
|
+
/* @__PURE__ */ jsx34(
|
|
23383
|
+
"h1",
|
|
23384
|
+
{
|
|
23385
|
+
style: {
|
|
23386
|
+
fontFamily: "var(--brand-font-heading)",
|
|
23387
|
+
fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
|
|
23388
|
+
lineHeight: 1.1,
|
|
23389
|
+
letterSpacing: "-0.025em",
|
|
23390
|
+
color: "var(--brand-text)",
|
|
23391
|
+
marginBottom: "1rem"
|
|
23392
|
+
},
|
|
23393
|
+
...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
|
|
23394
|
+
children: title
|
|
23395
|
+
}
|
|
23396
|
+
),
|
|
23397
|
+
/* @__PURE__ */ jsx34(
|
|
23398
|
+
"p",
|
|
23399
|
+
{
|
|
23400
|
+
style: {
|
|
23401
|
+
fontFamily: "var(--brand-font-body)",
|
|
23402
|
+
fontSize: "1rem",
|
|
23403
|
+
lineHeight: 1.7,
|
|
23404
|
+
fontWeight: 300,
|
|
23405
|
+
color: "var(--brand-text-muted)",
|
|
23406
|
+
maxWidth: "340px"
|
|
23407
|
+
},
|
|
23408
|
+
...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
|
|
23409
|
+
children: "This page doesn't have any content yet."
|
|
23410
|
+
}
|
|
23411
|
+
)
|
|
23412
|
+
] });
|
|
23413
|
+
}
|
|
22334
23414
|
export {
|
|
22335
23415
|
AI_DEFAULT_BRAND,
|
|
22336
23416
|
AI_TREE_SCHEMA_VERSIONS,
|
|
@@ -22347,6 +23427,7 @@ export {
|
|
|
22347
23427
|
DropdownMenuItem,
|
|
22348
23428
|
DropdownMenuSeparator,
|
|
22349
23429
|
DropdownMenuTrigger,
|
|
23430
|
+
EmptySection,
|
|
22350
23431
|
ItemActionToolbar,
|
|
22351
23432
|
ItemInteractionLayer,
|
|
22352
23433
|
LinkEditorPanel,
|