@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.cjs
CHANGED
|
@@ -46,6 +46,7 @@ __export(index_exports, {
|
|
|
46
46
|
DropdownMenuItem: () => DropdownMenuItem,
|
|
47
47
|
DropdownMenuSeparator: () => DropdownMenuSeparator,
|
|
48
48
|
DropdownMenuTrigger: () => DropdownMenuTrigger,
|
|
49
|
+
EmptySection: () => EmptySection,
|
|
49
50
|
ItemActionToolbar: () => ItemActionToolbar,
|
|
50
51
|
ItemInteractionLayer: () => ItemInteractionLayer,
|
|
51
52
|
LinkEditorPanel: () => LinkEditorPanel,
|
|
@@ -143,6 +144,9 @@ function isRenderableTree(value) {
|
|
|
143
144
|
// src/lib/ai-sections-store.ts
|
|
144
145
|
var AI_SECTIONS_KEY = "__ohw_ai_sections";
|
|
145
146
|
var AI_SLOT_KEY_PREFIX = "ai.";
|
|
147
|
+
function aiSlotKeyPrefixFor(sectionId) {
|
|
148
|
+
return `${AI_SLOT_KEY_PREFIX}${sectionId}.`;
|
|
149
|
+
}
|
|
146
150
|
var EMPTY_AI_SECTIONS = { v: 1, sections: [] };
|
|
147
151
|
function parseAiSectionsState(raw) {
|
|
148
152
|
if (!raw) return EMPTY_AI_SECTIONS;
|
|
@@ -254,6 +258,33 @@ function deleteSectionFromState(state, sectionId) {
|
|
|
254
258
|
if (removed.includes(sectionId)) return state;
|
|
255
259
|
return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
|
|
256
260
|
}
|
|
261
|
+
function reapRemovedAiSections(state, store, removedIds, excludeIds = /* @__PURE__ */ new Set()) {
|
|
262
|
+
const generated = new Set(state.sections.map((entry) => entry.id));
|
|
263
|
+
const reapedIds = [...new Set(removedIds)].filter((id) => generated.has(id) && !excludeIds.has(id));
|
|
264
|
+
if (reapedIds.length === 0) {
|
|
265
|
+
return { state, store, reapedIds: [], slotPrefixes: [], changed: false };
|
|
266
|
+
}
|
|
267
|
+
const reaped = new Set(reapedIds);
|
|
268
|
+
const slotPrefixes = reapedIds.map(aiSlotKeyPrefixFor);
|
|
269
|
+
const nextState = {
|
|
270
|
+
...state,
|
|
271
|
+
v: 1,
|
|
272
|
+
sections: state.sections.filter((entry) => !reaped.has(entry.id))
|
|
273
|
+
};
|
|
274
|
+
let nextStore = store;
|
|
275
|
+
if (store) {
|
|
276
|
+
const sections = {};
|
|
277
|
+
for (const [key, override] of Object.entries(store.sections)) {
|
|
278
|
+
if (!reaped.has(key)) sections[key] = override;
|
|
279
|
+
}
|
|
280
|
+
const nodes = {};
|
|
281
|
+
for (const [key, override] of Object.entries(store.nodes)) {
|
|
282
|
+
if (!slotPrefixes.some((prefix) => key.startsWith(prefix))) nodes[key] = override;
|
|
283
|
+
}
|
|
284
|
+
nextStore = { v: 1, sections, nodes };
|
|
285
|
+
}
|
|
286
|
+
return { state: nextState, store: nextStore, reapedIds, slotPrefixes, changed: true };
|
|
287
|
+
}
|
|
257
288
|
|
|
258
289
|
// src/lib/brand-chrome.ts
|
|
259
290
|
var BRAND_NAME_KEY = "__ohw_brand_name";
|
|
@@ -322,16 +353,17 @@ var LEGACY_BRAND_VAR_NAMES = [
|
|
|
322
353
|
"text-muted",
|
|
323
354
|
"surface",
|
|
324
355
|
"border",
|
|
325
|
-
"on-primary"
|
|
326
|
-
"navbar-background"
|
|
356
|
+
"on-primary"
|
|
327
357
|
].map((role) => `--brand-${role}`);
|
|
328
358
|
var FONT_VARS = {
|
|
329
359
|
heading: ["--font-heading", "--font-display", "--brand-font-heading"],
|
|
330
360
|
body: ["--font-body", "--brand-font-body"]
|
|
331
361
|
};
|
|
332
362
|
var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
|
|
333
|
-
|
|
334
|
-
|
|
363
|
+
var CUSTOM_FONT_STYLE_ID = "ohw-brand-custom-fonts";
|
|
364
|
+
var CUSTOM_FONT_FORMATS = /* @__PURE__ */ new Set(["woff2", "woff", "truetype", "opentype"]);
|
|
365
|
+
function brandColorVars(palette) {
|
|
366
|
+
const { dark, primary, accent, light } = palette;
|
|
335
367
|
const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
|
|
336
368
|
const surface = mix(light, 95, dark);
|
|
337
369
|
const border = mix(light, 85, dark);
|
|
@@ -354,22 +386,42 @@ function brandColorVars(kit) {
|
|
|
354
386
|
"--brand-border": border,
|
|
355
387
|
// Buttons/bands painted in the primary colour assume it's dark/saturated enough to need
|
|
356
388
|
// light text on top — the same assumption LOGO_IMAGE's light-on-dark navbar mark makes.
|
|
357
|
-
"--brand-on-primary": light
|
|
358
|
-
"--brand-navbar-background": dark
|
|
389
|
+
"--brand-on-primary": light
|
|
359
390
|
};
|
|
360
391
|
}
|
|
392
|
+
function parseCustomFontWeight(raw) {
|
|
393
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
394
|
+
const w = raw;
|
|
395
|
+
if (typeof w.weight !== "number" || !Number.isFinite(w.weight)) return null;
|
|
396
|
+
if (typeof w.url !== "string" || !w.url) return null;
|
|
397
|
+
if (typeof w.format !== "string" || !CUSTOM_FONT_FORMATS.has(w.format)) return null;
|
|
398
|
+
const weightEnd = typeof w.weightEnd === "number" && Number.isFinite(w.weightEnd) && w.weightEnd > w.weight ? w.weightEnd : void 0;
|
|
399
|
+
return { weight: w.weight, ...weightEnd !== void 0 ? { weightEnd } : {}, url: w.url, format: w.format };
|
|
400
|
+
}
|
|
401
|
+
function parseCustomFont(raw) {
|
|
402
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
403
|
+
const f = raw;
|
|
404
|
+
if (typeof f.family !== "string" || !f.family) return null;
|
|
405
|
+
if (typeof f.label !== "string" || !f.label) return null;
|
|
406
|
+
if (!Array.isArray(f.weights)) return null;
|
|
407
|
+
const weights = f.weights.map(parseCustomFontWeight).filter((w) => w !== null);
|
|
408
|
+
if (weights.length === 0) return null;
|
|
409
|
+
return { family: f.family, label: f.label, weights };
|
|
410
|
+
}
|
|
361
411
|
function parseBrandKit(raw) {
|
|
362
412
|
if (!raw) return null;
|
|
363
413
|
try {
|
|
364
414
|
const parsed = JSON.parse(raw);
|
|
365
415
|
const p = parsed?.palette;
|
|
366
416
|
const f = parsed?.fonts;
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
417
|
+
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;
|
|
418
|
+
const fonts = f && typeof f.heading === "string" && typeof f.body === "string" ? { heading: f.heading, body: f.body } : void 0;
|
|
419
|
+
const customFonts = Array.isArray(parsed?.customFonts) ? parsed.customFonts.map(parseCustomFont).filter((c) => c !== null) : void 0;
|
|
420
|
+
if (!palette && !fonts && !customFonts) return null;
|
|
370
421
|
return {
|
|
371
|
-
palette
|
|
372
|
-
fonts
|
|
422
|
+
...palette ? { palette } : {},
|
|
423
|
+
...fonts ? { fonts } : {},
|
|
424
|
+
...customFonts ? { customFonts } : {}
|
|
373
425
|
};
|
|
374
426
|
} catch {
|
|
375
427
|
return null;
|
|
@@ -379,11 +431,16 @@ function familyOf(stack) {
|
|
|
379
431
|
const first = stack.split(",")[0]?.trim() ?? "";
|
|
380
432
|
return first.replace(/^['"]|['"]$/g, "");
|
|
381
433
|
}
|
|
434
|
+
function quoteFamily(family) {
|
|
435
|
+
return `'${family.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
436
|
+
}
|
|
437
|
+
var WEIGHT_SCALE = [100, 200, 300, 400, 500, 600, 700, 800, 900];
|
|
382
438
|
function loadBrandFonts(families) {
|
|
383
439
|
const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
|
|
384
440
|
if (unique.length === 0) return;
|
|
385
|
-
const
|
|
386
|
-
const
|
|
441
|
+
const weights = WEIGHT_SCALE.join(";");
|
|
442
|
+
const spec = unique.map((f) => `family=${f.replace(/ /g, "+")}:wght@${weights}`).join("&");
|
|
443
|
+
const href = `https://fonts.googleapis.com/css2?${spec}&display=swap`;
|
|
387
444
|
let link = document.getElementById(BRAND_FONT_LINK_ID);
|
|
388
445
|
if (!link) {
|
|
389
446
|
link = document.createElement("link");
|
|
@@ -393,18 +450,54 @@ function loadBrandFonts(families) {
|
|
|
393
450
|
}
|
|
394
451
|
if (link.href !== href) link.href = href;
|
|
395
452
|
}
|
|
453
|
+
function escapeCssString(value) {
|
|
454
|
+
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
455
|
+
}
|
|
456
|
+
function loadCustomFonts(fonts) {
|
|
457
|
+
const list = fonts ?? [];
|
|
458
|
+
let style = document.getElementById(CUSTOM_FONT_STYLE_ID);
|
|
459
|
+
if (list.length === 0) {
|
|
460
|
+
style?.remove();
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
if (!style) {
|
|
464
|
+
style = document.createElement("style");
|
|
465
|
+
style.id = CUSTOM_FONT_STYLE_ID;
|
|
466
|
+
document.head.appendChild(style);
|
|
467
|
+
}
|
|
468
|
+
style.textContent = list.flatMap(
|
|
469
|
+
(font) => font.weights.map((w) => {
|
|
470
|
+
const weightDescriptor = w.weightEnd ? `${w.weight} ${w.weightEnd}` : `${w.weight}`;
|
|
471
|
+
return `@font-face { font-family: '${escapeCssString(font.family)}'; src: url('${escapeCssString(w.url)}') format('${w.format}'); font-weight: ${weightDescriptor}; font-display: swap; }`;
|
|
472
|
+
})
|
|
473
|
+
).join("\n");
|
|
474
|
+
}
|
|
396
475
|
function applyBrandToDom(kit) {
|
|
397
476
|
const root = document.documentElement;
|
|
398
477
|
if (!kit) {
|
|
399
478
|
for (const name of [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES]) root.style.removeProperty(name);
|
|
400
479
|
for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
|
|
401
480
|
document.getElementById(BRAND_FONT_LINK_ID)?.remove();
|
|
481
|
+
document.getElementById(CUSTOM_FONT_STYLE_ID)?.remove();
|
|
402
482
|
return;
|
|
403
483
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
484
|
+
if (kit.palette) {
|
|
485
|
+
for (const [name, value] of Object.entries(brandColorVars(kit.palette))) root.style.setProperty(name, value);
|
|
486
|
+
}
|
|
487
|
+
if (kit.customFonts) {
|
|
488
|
+
loadCustomFonts(kit.customFonts);
|
|
489
|
+
}
|
|
490
|
+
if (kit.fonts) {
|
|
491
|
+
const heading = quoteFamily(kit.fonts.heading);
|
|
492
|
+
const body = quoteFamily(kit.fonts.body);
|
|
493
|
+
for (const name of FONT_VARS.heading) root.style.setProperty(name, heading);
|
|
494
|
+
for (const name of FONT_VARS.body) root.style.setProperty(name, body);
|
|
495
|
+
const customFamilies = new Set((kit.customFonts ?? []).map((f) => f.family));
|
|
496
|
+
const googleFamilies = [familyOf(kit.fonts.heading), familyOf(kit.fonts.body)].filter(
|
|
497
|
+
(f) => !customFamilies.has(f)
|
|
498
|
+
);
|
|
499
|
+
loadBrandFonts(googleFamilies);
|
|
500
|
+
}
|
|
408
501
|
}
|
|
409
502
|
|
|
410
503
|
// src/lib/section-styles.ts
|
|
@@ -461,6 +554,12 @@ function styleSheetCss() {
|
|
|
461
554
|
`[data-ohw-style-spacing="${spacing}"] { padding-top: ${px}px !important; padding-bottom: ${px}px !important; }`
|
|
462
555
|
);
|
|
463
556
|
}
|
|
557
|
+
rules.push(
|
|
558
|
+
`[data-ohw-style-corners="sharp"] :is(.card, [data-ohw-card], img, picture, figure, [data-ohw-editable="bg-image"]) { border-radius: 0 !important; }`,
|
|
559
|
+
`[data-ohw-style-corners="sharp"] :has(> img) { border-radius: 0 !important; }`,
|
|
560
|
+
`[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; }`,
|
|
561
|
+
`[data-ohw-style-corners="rounded"] :has(> img) { border-radius: max(0.75rem, var(--radius, 0px)) !important; }`
|
|
562
|
+
);
|
|
464
563
|
for (const align of ["left", "center", "right"]) {
|
|
465
564
|
rules.push(`[data-ohw-style-align="${align}"] { text-align: ${align} !important; }`);
|
|
466
565
|
}
|
|
@@ -491,6 +590,7 @@ var SECTION_ATTRS = {
|
|
|
491
590
|
headlineScale: "data-ohw-style-headline",
|
|
492
591
|
imageAspect: "data-ohw-style-aspect",
|
|
493
592
|
spacing: "data-ohw-style-spacing",
|
|
593
|
+
cornerStyle: "data-ohw-style-corners",
|
|
494
594
|
align: "data-ohw-style-align"
|
|
495
595
|
};
|
|
496
596
|
var NODE_WROTE_ATTR = "data-ohw-style-node";
|
|
@@ -553,14 +653,39 @@ function buttonSurfaceOf(el) {
|
|
|
553
653
|
}
|
|
554
654
|
function alignSubjectOf(el) {
|
|
555
655
|
const button = el.closest('[data-ohw-role="button"]');
|
|
556
|
-
|
|
656
|
+
if (button?.parentElement) return button.parentElement;
|
|
657
|
+
let subject = el;
|
|
658
|
+
while (subject.parentElement && !subject.parentElement.hasAttribute("data-ohw-section") && /^inline/.test(getComputedStyle(subject).display)) {
|
|
659
|
+
subject = subject.parentElement;
|
|
660
|
+
}
|
|
661
|
+
const TEXT_ROW = /^(P|LI|H[1-6]|BLOCKQUOTE|FIGCAPTION|DT|DD)$/;
|
|
662
|
+
const parent = subject.parentElement;
|
|
663
|
+
if (parent && TEXT_ROW.test(parent.tagName) && /^(inline-)?flex$/.test(getComputedStyle(parent).display)) {
|
|
664
|
+
return parent;
|
|
665
|
+
}
|
|
666
|
+
if (parent && !parent.hasAttribute("data-ohw-section")) {
|
|
667
|
+
const pcs = getComputedStyle(parent);
|
|
668
|
+
const children = Array.from(parent.children);
|
|
669
|
+
const textRowChild = (c) => c.hasAttribute("data-ohw-editable") || (c.textContent ?? "").trim().length === 0 || c.getAttribute("aria-hidden") === "true";
|
|
670
|
+
if (/^(inline-)?flex$/.test(pcs.display) && pcs.flexDirection.startsWith("row") && children.length > 0 && children.some((c) => c.hasAttribute("data-ohw-editable")) && children.every(textRowChild)) {
|
|
671
|
+
return parent;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
const row = subject.closest("li");
|
|
675
|
+
if (row && row !== subject && /^(inline-)?flex$/.test(getComputedStyle(row).display)) {
|
|
676
|
+
return row;
|
|
677
|
+
}
|
|
678
|
+
return subject;
|
|
557
679
|
}
|
|
558
680
|
function applyStylesToDom(store) {
|
|
559
681
|
ensureStyleSheet();
|
|
560
682
|
clearSectionAttrs(document);
|
|
561
683
|
clearNodeProps(document);
|
|
562
684
|
loadStyleFonts(
|
|
563
|
-
store ?
|
|
685
|
+
store ? [
|
|
686
|
+
...Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []),
|
|
687
|
+
...Object.values(store.sections).flatMap((s) => s.fontFamily ? [s.fontFamily] : [])
|
|
688
|
+
] : []
|
|
564
689
|
);
|
|
565
690
|
if (!store) return;
|
|
566
691
|
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
@@ -580,6 +705,23 @@ function applyStylesToDom(store) {
|
|
|
580
705
|
section.style.setProperty("background", override.sectionBackgroundColor, "important");
|
|
581
706
|
section.setAttribute("data-ohw-style-bgcolor", "");
|
|
582
707
|
}
|
|
708
|
+
if (override.textColor !== void 0 || override.fontFamily !== void 0) {
|
|
709
|
+
const textEls = marker.querySelectorAll(
|
|
710
|
+
'[data-ohw-editable="text"], [data-ohw-editable="plain"], [data-ohw-field-label]'
|
|
711
|
+
);
|
|
712
|
+
for (const el of Array.from(textEls)) {
|
|
713
|
+
if (override.textColor !== void 0) {
|
|
714
|
+
saveInline(el, "color");
|
|
715
|
+
el.style.setProperty("color", override.textColor, "important");
|
|
716
|
+
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
717
|
+
}
|
|
718
|
+
if (override.fontFamily !== void 0) {
|
|
719
|
+
saveInline(el, "font-family");
|
|
720
|
+
el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
|
|
721
|
+
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
583
725
|
}
|
|
584
726
|
}
|
|
585
727
|
for (const [key, override] of Object.entries(store.nodes)) {
|
|
@@ -626,15 +768,557 @@ function applyStylesToDom(store) {
|
|
|
626
768
|
}
|
|
627
769
|
}
|
|
628
770
|
}
|
|
771
|
+
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
772
|
+
if (override.headingColor === void 0) continue;
|
|
773
|
+
const escaped = CSS.escape(sectionId);
|
|
774
|
+
const byInstance = document.querySelectorAll(`[data-ohw-instance="${escaped}"]`);
|
|
775
|
+
const sections = byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`);
|
|
776
|
+
for (const marker of Array.from(sections)) {
|
|
777
|
+
const headings = marker.querySelectorAll(
|
|
778
|
+
":is(h1, h2, h3, h4, h5, h6)[data-ohw-editable], :is(h1, h2, h3, h4, h5, h6) > [data-ohw-editable]"
|
|
779
|
+
);
|
|
780
|
+
for (const el of Array.from(headings)) {
|
|
781
|
+
saveInline(el, "color");
|
|
782
|
+
el.style.setProperty("color", override.headingColor, "important");
|
|
783
|
+
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
629
787
|
}
|
|
630
788
|
|
|
631
789
|
// src/ui/ai-tree/aiSectionsManager.tsx
|
|
632
790
|
var import_react_dom = require("react-dom");
|
|
633
791
|
var import_client = require("react-dom/client");
|
|
634
792
|
|
|
793
|
+
// src/lib/sections.ts
|
|
794
|
+
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
795
|
+
function isChromeSection(el) {
|
|
796
|
+
return el.matches("header, nav, footer, aside");
|
|
797
|
+
}
|
|
798
|
+
function titleCaseSectionId(id) {
|
|
799
|
+
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
800
|
+
}
|
|
801
|
+
function parseSectionsFromRoot(root) {
|
|
802
|
+
const seen = /* @__PURE__ */ new Set();
|
|
803
|
+
const sections = [];
|
|
804
|
+
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
805
|
+
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
806
|
+
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
807
|
+
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
808
|
+
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
809
|
+
continue;
|
|
810
|
+
seen.add(id);
|
|
811
|
+
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
812
|
+
sections.push({ id, label });
|
|
813
|
+
}
|
|
814
|
+
return sections;
|
|
815
|
+
}
|
|
816
|
+
function collectSectionsFromDom() {
|
|
817
|
+
if (typeof document === "undefined") return [];
|
|
818
|
+
return parseSectionsFromRoot(document);
|
|
819
|
+
}
|
|
820
|
+
function parseSectionsFromHtml(html) {
|
|
821
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
822
|
+
return parseSectionsFromRoot(doc);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// src/lib/section-instances.ts
|
|
826
|
+
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
827
|
+
var REMOVED_ATTR = "data-ohw-section-removed";
|
|
828
|
+
function isRemovedSection(el) {
|
|
829
|
+
return el.hasAttribute(REMOVED_ATTR);
|
|
830
|
+
}
|
|
831
|
+
function movableUnit(el) {
|
|
832
|
+
return el.closest("[data-ohw-section-container]") ?? el;
|
|
833
|
+
}
|
|
834
|
+
function sectionTypeOf(el) {
|
|
835
|
+
return el.getAttribute("data-ohw-section") ?? el.querySelector("[data-ohw-section]")?.getAttribute("data-ohw-section") ?? "";
|
|
836
|
+
}
|
|
837
|
+
function sectionElementOf(el) {
|
|
838
|
+
return el.hasAttribute("data-ohw-section") ? el : el.querySelector("[data-ohw-section]") ?? el;
|
|
839
|
+
}
|
|
840
|
+
function collectTopLevelUnits(predicate) {
|
|
841
|
+
const seen = /* @__PURE__ */ new Set();
|
|
842
|
+
const result = [];
|
|
843
|
+
document.querySelectorAll("[data-ohw-section]").forEach((el) => {
|
|
844
|
+
if (!predicate(el)) return;
|
|
845
|
+
const unit = movableUnit(el);
|
|
846
|
+
if (unit.parentElement?.closest("[data-ohw-section],[data-ohw-section-container]")) return;
|
|
847
|
+
if (seen.has(unit)) return;
|
|
848
|
+
seen.add(unit);
|
|
849
|
+
result.push(unit);
|
|
850
|
+
});
|
|
851
|
+
return result;
|
|
852
|
+
}
|
|
853
|
+
function topLevelSections() {
|
|
854
|
+
return collectTopLevelUnits((el) => !isChromeSection(el) && !isRemovedSection(movableUnit(el)));
|
|
855
|
+
}
|
|
856
|
+
function instanceIdOf(el) {
|
|
857
|
+
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
858
|
+
}
|
|
859
|
+
function findByInstanceId(instanceId) {
|
|
860
|
+
const escapedId = CSS.escape(instanceId);
|
|
861
|
+
const direct = document.querySelector(`[data-ohw-instance="${escapedId}"]`);
|
|
862
|
+
if (direct) return movableUnit(direct);
|
|
863
|
+
const bare = document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
864
|
+
return bare ? movableUnit(bare) : null;
|
|
865
|
+
}
|
|
866
|
+
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
867
|
+
const sections = topLevelSections();
|
|
868
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
869
|
+
if (index === -1) return null;
|
|
870
|
+
const dragged = sections[index];
|
|
871
|
+
const others = sections.filter((_, i) => i !== index);
|
|
872
|
+
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
873
|
+
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
874
|
+
return reordered.map((el, order) => ({
|
|
875
|
+
instanceId: instanceIdOf(el),
|
|
876
|
+
type: sectionTypeOf(el),
|
|
877
|
+
order,
|
|
878
|
+
pagePath: currentPath
|
|
879
|
+
}));
|
|
880
|
+
}
|
|
881
|
+
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
882
|
+
const sections = topLevelSections();
|
|
883
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
884
|
+
if (index === -1) return null;
|
|
885
|
+
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
886
|
+
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
887
|
+
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
888
|
+
if (!entries) return null;
|
|
889
|
+
applyPersistedOrder(entries);
|
|
890
|
+
return entries;
|
|
891
|
+
}
|
|
892
|
+
function syncRemovedFlags(entries) {
|
|
893
|
+
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
894
|
+
document.querySelectorAll(`[${REMOVED_ATTR}]`).forEach((el) => {
|
|
895
|
+
if (!removedIds.has(instanceIdOf(el))) {
|
|
896
|
+
el.style.removeProperty("display");
|
|
897
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
898
|
+
}
|
|
899
|
+
});
|
|
900
|
+
for (const id of removedIds) {
|
|
901
|
+
const el = findByInstanceId(id);
|
|
902
|
+
if (el) {
|
|
903
|
+
el.style.display = "none";
|
|
904
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
function applyPersistedOrder(entries) {
|
|
909
|
+
syncRemovedFlags(entries);
|
|
910
|
+
if (entries.length === 0) return;
|
|
911
|
+
const sections = topLevelSections();
|
|
912
|
+
if (sections.length === 0) return;
|
|
913
|
+
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
914
|
+
const ordered = [...sections].sort((a, b) => {
|
|
915
|
+
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
916
|
+
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
917
|
+
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
918
|
+
if (aOrder === void 0) return 1;
|
|
919
|
+
if (bOrder === void 0) return -1;
|
|
920
|
+
return aOrder - bOrder;
|
|
921
|
+
});
|
|
922
|
+
let prev = null;
|
|
923
|
+
for (const el of ordered) {
|
|
924
|
+
if (prev) prev.after(el);
|
|
925
|
+
prev = el;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
929
|
+
if (!findByInstanceId(instanceId)) return null;
|
|
930
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
931
|
+
const allSections = collectTopLevelUnits((el) => !isChromeSection(el));
|
|
932
|
+
allSections.forEach((el, order) => {
|
|
933
|
+
const id = instanceIdOf(el);
|
|
934
|
+
if (!byId.has(id)) {
|
|
935
|
+
byId.set(id, { instanceId: id, type: sectionTypeOf(el), order, pagePath: currentPath });
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
const target = byId.get(instanceId);
|
|
939
|
+
if (!target) return null;
|
|
940
|
+
byId.set(instanceId, { ...target, removed });
|
|
941
|
+
const entries = Array.from(byId.values());
|
|
942
|
+
applyPersistedOrder(entries);
|
|
943
|
+
return entries;
|
|
944
|
+
}
|
|
945
|
+
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
946
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
947
|
+
}
|
|
948
|
+
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
949
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
950
|
+
}
|
|
951
|
+
function duplicateSectionInstance(instanceId, newId, currentPath, existingEntries) {
|
|
952
|
+
const original = findByInstanceId(instanceId);
|
|
953
|
+
if (!original) return null;
|
|
954
|
+
const clone = original.cloneNode(true);
|
|
955
|
+
clone.setAttribute("data-ohw-instance", newId);
|
|
956
|
+
const keyRekeys = rekeySectionSubtree(clone, newId);
|
|
957
|
+
original.insertAdjacentElement("afterend", clone);
|
|
958
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
959
|
+
const entries = topLevelSections().map((el, order) => {
|
|
960
|
+
const id = instanceIdOf(el);
|
|
961
|
+
return {
|
|
962
|
+
instanceId: id,
|
|
963
|
+
type: sectionTypeOf(el),
|
|
964
|
+
order,
|
|
965
|
+
pagePath: currentPath,
|
|
966
|
+
...byId.get(id)?.removed ? { removed: true } : {}
|
|
967
|
+
};
|
|
968
|
+
});
|
|
969
|
+
applyPersistedOrder(entries);
|
|
970
|
+
return { entries, keyRekeys };
|
|
971
|
+
}
|
|
972
|
+
function newInstanceId() {
|
|
973
|
+
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
974
|
+
}
|
|
975
|
+
function getPageSectionOrderEntries(raw, currentPath) {
|
|
976
|
+
if (!raw) return [];
|
|
977
|
+
try {
|
|
978
|
+
const entries = JSON.parse(raw);
|
|
979
|
+
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
980
|
+
} catch {
|
|
981
|
+
return [];
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
function mergePageSectionOrder(raw, currentPath, pageEntries) {
|
|
985
|
+
let all = [];
|
|
986
|
+
if (raw) {
|
|
987
|
+
try {
|
|
988
|
+
const parsed = JSON.parse(raw);
|
|
989
|
+
if (Array.isArray(parsed)) all = parsed;
|
|
990
|
+
} catch {
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
const otherPages = all.filter((e) => e && e.pagePath && e.pagePath !== currentPath);
|
|
994
|
+
const pageIds = new Set(pageEntries.map((e) => e.instanceId));
|
|
995
|
+
const removedHere = all.filter(
|
|
996
|
+
(e) => e && (!e.pagePath || e.pagePath === currentPath) && e.removed && !pageIds.has(e.instanceId)
|
|
997
|
+
);
|
|
998
|
+
return [...otherPages, ...removedHere, ...pageEntries];
|
|
999
|
+
}
|
|
1000
|
+
function rekeySectionSubtree(root, instanceId) {
|
|
1001
|
+
const suffix = `::${instanceId}`;
|
|
1002
|
+
const pairs = [];
|
|
1003
|
+
const rekey = (el, attr) => {
|
|
1004
|
+
const current = el.getAttribute(attr);
|
|
1005
|
+
if (!current) return;
|
|
1006
|
+
const base = current.includes("::") ? current.slice(0, current.indexOf("::")) : current;
|
|
1007
|
+
const next = `${base}${suffix}`;
|
|
1008
|
+
el.setAttribute(attr, next);
|
|
1009
|
+
pairs.push({ from: current, to: next });
|
|
1010
|
+
};
|
|
1011
|
+
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
1012
|
+
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
1013
|
+
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
1014
|
+
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
1015
|
+
return pairs;
|
|
1016
|
+
}
|
|
1017
|
+
function initSectionInstancesFromContent(content, currentPath) {
|
|
1018
|
+
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
1019
|
+
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
1020
|
+
});
|
|
1021
|
+
document.querySelectorAll("[data-ohw-section-container]:not([data-ohw-instance])").forEach((el) => {
|
|
1022
|
+
const type = sectionTypeOf(el);
|
|
1023
|
+
if (type) el.setAttribute("data-ohw-instance", type);
|
|
1024
|
+
});
|
|
1025
|
+
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
1026
|
+
for (const entry of entries) {
|
|
1027
|
+
if (entry.instanceId === entry.type) continue;
|
|
1028
|
+
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
1029
|
+
const original = document.querySelector(
|
|
1030
|
+
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
1031
|
+
);
|
|
1032
|
+
if (!original) continue;
|
|
1033
|
+
const clone = original.cloneNode(true);
|
|
1034
|
+
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
1035
|
+
rekeySectionSubtree(clone, entry.instanceId);
|
|
1036
|
+
original.insertAdjacentElement("afterend", clone);
|
|
1037
|
+
}
|
|
1038
|
+
applyPersistedOrder(entries);
|
|
1039
|
+
}
|
|
1040
|
+
|
|
635
1041
|
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
636
1042
|
var import_react = __toESM(require("react"), 1);
|
|
637
1043
|
var import_lucide_react = require("lucide-react");
|
|
1044
|
+
|
|
1045
|
+
// src/lib/placeholder-imagery.ts
|
|
1046
|
+
var U = (id) => `https://images.unsplash.com/photo-${id}?auto=format&fit=crop&w=1600&q=80`;
|
|
1047
|
+
var GENERIC = [
|
|
1048
|
+
U("1441986300917-64674bd600d8"),
|
|
1049
|
+
U("1486406146926-c627a92ad1ab"),
|
|
1050
|
+
U("1497032628192-86f99bcd76bc"),
|
|
1051
|
+
U("1521737604893-d14cc237f11d"),
|
|
1052
|
+
U("1522071820081-009f0129c71c"),
|
|
1053
|
+
U("1519389950473-47ba0277781c"),
|
|
1054
|
+
U("1460925895917-afdab827c52f"),
|
|
1055
|
+
U("1504384308090-c894fdcc538d")
|
|
1056
|
+
];
|
|
1057
|
+
var PEOPLE = [
|
|
1058
|
+
U("1500648767791-00dcc994a43e"),
|
|
1059
|
+
U("1494790108377-be9c29b29330"),
|
|
1060
|
+
U("1507003211169-0a1dd7228f2d"),
|
|
1061
|
+
U("1438761681033-6461ffad8d80"),
|
|
1062
|
+
U("1544005313-94ddf0286df2"),
|
|
1063
|
+
U("1472099645785-5658abf4ff4e"),
|
|
1064
|
+
U("1519085360753-af0119f7cbe7"),
|
|
1065
|
+
U("1534528741775-53994a69daeb")
|
|
1066
|
+
];
|
|
1067
|
+
var THEMED = [
|
|
1068
|
+
{
|
|
1069
|
+
keywords: ["portrait", "headshot", "person", "people", "team", "staff", "avatar", "founder", "face"],
|
|
1070
|
+
pool: PEOPLE
|
|
1071
|
+
},
|
|
1072
|
+
{
|
|
1073
|
+
keywords: ["pet", "dog", "cat", "puppy", "kitten", "vet", "animal"],
|
|
1074
|
+
pool: [
|
|
1075
|
+
U("1548199973-03cce0bbc87b"),
|
|
1076
|
+
U("1450778869180-41d0601e046e"),
|
|
1077
|
+
U("1583511655857-d19b40a7a54e"),
|
|
1078
|
+
U("1587300003388-59208cc962cb"),
|
|
1079
|
+
U("1517849845537-4d257902454a"),
|
|
1080
|
+
U("1601758228041-f3b2795255f1")
|
|
1081
|
+
]
|
|
1082
|
+
},
|
|
1083
|
+
{
|
|
1084
|
+
keywords: [
|
|
1085
|
+
"baker",
|
|
1086
|
+
"bakery",
|
|
1087
|
+
"cafe",
|
|
1088
|
+
"coffee",
|
|
1089
|
+
"latte",
|
|
1090
|
+
"restaurant",
|
|
1091
|
+
"pastr",
|
|
1092
|
+
"bread",
|
|
1093
|
+
"cake",
|
|
1094
|
+
"cater",
|
|
1095
|
+
"chef",
|
|
1096
|
+
"kitchen",
|
|
1097
|
+
"food",
|
|
1098
|
+
"pizza",
|
|
1099
|
+
"dessert",
|
|
1100
|
+
"brunch",
|
|
1101
|
+
"bistro",
|
|
1102
|
+
"deli",
|
|
1103
|
+
"dish",
|
|
1104
|
+
"menu"
|
|
1105
|
+
],
|
|
1106
|
+
pool: [
|
|
1107
|
+
U("1509440159596-0249088772ff"),
|
|
1108
|
+
U("1555507036-ab1f4038808a"),
|
|
1109
|
+
U("1517433670267-08bbd4be890f"),
|
|
1110
|
+
U("1486427944299-d1955d23e34d"),
|
|
1111
|
+
U("1504754524776-8f4f37790ca0"),
|
|
1112
|
+
U("1495474472287-4d71bcdd2085"),
|
|
1113
|
+
U("1521017432531-fbd92d768814"),
|
|
1114
|
+
U("1556909114-f6e7ad7d3136")
|
|
1115
|
+
]
|
|
1116
|
+
},
|
|
1117
|
+
{
|
|
1118
|
+
keywords: [
|
|
1119
|
+
"shop",
|
|
1120
|
+
"store",
|
|
1121
|
+
"boutique",
|
|
1122
|
+
"retail",
|
|
1123
|
+
"clothing",
|
|
1124
|
+
"fashion",
|
|
1125
|
+
"jewel",
|
|
1126
|
+
"gift",
|
|
1127
|
+
"florist",
|
|
1128
|
+
"market",
|
|
1129
|
+
"grocer",
|
|
1130
|
+
"product",
|
|
1131
|
+
"storefront"
|
|
1132
|
+
],
|
|
1133
|
+
pool: [
|
|
1134
|
+
U("1441984904996-e0b6ba687e04"),
|
|
1135
|
+
U("1472851294608-062f824d29cc"),
|
|
1136
|
+
U("1523381210434-271e8be1f52b"),
|
|
1137
|
+
U("1534452203293-494d7ddbf7e0"),
|
|
1138
|
+
U("1445205170230-053b83016050"),
|
|
1139
|
+
U("1560243563-062bfc001d68")
|
|
1140
|
+
]
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
keywords: [
|
|
1144
|
+
"yoga",
|
|
1145
|
+
"pilates",
|
|
1146
|
+
"fitness",
|
|
1147
|
+
"gym",
|
|
1148
|
+
"workout",
|
|
1149
|
+
"trainer",
|
|
1150
|
+
"wellness",
|
|
1151
|
+
"meditat",
|
|
1152
|
+
"massage",
|
|
1153
|
+
"therap",
|
|
1154
|
+
"physio",
|
|
1155
|
+
"chiro",
|
|
1156
|
+
"nutrition",
|
|
1157
|
+
"spa",
|
|
1158
|
+
"studio"
|
|
1159
|
+
],
|
|
1160
|
+
pool: [
|
|
1161
|
+
U("1544367567-0f2fcb009e0b"),
|
|
1162
|
+
U("1506126613408-eca07ce68773"),
|
|
1163
|
+
U("1545205597-3d9d02c29597"),
|
|
1164
|
+
U("1552196563-55cd4e45efb3"),
|
|
1165
|
+
U("1518611012118-696072aa579a"),
|
|
1166
|
+
U("1571019613454-1cb2f99b2d8b"),
|
|
1167
|
+
U("1540555700478-4be289fbecef"),
|
|
1168
|
+
U("1519824145371-296894a0daa9")
|
|
1169
|
+
]
|
|
1170
|
+
},
|
|
1171
|
+
{
|
|
1172
|
+
keywords: [
|
|
1173
|
+
"salon",
|
|
1174
|
+
"hairdress",
|
|
1175
|
+
"haircut",
|
|
1176
|
+
"barber",
|
|
1177
|
+
"manicure",
|
|
1178
|
+
"pedicure",
|
|
1179
|
+
"nails",
|
|
1180
|
+
"beauty",
|
|
1181
|
+
"makeup",
|
|
1182
|
+
"cosmetic",
|
|
1183
|
+
"eyelash",
|
|
1184
|
+
"eyebrow",
|
|
1185
|
+
"skincare",
|
|
1186
|
+
"esthetic",
|
|
1187
|
+
"waxing",
|
|
1188
|
+
"hair"
|
|
1189
|
+
],
|
|
1190
|
+
pool: [
|
|
1191
|
+
U("1560066984-138dadb4c035"),
|
|
1192
|
+
U("1522337660859-02fbefca4702"),
|
|
1193
|
+
U("1562322140-8baeececf3df"),
|
|
1194
|
+
U("1521590832167-7bcbfaa6381f"),
|
|
1195
|
+
U("1487412947147-5cebf100ffc2"),
|
|
1196
|
+
U("1526045478516-99145907023c")
|
|
1197
|
+
]
|
|
1198
|
+
},
|
|
1199
|
+
{
|
|
1200
|
+
keywords: [
|
|
1201
|
+
"cleaning",
|
|
1202
|
+
"plumb",
|
|
1203
|
+
"electric",
|
|
1204
|
+
"landscap",
|
|
1205
|
+
"contractor",
|
|
1206
|
+
"handyman",
|
|
1207
|
+
"renov",
|
|
1208
|
+
"hvac",
|
|
1209
|
+
"roofing",
|
|
1210
|
+
"painting",
|
|
1211
|
+
"carpentry",
|
|
1212
|
+
"flooring",
|
|
1213
|
+
"movers",
|
|
1214
|
+
"construction",
|
|
1215
|
+
"tools"
|
|
1216
|
+
],
|
|
1217
|
+
pool: [
|
|
1218
|
+
U("1581578731548-c64695cc6952"),
|
|
1219
|
+
U("1504307651254-35680f356dfd"),
|
|
1220
|
+
U("1581092160562-40aa08e78837"),
|
|
1221
|
+
U("1621905251189-08b45d6a269e"),
|
|
1222
|
+
U("1558618666-fcd25c85cd64"),
|
|
1223
|
+
U("1585128792020-803d29415281")
|
|
1224
|
+
]
|
|
1225
|
+
},
|
|
1226
|
+
{
|
|
1227
|
+
keywords: [
|
|
1228
|
+
"legal",
|
|
1229
|
+
"attorney",
|
|
1230
|
+
"lawyer",
|
|
1231
|
+
"account",
|
|
1232
|
+
"bookkeep",
|
|
1233
|
+
"consult",
|
|
1234
|
+
"coaching",
|
|
1235
|
+
"financ",
|
|
1236
|
+
"insurance",
|
|
1237
|
+
"realtor",
|
|
1238
|
+
"estate",
|
|
1239
|
+
"marketing",
|
|
1240
|
+
"agency",
|
|
1241
|
+
"office",
|
|
1242
|
+
"business",
|
|
1243
|
+
"desk"
|
|
1244
|
+
],
|
|
1245
|
+
pool: [
|
|
1246
|
+
U("1497366216548-37526070297c"),
|
|
1247
|
+
U("1497366811353-6870744d04b2"),
|
|
1248
|
+
U("1454165804606-c3d57bc86b40"),
|
|
1249
|
+
U("1521791136064-7986c2920216"),
|
|
1250
|
+
U("1556761175-b413da4baf72"),
|
|
1251
|
+
U("1542744173-8e7e53415bb0")
|
|
1252
|
+
]
|
|
1253
|
+
},
|
|
1254
|
+
{
|
|
1255
|
+
keywords: [
|
|
1256
|
+
"wedding",
|
|
1257
|
+
"event",
|
|
1258
|
+
"party",
|
|
1259
|
+
"celebrat",
|
|
1260
|
+
"venue",
|
|
1261
|
+
"community",
|
|
1262
|
+
"nonprofit",
|
|
1263
|
+
"charity",
|
|
1264
|
+
"workshop",
|
|
1265
|
+
"photograph",
|
|
1266
|
+
"concert"
|
|
1267
|
+
],
|
|
1268
|
+
pool: [
|
|
1269
|
+
U("1511578314322-379afb476865"),
|
|
1270
|
+
U("1501281668745-f7f57925c3b4"),
|
|
1271
|
+
U("1523580494863-6f3031224c94"),
|
|
1272
|
+
U("1540575467063-178a50c2df87"),
|
|
1273
|
+
U("1505236858219-8359eb29e329"),
|
|
1274
|
+
U("1528605248644-14dd04022da1")
|
|
1275
|
+
]
|
|
1276
|
+
}
|
|
1277
|
+
];
|
|
1278
|
+
function poolForSubject(subject) {
|
|
1279
|
+
for (const theme of THEMED) {
|
|
1280
|
+
if (theme.keywords.some((k) => subject.includes(k))) {
|
|
1281
|
+
return theme.pool;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
return GENERIC;
|
|
1285
|
+
}
|
|
1286
|
+
function mixedHash(text) {
|
|
1287
|
+
let hash = 2166136261;
|
|
1288
|
+
for (let i = 0; i < text.length; i++) {
|
|
1289
|
+
hash ^= text.charCodeAt(i);
|
|
1290
|
+
hash = Math.imul(hash, 16777619);
|
|
1291
|
+
}
|
|
1292
|
+
return hash >>> 16 & 65535;
|
|
1293
|
+
}
|
|
1294
|
+
function resolvePlaceholderRef(ref) {
|
|
1295
|
+
const match = /^placeholder:([a-z0-9-]+)$/.exec(ref);
|
|
1296
|
+
if (!match) return null;
|
|
1297
|
+
const subject = match[1];
|
|
1298
|
+
const pool = poolForSubject(subject.replace(/-\d+$/, ""));
|
|
1299
|
+
return pool[mixedHash(ref) % pool.length];
|
|
1300
|
+
}
|
|
1301
|
+
function collectPlaceholderRefs(tree) {
|
|
1302
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1303
|
+
for (const match of JSON.stringify(tree ?? null).matchAll(/"(placeholder:[a-z0-9-]+)"/gu)) {
|
|
1304
|
+
seen.add(match[1]);
|
|
1305
|
+
}
|
|
1306
|
+
return [...seen];
|
|
1307
|
+
}
|
|
1308
|
+
function buildPlaceholderMap(tree) {
|
|
1309
|
+
const map = {};
|
|
1310
|
+
const cursor = /* @__PURE__ */ new Map();
|
|
1311
|
+
for (const ref of collectPlaceholderRefs(tree)) {
|
|
1312
|
+
const subject = ref.slice("placeholder:".length).replace(/-\d+$/, "");
|
|
1313
|
+
const pool = poolForSubject(subject);
|
|
1314
|
+
const start = cursor.get(pool) ?? mixedHash(ref) % pool.length;
|
|
1315
|
+
map[ref] = pool[start % pool.length];
|
|
1316
|
+
cursor.set(pool, start + 1);
|
|
1317
|
+
}
|
|
1318
|
+
return map;
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
638
1322
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
639
1323
|
function lucideByName(name) {
|
|
640
1324
|
const pascal = name.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
@@ -648,6 +1332,7 @@ var typeStyle = (spec, font) => ({
|
|
|
648
1332
|
fontWeight: spec.weight
|
|
649
1333
|
});
|
|
650
1334
|
var str = (value) => typeof value === "string" ? value : "";
|
|
1335
|
+
var cardRadius = (slots) => slots.cornerStyle === "sharp" ? 0 : AI_TREE_TOKENS.radiusCard;
|
|
651
1336
|
var featureLines = (value) => value.split(/\n|<br\s*\/?>/i).map((line) => line.trim()).filter(Boolean);
|
|
652
1337
|
var CHECK_MASK = `data:image/svg+xml,${encodeURIComponent(
|
|
653
1338
|
'<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>'
|
|
@@ -674,6 +1359,25 @@ var FEATURE_LINE_CSS = [
|
|
|
674
1359
|
`background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
|
|
675
1360
|
`mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
|
|
676
1361
|
].join("");
|
|
1362
|
+
function buttonShellStyle(ctx, fullWidth) {
|
|
1363
|
+
const bs = ctx.buttonStyle;
|
|
1364
|
+
if (bs) {
|
|
1365
|
+
return {
|
|
1366
|
+
borderRadius: bs.radius,
|
|
1367
|
+
...bs.padding ? { padding: bs.padding } : {},
|
|
1368
|
+
...bs.fontFamily ? { fontFamily: bs.fontFamily } : { fontFamily: ctx.brand.fonts.body },
|
|
1369
|
+
...bs.fontSize ? { fontSize: bs.fontSize } : {},
|
|
1370
|
+
...bs.fontWeight ? { fontWeight: bs.fontWeight } : {},
|
|
1371
|
+
...bs.letterSpacing && bs.letterSpacing !== "normal" ? { letterSpacing: bs.letterSpacing } : {},
|
|
1372
|
+
...bs.textTransform && bs.textTransform !== "none" ? { textTransform: bs.textTransform } : {}
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
return {
|
|
1376
|
+
borderRadius: AI_TREE_TOKENS.radiusButton,
|
|
1377
|
+
padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
|
|
1378
|
+
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
1379
|
+
};
|
|
1380
|
+
}
|
|
677
1381
|
function hexLuminance(color) {
|
|
678
1382
|
const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
|
|
679
1383
|
if (!m) return null;
|
|
@@ -690,6 +1394,12 @@ function hexContrast(a, b) {
|
|
|
690
1394
|
const [hi, lo] = la > lb ? [la, lb] : [lb, la];
|
|
691
1395
|
return (hi + 0.05) / (lo + 0.05);
|
|
692
1396
|
}
|
|
1397
|
+
function primaryButtonLabel(brand) {
|
|
1398
|
+
const darkC = hexContrast(brand.palette.primary, brand.palette.dark);
|
|
1399
|
+
const lightC = hexContrast(brand.palette.primary, AI_TREE_TOKENS.textPrimaryForeground);
|
|
1400
|
+
if (darkC === null || lightC === null) return AI_TREE_TOKENS.textPrimaryForeground;
|
|
1401
|
+
return darkC > lightC ? brand.palette.dark : AI_TREE_TOKENS.textPrimaryForeground;
|
|
1402
|
+
}
|
|
693
1403
|
function accentBandContext(brand) {
|
|
694
1404
|
const p = brand.palette;
|
|
695
1405
|
const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
|
|
@@ -707,6 +1417,22 @@ function accentBandContext(brand) {
|
|
|
707
1417
|
function textAttrs(ctx, path) {
|
|
708
1418
|
return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
|
|
709
1419
|
}
|
|
1420
|
+
var AI_RESPONSIVE_CSS = [
|
|
1421
|
+
"@media (max-width: 960px) {",
|
|
1422
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
|
|
1423
|
+
' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
|
|
1424
|
+
"}",
|
|
1425
|
+
"@media (max-width: 640px) {",
|
|
1426
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
|
|
1427
|
+
" [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
|
|
1428
|
+
// Group containers flatten to a column on phones; span placements come along for free.
|
|
1429
|
+
" [data-ai-responsive] [data-ai-group] { display: flex !important; flex-direction: column !important; }",
|
|
1430
|
+
" [data-ai-responsive] [data-ai-group] > * { grid-column: auto !important; }",
|
|
1431
|
+
" [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
|
|
1432
|
+
" [data-ai-responsive] { overflow-x: hidden; }",
|
|
1433
|
+
" [data-ai-responsive] img { max-width: 100%; }",
|
|
1434
|
+
"}"
|
|
1435
|
+
].join("\n");
|
|
710
1436
|
var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
711
1437
|
function MediaBox({
|
|
712
1438
|
refValue,
|
|
@@ -719,13 +1445,17 @@ function MediaBox({
|
|
|
719
1445
|
const url = refValue ? ctx.resolveMedia(refValue) : null;
|
|
720
1446
|
const isIcon = /^(lucide|simple):/.test(refValue);
|
|
721
1447
|
const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
|
|
722
|
-
const editAttrs = ctx.keyFor && editPath
|
|
1448
|
+
const editAttrs = ctx.keyFor && editPath ? {
|
|
1449
|
+
"data-ohw-key": ctx.keyFor(editPath),
|
|
1450
|
+
"data-ohw-editable": isIcon ? "icon" : "image"
|
|
1451
|
+
} : {};
|
|
723
1452
|
if (isIcon) {
|
|
724
1453
|
const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
|
|
725
1454
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
726
1455
|
"span",
|
|
727
1456
|
{
|
|
728
1457
|
"data-ai-icon": refValue,
|
|
1458
|
+
...editAttrs,
|
|
729
1459
|
style: {
|
|
730
1460
|
display: "inline-flex",
|
|
731
1461
|
width: 48,
|
|
@@ -789,12 +1519,15 @@ function ButtonEl({
|
|
|
789
1519
|
width: fullWidth ? "100%" : void 0,
|
|
790
1520
|
alignItems: "center",
|
|
791
1521
|
justifyContent: "center",
|
|
792
|
-
padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
|
|
793
|
-
borderRadius: AI_TREE_TOKENS.radiusButton,
|
|
794
1522
|
textDecoration: "none",
|
|
795
1523
|
cursor: "pointer",
|
|
796
|
-
...
|
|
797
|
-
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } :
|
|
1524
|
+
...buttonShellStyle(ctx, fullWidth),
|
|
1525
|
+
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : (
|
|
1526
|
+
// Off-band, prefer the template button's measured fill/label pair — a template may
|
|
1527
|
+
// fill its CTAs with any token (hvac: accent bg, primary text). On an accent band
|
|
1528
|
+
// the flipped palette keeps contrast, so the brand-driven colours stay.
|
|
1529
|
+
!ctx.buttonLabel && ctx.buttonStyle?.background ? { background: ctx.buttonStyle.background, color: ctx.buttonStyle.color } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand) }
|
|
1530
|
+
)
|
|
798
1531
|
},
|
|
799
1532
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
|
|
800
1533
|
}
|
|
@@ -970,10 +1703,11 @@ function PricingCard({ node, ctx, path }) {
|
|
|
970
1703
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
971
1704
|
"div",
|
|
972
1705
|
{
|
|
1706
|
+
"data-ohw-card": "",
|
|
973
1707
|
style: {
|
|
974
1708
|
background: hasBg ? ctx.brand.palette.light : "transparent",
|
|
975
1709
|
border: `1px solid ${dark}`,
|
|
976
|
-
borderRadius:
|
|
1710
|
+
borderRadius: cardRadius(slots),
|
|
977
1711
|
padding: AI_TREE_TOKENS.paddingBlock,
|
|
978
1712
|
display: "flex",
|
|
979
1713
|
flexDirection: "column",
|
|
@@ -1078,10 +1812,11 @@ function TestimonialCard({ node, ctx, path }) {
|
|
|
1078
1812
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1079
1813
|
"div",
|
|
1080
1814
|
{
|
|
1815
|
+
"data-ohw-card": "",
|
|
1081
1816
|
"data-ai-avatar-pos": avatarPos ?? void 0,
|
|
1082
1817
|
style: {
|
|
1083
1818
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1084
|
-
borderRadius: hasBg ?
|
|
1819
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1085
1820
|
overflow: "hidden",
|
|
1086
1821
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1087
1822
|
minWidth: 0
|
|
@@ -1116,10 +1851,11 @@ function TeamCard({ node, ctx, path }) {
|
|
|
1116
1851
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1117
1852
|
"div",
|
|
1118
1853
|
{
|
|
1854
|
+
"data-ohw-card": "",
|
|
1119
1855
|
"data-ai-avatar-pos": avatarPos ?? void 0,
|
|
1120
1856
|
style: {
|
|
1121
1857
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1122
|
-
borderRadius: hasBg ?
|
|
1858
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1123
1859
|
overflow: "hidden",
|
|
1124
1860
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1125
1861
|
minWidth: 0,
|
|
@@ -1290,9 +2026,10 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1290
2026
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1291
2027
|
"div",
|
|
1292
2028
|
{
|
|
2029
|
+
"data-ohw-card": "",
|
|
1293
2030
|
style: {
|
|
1294
2031
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1295
|
-
borderRadius: hasBg ?
|
|
2032
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1296
2033
|
overflow: "hidden",
|
|
1297
2034
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1298
2035
|
display: horizontal ? "flex" : "block",
|
|
@@ -1320,7 +2057,7 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1320
2057
|
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1321
2058
|
"div",
|
|
1322
2059
|
{
|
|
1323
|
-
style: /^(lucide|simple):/.test(mediaRef) ? { padding: `${AI_TREE_TOKENS.paddingBlock}px ${AI_TREE_TOKENS.paddingBlock}px 0` } : hasBg ? void 0 : { borderRadius:
|
|
2060
|
+
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" },
|
|
1324
2061
|
children: media
|
|
1325
2062
|
}
|
|
1326
2063
|
)),
|
|
@@ -1611,7 +2348,7 @@ function CollectionBlock({ node, ctx, path }) {
|
|
|
1611
2348
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1612
2349
|
"div",
|
|
1613
2350
|
{
|
|
1614
|
-
"data-ai-grid":
|
|
2351
|
+
"data-ai-grid": String(itemsPerRow),
|
|
1615
2352
|
style: {
|
|
1616
2353
|
display: "grid",
|
|
1617
2354
|
gridTemplateColumns: `repeat(${itemsPerRow}, 1fr)`,
|
|
@@ -1731,6 +2468,32 @@ function renderNode(node, ctx, path) {
|
|
|
1731
2468
|
if (child) {
|
|
1732
2469
|
return renderNode(child, ctx, `${path}.c0`);
|
|
1733
2470
|
}
|
|
2471
|
+
if (str(slots.provider) === "map" && str(slots.query)) {
|
|
2472
|
+
const query = str(slots.query);
|
|
2473
|
+
const mapAttrs = ctx.keyFor ? {
|
|
2474
|
+
"data-ohw-key": ctx.keyFor(`${path}.query`),
|
|
2475
|
+
"data-ohw-editable": "map",
|
|
2476
|
+
"data-ohw-map-query": query
|
|
2477
|
+
} : {};
|
|
2478
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2479
|
+
"iframe",
|
|
2480
|
+
{
|
|
2481
|
+
...mapAttrs,
|
|
2482
|
+
"data-ai-embed": "map",
|
|
2483
|
+
title: str(slots.title) || "Map",
|
|
2484
|
+
src: `https://www.google.com/maps?q=${encodeURIComponent(query)}&output=embed`,
|
|
2485
|
+
loading: "lazy",
|
|
2486
|
+
referrerPolicy: "no-referrer-when-downgrade",
|
|
2487
|
+
style: {
|
|
2488
|
+
width: "100%",
|
|
2489
|
+
minHeight: 320,
|
|
2490
|
+
border: 0,
|
|
2491
|
+
borderRadius: AI_TREE_TOKENS.radiusCard,
|
|
2492
|
+
display: "block"
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
);
|
|
2496
|
+
}
|
|
1734
2497
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1735
2498
|
"div",
|
|
1736
2499
|
{
|
|
@@ -1834,15 +2597,14 @@ function renderNode(node, ctx, path) {
|
|
|
1834
2597
|
alignSelf: submitAlign,
|
|
1835
2598
|
border: "none",
|
|
1836
2599
|
cursor: "pointer",
|
|
1837
|
-
padding
|
|
1838
|
-
|
|
1839
|
-
//
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
2600
|
+
// Shape/padding/typography follow the host template's own buttons.
|
|
2601
|
+
...buttonShellStyle(ctx),
|
|
2602
|
+
// Brand-styled: the template button's measured fill/label pair off-band, else
|
|
2603
|
+
// primary fill with a brand-derived label so it reads on custom palettes.
|
|
2604
|
+
...!ctx.buttonLabel && ctx.buttonStyle?.background ? { background: ctx.buttonStyle.background, color: ctx.buttonStyle.color } : {
|
|
2605
|
+
background: ctx.brand.palette.primary,
|
|
2606
|
+
color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand)
|
|
2607
|
+
}
|
|
1846
2608
|
},
|
|
1847
2609
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
|
|
1848
2610
|
},
|
|
@@ -1877,7 +2639,7 @@ function renderNode(node, ctx, path) {
|
|
|
1877
2639
|
function AiTreeRenderer({
|
|
1878
2640
|
tree,
|
|
1879
2641
|
brand,
|
|
1880
|
-
|
|
2642
|
+
buttonStyle,
|
|
1881
2643
|
resolveMedia,
|
|
1882
2644
|
editKeyPrefix
|
|
1883
2645
|
}) {
|
|
@@ -1887,13 +2649,18 @@ function AiTreeRenderer({
|
|
|
1887
2649
|
const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
|
|
1888
2650
|
const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
|
|
1889
2651
|
const blockBrand = band?.brand ?? resolvedBrand;
|
|
2652
|
+
const placeholderMap = buildPlaceholderMap(tree);
|
|
1890
2653
|
const ctx = {
|
|
1891
2654
|
brand: blockBrand,
|
|
1892
|
-
|
|
2655
|
+
// An owner/library ref resolves through the host resolver; a `placeholder:<subject>` ref the
|
|
2656
|
+
// host cannot resolve falls back to real stock photography (the per-section map first, then a
|
|
2657
|
+
// standalone resolve), so generated galleries, image rows, and overlay backgrounds arrive with
|
|
2658
|
+
// photos instead of grey boxes.
|
|
2659
|
+
resolveMedia: (ref) => resolveMedia?.(ref) ?? placeholderMap[ref] ?? resolvePlaceholderRef(ref),
|
|
1893
2660
|
cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
|
|
1894
2661
|
keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
|
|
1895
2662
|
sectionAlignment: (tree.settings ?? {}).alignment === "center" ? "center" : "left",
|
|
1896
|
-
|
|
2663
|
+
buttonStyle,
|
|
1897
2664
|
...band ? { buttonLabel: band.buttonLabel } : {}
|
|
1898
2665
|
};
|
|
1899
2666
|
const settings = tree.settings ?? {};
|
|
@@ -1934,6 +2701,7 @@ function AiTreeRenderer({
|
|
|
1934
2701
|
{
|
|
1935
2702
|
"data-ai-section": tree.tag ?? "",
|
|
1936
2703
|
...bgAttrs,
|
|
2704
|
+
"data-ai-responsive": "",
|
|
1937
2705
|
style: {
|
|
1938
2706
|
position: "relative",
|
|
1939
2707
|
padding: `${pad}px 0`,
|
|
@@ -1944,12 +2712,13 @@ function AiTreeRenderer({
|
|
|
1944
2712
|
color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
|
|
1945
2713
|
},
|
|
1946
2714
|
children: [
|
|
1947
|
-
|
|
2715
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
|
|
1948
2716
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
|
|
2717
|
+
isOverlay && backgroundUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
|
|
1949
2718
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1950
2719
|
"div",
|
|
1951
2720
|
{
|
|
1952
|
-
"data-ai-
|
|
2721
|
+
"data-ai-section-inner": "",
|
|
1953
2722
|
style: {
|
|
1954
2723
|
position: "relative",
|
|
1955
2724
|
maxWidth: AI_TREE_TOKENS.sectionMaxWidth,
|
|
@@ -1960,7 +2729,7 @@ function AiTreeRenderer({
|
|
|
1960
2729
|
children: tree.rows.map((row, r2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1961
2730
|
"div",
|
|
1962
2731
|
{
|
|
1963
|
-
"data-ai-
|
|
2732
|
+
"data-ai-columns": "",
|
|
1964
2733
|
style: {
|
|
1965
2734
|
display: "grid",
|
|
1966
2735
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
@@ -1999,21 +2768,63 @@ function AiTreeRenderer({
|
|
|
1999
2768
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
2000
2769
|
var CONTAINER_ATTR = "data-ohw-ai-generated";
|
|
2001
2770
|
var REPLACED_ATTR = "data-ohw-ai-replaced-by";
|
|
2002
|
-
var
|
|
2771
|
+
var REMOVED_ATTR2 = "data-ohw-ai-removed";
|
|
2003
2772
|
var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
|
|
2004
2773
|
var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
2774
|
+
function isChromeSection2(el) {
|
|
2775
|
+
if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) return true;
|
|
2776
|
+
return el.tagName === "HEADER" || el.tagName === "FOOTER";
|
|
2777
|
+
}
|
|
2005
2778
|
function readRootVar(name) {
|
|
2006
2779
|
if (typeof document === "undefined") return "";
|
|
2007
2780
|
return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
2008
2781
|
}
|
|
2782
|
+
function normalizeColorToHex(value) {
|
|
2783
|
+
if (!value || typeof document === "undefined") return value;
|
|
2784
|
+
const canvas = document.createElement("canvas");
|
|
2785
|
+
canvas.width = 1;
|
|
2786
|
+
canvas.height = 1;
|
|
2787
|
+
const ctx = canvas.getContext("2d");
|
|
2788
|
+
if (!ctx) return value;
|
|
2789
|
+
ctx.fillStyle = value;
|
|
2790
|
+
ctx.fillRect(0, 0, 1, 1);
|
|
2791
|
+
const [r2, g, b] = ctx.getImageData(0, 0, 1, 1).data;
|
|
2792
|
+
const toHex = (n) => n.toString(16).padStart(2, "0");
|
|
2793
|
+
return `#${toHex(r2)}${toHex(g)}${toHex(b)}`;
|
|
2794
|
+
}
|
|
2795
|
+
var GENERIC_FONT_KEYWORDS = /* @__PURE__ */ new Set([
|
|
2796
|
+
"serif",
|
|
2797
|
+
"sans-serif",
|
|
2798
|
+
"monospace",
|
|
2799
|
+
"cursive",
|
|
2800
|
+
"fantasy",
|
|
2801
|
+
"system-ui",
|
|
2802
|
+
"ui-serif",
|
|
2803
|
+
"ui-sans-serif",
|
|
2804
|
+
"ui-monospace",
|
|
2805
|
+
"ui-rounded",
|
|
2806
|
+
"math",
|
|
2807
|
+
"emoji",
|
|
2808
|
+
"fangsong"
|
|
2809
|
+
]);
|
|
2810
|
+
function primaryFontFamily(stack) {
|
|
2811
|
+
const first = stack.split(",").map((part) => part.trim().replace(/^["']|["']$/g, "")).find((part) => part && !GENERIC_FONT_KEYWORDS.has(part.toLowerCase()));
|
|
2812
|
+
return first ?? "";
|
|
2813
|
+
}
|
|
2814
|
+
function humanizeFontFamily(name) {
|
|
2815
|
+
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());
|
|
2816
|
+
}
|
|
2817
|
+
function readFontVar(name) {
|
|
2818
|
+
return humanizeFontFamily(primaryFontFamily(readRootVar(name)));
|
|
2819
|
+
}
|
|
2009
2820
|
function deriveBrandOverride() {
|
|
2010
2821
|
const dark = readRootVar("--ohw-brand-dark");
|
|
2011
2822
|
const primary = readRootVar("--ohw-brand-primary");
|
|
2012
2823
|
const light = readRootVar("--ohw-brand-light");
|
|
2013
2824
|
if (!dark || !primary || !light) return null;
|
|
2014
2825
|
const accent = readRootVar("--ohw-brand-accent");
|
|
2015
|
-
const heading =
|
|
2016
|
-
const body =
|
|
2826
|
+
const heading = readFontVar("--font-heading") || readFontVar("--font-display");
|
|
2827
|
+
const body = readFontVar("--font-body");
|
|
2017
2828
|
return {
|
|
2018
2829
|
palette: { dark, primary, accent: accent || dark, light },
|
|
2019
2830
|
fonts: {
|
|
@@ -2022,28 +2833,98 @@ function deriveBrandOverride() {
|
|
|
2022
2833
|
}
|
|
2023
2834
|
};
|
|
2024
2835
|
}
|
|
2025
|
-
function
|
|
2026
|
-
const dark = readRootVar("--color-dark");
|
|
2027
|
-
const primary = readRootVar("--color-primary");
|
|
2028
|
-
const light = readRootVar("--color-light");
|
|
2836
|
+
function deriveTemplateBrandLive() {
|
|
2837
|
+
const dark = readRootVar("--color-dark") || readRootVar("--brand-text");
|
|
2838
|
+
const primary = readRootVar("--color-primary") || readRootVar("--brand-primary");
|
|
2839
|
+
const light = readRootVar("--color-light") || readRootVar("--brand-background");
|
|
2029
2840
|
if (!dark || !primary || !light) return null;
|
|
2030
|
-
const accent = readRootVar("--color-accent");
|
|
2031
|
-
const heading =
|
|
2032
|
-
const body =
|
|
2841
|
+
const accent = readRootVar("--color-accent") || readRootVar("--brand-accent");
|
|
2842
|
+
const heading = readFontVar("--brand-font-heading") || readFontVar("--font-heading") || readFontVar("--font-display");
|
|
2843
|
+
const body = readFontVar("--brand-font-body") || readFontVar("--font-body");
|
|
2033
2844
|
return {
|
|
2034
|
-
palette: {
|
|
2845
|
+
palette: {
|
|
2846
|
+
dark: normalizeColorToHex(dark),
|
|
2847
|
+
primary: normalizeColorToHex(primary),
|
|
2848
|
+
accent: normalizeColorToHex(accent || dark),
|
|
2849
|
+
light: normalizeColorToHex(light)
|
|
2850
|
+
},
|
|
2035
2851
|
fonts: {
|
|
2036
2852
|
heading: heading || AI_DEFAULT_BRAND.fonts.heading,
|
|
2037
2853
|
body: body || AI_DEFAULT_BRAND.fonts.body
|
|
2038
2854
|
}
|
|
2039
2855
|
};
|
|
2040
2856
|
}
|
|
2041
|
-
function
|
|
2857
|
+
function deriveTemplateFontsLive() {
|
|
2858
|
+
const heading = readFontVar("--brand-font-heading") || readFontVar("--font-heading") || readFontVar("--font-display");
|
|
2859
|
+
const body = readFontVar("--brand-font-body") || readFontVar("--font-body");
|
|
2860
|
+
if (!heading && !body) return null;
|
|
2861
|
+
return {
|
|
2862
|
+
heading: heading || AI_DEFAULT_BRAND.fonts.heading,
|
|
2863
|
+
body: body || AI_DEFAULT_BRAND.fonts.body
|
|
2864
|
+
};
|
|
2865
|
+
}
|
|
2866
|
+
var OVERRIDE_VAR_NAMES = [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES, ...FONT_VARS.heading, ...FONT_VARS.body];
|
|
2867
|
+
function withOverrideStripped(read) {
|
|
2868
|
+
const root = document.documentElement;
|
|
2869
|
+
const restore = OVERRIDE_VAR_NAMES.map((name) => [name, root.style.getPropertyValue(name)]);
|
|
2870
|
+
for (const name of OVERRIDE_VAR_NAMES) root.style.removeProperty(name);
|
|
2871
|
+
try {
|
|
2872
|
+
return read();
|
|
2873
|
+
} finally {
|
|
2874
|
+
for (const [name, value] of restore) if (value) root.style.setProperty(name, value);
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
var TEMPLATE_BRAND_SNAPSHOT = typeof document === "undefined" ? null : withOverrideStripped(deriveTemplateBrandLive);
|
|
2878
|
+
var TEMPLATE_FONTS_SNAPSHOT = typeof document === "undefined" ? null : withOverrideStripped(deriveTemplateFontsLive);
|
|
2879
|
+
function deriveTemplateBrand() {
|
|
2880
|
+
return TEMPLATE_BRAND_SNAPSHOT;
|
|
2881
|
+
}
|
|
2882
|
+
function deriveTemplateFonts() {
|
|
2883
|
+
return TEMPLATE_FONTS_SNAPSHOT;
|
|
2884
|
+
}
|
|
2885
|
+
function deriveTemplateButtonStyle() {
|
|
2042
2886
|
if (typeof document === "undefined") return null;
|
|
2043
|
-
const
|
|
2887
|
+
const candidates = Array.from(
|
|
2888
|
+
document.querySelectorAll('[data-ohw-role="button"]')
|
|
2889
|
+
).filter(
|
|
2890
|
+
(el) => !el.closest(`[${CONTAINER_ATTR}]`) && // Whole-card links legitimately carry the button role (serene's clickable treatment
|
|
2891
|
+
// cards) but must never donate the "button look" — a real button holds at most its
|
|
2892
|
+
// one editable label, a card holds a headline, copy and prices.
|
|
2893
|
+
el.querySelectorAll("[data-ohw-editable]").length <= 1
|
|
2894
|
+
);
|
|
2895
|
+
const isFilled = (el) => {
|
|
2896
|
+
const bg = getComputedStyle(el).backgroundColor;
|
|
2897
|
+
if (!bg || bg === "transparent") return false;
|
|
2898
|
+
const alpha = bg.match(/rgba?\([^)]*,\s*([\d.]+)\)$/);
|
|
2899
|
+
return !alpha || parseFloat(alpha[1]) > 0;
|
|
2900
|
+
};
|
|
2901
|
+
const btn = candidates.find(isFilled) ?? candidates[0];
|
|
2044
2902
|
if (!btn) return null;
|
|
2045
|
-
const
|
|
2046
|
-
|
|
2903
|
+
const cs = getComputedStyle(btn);
|
|
2904
|
+
const filled = isFilled(btn);
|
|
2905
|
+
const corners = [
|
|
2906
|
+
cs.borderTopLeftRadius,
|
|
2907
|
+
cs.borderTopRightRadius,
|
|
2908
|
+
cs.borderBottomRightRadius,
|
|
2909
|
+
cs.borderBottomLeftRadius
|
|
2910
|
+
].map((v) => v || "0px");
|
|
2911
|
+
const radius = corners.every((v) => v === corners[0]) ? corners[0] : corners.join(" ");
|
|
2912
|
+
const px = (v) => parseFloat(v) || 0;
|
|
2913
|
+
const lineHeight = px(cs.lineHeight) || px(cs.fontSize) * 1.2;
|
|
2914
|
+
const contentH = btn.getBoundingClientRect().height - px(cs.borderTopWidth) - px(cs.borderBottomWidth);
|
|
2915
|
+
const impliedY = Math.round(Math.max(0, (contentH - lineHeight) / 2));
|
|
2916
|
+
const padY = Math.max(px(cs.paddingTop), px(cs.paddingBottom), impliedY);
|
|
2917
|
+
const padX = Math.max(px(cs.paddingLeft), px(cs.paddingRight));
|
|
2918
|
+
return {
|
|
2919
|
+
radius: radius || "10px",
|
|
2920
|
+
padding: `${padY}px ${padX}px`,
|
|
2921
|
+
...filled ? { background: cs.backgroundColor, color: cs.color } : {},
|
|
2922
|
+
fontFamily: cs.fontFamily || "",
|
|
2923
|
+
fontSize: cs.fontSize || "",
|
|
2924
|
+
fontWeight: cs.fontWeight || "",
|
|
2925
|
+
letterSpacing: cs.letterSpacing || "",
|
|
2926
|
+
textTransform: cs.textTransform || ""
|
|
2927
|
+
};
|
|
2047
2928
|
}
|
|
2048
2929
|
var mounted = /* @__PURE__ */ new Map();
|
|
2049
2930
|
function findTemplateSection(id) {
|
|
@@ -2059,6 +2940,19 @@ function findPlacementAnchor(id, exclude) {
|
|
|
2059
2940
|
for (const el of document.querySelectorAll(`[data-ohw-section="${CSS.escape(id)}"]`)) {
|
|
2060
2941
|
if (el === exclude) continue;
|
|
2061
2942
|
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
2943
|
+
if (isChromeSection2(el)) return null;
|
|
2944
|
+
return el;
|
|
2945
|
+
}
|
|
2946
|
+
return null;
|
|
2947
|
+
}
|
|
2948
|
+
function findFooterSection() {
|
|
2949
|
+
const byId = findTemplateSection("footer");
|
|
2950
|
+
if (byId) return byId;
|
|
2951
|
+
for (const el of Array.from(
|
|
2952
|
+
document.querySelectorAll("footer[data-ohw-section]")
|
|
2953
|
+
).reverse()) {
|
|
2954
|
+
if (el.hasAttribute(CONTAINER_ATTR)) continue;
|
|
2955
|
+
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
2062
2956
|
return el;
|
|
2063
2957
|
}
|
|
2064
2958
|
return null;
|
|
@@ -2085,7 +2979,7 @@ function placeContainer(container, entry) {
|
|
|
2085
2979
|
return;
|
|
2086
2980
|
}
|
|
2087
2981
|
}
|
|
2088
|
-
const footer =
|
|
2982
|
+
const footer = findFooterSection();
|
|
2089
2983
|
if (footer) {
|
|
2090
2984
|
footer.insertAdjacentElement("beforebegin", container);
|
|
2091
2985
|
} else {
|
|
@@ -2094,18 +2988,18 @@ function placeContainer(container, entry) {
|
|
|
2094
2988
|
}
|
|
2095
2989
|
function syncRemovedSections(state) {
|
|
2096
2990
|
const removed = new Set(state.removed ?? []);
|
|
2097
|
-
for (const el of document.querySelectorAll(`[${
|
|
2991
|
+
for (const el of document.querySelectorAll(`[${REMOVED_ATTR2}]`)) {
|
|
2098
2992
|
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
2099
2993
|
if (!removed.has(id)) {
|
|
2100
2994
|
el.style.removeProperty("display");
|
|
2101
|
-
el.removeAttribute(
|
|
2995
|
+
el.removeAttribute(REMOVED_ATTR2);
|
|
2102
2996
|
}
|
|
2103
2997
|
}
|
|
2104
2998
|
for (const id of removed) {
|
|
2105
2999
|
const section = findTemplateSection(id);
|
|
2106
3000
|
if (section && !section.hasAttribute(REPLACED_ATTR)) {
|
|
2107
3001
|
section.style.display = "none";
|
|
2108
|
-
section.setAttribute(
|
|
3002
|
+
section.setAttribute(REMOVED_ATTR2, "");
|
|
2109
3003
|
}
|
|
2110
3004
|
}
|
|
2111
3005
|
}
|
|
@@ -2120,9 +3014,9 @@ function syncTemplateHidden(state, pageHasSections) {
|
|
|
2120
3014
|
if (!hide) return;
|
|
2121
3015
|
for (const el of Array.from(document.querySelectorAll("[data-ohw-section]"))) {
|
|
2122
3016
|
if (el.hasAttribute(CONTAINER_ATTR)) continue;
|
|
2123
|
-
if (
|
|
3017
|
+
if (isChromeSection2(el)) continue;
|
|
2124
3018
|
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
2125
|
-
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(
|
|
3019
|
+
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR2)) continue;
|
|
2126
3020
|
el.style.display = "none";
|
|
2127
3021
|
el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
|
|
2128
3022
|
}
|
|
@@ -2146,18 +3040,23 @@ function syncReplacedOriginals(state) {
|
|
|
2146
3040
|
}
|
|
2147
3041
|
}
|
|
2148
3042
|
var sectionOrderIndex = /* @__PURE__ */ new Map();
|
|
3043
|
+
var removedSectionIds = /* @__PURE__ */ new Set();
|
|
2149
3044
|
function setAiSectionOrder(raw, currentPath) {
|
|
2150
3045
|
const next = /* @__PURE__ */ new Map();
|
|
3046
|
+
const removed = /* @__PURE__ */ new Set();
|
|
2151
3047
|
if (raw) {
|
|
2152
3048
|
try {
|
|
2153
3049
|
const entries = JSON.parse(raw);
|
|
2154
3050
|
for (const entry of entries) {
|
|
2155
|
-
if (
|
|
3051
|
+
if (entry.pagePath && entry.pagePath !== currentPath) continue;
|
|
3052
|
+
next.set(entry.instanceId, entry.order);
|
|
3053
|
+
if (entry.removed) removed.add(entry.instanceId);
|
|
2156
3054
|
}
|
|
2157
3055
|
} catch {
|
|
2158
3056
|
}
|
|
2159
3057
|
}
|
|
2160
3058
|
sectionOrderIndex = next;
|
|
3059
|
+
removedSectionIds = removed;
|
|
2161
3060
|
}
|
|
2162
3061
|
function applyExplicitOrder(entries) {
|
|
2163
3062
|
if (sectionOrderIndex.size === 0) return entries;
|
|
@@ -2193,11 +3092,23 @@ function orderByChain(sections) {
|
|
|
2193
3092
|
for (const root of roots) visit(root);
|
|
2194
3093
|
return out.length === sections.length ? out : sections;
|
|
2195
3094
|
}
|
|
3095
|
+
function syncSoftRemovedGenerated() {
|
|
3096
|
+
for (const [id, section] of mounted) {
|
|
3097
|
+
const el = section.container;
|
|
3098
|
+
if (removedSectionIds.has(id)) {
|
|
3099
|
+
el.style.display = "none";
|
|
3100
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
3101
|
+
} else if (el.hasAttribute(REMOVED_ATTR)) {
|
|
3102
|
+
el.style.removeProperty("display");
|
|
3103
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
3104
|
+
}
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
2196
3107
|
function applyAiSectionsToDom(state, options) {
|
|
2197
3108
|
if (typeof document === "undefined") return;
|
|
2198
3109
|
const brandOverride = deriveBrandOverride();
|
|
2199
3110
|
const templateBrand = deriveTemplateBrand();
|
|
2200
|
-
const
|
|
3111
|
+
const templateButtonStyle = deriveTemplateButtonStyle();
|
|
2201
3112
|
const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
|
|
2202
3113
|
const pagePath = window.location.pathname;
|
|
2203
3114
|
const pageSections = state.sections.filter((entry) => (entry.path ?? "/") === pagePath);
|
|
@@ -2237,7 +3148,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2237
3148
|
{
|
|
2238
3149
|
tree: entry.tree,
|
|
2239
3150
|
brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
|
|
2240
|
-
|
|
3151
|
+
buttonStyle: templateButtonStyle,
|
|
2241
3152
|
resolveMedia,
|
|
2242
3153
|
editKeyPrefix: `ai.${entry.id}`
|
|
2243
3154
|
}
|
|
@@ -2260,6 +3171,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2260
3171
|
syncReplacedOriginals(state);
|
|
2261
3172
|
syncRemovedSections(state);
|
|
2262
3173
|
syncTemplateHidden(state, pageSections.length > 0);
|
|
3174
|
+
syncSoftRemovedGenerated();
|
|
2263
3175
|
}
|
|
2264
3176
|
|
|
2265
3177
|
// src/useLinkHrefGuardian.ts
|
|
@@ -6451,12 +7363,12 @@ var cva = (base, config) => (props) => {
|
|
|
6451
7363
|
var import_radix_ui2 = require("radix-ui");
|
|
6452
7364
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
6453
7365
|
var toggleVariants = cva(
|
|
6454
|
-
"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",
|
|
7366
|
+
"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",
|
|
6455
7367
|
{
|
|
6456
7368
|
variants: {
|
|
6457
7369
|
variant: {
|
|
6458
7370
|
default: "bg-transparent border-0",
|
|
6459
|
-
outline: "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground"
|
|
7371
|
+
outline: "border border-input bg-transparent shadow-xs hover:bg-bridge-accent hover:text-accent-foreground"
|
|
6460
7372
|
},
|
|
6461
7373
|
size: {
|
|
6462
7374
|
default: "px-2 py-1",
|
|
@@ -6549,10 +7461,10 @@ var DragHandle = React4.forwardRef(
|
|
|
6549
7461
|
type,
|
|
6550
7462
|
"data-slot": "drag-handle",
|
|
6551
7463
|
className: cn(
|
|
6552
|
-
"inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-
|
|
7464
|
+
"inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-7.5",
|
|
6553
7465
|
"bg-white border border-transparent text-stone-500 shadow-md cursor-grab",
|
|
6554
7466
|
"enabled:hover:border enabled:hover:border-stone-200 enabled:hover:text-stone-950",
|
|
6555
|
-
"enabled:active:border enabled:active:border-primary enabled:active:bg-primary-50 enabled:active:text-stone-950 enabled:active:shadow enabled:active:cursor-grabbing",
|
|
7467
|
+
"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",
|
|
6556
7468
|
"disabled:cursor-not-allowed disabled:opacity-40 disabled:text-stone-950 disabled:pointer-events-none",
|
|
6557
7469
|
className
|
|
6558
7470
|
),
|
|
@@ -6574,7 +7486,7 @@ var CustomToolbar = React5.forwardRef(({ className, onMouseDown, ...props }, ref
|
|
|
6574
7486
|
"data-ohw-toolbar": "",
|
|
6575
7487
|
className: cn(
|
|
6576
7488
|
// Figma: bg background, radius 8, gap-1, p-0.5, shadow-md — no border
|
|
6577
|
-
"inline-flex h-8 items-center gap-1 rounded-
|
|
7489
|
+
"inline-flex h-8 items-center gap-1 rounded-(--radius,0.5rem) bg-background p-0.5 font-sans whitespace-nowrap shadow-md",
|
|
6578
7490
|
className
|
|
6579
7491
|
),
|
|
6580
7492
|
onMouseDown: (e) => {
|
|
@@ -6603,7 +7515,7 @@ var CustomToolbarButton = React5.forwardRef(
|
|
|
6603
7515
|
type,
|
|
6604
7516
|
className: cn(
|
|
6605
7517
|
"inline-flex size-7 shrink-0 items-center justify-center rounded-[calc(var(--radius,0.5rem)-2px)] text-foreground transition-colors",
|
|
6606
|
-
active ? "bg-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
|
|
7518
|
+
active ? "bg-bridge-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
|
|
6607
7519
|
className
|
|
6608
7520
|
),
|
|
6609
7521
|
...props
|
|
@@ -6808,9 +7720,7 @@ function ItemActionToolbar({
|
|
|
6808
7720
|
ToggleGroup,
|
|
6809
7721
|
{
|
|
6810
7722
|
value: dropdownOpen ? "open" : "closed",
|
|
6811
|
-
onValueChange: (
|
|
6812
|
-
if (value !== "open" && value !== "closed") return;
|
|
6813
|
-
onDropdownOpenChange?.(value === "open");
|
|
7723
|
+
onValueChange: () => {
|
|
6814
7724
|
},
|
|
6815
7725
|
className: "h-7 gap-0.5 rounded-[calc(var(--radius,0.5rem)-2px)] bg-muted p-0.5",
|
|
6816
7726
|
onMouseDown: (e) => {
|
|
@@ -6825,6 +7735,11 @@ function ItemActionToolbar({
|
|
|
6825
7735
|
size: "sm",
|
|
6826
7736
|
"aria-label": "Closed",
|
|
6827
7737
|
className: "h-6 min-w-0 px-2 text-xs font-medium",
|
|
7738
|
+
onMouseDown: (e) => {
|
|
7739
|
+
e.preventDefault();
|
|
7740
|
+
e.stopPropagation();
|
|
7741
|
+
if (dropdownOpen !== false) onDropdownOpenChange?.(false);
|
|
7742
|
+
},
|
|
6828
7743
|
children: "Closed"
|
|
6829
7744
|
}
|
|
6830
7745
|
),
|
|
@@ -6835,6 +7750,11 @@ function ItemActionToolbar({
|
|
|
6835
7750
|
size: "sm",
|
|
6836
7751
|
"aria-label": "Open",
|
|
6837
7752
|
className: "h-6 min-w-0 px-2 text-xs font-medium",
|
|
7753
|
+
onMouseDown: (e) => {
|
|
7754
|
+
e.preventDefault();
|
|
7755
|
+
e.stopPropagation();
|
|
7756
|
+
if (dropdownOpen !== true) onDropdownOpenChange?.(true);
|
|
7757
|
+
},
|
|
6838
7758
|
children: "Open"
|
|
6839
7759
|
}
|
|
6840
7760
|
)
|
|
@@ -7797,13 +8717,13 @@ function FormFieldToolbar({
|
|
|
7797
8717
|
]
|
|
7798
8718
|
}
|
|
7799
8719
|
) }),
|
|
7800
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-
|
|
8720
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-47.5 p-1", children: FIELD_TYPES.map((entry) => {
|
|
7801
8721
|
const Icon = TYPE_ICONS[entry.type];
|
|
7802
8722
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
7803
8723
|
DropdownMenuItem,
|
|
7804
8724
|
{
|
|
7805
8725
|
onSelect: () => onTypeChange(entry.type),
|
|
7806
|
-
className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-primary/10" : ""),
|
|
8726
|
+
className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-bridge-primary/10" : ""),
|
|
7807
8727
|
children: [
|
|
7808
8728
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
|
|
7809
8729
|
entry.label
|
|
@@ -7820,7 +8740,7 @@ function FormFieldToolbar({
|
|
|
7820
8740
|
type: "button",
|
|
7821
8741
|
"aria-pressed": required,
|
|
7822
8742
|
onClick: onRequiredToggle,
|
|
7823
|
-
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"),
|
|
8743
|
+
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"),
|
|
7824
8744
|
"data-ohw-field-required-toggle": "",
|
|
7825
8745
|
children: [
|
|
7826
8746
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Asterisk, { size: 14, strokeWidth: 2, "aria-hidden": true }),
|
|
@@ -7840,7 +8760,7 @@ function FormFieldToolbar({
|
|
|
7840
8760
|
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.MoreHorizontal, { size: 15, "aria-hidden": true })
|
|
7841
8761
|
}
|
|
7842
8762
|
) }),
|
|
7843
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-
|
|
8763
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-42.5 p-1", children: [
|
|
7844
8764
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuItem, { onSelect: onDuplicate, className: "rounded-md py-2 text-[13px]", children: [
|
|
7845
8765
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Copy, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
|
|
7846
8766
|
"Duplicate"
|
|
@@ -7860,7 +8780,7 @@ function FieldTypePicker({ onPick }) {
|
|
|
7860
8780
|
"div",
|
|
7861
8781
|
{
|
|
7862
8782
|
"data-ohw-field-type-picker": "",
|
|
7863
|
-
className: "pointer-events-auto grid w-
|
|
8783
|
+
className: "pointer-events-auto grid w-105 grid-cols-3 gap-3 rounded-xl border border-border bg-background p-4 shadow-lg",
|
|
7864
8784
|
children: FIELD_TYPES.map((entry) => {
|
|
7865
8785
|
const Icon = TYPE_ICONS[entry.type];
|
|
7866
8786
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
@@ -7868,7 +8788,7 @@ function FieldTypePicker({ onPick }) {
|
|
|
7868
8788
|
{
|
|
7869
8789
|
type: "button",
|
|
7870
8790
|
onClick: () => onPick(entry.type),
|
|
7871
|
-
className: "flex h-
|
|
8791
|
+
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",
|
|
7872
8792
|
children: [
|
|
7873
8793
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 26, strokeWidth: 1.5, "aria-hidden": true }),
|
|
7874
8794
|
entry.label
|
|
@@ -7894,7 +8814,7 @@ var buttonVariants = cva(
|
|
|
7894
8814
|
{
|
|
7895
8815
|
variants: {
|
|
7896
8816
|
variant: {
|
|
7897
|
-
default: "bg-primary text-primary-foreground hover:opacity-90",
|
|
8817
|
+
default: "bg-bridge-primary text-primary-foreground hover:opacity-90",
|
|
7898
8818
|
outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
|
|
7899
8819
|
ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
|
|
7900
8820
|
},
|
|
@@ -7989,6 +8909,7 @@ function MediaOverlay({
|
|
|
7989
8909
|
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
7990
8910
|
);
|
|
7991
8911
|
}, [isVideo]);
|
|
8912
|
+
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
7992
8913
|
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
7993
8914
|
const box = {
|
|
7994
8915
|
position: "fixed",
|
|
@@ -8094,8 +9015,8 @@ function MediaOverlay({
|
|
|
8094
9015
|
pointerEvents: hover.hasTextOverlap ? "none" : "auto",
|
|
8095
9016
|
// Selected: a firm component ring with no wash, so the image reads as chosen rather
|
|
8096
9017
|
// than hovered. Hover keeps the existing tinted preview.
|
|
8097
|
-
boxShadow: selected ? "inset 0 0 0 2px var(--color-primary)" : "inset 0 0 0 1.5px var(--color-primary)",
|
|
8098
|
-
background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
9018
|
+
boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
9019
|
+
background: selected ? "transparent" : "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
|
|
8099
9020
|
},
|
|
8100
9021
|
onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
|
|
8101
9022
|
children: [
|
|
@@ -8118,17 +9039,17 @@ function MediaOverlay({
|
|
|
8118
9039
|
},
|
|
8119
9040
|
children: [
|
|
8120
9041
|
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
8121
|
-
|
|
9042
|
+
replaceLabel
|
|
8122
9043
|
]
|
|
8123
9044
|
}
|
|
8124
9045
|
),
|
|
8125
|
-
replaceMode
|
|
9046
|
+
showChrome && replaceMode !== "none" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
8126
9047
|
Button,
|
|
8127
9048
|
{
|
|
8128
9049
|
"data-ohw-media-overlay": "",
|
|
8129
9050
|
variant: "outline",
|
|
8130
9051
|
size: "sm",
|
|
8131
|
-
"aria-label":
|
|
9052
|
+
"aria-label": replaceLabel,
|
|
8132
9053
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
8133
9054
|
style: {
|
|
8134
9055
|
...OVERLAY_BUTTON_STYLE,
|
|
@@ -8151,7 +9072,7 @@ function MediaOverlay({
|
|
|
8151
9072
|
},
|
|
8152
9073
|
children: [
|
|
8153
9074
|
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
8154
|
-
replaceMode === "full" ?
|
|
9075
|
+
replaceMode === "full" ? replaceLabel : null
|
|
8155
9076
|
]
|
|
8156
9077
|
}
|
|
8157
9078
|
)
|
|
@@ -8189,8 +9110,8 @@ function CarouselOverlay({
|
|
|
8189
9110
|
height: rect.height,
|
|
8190
9111
|
zIndex: 2147483646,
|
|
8191
9112
|
pointerEvents: "auto",
|
|
8192
|
-
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
8193
|
-
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
9113
|
+
boxShadow: "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
9114
|
+
background: "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
|
|
8194
9115
|
},
|
|
8195
9116
|
onClick: () => onEdit(hover.key),
|
|
8196
9117
|
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
@@ -8210,229 +9131,17 @@ function CarouselOverlay({
|
|
|
8210
9131
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react6.GalleryHorizontal, { size: 14 }),
|
|
8211
9132
|
"Edit gallery"
|
|
8212
9133
|
]
|
|
8213
|
-
}
|
|
8214
|
-
)
|
|
8215
|
-
}
|
|
8216
|
-
);
|
|
8217
|
-
}
|
|
8218
|
-
|
|
8219
|
-
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
8220
|
-
var import_react8 = require("react");
|
|
8221
|
-
var import_lucide_react7 = require("lucide-react");
|
|
8222
|
-
|
|
8223
|
-
// src/lib/sections.ts
|
|
8224
|
-
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
8225
|
-
function isChromeSection(el) {
|
|
8226
|
-
return el.matches("header, nav, footer, aside");
|
|
8227
|
-
}
|
|
8228
|
-
function titleCaseSectionId(id) {
|
|
8229
|
-
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
8230
|
-
}
|
|
8231
|
-
function parseSectionsFromRoot(root) {
|
|
8232
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8233
|
-
const sections = [];
|
|
8234
|
-
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
8235
|
-
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
8236
|
-
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
8237
|
-
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
8238
|
-
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
8239
|
-
continue;
|
|
8240
|
-
seen.add(id);
|
|
8241
|
-
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
8242
|
-
sections.push({ id, label });
|
|
8243
|
-
}
|
|
8244
|
-
return sections;
|
|
8245
|
-
}
|
|
8246
|
-
function collectSectionsFromDom() {
|
|
8247
|
-
if (typeof document === "undefined") return [];
|
|
8248
|
-
return parseSectionsFromRoot(document);
|
|
8249
|
-
}
|
|
8250
|
-
function parseSectionsFromHtml(html) {
|
|
8251
|
-
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
8252
|
-
return parseSectionsFromRoot(doc);
|
|
8253
|
-
}
|
|
8254
|
-
|
|
8255
|
-
// src/lib/section-instances.ts
|
|
8256
|
-
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
8257
|
-
var REMOVED_ATTR2 = "data-ohw-section-removed";
|
|
8258
|
-
function isRemovedSection(el) {
|
|
8259
|
-
return el.hasAttribute(REMOVED_ATTR2);
|
|
8260
|
-
}
|
|
8261
|
-
function topLevelSections() {
|
|
8262
|
-
return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
8263
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el) && !isRemovedSection(el)
|
|
8264
|
-
);
|
|
8265
|
-
}
|
|
8266
|
-
function instanceIdOf(el) {
|
|
8267
|
-
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
8268
|
-
}
|
|
8269
|
-
function findByInstanceId(instanceId) {
|
|
8270
|
-
const escapedId = CSS.escape(instanceId);
|
|
8271
|
-
return document.querySelector(`[data-ohw-instance="${escapedId}"]`) ?? document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
8272
|
-
}
|
|
8273
|
-
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
8274
|
-
const sections = topLevelSections();
|
|
8275
|
-
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8276
|
-
if (index === -1) return null;
|
|
8277
|
-
const dragged = sections[index];
|
|
8278
|
-
const others = sections.filter((_, i) => i !== index);
|
|
8279
|
-
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
8280
|
-
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
8281
|
-
return reordered.map((el, order) => ({
|
|
8282
|
-
instanceId: instanceIdOf(el),
|
|
8283
|
-
type: el.getAttribute("data-ohw-section") ?? "",
|
|
8284
|
-
order,
|
|
8285
|
-
pagePath: currentPath
|
|
8286
|
-
}));
|
|
8287
|
-
}
|
|
8288
|
-
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
8289
|
-
const sections = topLevelSections();
|
|
8290
|
-
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8291
|
-
if (index === -1) return null;
|
|
8292
|
-
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
8293
|
-
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
8294
|
-
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
8295
|
-
if (!entries) return null;
|
|
8296
|
-
applyPersistedOrder(entries);
|
|
8297
|
-
return entries;
|
|
8298
|
-
}
|
|
8299
|
-
function syncRemovedFlags(entries) {
|
|
8300
|
-
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
8301
|
-
document.querySelectorAll(`[${REMOVED_ATTR2}]`).forEach((el) => {
|
|
8302
|
-
if (!removedIds.has(instanceIdOf(el))) {
|
|
8303
|
-
el.style.removeProperty("display");
|
|
8304
|
-
el.removeAttribute(REMOVED_ATTR2);
|
|
8305
|
-
}
|
|
8306
|
-
});
|
|
8307
|
-
for (const id of removedIds) {
|
|
8308
|
-
const el = findByInstanceId(id);
|
|
8309
|
-
if (el) {
|
|
8310
|
-
el.style.display = "none";
|
|
8311
|
-
el.setAttribute(REMOVED_ATTR2, "");
|
|
8312
|
-
}
|
|
8313
|
-
}
|
|
8314
|
-
}
|
|
8315
|
-
function applyPersistedOrder(entries) {
|
|
8316
|
-
syncRemovedFlags(entries);
|
|
8317
|
-
if (entries.length === 0) return;
|
|
8318
|
-
const sections = topLevelSections();
|
|
8319
|
-
if (sections.length === 0) return;
|
|
8320
|
-
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
8321
|
-
const ordered = [...sections].sort((a, b) => {
|
|
8322
|
-
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
8323
|
-
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
8324
|
-
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
8325
|
-
if (aOrder === void 0) return 1;
|
|
8326
|
-
if (bOrder === void 0) return -1;
|
|
8327
|
-
return aOrder - bOrder;
|
|
8328
|
-
});
|
|
8329
|
-
let prev = null;
|
|
8330
|
-
for (const el of ordered) {
|
|
8331
|
-
if (prev) prev.after(el);
|
|
8332
|
-
prev = el;
|
|
8333
|
-
}
|
|
8334
|
-
}
|
|
8335
|
-
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
8336
|
-
if (!findByInstanceId(instanceId)) return null;
|
|
8337
|
-
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
8338
|
-
const allSections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
8339
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
|
|
8340
|
-
);
|
|
8341
|
-
allSections.forEach((el, order) => {
|
|
8342
|
-
const id = instanceIdOf(el);
|
|
8343
|
-
if (!byId.has(id)) {
|
|
8344
|
-
byId.set(id, { instanceId: id, type: el.getAttribute("data-ohw-section") ?? "", order, pagePath: currentPath });
|
|
8345
|
-
}
|
|
8346
|
-
});
|
|
8347
|
-
const target = byId.get(instanceId);
|
|
8348
|
-
if (!target) return null;
|
|
8349
|
-
byId.set(instanceId, { ...target, removed });
|
|
8350
|
-
const entries = Array.from(byId.values());
|
|
8351
|
-
applyPersistedOrder(entries);
|
|
8352
|
-
return entries;
|
|
8353
|
-
}
|
|
8354
|
-
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
8355
|
-
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
8356
|
-
}
|
|
8357
|
-
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
8358
|
-
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
8359
|
-
}
|
|
8360
|
-
function duplicateSectionInstance(instanceId, newId, currentPath, existingEntries) {
|
|
8361
|
-
const original = findByInstanceId(instanceId);
|
|
8362
|
-
if (!original) return null;
|
|
8363
|
-
const clone = original.cloneNode(true);
|
|
8364
|
-
clone.setAttribute("data-ohw-instance", newId);
|
|
8365
|
-
const keyRekeys = rekeySectionSubtree(clone, newId);
|
|
8366
|
-
original.insertAdjacentElement("afterend", clone);
|
|
8367
|
-
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
8368
|
-
const entries = topLevelSections().map((el, order) => {
|
|
8369
|
-
const id = instanceIdOf(el);
|
|
8370
|
-
return {
|
|
8371
|
-
instanceId: id,
|
|
8372
|
-
type: el.getAttribute("data-ohw-section") ?? "",
|
|
8373
|
-
order,
|
|
8374
|
-
pagePath: currentPath,
|
|
8375
|
-
...byId.get(id)?.removed ? { removed: true } : {}
|
|
8376
|
-
};
|
|
8377
|
-
});
|
|
8378
|
-
applyPersistedOrder(entries);
|
|
8379
|
-
return { entries, keyRekeys };
|
|
8380
|
-
}
|
|
8381
|
-
function newInstanceId() {
|
|
8382
|
-
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
8383
|
-
}
|
|
8384
|
-
function getPageSectionOrderEntries(raw, currentPath) {
|
|
8385
|
-
if (!raw) return [];
|
|
8386
|
-
try {
|
|
8387
|
-
const entries = JSON.parse(raw);
|
|
8388
|
-
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
8389
|
-
} catch {
|
|
8390
|
-
return [];
|
|
8391
|
-
}
|
|
8392
|
-
}
|
|
8393
|
-
function rekeySectionSubtree(root, instanceId) {
|
|
8394
|
-
const suffix = `::${instanceId}`;
|
|
8395
|
-
const pairs = [];
|
|
8396
|
-
const rekey = (el, attr) => {
|
|
8397
|
-
const current = el.getAttribute(attr);
|
|
8398
|
-
if (!current) return;
|
|
8399
|
-
const base = current.includes("::") ? current.slice(0, current.indexOf("::")) : current;
|
|
8400
|
-
const next = `${base}${suffix}`;
|
|
8401
|
-
el.setAttribute(attr, next);
|
|
8402
|
-
pairs.push({ from: current, to: next });
|
|
8403
|
-
};
|
|
8404
|
-
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
8405
|
-
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
8406
|
-
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
8407
|
-
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
8408
|
-
return pairs;
|
|
8409
|
-
}
|
|
8410
|
-
function initSectionInstancesFromContent(content, currentPath) {
|
|
8411
|
-
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
8412
|
-
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
8413
|
-
});
|
|
8414
|
-
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
8415
|
-
for (const entry of entries) {
|
|
8416
|
-
if (entry.instanceId === entry.type) continue;
|
|
8417
|
-
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
8418
|
-
const original = document.querySelector(
|
|
8419
|
-
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
8420
|
-
);
|
|
8421
|
-
if (!original) continue;
|
|
8422
|
-
const clone = original.cloneNode(true);
|
|
8423
|
-
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
8424
|
-
rekeySectionSubtree(clone, entry.instanceId);
|
|
8425
|
-
original.insertAdjacentElement("afterend", clone);
|
|
8426
|
-
}
|
|
8427
|
-
applyPersistedOrder(entries);
|
|
9134
|
+
}
|
|
9135
|
+
)
|
|
9136
|
+
}
|
|
9137
|
+
);
|
|
8428
9138
|
}
|
|
8429
9139
|
|
|
8430
9140
|
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
9141
|
+
var import_react8 = require("react");
|
|
9142
|
+
var import_lucide_react7 = require("lucide-react");
|
|
8431
9143
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
8432
|
-
|
|
8433
|
-
const escaped = CSS.escape(instanceId);
|
|
8434
|
-
return document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]:not([data-ohw-instance])`);
|
|
8435
|
-
}
|
|
9144
|
+
var findSectionElement = findByInstanceId;
|
|
8436
9145
|
function readRect(instanceId) {
|
|
8437
9146
|
const el = findSectionElement(instanceId);
|
|
8438
9147
|
if (!el) return null;
|
|
@@ -8472,7 +9181,7 @@ function useLiveSectionRect(sectionId) {
|
|
|
8472
9181
|
}
|
|
8473
9182
|
function computeSectionBoundaryFlags(instanceId) {
|
|
8474
9183
|
const topLevel = topLevelSections();
|
|
8475
|
-
const index = topLevel.findIndex((el) => (el
|
|
9184
|
+
const index = topLevel.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8476
9185
|
if (index === -1) return { isFirst: true, isLast: true };
|
|
8477
9186
|
return { isFirst: index === 0, isLast: index === topLevel.length - 1 };
|
|
8478
9187
|
}
|
|
@@ -8556,18 +9265,20 @@ function AiSectionOverlay({
|
|
|
8556
9265
|
selectedIdRef.current = selectedId;
|
|
8557
9266
|
const report = (0, import_react8.useCallback)(
|
|
8558
9267
|
(el) => {
|
|
9268
|
+
const labelSrc = el ? sectionElementOf(el) : null;
|
|
8559
9269
|
postToParent2({
|
|
8560
9270
|
type: "ow:section-selected",
|
|
8561
|
-
sectionId: el ? el
|
|
8562
|
-
sectionLabel:
|
|
9271
|
+
sectionId: el ? instanceIdOf(el) || null : null,
|
|
9272
|
+
sectionLabel: labelSrc ? labelSrc.dataset.ohwSectionLabel ?? titleCaseSectionId(labelSrc.dataset.ohwSection ?? "") : null
|
|
8563
9273
|
});
|
|
8564
9274
|
},
|
|
8565
9275
|
[postToParent2]
|
|
8566
9276
|
);
|
|
8567
9277
|
const selectFromElement = (0, import_react8.useCallback)(
|
|
8568
9278
|
(el, options) => {
|
|
8569
|
-
const
|
|
8570
|
-
const
|
|
9279
|
+
const inner = el?.closest("[data-ohw-section]") ?? null;
|
|
9280
|
+
const sectionEl = inner ? movableUnit(inner) : null;
|
|
9281
|
+
const id = sectionEl ? instanceIdOf(sectionEl) || null : null;
|
|
8571
9282
|
if (id === selectedIdRef.current) return;
|
|
8572
9283
|
setSelectedId(id);
|
|
8573
9284
|
if (options?.report !== false) report(sectionEl);
|
|
@@ -8633,7 +9344,8 @@ function AiSectionOverlay({
|
|
|
8633
9344
|
return;
|
|
8634
9345
|
}
|
|
8635
9346
|
const sec = t.closest("[data-ohw-section]");
|
|
8636
|
-
|
|
9347
|
+
const unit = sec ? movableUnit(sec) : null;
|
|
9348
|
+
setHoveredId(unit ? instanceIdOf(unit) || null : null);
|
|
8637
9349
|
};
|
|
8638
9350
|
const onLeave = () => setHoveredId(null);
|
|
8639
9351
|
document.addEventListener("mousemove", onMove, { passive: true });
|
|
@@ -9237,7 +9949,7 @@ function SectionTreeItem({
|
|
|
9237
9949
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
9238
9950
|
"div",
|
|
9239
9951
|
{
|
|
9240
|
-
className: "mr-
|
|
9952
|
+
className: "-mr-px h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
|
|
9241
9953
|
"aria-hidden": true
|
|
9242
9954
|
}
|
|
9243
9955
|
),
|
|
@@ -9256,7 +9968,7 @@ function SectionTreeItem({
|
|
|
9256
9968
|
className: cn(
|
|
9257
9969
|
"flex h-9 min-w-0 flex-1 items-center gap-2 rounded-md border border-border bg-background p-3",
|
|
9258
9970
|
interactive && "cursor-pointer hover:bg-muted/30",
|
|
9259
|
-
interactive && selected && "border-primary"
|
|
9971
|
+
interactive && selected && "border-bridge-primary"
|
|
9260
9972
|
),
|
|
9261
9973
|
children: [
|
|
9262
9974
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
@@ -9386,7 +10098,7 @@ function UrlOrPageInput({
|
|
|
9386
10098
|
};
|
|
9387
10099
|
const fieldClassName = cn(
|
|
9388
10100
|
"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]",
|
|
9389
|
-
urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
|
|
10101
|
+
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"
|
|
9390
10102
|
);
|
|
9391
10103
|
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
|
|
9392
10104
|
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
|
|
@@ -10430,6 +11142,32 @@ function getNavbarDesktopContainer() {
|
|
|
10430
11142
|
function getNavbarDrawerContainer() {
|
|
10431
11143
|
return document.querySelector("[data-ohw-nav-drawer]");
|
|
10432
11144
|
}
|
|
11145
|
+
function isNavbarListContainerVisible(el) {
|
|
11146
|
+
if (el.hasAttribute("hidden")) return false;
|
|
11147
|
+
if (el.getClientRects().length === 0) return false;
|
|
11148
|
+
const style = window.getComputedStyle(el);
|
|
11149
|
+
return style.display !== "none" && style.visibility !== "hidden";
|
|
11150
|
+
}
|
|
11151
|
+
function getActiveNavbarListContainer(draggedEl) {
|
|
11152
|
+
const desktop = getNavbarDesktopContainer();
|
|
11153
|
+
const drawer = getNavbarDrawerContainer();
|
|
11154
|
+
if (draggedEl) {
|
|
11155
|
+
if (drawer?.contains(draggedEl)) return drawer;
|
|
11156
|
+
if (desktop?.contains(draggedEl)) return desktop;
|
|
11157
|
+
}
|
|
11158
|
+
if (desktop && isNavbarListContainerVisible(desktop)) return desktop;
|
|
11159
|
+
if (drawer && isNavbarListContainerVisible(drawer)) return drawer;
|
|
11160
|
+
return desktop ?? drawer;
|
|
11161
|
+
}
|
|
11162
|
+
function listActiveNavbarItems(draggedEl) {
|
|
11163
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
11164
|
+
if (container) {
|
|
11165
|
+
return Array.from(container.querySelectorAll("[data-ohw-href-key]")).filter(
|
|
11166
|
+
isNavbarLinkItem
|
|
11167
|
+
);
|
|
11168
|
+
}
|
|
11169
|
+
return listNavbarItems();
|
|
11170
|
+
}
|
|
10433
11171
|
function listNavbarItems() {
|
|
10434
11172
|
const desktop = getNavbarDesktopContainer();
|
|
10435
11173
|
if (desktop) {
|
|
@@ -11542,20 +12280,23 @@ function isEmptyLabelValue(value) {
|
|
|
11542
12280
|
function applyStoredValues(item, content) {
|
|
11543
12281
|
const hrefKey = socialHrefKey(item);
|
|
11544
12282
|
const iconKey = socialIconKey(item);
|
|
12283
|
+
const baseKey = hrefKey?.replace(/-href$/, "");
|
|
11545
12284
|
if (hrefKey && content[hrefKey] !== void 0) item.setAttribute("href", content[hrefKey]);
|
|
11546
|
-
|
|
12285
|
+
const glyphKey = iconKey ?? baseKey ?? null;
|
|
12286
|
+
const glyphStored = glyphKey ? content[glyphKey]?.trim() : void 0;
|
|
12287
|
+
if (glyphStored) {
|
|
12288
|
+
ensureIconSlot(item);
|
|
11547
12289
|
const glyph = item.querySelector(ICON_SELECTOR);
|
|
11548
|
-
if (glyph
|
|
11549
|
-
applyIconMarkup(glyph,
|
|
12290
|
+
if (glyph) {
|
|
12291
|
+
applyIconMarkup(glyph, glyphStored);
|
|
11550
12292
|
glyph.removeAttribute(SOCIALS_ICON_PLACEHOLDER_ATTR);
|
|
11551
12293
|
}
|
|
11552
|
-
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
}
|
|
12294
|
+
}
|
|
12295
|
+
const label = socialLabelElement(item);
|
|
12296
|
+
const labelKey = label?.getAttribute("data-ohw-key");
|
|
12297
|
+
if (label && labelKey && content[labelKey] !== void 0) {
|
|
12298
|
+
const words = isEmptyLabelValue(content[labelKey]) ? "" : content[labelKey];
|
|
12299
|
+
if (label.innerHTML !== words) label.innerHTML = words;
|
|
11559
12300
|
}
|
|
11560
12301
|
}
|
|
11561
12302
|
function socialPlatformKey(iconKey) {
|
|
@@ -11644,6 +12385,9 @@ function insertSocialItem(row, after, content = {}, { placeholder = true, keys }
|
|
|
11644
12385
|
if (placeholder) {
|
|
11645
12386
|
const label = socialLabelElement(item);
|
|
11646
12387
|
if (label) label.textContent = PLACEHOLDER_SOCIAL_LABEL;
|
|
12388
|
+
} else if (keys) {
|
|
12389
|
+
const label = socialLabelElement(item);
|
|
12390
|
+
if (label) label.textContent = "";
|
|
11647
12391
|
}
|
|
11648
12392
|
applySocialsDisplayToRow(row, display);
|
|
11649
12393
|
return { item, hrefKey, iconKey, order: getSocialsOrderFromDom(row.ownerDocument) };
|
|
@@ -13144,6 +13888,7 @@ function readLogoSizeState(content, placement) {
|
|
|
13144
13888
|
function getLogoElement(el) {
|
|
13145
13889
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
13146
13890
|
if (marked) return marked;
|
|
13891
|
+
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
13147
13892
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
13148
13893
|
if (!root) return null;
|
|
13149
13894
|
const anchor = el.closest("a");
|
|
@@ -13431,7 +14176,7 @@ function DisplaySwitch({
|
|
|
13431
14176
|
onClick: () => onChange(!checked),
|
|
13432
14177
|
className: cn(
|
|
13433
14178
|
"relative h-5 w-9 shrink-0 rounded-full transition-colors",
|
|
13434
|
-
checked ? "bg-primary" : "bg-primary-50",
|
|
14179
|
+
checked ? "bg-bridge-primary" : "bg-primary-50",
|
|
13435
14180
|
disabled ? "cursor-default opacity-50" : "cursor-pointer"
|
|
13436
14181
|
),
|
|
13437
14182
|
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
@@ -13439,7 +14184,7 @@ function DisplaySwitch({
|
|
|
13439
14184
|
{
|
|
13440
14185
|
className: cn(
|
|
13441
14186
|
"absolute top-0.5 h-4 w-4 rounded-full bg-white transition-all",
|
|
13442
|
-
checked ? "left-
|
|
14187
|
+
checked ? "left-4.5" : "left-0.5"
|
|
13443
14188
|
)
|
|
13444
14189
|
}
|
|
13445
14190
|
)
|
|
@@ -13500,8 +14245,8 @@ var lockFooterDuringDrag = lockItemDuringDrag;
|
|
|
13500
14245
|
var unlockFooterDragInteraction = unlockItemDragInteraction;
|
|
13501
14246
|
|
|
13502
14247
|
// src/lib/nav-dnd.ts
|
|
13503
|
-
function listReorderableNavItems() {
|
|
13504
|
-
return
|
|
14248
|
+
function listReorderableNavItems(draggedEl) {
|
|
14249
|
+
return listActiveNavbarItems(draggedEl).filter((el) => {
|
|
13505
14250
|
const key = el.getAttribute("data-ohw-href-key");
|
|
13506
14251
|
return isNavbarHrefKey(key) && !isNestedNavChild(el);
|
|
13507
14252
|
});
|
|
@@ -13516,8 +14261,8 @@ function resolveParentNavHrefKey(child) {
|
|
|
13516
14261
|
const key = trigger?.getAttribute("data-ohw-href-key");
|
|
13517
14262
|
return key && isNavbarHrefKey(key) ? key : null;
|
|
13518
14263
|
}
|
|
13519
|
-
function listNavChildren(parentHrefKey) {
|
|
13520
|
-
const items =
|
|
14264
|
+
function listNavChildren(parentHrefKey, draggedEl) {
|
|
14265
|
+
const items = listActiveNavbarItems(draggedEl);
|
|
13521
14266
|
const parent = items.find((el) => el.getAttribute("data-ohw-href-key") === parentHrefKey);
|
|
13522
14267
|
if (!parent) return [];
|
|
13523
14268
|
const group = parent.closest("[data-ohw-nav-group]");
|
|
@@ -13527,20 +14272,83 @@ function listNavChildren(parentHrefKey) {
|
|
|
13527
14272
|
(el) => isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))
|
|
13528
14273
|
);
|
|
13529
14274
|
}
|
|
13530
|
-
function
|
|
13531
|
-
const
|
|
13532
|
-
if (
|
|
13533
|
-
const
|
|
13534
|
-
|
|
14275
|
+
function isVerticalNavLayout(items, draggedEl) {
|
|
14276
|
+
const visible = items.filter((el) => el.getClientRects().length > 0);
|
|
14277
|
+
if (visible.length >= 2) {
|
|
14278
|
+
const a = visible[0].getBoundingClientRect();
|
|
14279
|
+
const b = visible[1].getBoundingClientRect();
|
|
14280
|
+
const verticalGap = b.top - a.bottom;
|
|
14281
|
+
const horizontalGap = b.left - a.right;
|
|
14282
|
+
return verticalGap > horizontalGap;
|
|
14283
|
+
}
|
|
14284
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
14285
|
+
if (!container) return false;
|
|
14286
|
+
const style = window.getComputedStyle(container);
|
|
14287
|
+
return style.flexDirection === "column" || style.flexDirection === "column-reverse";
|
|
14288
|
+
}
|
|
14289
|
+
function buildVerticalRootNavDropSlots(items, draggedEl) {
|
|
14290
|
+
const slots = [];
|
|
14291
|
+
const barThickness = 3;
|
|
14292
|
+
if (items.length === 0) {
|
|
14293
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
14294
|
+
if (!container) return slots;
|
|
14295
|
+
const rect = container.getBoundingClientRect();
|
|
14296
|
+
slots.push({
|
|
14297
|
+
insertIndex: 0,
|
|
14298
|
+
parentId: null,
|
|
14299
|
+
left: rect.left,
|
|
14300
|
+
top: rect.top + rect.height / 2 - barThickness / 2,
|
|
14301
|
+
width: Math.max(rect.width, 40),
|
|
14302
|
+
height: barThickness,
|
|
14303
|
+
direction: "horizontal"
|
|
14304
|
+
});
|
|
14305
|
+
return slots;
|
|
14306
|
+
}
|
|
14307
|
+
const edgeGap = (() => {
|
|
14308
|
+
if (items.length < 2) return 16;
|
|
14309
|
+
const a = items[0].getBoundingClientRect();
|
|
14310
|
+
const b = items[1].getBoundingClientRect();
|
|
14311
|
+
return Math.max(0, b.top - a.bottom);
|
|
14312
|
+
})();
|
|
14313
|
+
for (let i = 0; i <= items.length; i++) {
|
|
14314
|
+
let top;
|
|
14315
|
+
let width;
|
|
14316
|
+
let left;
|
|
14317
|
+
if (i === 0) {
|
|
14318
|
+
const first = items[0].getBoundingClientRect();
|
|
14319
|
+
top = first.top - edgeGap / 2 - barThickness / 2;
|
|
14320
|
+
left = first.left;
|
|
14321
|
+
width = first.width;
|
|
14322
|
+
} else if (i === items.length) {
|
|
14323
|
+
const last = items[items.length - 1].getBoundingClientRect();
|
|
14324
|
+
const lastGap = items.length >= 2 ? Math.max(0, last.top - items[items.length - 2].getBoundingClientRect().bottom) : edgeGap;
|
|
14325
|
+
top = last.bottom + lastGap / 2 - barThickness / 2;
|
|
14326
|
+
left = last.left;
|
|
14327
|
+
width = last.width;
|
|
14328
|
+
} else {
|
|
14329
|
+
const prev = items[i - 1].getBoundingClientRect();
|
|
14330
|
+
const next = items[i].getBoundingClientRect();
|
|
14331
|
+
top = (prev.bottom + next.top) / 2 - barThickness / 2;
|
|
14332
|
+
left = Math.min(prev.left, next.left);
|
|
14333
|
+
width = Math.max(prev.right, next.right) - left;
|
|
14334
|
+
}
|
|
14335
|
+
slots.push({
|
|
14336
|
+
insertIndex: i,
|
|
14337
|
+
parentId: null,
|
|
14338
|
+
left,
|
|
14339
|
+
top,
|
|
14340
|
+
width: Math.max(width, 40),
|
|
14341
|
+
height: barThickness,
|
|
14342
|
+
direction: "horizontal"
|
|
14343
|
+
});
|
|
13535
14344
|
}
|
|
13536
|
-
return
|
|
14345
|
+
return slots;
|
|
13537
14346
|
}
|
|
13538
|
-
function
|
|
13539
|
-
const items = listReorderableNavItems();
|
|
14347
|
+
function buildHorizontalRootNavDropSlots(items, draggedEl) {
|
|
13540
14348
|
const slots = [];
|
|
13541
14349
|
const barThickness = 3;
|
|
13542
14350
|
if (items.length === 0) {
|
|
13543
|
-
const container =
|
|
14351
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
13544
14352
|
if (!container) return slots;
|
|
13545
14353
|
const rect = container.getBoundingClientRect();
|
|
13546
14354
|
slots.push({
|
|
@@ -13571,10 +14379,7 @@ function buildRootNavDropSlots() {
|
|
|
13571
14379
|
height = first.height;
|
|
13572
14380
|
} else if (i === items.length) {
|
|
13573
14381
|
const last = items[items.length - 1].getBoundingClientRect();
|
|
13574
|
-
const lastGap = items.length >= 2 ? Math.max(
|
|
13575
|
-
0,
|
|
13576
|
-
last.left - items[items.length - 2].getBoundingClientRect().right
|
|
13577
|
-
) : edgeGap;
|
|
14382
|
+
const lastGap = items.length >= 2 ? Math.max(0, last.left - items[items.length - 2].getBoundingClientRect().right) : edgeGap;
|
|
13578
14383
|
left = last.right + lastGap / 2 - barThickness / 2;
|
|
13579
14384
|
top = last.top;
|
|
13580
14385
|
height = last.height;
|
|
@@ -13597,8 +14402,15 @@ function buildRootNavDropSlots() {
|
|
|
13597
14402
|
}
|
|
13598
14403
|
return slots;
|
|
13599
14404
|
}
|
|
13600
|
-
function
|
|
13601
|
-
const
|
|
14405
|
+
function buildRootNavDropSlots(draggedEl) {
|
|
14406
|
+
const items = listReorderableNavItems(draggedEl);
|
|
14407
|
+
if (isVerticalNavLayout(items, draggedEl)) {
|
|
14408
|
+
return buildVerticalRootNavDropSlots(items, draggedEl);
|
|
14409
|
+
}
|
|
14410
|
+
return buildHorizontalRootNavDropSlots(items, draggedEl);
|
|
14411
|
+
}
|
|
14412
|
+
function buildChildNavDropSlots(parentHrefKey, draggedEl) {
|
|
14413
|
+
const children = listNavChildren(parentHrefKey, draggedEl);
|
|
13602
14414
|
const slots = [];
|
|
13603
14415
|
const barThickness = 3;
|
|
13604
14416
|
if (children.length === 0) return slots;
|
|
@@ -13619,10 +14431,7 @@ function buildChildNavDropSlots(parentHrefKey) {
|
|
|
13619
14431
|
width = first.width;
|
|
13620
14432
|
} else if (i === children.length) {
|
|
13621
14433
|
const last = children[children.length - 1].getBoundingClientRect();
|
|
13622
|
-
const lastGap = children.length >= 2 ? Math.max(
|
|
13623
|
-
0,
|
|
13624
|
-
last.top - children[children.length - 2].getBoundingClientRect().bottom
|
|
13625
|
-
) : edgeGap;
|
|
14434
|
+
const lastGap = children.length >= 2 ? Math.max(0, last.top - children[children.length - 2].getBoundingClientRect().bottom) : edgeGap;
|
|
13626
14435
|
top = last.bottom + lastGap / 2 - barThickness / 2;
|
|
13627
14436
|
left = last.left;
|
|
13628
14437
|
width = last.width;
|
|
@@ -13645,18 +14454,19 @@ function buildChildNavDropSlots(parentHrefKey) {
|
|
|
13645
14454
|
}
|
|
13646
14455
|
return slots;
|
|
13647
14456
|
}
|
|
13648
|
-
function buildAllNavDropSlots(draggedHrefKey) {
|
|
13649
|
-
const
|
|
13650
|
-
|
|
14457
|
+
function buildAllNavDropSlots(draggedHrefKey, draggedEl) {
|
|
14458
|
+
const activeItems = listActiveNavbarItems(draggedEl);
|
|
14459
|
+
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);
|
|
14460
|
+
if (!dragged) return buildRootNavDropSlots(draggedEl);
|
|
13651
14461
|
if (isNestedNavChild(dragged)) {
|
|
13652
14462
|
const parentKey = resolveParentNavHrefKey(dragged);
|
|
13653
14463
|
if (!parentKey) return [];
|
|
13654
|
-
return buildChildNavDropSlots(parentKey);
|
|
14464
|
+
return buildChildNavDropSlots(parentKey, draggedEl);
|
|
13655
14465
|
}
|
|
13656
|
-
return buildRootNavDropSlots();
|
|
14466
|
+
return buildRootNavDropSlots(draggedEl);
|
|
13657
14467
|
}
|
|
13658
|
-
function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
|
|
13659
|
-
const slots = buildAllNavDropSlots(draggedHrefKey);
|
|
14468
|
+
function hitTestNavDropSlot(clientX, clientY, draggedHrefKey, draggedEl) {
|
|
14469
|
+
const slots = buildAllNavDropSlots(draggedHrefKey, draggedEl);
|
|
13660
14470
|
let best = null;
|
|
13661
14471
|
for (const slot of slots) {
|
|
13662
14472
|
const cx2 = slot.left + slot.width / 2;
|
|
@@ -13707,6 +14517,12 @@ function useNavItemDrag({
|
|
|
13707
14517
|
setIsItemDragging(false);
|
|
13708
14518
|
if (keepOpenEl?.isConnected) {
|
|
13709
14519
|
setNavGroupForceOpen(keepOpenEl, true);
|
|
14520
|
+
requestAnimationFrame(() => {
|
|
14521
|
+
if (keepOpenEl.isConnected) setNavGroupForceOpen(keepOpenEl, true);
|
|
14522
|
+
requestAnimationFrame(() => {
|
|
14523
|
+
if (keepOpenEl.isConnected) setNavGroupForceOpen(keepOpenEl, true);
|
|
14524
|
+
});
|
|
14525
|
+
});
|
|
13710
14526
|
} else {
|
|
13711
14527
|
setNavGroupForceOpen(null, false);
|
|
13712
14528
|
}
|
|
@@ -13722,7 +14538,7 @@ function useNavItemDrag({
|
|
|
13722
14538
|
}
|
|
13723
14539
|
session.activeSlot = activeSlot;
|
|
13724
14540
|
setSiblingHintRects([]);
|
|
13725
|
-
const slots = buildAllNavDropSlots(session.hrefKey);
|
|
14541
|
+
const slots = buildAllNavDropSlots(session.hrefKey, session.draggedEl);
|
|
13726
14542
|
setNavDropSlots(slots);
|
|
13727
14543
|
const activeIdx = activeSlot ? slots.findIndex(
|
|
13728
14544
|
(s) => s.parentId === activeSlot.parentId && s.insertIndex === activeSlot.insertIndex
|
|
@@ -13758,7 +14574,12 @@ function useNavItemDrag({
|
|
|
13758
14574
|
if (session.wasSelected && selectedElRef.current === session.draggedEl) {
|
|
13759
14575
|
setToolbarRect(rect);
|
|
13760
14576
|
}
|
|
13761
|
-
const initialSlot = hitTestNavDropSlot(
|
|
14577
|
+
const initialSlot = hitTestNavDropSlot(
|
|
14578
|
+
session.lastClientX,
|
|
14579
|
+
session.lastClientY,
|
|
14580
|
+
session.hrefKey,
|
|
14581
|
+
session.draggedEl
|
|
14582
|
+
);
|
|
13762
14583
|
refreshNavDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
|
|
13763
14584
|
},
|
|
13764
14585
|
[
|
|
@@ -13780,10 +14601,11 @@ function useNavItemDrag({
|
|
|
13780
14601
|
}
|
|
13781
14602
|
const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
|
|
13782
14603
|
const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
|
|
13783
|
-
const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey);
|
|
14604
|
+
const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey, session.draggedEl);
|
|
13784
14605
|
const planned = slot != null ? planNavItemMove(session.hrefKey, slot.parentId, slot.insertIndex) : null;
|
|
13785
14606
|
const wasSelected = session.wasSelected;
|
|
13786
14607
|
const hrefKey = session.hrefKey;
|
|
14608
|
+
const keepDropdownOpen = Boolean(session.draggedEl.closest("[data-ohw-nav-children]"));
|
|
13787
14609
|
const applySelectionAfterDrop = () => {
|
|
13788
14610
|
if (!wasSelected) {
|
|
13789
14611
|
deselectRef.current();
|
|
@@ -13817,6 +14639,14 @@ function useNavItemDrag({
|
|
|
13817
14639
|
});
|
|
13818
14640
|
applySelectionAfterDrop();
|
|
13819
14641
|
clearNavDragVisuals();
|
|
14642
|
+
if (keepDropdownOpen) {
|
|
14643
|
+
requestAnimationFrame(() => {
|
|
14644
|
+
const desktop = document.querySelector("[data-ohw-nav-container]");
|
|
14645
|
+
const drawer = document.querySelector("[data-ohw-nav-drawer]");
|
|
14646
|
+
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)}"]`);
|
|
14647
|
+
if (link) setNavGroupForceOpen(link, true);
|
|
14648
|
+
});
|
|
14649
|
+
}
|
|
13820
14650
|
requestAnimationFrame(() => {
|
|
13821
14651
|
if (editContentRef.current[NAV_ORDER_KEY] === planned.orderJson) {
|
|
13822
14652
|
applyNavForest(planned.forest);
|
|
@@ -13856,7 +14686,7 @@ function useNavItemDrag({
|
|
|
13856
14686
|
if (!session) return false;
|
|
13857
14687
|
e.preventDefault();
|
|
13858
14688
|
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
13859
|
-
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
14689
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey, session.draggedEl);
|
|
13860
14690
|
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
13861
14691
|
return true;
|
|
13862
14692
|
},
|
|
@@ -13902,7 +14732,7 @@ function useNavItemDrag({
|
|
|
13902
14732
|
clearTextSelection();
|
|
13903
14733
|
const session = navDragRef.current;
|
|
13904
14734
|
if (!session) return;
|
|
13905
|
-
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
14735
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey, session.draggedEl);
|
|
13906
14736
|
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
13907
14737
|
return;
|
|
13908
14738
|
}
|
|
@@ -13918,7 +14748,8 @@ function useNavItemDrag({
|
|
|
13918
14748
|
} catch {
|
|
13919
14749
|
}
|
|
13920
14750
|
if (linkPopoverOpenRef.current) setLinkPopover(null);
|
|
13921
|
-
|
|
14751
|
+
const isNestedDrag = Boolean(pending.el.closest("[data-ohw-nav-children]"));
|
|
14752
|
+
if (activeElRef.current && !isNestedDrag) deactivateRef.current();
|
|
13922
14753
|
const key = pending.el.getAttribute("data-ohw-href-key");
|
|
13923
14754
|
if (!key) return;
|
|
13924
14755
|
beginNavDragRef.current({
|
|
@@ -13929,6 +14760,9 @@ function useNavItemDrag({
|
|
|
13929
14760
|
lastClientY: e.clientY,
|
|
13930
14761
|
activeSlot: null
|
|
13931
14762
|
});
|
|
14763
|
+
if (activeElRef.current && isNestedDrag) {
|
|
14764
|
+
deactivateRef.current();
|
|
14765
|
+
}
|
|
13932
14766
|
};
|
|
13933
14767
|
const endPointerDrag = (e) => {
|
|
13934
14768
|
const pending = navPointerDragRef.current;
|
|
@@ -14006,6 +14840,7 @@ function useNavItemDrag({
|
|
|
14006
14840
|
);
|
|
14007
14841
|
return {
|
|
14008
14842
|
navDragRef,
|
|
14843
|
+
navPointerDragRef,
|
|
14009
14844
|
navDropSlots,
|
|
14010
14845
|
activeNavDropIndex,
|
|
14011
14846
|
startNavLinkDrag,
|
|
@@ -14210,15 +15045,17 @@ function useSectionDrag({
|
|
|
14210
15045
|
clearSectionDragVisuals();
|
|
14211
15046
|
return;
|
|
14212
15047
|
}
|
|
14213
|
-
const orderJson = JSON.stringify(
|
|
15048
|
+
const orderJson = JSON.stringify(
|
|
15049
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
15050
|
+
);
|
|
14214
15051
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
14215
15052
|
setAiSectionOrder(orderJson, window.location.pathname);
|
|
14216
15053
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
14217
|
-
applyPersistedOrder(
|
|
15054
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
14218
15055
|
clearSectionDragVisuals();
|
|
14219
15056
|
requestAnimationFrame(() => {
|
|
14220
15057
|
if (editContentRef.current[SECTION_ORDER_KEY] === orderJson) {
|
|
14221
|
-
applyPersistedOrder(
|
|
15058
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
14222
15059
|
}
|
|
14223
15060
|
requestAnimationFrame(() => {
|
|
14224
15061
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -14251,8 +15088,9 @@ function useSectionDrag({
|
|
|
14251
15088
|
const target = e.target;
|
|
14252
15089
|
if (!(target instanceof HTMLElement)) return;
|
|
14253
15090
|
if (target.closest(SECTION_DRAG_EXCLUDED_SELECTOR)) return;
|
|
14254
|
-
const
|
|
14255
|
-
if (!
|
|
15091
|
+
const inner = target.closest("[data-ohw-section]");
|
|
15092
|
+
if (!inner || isChromeSection(inner) || inner.dataset.ohwSection === "footer") return;
|
|
15093
|
+
const sectionEl = movableUnit(inner);
|
|
14256
15094
|
if (!topLevelSections().includes(sectionEl)) return;
|
|
14257
15095
|
startSectionPressDrag(sectionEl, e.clientX, e.clientY, e.pointerId);
|
|
14258
15096
|
};
|
|
@@ -14519,10 +15357,15 @@ function collectEditableNodes(extraContent, root = document) {
|
|
|
14519
15357
|
if (el.dataset.ohwEditable === "link") {
|
|
14520
15358
|
return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref3(el) };
|
|
14521
15359
|
}
|
|
15360
|
+
if (el.dataset.ohwEditable === "map") {
|
|
15361
|
+
return { key: el.dataset.ohwKey ?? "", type: "map", text: el.dataset.ohwMapQuery ?? "" };
|
|
15362
|
+
}
|
|
14522
15363
|
return {
|
|
14523
15364
|
key: el.dataset.ohwKey ?? "",
|
|
14524
15365
|
type: el.dataset.ohwEditable ?? "text",
|
|
14525
|
-
|
|
15366
|
+
// innerText does not exist on SVG elements (a circular-badge <textPath> is a legitimate
|
|
15367
|
+
// plain editable) — textContent is the value there.
|
|
15368
|
+
text: el.dataset.ohwEditable === "plain" ? el.innerText ?? el.textContent ?? "" : el.innerHTML
|
|
14526
15369
|
};
|
|
14527
15370
|
});
|
|
14528
15371
|
const hrefEls = Array.from(root.querySelectorAll("[data-ohw-href-key]"));
|
|
@@ -14959,7 +15802,7 @@ var badgeVariants = cva(
|
|
|
14959
15802
|
{
|
|
14960
15803
|
variants: {
|
|
14961
15804
|
variant: {
|
|
14962
|
-
default: "border-transparent bg-primary text-primary-foreground",
|
|
15805
|
+
default: "border-transparent bg-bridge-primary text-primary-foreground",
|
|
14963
15806
|
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
14964
15807
|
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
14965
15808
|
outline: "text-foreground"
|
|
@@ -15081,21 +15924,10 @@ function parseSchedulingInsertAfter(insertAfter) {
|
|
|
15081
15924
|
insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
|
|
15082
15925
|
};
|
|
15083
15926
|
}
|
|
15084
|
-
function
|
|
15085
|
-
|
|
15086
|
-
const
|
|
15087
|
-
|
|
15088
|
-
return { effectiveInsertAfter, insertBefore };
|
|
15089
|
-
}
|
|
15090
|
-
function getSchedulingMountPoint(insertAfter) {
|
|
15091
|
-
const { anchor } = parseSchedulingInsertAfter(insertAfter);
|
|
15092
|
-
let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
|
|
15093
|
-
if (!anchorEl && anchor === "scheduling") {
|
|
15094
|
-
const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
|
|
15095
|
-
anchorEl = widgets.at(-1) ?? null;
|
|
15096
|
-
}
|
|
15097
|
-
if (!anchorEl) return null;
|
|
15098
|
-
return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
15927
|
+
function resolveEntryAnchor(entry) {
|
|
15928
|
+
if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
|
|
15929
|
+
const parsed = parseSchedulingInsertAfter(entry.insertAfter);
|
|
15930
|
+
return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
|
|
15099
15931
|
}
|
|
15100
15932
|
function schedulingMountDepth(insertAfter) {
|
|
15101
15933
|
if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
|
|
@@ -15112,8 +15944,7 @@ function getPageSchedulingEntries(raw) {
|
|
|
15112
15944
|
}
|
|
15113
15945
|
}
|
|
15114
15946
|
function isSchedulingWidgetMissing(entry) {
|
|
15115
|
-
|
|
15116
|
-
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
|
|
15947
|
+
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
|
|
15117
15948
|
}
|
|
15118
15949
|
function hasMissingSchedulingWidgets(entries) {
|
|
15119
15950
|
return entries.some(isSchedulingWidgetMissing);
|
|
@@ -15151,18 +15982,18 @@ function initSectionsFromContent(content, removeExisting = false, currentPath =
|
|
|
15151
15982
|
} catch {
|
|
15152
15983
|
}
|
|
15153
15984
|
}
|
|
15154
|
-
function mountSchedulingWidget(
|
|
15155
|
-
const
|
|
15156
|
-
const sectionId = schedulingSectionId(
|
|
15985
|
+
function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
|
|
15986
|
+
const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
|
|
15987
|
+
const sectionId = schedulingSectionId(widgetId);
|
|
15157
15988
|
if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
|
|
15158
|
-
const
|
|
15159
|
-
if (!
|
|
15989
|
+
const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
|
|
15990
|
+
if (!anchorEl) return false;
|
|
15991
|
+
const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
15160
15992
|
const container = document.createElement("div");
|
|
15161
15993
|
container.dataset.ohwSectionContainer = "scheduling";
|
|
15162
|
-
container.dataset.ohwSection = sectionId;
|
|
15163
15994
|
container.dataset.ohwInstance = sectionId;
|
|
15164
|
-
if (
|
|
15165
|
-
const beforeAnchor = document.querySelector(`[data-ohw-section="${
|
|
15995
|
+
if (beforeId) {
|
|
15996
|
+
const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
|
|
15166
15997
|
const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
|
|
15167
15998
|
if (!beforePoint) return false;
|
|
15168
15999
|
beforePoint.insertAdjacentElement("beforebegin", container);
|
|
@@ -15173,20 +16004,26 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
15173
16004
|
}
|
|
15174
16005
|
tail.insertAdjacentElement("afterend", container);
|
|
15175
16006
|
}
|
|
15176
|
-
|
|
15177
|
-
|
|
15178
|
-
|
|
15179
|
-
|
|
15180
|
-
|
|
15181
|
-
|
|
15182
|
-
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
|
|
15187
|
-
|
|
15188
|
-
|
|
15189
|
-
|
|
16007
|
+
try {
|
|
16008
|
+
const root = (0, import_client2.createRoot)(container);
|
|
16009
|
+
schedulingRoots.set(container, root);
|
|
16010
|
+
(0, import_react_dom3.flushSync)(() => {
|
|
16011
|
+
root.render(
|
|
16012
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
16013
|
+
SchedulingWidget,
|
|
16014
|
+
{
|
|
16015
|
+
notifyOnConnect,
|
|
16016
|
+
initialScheduleId: scheduleId,
|
|
16017
|
+
insertAfter: widgetId
|
|
16018
|
+
}
|
|
16019
|
+
)
|
|
16020
|
+
);
|
|
16021
|
+
});
|
|
16022
|
+
} catch (err) {
|
|
16023
|
+
console.error("[ow:scheduling] render threw", err);
|
|
16024
|
+
container.remove();
|
|
16025
|
+
return false;
|
|
16026
|
+
}
|
|
15190
16027
|
const tracker = getSectionsTracker();
|
|
15191
16028
|
let sections = [];
|
|
15192
16029
|
try {
|
|
@@ -15194,10 +16031,12 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
15194
16031
|
} catch {
|
|
15195
16032
|
}
|
|
15196
16033
|
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
15197
|
-
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter ===
|
|
16034
|
+
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
|
|
15198
16035
|
sections.push({
|
|
15199
16036
|
type: "scheduling",
|
|
15200
|
-
insertAfter:
|
|
16037
|
+
insertAfter: widgetId,
|
|
16038
|
+
anchorId,
|
|
16039
|
+
beforeId: beforeId ?? null,
|
|
15201
16040
|
pagePath: window.location.pathname,
|
|
15202
16041
|
...scheduleId ? { scheduleId } : {}
|
|
15203
16042
|
});
|
|
@@ -15211,7 +16050,8 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
|
15211
16050
|
for (let i = pending.length - 1; i >= 0; i--) {
|
|
15212
16051
|
const entry = pending[i];
|
|
15213
16052
|
const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
|
|
15214
|
-
|
|
16053
|
+
const { anchorId, beforeId } = resolveEntryAnchor(entry);
|
|
16054
|
+
if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
|
|
15215
16055
|
pending.splice(i, 1);
|
|
15216
16056
|
}
|
|
15217
16057
|
}
|
|
@@ -15303,7 +16143,7 @@ var EDITOR_CHROME_SELECTOR = '[data-ohw-toolbar], [data-ohw-form-toolbar], [data
|
|
|
15303
16143
|
function isOverEditorChrome(x, y) {
|
|
15304
16144
|
return document.elementsFromPoint(x, y).some((el) => el instanceof HTMLElement && el.matches(EDITOR_CHROME_SELECTOR));
|
|
15305
16145
|
}
|
|
15306
|
-
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"])';
|
|
16146
|
+
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"])';
|
|
15307
16147
|
function getVideoEl2(el) {
|
|
15308
16148
|
return el instanceof HTMLVideoElement ? el : el.querySelector("video");
|
|
15309
16149
|
}
|
|
@@ -15359,6 +16199,12 @@ function applyVideoSettingNode(key, val) {
|
|
|
15359
16199
|
});
|
|
15360
16200
|
return true;
|
|
15361
16201
|
}
|
|
16202
|
+
function applyMapQuery(el, val) {
|
|
16203
|
+
if (!(el instanceof HTMLIFrameElement)) return;
|
|
16204
|
+
const nextSrc = `https://www.google.com/maps?q=${encodeURIComponent(val)}&output=embed`;
|
|
16205
|
+
if (el.src !== nextSrc) el.src = nextSrc;
|
|
16206
|
+
el.setAttribute("data-ohw-map-query", val);
|
|
16207
|
+
}
|
|
15362
16208
|
function applyLinkByKey(key, val) {
|
|
15363
16209
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
15364
16210
|
if (el.dataset.ohwEditable === "link") applyLinkHref(el, val);
|
|
@@ -15369,6 +16215,11 @@ function applyLinkByKey(key, val) {
|
|
|
15369
16215
|
hrefAnchors.forEach((el) => applyLinkHref(el, val));
|
|
15370
16216
|
}
|
|
15371
16217
|
}
|
|
16218
|
+
function isInsideLinkEditor(target) {
|
|
16219
|
+
return Boolean(
|
|
16220
|
+
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"]')
|
|
16221
|
+
);
|
|
16222
|
+
}
|
|
15372
16223
|
function isInsideFloatingPanel(target) {
|
|
15373
16224
|
return Boolean(target.closest("[data-ohw-floating-panel]"));
|
|
15374
16225
|
}
|
|
@@ -15376,11 +16227,6 @@ function isPointOverFloatingPanel(clientX, clientY) {
|
|
|
15376
16227
|
const el = document.elementFromPoint(clientX, clientY);
|
|
15377
16228
|
return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
|
|
15378
16229
|
}
|
|
15379
|
-
function isInsideLinkEditor(target) {
|
|
15380
|
-
return Boolean(
|
|
15381
|
-
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"]')
|
|
15382
|
-
);
|
|
15383
|
-
}
|
|
15384
16230
|
function getHrefKeyFromElement(el) {
|
|
15385
16231
|
if (!el) return null;
|
|
15386
16232
|
const anchor = el.closest("[data-ohw-href-key]");
|
|
@@ -15393,6 +16239,7 @@ function isNavDropdownPanelOpen(childrenRoot) {
|
|
|
15393
16239
|
if (childrenRoot.closest("[data-ohw-nav-drawer]")) return true;
|
|
15394
16240
|
const group = childrenRoot.closest("[data-ohw-nav-group]");
|
|
15395
16241
|
if (group?.hasAttribute("data-ohw-nav-force-open")) return true;
|
|
16242
|
+
if (navDropdownsOpenOnClick()) return false;
|
|
15396
16243
|
if (childrenRoot.clientHeight < 2 || childrenRoot.clientWidth < 2) return false;
|
|
15397
16244
|
const style = window.getComputedStyle(childrenRoot);
|
|
15398
16245
|
if (style.display === "none" || style.visibility === "hidden") return false;
|
|
@@ -15436,6 +16283,11 @@ function getNavigationItemAnchor(el) {
|
|
|
15436
16283
|
function isNavigationItem2(el) {
|
|
15437
16284
|
return getNavigationItemAnchor(el) !== null;
|
|
15438
16285
|
}
|
|
16286
|
+
function isNavFooterScopedNavigationItem(el) {
|
|
16287
|
+
return Boolean(
|
|
16288
|
+
el.closest("nav, footer, [data-ohw-nav-container], [data-ohw-nav-drawer]")
|
|
16289
|
+
);
|
|
16290
|
+
}
|
|
15439
16291
|
function socialWordsClicked(target, item) {
|
|
15440
16292
|
const text = target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
|
|
15441
16293
|
return Boolean(text && item.contains(text));
|
|
@@ -15639,13 +16491,14 @@ function getNavigationSelectionParent(el) {
|
|
|
15639
16491
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
15640
16492
|
return getFooterLinksContainer();
|
|
15641
16493
|
}
|
|
15642
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
16494
|
+
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)) {
|
|
15643
16495
|
return getNavigationRoot(el);
|
|
15644
16496
|
}
|
|
15645
16497
|
return null;
|
|
15646
16498
|
}
|
|
15647
16499
|
function collectNavigationItemSiblingHintRects(selected) {
|
|
15648
16500
|
if (!isNavigationItem2(selected)) return [];
|
|
16501
|
+
if (!isNavFooterScopedNavigationItem(selected)) return [];
|
|
15649
16502
|
const socialsRow = findSocialsRow(selected);
|
|
15650
16503
|
if (socialsRow) {
|
|
15651
16504
|
return listSocialItems(socialsRow).filter((item) => item !== selected).map((item) => item.getBoundingClientRect());
|
|
@@ -15854,7 +16707,6 @@ var ICONS = {
|
|
|
15854
16707
|
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"/>',
|
|
15855
16708
|
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"/>'
|
|
15856
16709
|
};
|
|
15857
|
-
var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
|
|
15858
16710
|
var SELECTION_CHROME_GAP2 = 4;
|
|
15859
16711
|
var TOOLBAR_STROKE_GAP2 = 4;
|
|
15860
16712
|
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
@@ -16234,6 +17086,7 @@ function StateToggle({
|
|
|
16234
17086
|
);
|
|
16235
17087
|
}
|
|
16236
17088
|
var contentCache = /* @__PURE__ */ new Map();
|
|
17089
|
+
var fetchedContentPaths = /* @__PURE__ */ new Set();
|
|
16237
17090
|
var brandingCache = /* @__PURE__ */ new Map();
|
|
16238
17091
|
var OHW_LOADER_STYLE = {
|
|
16239
17092
|
position: "fixed",
|
|
@@ -16763,13 +17616,6 @@ function OhhwellsBridge() {
|
|
|
16763
17616
|
const [isItemDragging, setIsItemDragging] = (0, import_react17.useState)(false);
|
|
16764
17617
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react17.useState)(false);
|
|
16765
17618
|
isFooterFrameSelectionRef.current = isFooterFrameSelection;
|
|
16766
|
-
const [floatingPanel, setFloatingPanel] = (0, import_react17.useState)(null);
|
|
16767
|
-
const floatingPanelOpenRef = (0, import_react17.useRef)(false);
|
|
16768
|
-
floatingPanelOpenRef.current = floatingPanel !== null;
|
|
16769
|
-
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react17.useState)(null);
|
|
16770
|
-
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react17.useState)(null);
|
|
16771
|
-
const [editorViewport, setEditorViewport] = (0, import_react17.useState)("desktop");
|
|
16772
|
-
const [parentScrollSnap, setParentScrollSnap] = (0, import_react17.useState)(null);
|
|
16773
17619
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react17.useState)(null);
|
|
16774
17620
|
const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react17.useState)(null);
|
|
16775
17621
|
const footerDragRef = (0, import_react17.useRef)(null);
|
|
@@ -16787,6 +17633,13 @@ function OhhwellsBridge() {
|
|
|
16787
17633
|
const brandKitRef = (0, import_react17.useRef)("");
|
|
16788
17634
|
const stylesRef = (0, import_react17.useRef)("");
|
|
16789
17635
|
const pendingDeleteUndoRef = (0, import_react17.useRef)(null);
|
|
17636
|
+
const [floatingPanel, setFloatingPanel] = (0, import_react17.useState)(null);
|
|
17637
|
+
const floatingPanelOpenRef = (0, import_react17.useRef)(false);
|
|
17638
|
+
const setFloatingPanelRef = (0, import_react17.useRef)(setFloatingPanel);
|
|
17639
|
+
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react17.useState)(null);
|
|
17640
|
+
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react17.useState)(null);
|
|
17641
|
+
const [editorViewport, setEditorViewport] = (0, import_react17.useState)("desktop");
|
|
17642
|
+
const [parentScrollSnap, setParentScrollSnap] = (0, import_react17.useState)(null);
|
|
16790
17643
|
const [sitePages, setSitePages] = (0, import_react17.useState)([]);
|
|
16791
17644
|
const [sectionsByPath, setSectionsByPath] = (0, import_react17.useState)({});
|
|
16792
17645
|
const sectionsPrefetchGenRef = (0, import_react17.useRef)(0);
|
|
@@ -16795,9 +17648,21 @@ function OhhwellsBridge() {
|
|
|
16795
17648
|
const linkPopoverOpenRef = (0, import_react17.useRef)(false);
|
|
16796
17649
|
const linkPopoverGraceUntilRef = (0, import_react17.useRef)(0);
|
|
16797
17650
|
setLinkPopoverRef.current = setLinkPopover;
|
|
17651
|
+
setFloatingPanelRef.current = setFloatingPanel;
|
|
16798
17652
|
linkPopoverSessionRef.current = linkPopover;
|
|
17653
|
+
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
17654
|
+
(0, import_react17.useEffect)(() => {
|
|
17655
|
+
const syncViewport = () => {
|
|
17656
|
+
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
17657
|
+
setEditorViewport((prev) => prev === next ? prev : next);
|
|
17658
|
+
};
|
|
17659
|
+
syncViewport();
|
|
17660
|
+
window.addEventListener("resize", syncViewport);
|
|
17661
|
+
return () => window.removeEventListener("resize", syncViewport);
|
|
17662
|
+
}, []);
|
|
16799
17663
|
const {
|
|
16800
17664
|
navDragRef,
|
|
17665
|
+
navPointerDragRef,
|
|
16801
17666
|
navDropSlots,
|
|
16802
17667
|
activeNavDropIndex,
|
|
16803
17668
|
startNavLinkDrag,
|
|
@@ -17000,7 +17865,12 @@ function OhhwellsBridge() {
|
|
|
17000
17865
|
if (owner) persistFieldsRef.current(owner);
|
|
17001
17866
|
}
|
|
17002
17867
|
activeElRef.current = null;
|
|
17003
|
-
|
|
17868
|
+
const preserveNavDropdown = Boolean(navPointerDragRef.current?.el?.closest("[data-ohw-nav-children]")) || Boolean(navDragRef.current?.draggedEl?.closest("[data-ohw-nav-children]")) || Boolean(
|
|
17869
|
+
selectedElRef.current?.closest("[data-ohw-nav-children]") && selectedElRef.current?.closest("[data-ohw-nav-group]")?.hasAttribute("data-ohw-nav-force-open")
|
|
17870
|
+
);
|
|
17871
|
+
if (!preserveNavDropdown) {
|
|
17872
|
+
setNavGroupForceOpen(null, false);
|
|
17873
|
+
}
|
|
17004
17874
|
setReorderHrefKey(null);
|
|
17005
17875
|
setReorderDragDisabled(false);
|
|
17006
17876
|
if (!selectedElRef.current) {
|
|
@@ -17122,7 +17992,10 @@ function OhhwellsBridge() {
|
|
|
17122
17992
|
setSelectedIsSocialsRow(false);
|
|
17123
17993
|
const isDropdownTrigger = !isNestedNavChild(navAnchor) && (navItemHasDropdownChildren(navAnchor) || navItemOwnsDropdownPanel(navAnchor));
|
|
17124
17994
|
if (isNestedNavChild(navAnchor)) {
|
|
17125
|
-
|
|
17995
|
+
const group = navAnchor.closest("[data-ohw-nav-group]");
|
|
17996
|
+
if (group?.hasAttribute("data-ohw-nav-force-open")) {
|
|
17997
|
+
setNavGroupForceOpen(navAnchor, true);
|
|
17998
|
+
}
|
|
17126
17999
|
setNavDropdownPreviewOpen(null);
|
|
17127
18000
|
} else if (isDropdownTrigger) {
|
|
17128
18001
|
const group = navAnchor.closest("[data-ohw-nav-group]");
|
|
@@ -17204,6 +18077,10 @@ function OhhwellsBridge() {
|
|
|
17204
18077
|
const handleNavDropdownOpenChange = (0, import_react17.useCallback)((open) => {
|
|
17205
18078
|
const selected = selectedElRef.current;
|
|
17206
18079
|
if (!selected || !isNavigationItem2(selected)) return;
|
|
18080
|
+
if (isNestedNavChild(selected)) return;
|
|
18081
|
+
const group = selected.closest("[data-ohw-nav-group]");
|
|
18082
|
+
const domOpen = Boolean(group?.hasAttribute("data-ohw-nav-force-open"));
|
|
18083
|
+
if (open === domOpen) return;
|
|
17207
18084
|
setNavGroupForceOpen(selected, open);
|
|
17208
18085
|
setNavDropdownPreviewOpen(open);
|
|
17209
18086
|
requestAnimationFrame(() => {
|
|
@@ -17733,7 +18610,10 @@ function OhhwellsBridge() {
|
|
|
17733
18610
|
clearHrefKeyHover(anchor);
|
|
17734
18611
|
const isDropdownTrigger = !isNestedNavChild(anchor) && (navItemHasDropdownChildren(anchor) || navItemOwnsDropdownPanel(anchor));
|
|
17735
18612
|
if (isNestedNavChild(anchor)) {
|
|
17736
|
-
|
|
18613
|
+
const group = anchor.closest("[data-ohw-nav-group]");
|
|
18614
|
+
if (group?.hasAttribute("data-ohw-nav-force-open")) {
|
|
18615
|
+
setNavGroupForceOpen(anchor, true);
|
|
18616
|
+
}
|
|
17737
18617
|
setNavDropdownPreviewOpen(null);
|
|
17738
18618
|
} else if (isDropdownTrigger) {
|
|
17739
18619
|
setNavGroupForceOpen(null, false);
|
|
@@ -18120,6 +19000,7 @@ function OhhwellsBridge() {
|
|
|
18120
19000
|
}
|
|
18121
19001
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
18122
19002
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
19003
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
18123
19004
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
18124
19005
|
}
|
|
18125
19006
|
applyBrandChrome(content);
|
|
@@ -18127,11 +19008,11 @@ function OhhwellsBridge() {
|
|
|
18127
19008
|
for (const [key, val] of Object.entries(content)) {
|
|
18128
19009
|
if (key === "__ohw_sections") continue;
|
|
18129
19010
|
if (key === AI_SECTIONS_KEY) continue;
|
|
19011
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
19012
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18130
19013
|
if (key === BRAND_KIT_KEY) continue;
|
|
18131
19014
|
if (key === STYLE_STORE_KEY) continue;
|
|
18132
19015
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
18133
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18134
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18135
19016
|
if (applyVideoSettingNode(key, val)) continue;
|
|
18136
19017
|
if (applyCarouselNode(key, val)) continue;
|
|
18137
19018
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -18159,6 +19040,8 @@ function OhhwellsBridge() {
|
|
|
18159
19040
|
}
|
|
18160
19041
|
} else if (el.dataset.ohwEditable === "link") {
|
|
18161
19042
|
applyLinkHref(el, val);
|
|
19043
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
19044
|
+
applyMapQuery(el, val);
|
|
18162
19045
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
18163
19046
|
applyIconMarkup(el, val);
|
|
18164
19047
|
} else if (el.dataset.ohwEditable === "form") {
|
|
@@ -18177,6 +19060,9 @@ function OhhwellsBridge() {
|
|
|
18177
19060
|
applySocialsDisplayFromContent(content);
|
|
18178
19061
|
applySocialsLabelsFromContent(content, document, { fillEmptyOnly: isEditModeRef.current });
|
|
18179
19062
|
if (isEditModeRef.current) requestMissingSocialIconsRef.current();
|
|
19063
|
+
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
19064
|
+
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
19065
|
+
}
|
|
18180
19066
|
enforceLinkHrefs();
|
|
18181
19067
|
initSectionsFromContent(content, true);
|
|
18182
19068
|
sectionsLoadedRef.current = true;
|
|
@@ -18197,7 +19083,9 @@ function OhhwellsBridge() {
|
|
|
18197
19083
|
let cancelled = false;
|
|
18198
19084
|
setFetchState("loading");
|
|
18199
19085
|
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
18200
|
-
|
|
19086
|
+
const initialPath = pathname;
|
|
19087
|
+
fetchedContentPaths.add(`${subdomain}::${initialPath}`);
|
|
19088
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
18201
19089
|
if (cancelled) return;
|
|
18202
19090
|
const content = data?.content ?? {};
|
|
18203
19091
|
const branding = Boolean(data?.showBranding);
|
|
@@ -18306,7 +19194,9 @@ function OhhwellsBridge() {
|
|
|
18306
19194
|
}, [isEditMode]);
|
|
18307
19195
|
(0, import_react17.useEffect)(() => {
|
|
18308
19196
|
if (isEditMode || fetchState !== "done") return;
|
|
19197
|
+
console.log("env", process.env.NEXT_PUBLIC_FLOWOPS_API_URL);
|
|
18309
19198
|
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
19199
|
+
console.log({ apiUrl, subdomain });
|
|
18310
19200
|
bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
|
|
18311
19201
|
}, [isEditMode, fetchState, subdomain]);
|
|
18312
19202
|
(0, import_react17.useEffect)(() => {
|
|
@@ -18316,10 +19206,10 @@ function OhhwellsBridge() {
|
|
|
18316
19206
|
const applyFromCache = () => {
|
|
18317
19207
|
const content = contentCache.get(subdomain);
|
|
18318
19208
|
if (!content) return;
|
|
18319
|
-
retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
|
|
18320
|
-
initSectionInstancesFromContent(content, window.location.pathname);
|
|
18321
19209
|
observer?.disconnect();
|
|
18322
19210
|
try {
|
|
19211
|
+
retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
|
|
19212
|
+
initSectionInstancesFromContent(content, window.location.pathname);
|
|
18323
19213
|
applyBrandChrome(content);
|
|
18324
19214
|
if (typeof content[BRAND_KIT_KEY] === "string") {
|
|
18325
19215
|
applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
|
|
@@ -18331,16 +19221,17 @@ function OhhwellsBridge() {
|
|
|
18331
19221
|
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
18332
19222
|
}
|
|
18333
19223
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
19224
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
18334
19225
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
18335
19226
|
}
|
|
18336
19227
|
for (const [key, val] of Object.entries(content)) {
|
|
18337
19228
|
if (key === "__ohw_sections") continue;
|
|
18338
19229
|
if (key === AI_SECTIONS_KEY) continue;
|
|
19230
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
19231
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18339
19232
|
if (key === BRAND_KIT_KEY) continue;
|
|
18340
19233
|
if (key === STYLE_STORE_KEY) continue;
|
|
18341
19234
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
18342
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18343
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18344
19235
|
if (applyVideoSettingNode(key, val)) continue;
|
|
18345
19236
|
if (applyCarouselNode(key, val)) continue;
|
|
18346
19237
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -18355,6 +19246,8 @@ function OhhwellsBridge() {
|
|
|
18355
19246
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
18356
19247
|
} else if (el.dataset.ohwEditable === "link") {
|
|
18357
19248
|
applyLinkHref(el, val);
|
|
19249
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
19250
|
+
applyMapQuery(el, val);
|
|
18358
19251
|
} else if (el.dataset.ohwEditable === "form") {
|
|
18359
19252
|
} else if (isIconMarkupValue(val)) {
|
|
18360
19253
|
} else if (el.innerHTML !== val) {
|
|
@@ -18370,6 +19263,9 @@ function OhhwellsBridge() {
|
|
|
18370
19263
|
applySocialsDisplayFromContent(content);
|
|
18371
19264
|
applySocialsLabelsFromContent(content, document, { fillEmptyOnly: isEditModeRef.current });
|
|
18372
19265
|
if (isEditModeRef.current) requestMissingSocialIconsRef.current();
|
|
19266
|
+
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
19267
|
+
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
19268
|
+
}
|
|
18373
19269
|
document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
|
|
18374
19270
|
if (!form.querySelector("[data-ohw-form-success]")) {
|
|
18375
19271
|
reconcileFieldsFromContent(form, content);
|
|
@@ -18386,6 +19282,17 @@ function OhhwellsBridge() {
|
|
|
18386
19282
|
debounceTimer = setTimeout(applyFromCache, 150);
|
|
18387
19283
|
};
|
|
18388
19284
|
applyFromCache();
|
|
19285
|
+
const pathCacheKey = `${subdomain}::${pathname}`;
|
|
19286
|
+
if (!fetchedContentPaths.has(pathCacheKey)) {
|
|
19287
|
+
fetchedContentPaths.add(pathCacheKey);
|
|
19288
|
+
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
19289
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
19290
|
+
if (!data?.content) return;
|
|
19291
|
+
contentCache.set(subdomain, data.content);
|
|
19292
|
+
applyFromCache();
|
|
19293
|
+
}).catch(() => {
|
|
19294
|
+
});
|
|
19295
|
+
}
|
|
18389
19296
|
observer = new MutationObserver(scheduleApply);
|
|
18390
19297
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
18391
19298
|
return () => {
|
|
@@ -18410,6 +19317,10 @@ function OhhwellsBridge() {
|
|
|
18410
19317
|
deselectRef.current();
|
|
18411
19318
|
deactivateRef.current();
|
|
18412
19319
|
}, [pathname, isEditMode]);
|
|
19320
|
+
(0, import_react17.useEffect)(() => {
|
|
19321
|
+
if (!isEditMode) return;
|
|
19322
|
+
initSectionInstancesFromContent(editContentRef.current, pathname);
|
|
19323
|
+
}, [pathname, isEditMode]);
|
|
18413
19324
|
(0, import_react17.useEffect)(() => {
|
|
18414
19325
|
const contentForNav = () => {
|
|
18415
19326
|
if (isEditMode) return editContentRef.current;
|
|
@@ -18501,26 +19412,11 @@ function OhhwellsBridge() {
|
|
|
18501
19412
|
const t2 = setTimeout(measure, 500);
|
|
18502
19413
|
const ro = new ResizeObserver(schedule);
|
|
18503
19414
|
ro.observe(document.body);
|
|
18504
|
-
let lastWidth = window.innerWidth;
|
|
18505
|
-
let resizeTimers = [];
|
|
18506
|
-
const clearResizeTimers = () => {
|
|
18507
|
-
resizeTimers.forEach(clearTimeout);
|
|
18508
|
-
resizeTimers = [];
|
|
18509
|
-
};
|
|
18510
|
-
const handleResize = () => {
|
|
18511
|
-
if (window.innerWidth === lastWidth) return;
|
|
18512
|
-
lastWidth = window.innerWidth;
|
|
18513
|
-
clearResizeTimers();
|
|
18514
|
-
resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
|
|
18515
|
-
};
|
|
18516
|
-
window.addEventListener("resize", handleResize);
|
|
18517
19415
|
return () => {
|
|
18518
19416
|
clearTimeout(t1);
|
|
18519
19417
|
clearTimeout(t2);
|
|
18520
19418
|
if (raf != null) cancelAnimationFrame(raf);
|
|
18521
19419
|
ro.disconnect();
|
|
18522
|
-
clearResizeTimers();
|
|
18523
|
-
window.removeEventListener("resize", handleResize);
|
|
18524
19420
|
};
|
|
18525
19421
|
}, [pathname, isEditMode, postToParent2]);
|
|
18526
19422
|
(0, import_react17.useEffect)(() => {
|
|
@@ -18551,28 +19447,19 @@ function OhhwellsBridge() {
|
|
|
18551
19447
|
return;
|
|
18552
19448
|
}
|
|
18553
19449
|
const existing = editStylesRef.current;
|
|
18554
|
-
|
|
18555
|
-
if (existing?.base.textContent) {
|
|
18556
|
-
const match = existing.base.textContent.match(/\.min-h-screen[^{]*\{[^}]*min-height:\s*(\d+)px/);
|
|
18557
|
-
if (match) initialVh = parseInt(match[1], 10);
|
|
18558
|
-
}
|
|
19450
|
+
const canvasHeight = "var(--ohw-canvas-h, 852px)";
|
|
18559
19451
|
const baseCss = `
|
|
18560
19452
|
html { height: auto !important; }
|
|
18561
19453
|
body { height: auto !important; min-height: 0 !important; overflow: hidden !important; }
|
|
18562
|
-
.min-h-screen, .min-h-svh, .min-h-dvh { min-height: ${
|
|
18563
|
-
.h-screen, .h-svh, .h-dvh { height: ${
|
|
18564
|
-
|
|
18565
|
-
|
|
18566
|
-
[style*="
|
|
18567
|
-
|
|
18568
|
-
|
|
18569
|
-
|
|
18570
|
-
|
|
18571
|
-
so content taller than one screen (a long mobile hero, say) overflows a centered flex
|
|
18572
|
-
column upward, under whatever sits above it. Only the min-height half belongs to it. */
|
|
18573
|
-
[style*="min-height"][style*="100vh"],
|
|
18574
|
-
[style*="min-height"][style*="100svh"],
|
|
18575
|
-
[style*="min-height"][style*="100dvh"] { height: auto !important; }
|
|
19454
|
+
.min-h-screen, .min-h-svh, .min-h-dvh { min-height: ${canvasHeight} !important; }
|
|
19455
|
+
.h-screen, .h-svh, .h-dvh { height: ${canvasHeight} !important; }
|
|
19456
|
+
/* Literal inline viewport units only \u2014 skip R11 sections that already reference --ohw-canvas-h
|
|
19457
|
+
(their style attribute contains "100svh" only as a var() fallback string). */
|
|
19458
|
+
[style*="100vh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
|
|
19459
|
+
[style*="100svh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
|
|
19460
|
+
[style*="100dvh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
|
|
19461
|
+
/* R11: min-height via --ohw-canvas-h; height must grow with content taller than one screen. */
|
|
19462
|
+
[style*="min-height"][style*="--ohw-canvas-h"] { height: auto !important; }
|
|
18576
19463
|
/* Emptied text keeps somewhere to click. A label typed down to nothing collapses to a
|
|
18577
19464
|
couple of pixels, and getting back into it meant hunting for the caret with the mouse.
|
|
18578
19465
|
Edit mode only \u2014 the published page shows nothing where there is nothing (OHH-736). */
|
|
@@ -18719,6 +19606,10 @@ function OhhwellsBridge() {
|
|
|
18719
19606
|
outline-offset: 0 !important;
|
|
18720
19607
|
box-shadow: none !important;
|
|
18721
19608
|
}
|
|
19609
|
+
/* Open nav dropdown panels paint above AI section selection chrome (2147483000). */
|
|
19610
|
+
[data-ohw-nav-group][data-ohw-nav-force-open] > [data-ohw-nav-children] {
|
|
19611
|
+
z-index: 2147483100 !important;
|
|
19612
|
+
}
|
|
18722
19613
|
/* Text edit wins over grab/default (must beat [data-ohw-can-drag] *). */
|
|
18723
19614
|
[data-ohw-editing],
|
|
18724
19615
|
[data-ohw-editing] *,
|
|
@@ -18737,6 +19628,10 @@ function OhhwellsBridge() {
|
|
|
18737
19628
|
[data-ohw-editable-state], [data-ohw-editable-state] * { pointer-events: none !important; }
|
|
18738
19629
|
[data-ohw-editable-state][data-ohw-active-state] [data-ohw-editable] { pointer-events: auto !important; }
|
|
18739
19630
|
[data-ohw-editable-state][data-ohw-active-state][data-ohw-editable] { pointer-events: auto !important; }
|
|
19631
|
+
/* SVG hit-tests painted glyphs only, so an editable curved-text badge answered clicks
|
|
19632
|
+
on its letter strokes alone (and a spinning one barely at all). In edit mode the
|
|
19633
|
+
whole box takes the click; the handler resolves it to the editable inside. */
|
|
19634
|
+
svg:has([data-ohw-editable]) { pointer-events: bounding-box !important; }
|
|
18740
19635
|
`;
|
|
18741
19636
|
if (!existing) {
|
|
18742
19637
|
const base = document.createElement("style");
|
|
@@ -18775,9 +19670,6 @@ function OhhwellsBridge() {
|
|
|
18775
19670
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
18776
19671
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
18777
19672
|
if (isInsideLinkEditor(target)) return;
|
|
18778
|
-
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
18779
|
-
clearMediaSelectionRef.current();
|
|
18780
|
-
}
|
|
18781
19673
|
if (isInsideFloatingPanel(target)) return;
|
|
18782
19674
|
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
18783
19675
|
if (target.closest(
|
|
@@ -18785,6 +19677,9 @@ function OhhwellsBridge() {
|
|
|
18785
19677
|
)) {
|
|
18786
19678
|
return;
|
|
18787
19679
|
}
|
|
19680
|
+
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
19681
|
+
clearMediaSelectionRef.current();
|
|
19682
|
+
}
|
|
18788
19683
|
{
|
|
18789
19684
|
const formEl = getFormElement(target);
|
|
18790
19685
|
const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
|
|
@@ -18907,7 +19802,19 @@ function OhhwellsBridge() {
|
|
|
18907
19802
|
openLogoSizePanelRef.current(logoEl);
|
|
18908
19803
|
return;
|
|
18909
19804
|
}
|
|
18910
|
-
|
|
19805
|
+
let editable = target.closest("[data-ohw-editable]");
|
|
19806
|
+
if (!editable && target instanceof SVGElement) {
|
|
19807
|
+
const inner = target.closest("svg")?.querySelectorAll("[data-ohw-editable]");
|
|
19808
|
+
if (inner && inner.length === 1) editable = inner[0];
|
|
19809
|
+
}
|
|
19810
|
+
if (editable && !(editable instanceof HTMLElement)) {
|
|
19811
|
+
e.preventDefault();
|
|
19812
|
+
e.stopPropagation();
|
|
19813
|
+
deselectRef.current();
|
|
19814
|
+
deactivateRef.current();
|
|
19815
|
+
aiSectionApiRef.current?.selectFromElement(editable);
|
|
19816
|
+
return;
|
|
19817
|
+
}
|
|
18911
19818
|
if (editable) {
|
|
18912
19819
|
if (editable.dataset.ohwEditable === "link") {
|
|
18913
19820
|
e.preventDefault();
|
|
@@ -18936,14 +19843,6 @@ function OhhwellsBridge() {
|
|
|
18936
19843
|
}
|
|
18937
19844
|
const clickedButton = findClosestButtonLike(target);
|
|
18938
19845
|
const buttonOnMedia = Boolean(clickedButton && isMediaEditable(editable) && editable.contains(clickedButton));
|
|
18939
|
-
console.log("[click-debug]", {
|
|
18940
|
-
editableType: editable.dataset.ohwEditable,
|
|
18941
|
-
editableTag: editable.tagName,
|
|
18942
|
-
targetTag: target.tagName,
|
|
18943
|
-
clickedButtonTag: clickedButton?.tagName ?? null,
|
|
18944
|
-
buttonOnMedia,
|
|
18945
|
-
isMediaEditableEditable: isMediaEditable(editable)
|
|
18946
|
-
});
|
|
18947
19846
|
if (isMediaEditable(editable) && !buttonOnMedia) {
|
|
18948
19847
|
e.preventDefault();
|
|
18949
19848
|
e.stopPropagation();
|
|
@@ -18970,11 +19869,6 @@ function OhhwellsBridge() {
|
|
|
18970
19869
|
const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
|
|
18971
19870
|
const hrefCtx = getHrefKeyFromElement(hrefLookupTarget);
|
|
18972
19871
|
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
18973
|
-
console.log("[click-debug 2]", {
|
|
18974
|
-
hrefLookupTargetTag: hrefLookupTarget.tagName,
|
|
18975
|
-
hrefCtx: hrefCtx ? { key: hrefCtx.key } : null,
|
|
18976
|
-
navAnchorTag: navAnchor?.tagName ?? null
|
|
18977
|
-
});
|
|
18978
19872
|
if (navAnchor) {
|
|
18979
19873
|
e.preventDefault();
|
|
18980
19874
|
e.stopPropagation();
|
|
@@ -19144,6 +20038,9 @@ function OhhwellsBridge() {
|
|
|
19144
20038
|
setHoveredItemRect(null);
|
|
19145
20039
|
hoveredNavContainerRef.current = null;
|
|
19146
20040
|
setHoveredNavContainerRect(null);
|
|
20041
|
+
siblingHintElRef.current = null;
|
|
20042
|
+
setSiblingHintRect(null);
|
|
20043
|
+
setSiblingHintRects([]);
|
|
19147
20044
|
return;
|
|
19148
20045
|
}
|
|
19149
20046
|
{
|
|
@@ -19262,7 +20159,6 @@ function OhhwellsBridge() {
|
|
|
19262
20159
|
hoveredNavContainerRef.current = null;
|
|
19263
20160
|
setHoveredNavContainerRect(null);
|
|
19264
20161
|
hoveredItemElRef.current = editable;
|
|
19265
|
-
setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
|
|
19266
20162
|
}
|
|
19267
20163
|
}
|
|
19268
20164
|
}
|
|
@@ -19559,7 +20455,7 @@ function OhhwellsBridge() {
|
|
|
19559
20455
|
}
|
|
19560
20456
|
};
|
|
19561
20457
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
19562
|
-
if (linkPopoverOpenRef.current) {
|
|
20458
|
+
if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
19563
20459
|
if (hoveredImageRef.current) {
|
|
19564
20460
|
hoveredImageRef.current = null;
|
|
19565
20461
|
hoveredImageHasTextOverlapRef.current = false;
|
|
@@ -19648,6 +20544,15 @@ function OhhwellsBridge() {
|
|
|
19648
20544
|
}
|
|
19649
20545
|
return;
|
|
19650
20546
|
}
|
|
20547
|
+
const cardHit = !isDragOver && Array.from(document.querySelectorAll(".card, [data-ohw-card]")).some((card) => {
|
|
20548
|
+
if (card.contains(imgEl)) return false;
|
|
20549
|
+
const r2 = card.getBoundingClientRect();
|
|
20550
|
+
return x2 >= r2.left && x2 <= r2.right && y2 >= r2.top && y2 <= r2.bottom;
|
|
20551
|
+
});
|
|
20552
|
+
if (cardHit) {
|
|
20553
|
+
dismissImageHover();
|
|
20554
|
+
return;
|
|
20555
|
+
}
|
|
19651
20556
|
const topEl = document.elementFromPoint(x2, y2);
|
|
19652
20557
|
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"]')) {
|
|
19653
20558
|
if (hoveredImageRef.current) {
|
|
@@ -19924,8 +20829,7 @@ function OhhwellsBridge() {
|
|
|
19924
20829
|
};
|
|
19925
20830
|
const handleMouseMove = (e) => {
|
|
19926
20831
|
const { clientX, clientY } = e;
|
|
19927
|
-
if (
|
|
19928
|
-
if (isOverEditorChrome(clientX, clientY)) {
|
|
20832
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
|
|
19929
20833
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
19930
20834
|
formHoverElRef.current = null;
|
|
19931
20835
|
setFormHoverRect(null);
|
|
@@ -19933,6 +20837,12 @@ function OhhwellsBridge() {
|
|
|
19933
20837
|
setHoveredItemRect(null);
|
|
19934
20838
|
hoveredNavContainerRef.current = null;
|
|
19935
20839
|
setHoveredNavContainerRect(null);
|
|
20840
|
+
siblingHintElRef.current = null;
|
|
20841
|
+
setSiblingHintRect(null);
|
|
20842
|
+
setSiblingHintRects([]);
|
|
20843
|
+
dismissImageHover();
|
|
20844
|
+
clearImageHover();
|
|
20845
|
+
setSectionGap(null);
|
|
19936
20846
|
return;
|
|
19937
20847
|
}
|
|
19938
20848
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
@@ -19944,7 +20854,11 @@ function OhhwellsBridge() {
|
|
|
19944
20854
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
19945
20855
|
const { clientX, clientY } = e.data;
|
|
19946
20856
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
19947
|
-
if (
|
|
20857
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
20858
|
+
dismissImageHover();
|
|
20859
|
+
clearImageHover();
|
|
20860
|
+
return;
|
|
20861
|
+
}
|
|
19948
20862
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
19949
20863
|
probeSectionGapAt(clientX, clientY);
|
|
19950
20864
|
probeImageAt(clientX, clientY);
|
|
@@ -20058,7 +20972,11 @@ function OhhwellsBridge() {
|
|
|
20058
20972
|
const slotFromItem = hrefKey ? findSocialByHrefKey(hrefKey)?.querySelector('[data-ohw-editable="icon"]') : null;
|
|
20059
20973
|
const requestedIsIconSlot = Boolean(requestedIconKey) && Boolean(document.querySelector(`[data-ohw-key="${requestedIconKey}"][data-ohw-editable="icon"]`));
|
|
20060
20974
|
const requestedIsFree = Boolean(requestedIconKey) && !document.querySelector(`[data-ohw-key="${requestedIconKey}"]`);
|
|
20061
|
-
|
|
20975
|
+
let iconKey = requestedIsIconSlot ? requestedIconKey : slotFromItem?.dataset.ohwKey ?? (requestedIsFree ? requestedIconKey : void 0);
|
|
20976
|
+
const item = hrefKey ? findSocialByHrefKey(hrefKey) : null;
|
|
20977
|
+
if (item && typeof iconMarkup === "string" && iconMarkup) {
|
|
20978
|
+
iconKey = ensureIconSlot(item) ?? iconKey;
|
|
20979
|
+
}
|
|
20062
20980
|
if (iconKey && typeof iconMarkup === "string" && iconMarkup) {
|
|
20063
20981
|
document.querySelectorAll(`[data-ohw-key="${iconKey}"][data-ohw-editable="icon"]`).forEach((el) => {
|
|
20064
20982
|
applyIconMarkup(el, iconMarkup);
|
|
@@ -20068,7 +20986,7 @@ function OhhwellsBridge() {
|
|
|
20068
20986
|
}
|
|
20069
20987
|
if (iconKey && platformId) nodes.push({ key: socialPlatformKey(iconKey), text: platformId });
|
|
20070
20988
|
if (iconKey && label) {
|
|
20071
|
-
const labelKey = socialLabelKey(iconKey);
|
|
20989
|
+
const labelKey = (item ? socialLabelElement(item)?.getAttribute("data-ohw-key") : null) ?? socialLabelKey(iconKey);
|
|
20072
20990
|
document.querySelectorAll(`[data-ohw-key="${labelKey}"]`).forEach((el) => {
|
|
20073
20991
|
if (keepLabel && el.textContent?.trim()) return;
|
|
20074
20992
|
el.textContent = label;
|
|
@@ -20223,6 +21141,44 @@ function OhhwellsBridge() {
|
|
|
20223
21141
|
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
20224
21142
|
}, 400));
|
|
20225
21143
|
};
|
|
21144
|
+
const reapCommittedAiSections = (excludeIds) => {
|
|
21145
|
+
const aiState = parseAiSectionsState(aiSectionsRef.current);
|
|
21146
|
+
if (aiState.sections.length === 0) return [];
|
|
21147
|
+
let orderEntries = [];
|
|
21148
|
+
try {
|
|
21149
|
+
const parsed = JSON.parse(editContentRef.current[SECTION_ORDER_KEY] ?? "[]");
|
|
21150
|
+
if (Array.isArray(parsed)) orderEntries = parsed;
|
|
21151
|
+
} catch {
|
|
21152
|
+
return [];
|
|
21153
|
+
}
|
|
21154
|
+
const removedIds = orderEntries.filter((entry) => entry && typeof entry.instanceId === "string" && entry.removed).map((entry) => entry.instanceId);
|
|
21155
|
+
if (removedIds.length === 0) return [];
|
|
21156
|
+
const result = reapRemovedAiSections(aiState, parseStyleStore(stylesRef.current), removedIds, excludeIds);
|
|
21157
|
+
if (!result.changed) return [];
|
|
21158
|
+
const nodes = [];
|
|
21159
|
+
aiSectionsRef.current = serializeAiSectionsState(result.state);
|
|
21160
|
+
nodes.push({ key: AI_SECTIONS_KEY, text: aiSectionsRef.current });
|
|
21161
|
+
const reaped = new Set(result.reapedIds);
|
|
21162
|
+
const nextOrderJson = JSON.stringify(orderEntries.filter((entry) => !reaped.has(entry.instanceId)));
|
|
21163
|
+
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: nextOrderJson };
|
|
21164
|
+
setAiSectionOrder(nextOrderJson, window.location.pathname);
|
|
21165
|
+
nodes.push({ key: SECTION_ORDER_KEY, text: nextOrderJson });
|
|
21166
|
+
if (result.store) {
|
|
21167
|
+
stylesRef.current = JSON.stringify(result.store);
|
|
21168
|
+
nodes.push({ key: STYLE_STORE_KEY, text: stylesRef.current });
|
|
21169
|
+
}
|
|
21170
|
+
const nextContent = { ...editContentRef.current };
|
|
21171
|
+
for (const key of Object.keys(nextContent)) {
|
|
21172
|
+
if (key.startsWith(AI_SLOT_KEY_PREFIX) && result.slotPrefixes.some((prefix) => key.startsWith(prefix)) && nextContent[key] !== "") {
|
|
21173
|
+
nextContent[key] = "";
|
|
21174
|
+
nodes.push({ key, text: "" });
|
|
21175
|
+
}
|
|
21176
|
+
}
|
|
21177
|
+
editContentRef.current = nextContent;
|
|
21178
|
+
applyAiSectionsToDom(result.state);
|
|
21179
|
+
applyStylesToDom(parseStyleStore(stylesRef.current));
|
|
21180
|
+
return nodes;
|
|
21181
|
+
};
|
|
20226
21182
|
const handleHydrate = (e) => {
|
|
20227
21183
|
if (e.data?.type !== "ow:hydrate") return;
|
|
20228
21184
|
const content = e.data.content;
|
|
@@ -20241,6 +21197,7 @@ function OhhwellsBridge() {
|
|
|
20241
21197
|
}
|
|
20242
21198
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
20243
21199
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
21200
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
20244
21201
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
20245
21202
|
}
|
|
20246
21203
|
applyBrandChrome(content);
|
|
@@ -20252,11 +21209,11 @@ function OhhwellsBridge() {
|
|
|
20252
21209
|
continue;
|
|
20253
21210
|
}
|
|
20254
21211
|
if (key === AI_SECTIONS_KEY) continue;
|
|
21212
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
21213
|
+
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
20255
21214
|
if (key === BRAND_KIT_KEY) continue;
|
|
20256
21215
|
if (key === STYLE_STORE_KEY) continue;
|
|
20257
21216
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
20258
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
20259
|
-
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
20260
21217
|
if (applyVideoSettingNode(key, val)) continue;
|
|
20261
21218
|
if (applyCarouselNode(key, val)) continue;
|
|
20262
21219
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -20270,6 +21227,8 @@ function OhhwellsBridge() {
|
|
|
20270
21227
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
20271
21228
|
} else if (el.dataset.ohwEditable === "link") {
|
|
20272
21229
|
applyLinkHref(el, val);
|
|
21230
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
21231
|
+
applyMapQuery(el, val);
|
|
20273
21232
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
20274
21233
|
applyIconMarkup(el, val);
|
|
20275
21234
|
} else if (isIconMarkupValue(val)) {
|
|
@@ -20290,9 +21249,20 @@ function OhhwellsBridge() {
|
|
|
20290
21249
|
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
20291
21250
|
reconcileFooterOrderFromContent(editContentRef.current);
|
|
20292
21251
|
syncNavigationDragCursorAttrs();
|
|
21252
|
+
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
21253
|
+
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
21254
|
+
}
|
|
20293
21255
|
enforceLinkHrefs();
|
|
21256
|
+
const hydrateReapExclude = /* @__PURE__ */ new Set();
|
|
21257
|
+
const hydratePendingUndo = pendingDeleteUndoRef.current;
|
|
21258
|
+
if (hydratePendingUndo?.sectionInstanceId) hydrateReapExclude.add(hydratePendingUndo.sectionInstanceId);
|
|
21259
|
+
const reapNodes = reapCommittedAiSections(hydrateReapExclude);
|
|
21260
|
+
if (reapNodes.length > 0) postToParentRef.current({ type: "ow:change", nodes: reapNodes });
|
|
20294
21261
|
const hydratedHeight = document.body.scrollHeight;
|
|
20295
21262
|
if (hydratedHeight > 50) postToParentRef.current({ type: "ow:height", height: hydratedHeight });
|
|
21263
|
+
if (parseAiSectionsState(aiSectionsRef.current).sections.length > 0) {
|
|
21264
|
+
postAiSectionsChanged();
|
|
21265
|
+
}
|
|
20296
21266
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
20297
21267
|
};
|
|
20298
21268
|
const handleUpdateLogoIdentity = (e) => {
|
|
@@ -20464,10 +21434,26 @@ function OhhwellsBridge() {
|
|
|
20464
21434
|
const handleGetBrand = (e) => {
|
|
20465
21435
|
if (e.data?.type !== "ow:get-brand") return;
|
|
20466
21436
|
const template = deriveTemplateBrand();
|
|
20467
|
-
const
|
|
21437
|
+
const fallback = template ?? (() => {
|
|
21438
|
+
const fonts = deriveTemplateFonts();
|
|
21439
|
+
return fonts ? { palette: AI_DEFAULT_BRAND.palette, fonts } : null;
|
|
21440
|
+
})();
|
|
21441
|
+
const value = brandKitRef.current || (fallback ? JSON.stringify(fallback) : "");
|
|
20468
21442
|
postToParentRef.current({ type: "ow:brand-value", value });
|
|
20469
21443
|
};
|
|
20470
21444
|
window.addEventListener("message", handleGetBrand);
|
|
21445
|
+
const handleGetTemplateFonts = (e) => {
|
|
21446
|
+
if (e.data?.type !== "ow:get-template-fonts") return;
|
|
21447
|
+
const fonts = deriveTemplateFonts();
|
|
21448
|
+
postToParentRef.current({ type: "ow:template-fonts-value", value: fonts ? JSON.stringify(fonts) : "" });
|
|
21449
|
+
};
|
|
21450
|
+
window.addEventListener("message", handleGetTemplateFonts);
|
|
21451
|
+
const handleGetTemplateBrand = (e) => {
|
|
21452
|
+
if (e.data?.type !== "ow:get-template-brand") return;
|
|
21453
|
+
const brand = deriveTemplateBrand();
|
|
21454
|
+
postToParentRef.current({ type: "ow:template-brand-value", value: brand ? JSON.stringify(brand) : "" });
|
|
21455
|
+
};
|
|
21456
|
+
window.addEventListener("message", handleGetTemplateBrand);
|
|
20471
21457
|
const handleMoveSection = (e) => {
|
|
20472
21458
|
if (e.data?.type !== "ow:move-section") return;
|
|
20473
21459
|
const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
|
|
@@ -20475,8 +21461,11 @@ function OhhwellsBridge() {
|
|
|
20475
21461
|
if (!instanceId || !direction) return;
|
|
20476
21462
|
const entries = moveSectionInstance(instanceId, direction, window.location.pathname);
|
|
20477
21463
|
if (!entries) return;
|
|
20478
|
-
const orderJson = JSON.stringify(
|
|
21464
|
+
const orderJson = JSON.stringify(
|
|
21465
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
21466
|
+
);
|
|
20479
21467
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
21468
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
20480
21469
|
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20481
21470
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
20482
21471
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20522,8 +21511,11 @@ function OhhwellsBridge() {
|
|
|
20522
21511
|
const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname);
|
|
20523
21512
|
const entries = deleteSectionInstance(instanceId, window.location.pathname, currentEntries);
|
|
20524
21513
|
if (!entries) return;
|
|
20525
|
-
const orderJson = JSON.stringify(
|
|
21514
|
+
const orderJson = JSON.stringify(
|
|
21515
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
21516
|
+
);
|
|
20526
21517
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
21518
|
+
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20527
21519
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
20528
21520
|
aiSectionApiRef.current?.clear();
|
|
20529
21521
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20532,6 +21524,7 @@ function OhhwellsBridge() {
|
|
|
20532
21524
|
const actionId = newInstanceId();
|
|
20533
21525
|
pendingDeleteUndoRef.current = {
|
|
20534
21526
|
actionId,
|
|
21527
|
+
sectionInstanceId: instanceId,
|
|
20535
21528
|
restore: () => {
|
|
20536
21529
|
const restoredEntries = getPageSectionOrderEntries(
|
|
20537
21530
|
editContentRef.current[SECTION_ORDER_KEY],
|
|
@@ -20539,8 +21532,11 @@ function OhhwellsBridge() {
|
|
|
20539
21532
|
);
|
|
20540
21533
|
const restored = restoreSectionInstance(instanceId, window.location.pathname, restoredEntries);
|
|
20541
21534
|
if (!restored) return;
|
|
20542
|
-
const restoredJson = JSON.stringify(
|
|
21535
|
+
const restoredJson = JSON.stringify(
|
|
21536
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, restored)
|
|
21537
|
+
);
|
|
20543
21538
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: restoredJson };
|
|
21539
|
+
setAiSectionOrder(restoredJson, window.location.pathname);
|
|
20544
21540
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: restoredJson }] });
|
|
20545
21541
|
window.dispatchEvent(new Event("resize"));
|
|
20546
21542
|
const restoreHeight = document.body.scrollHeight;
|
|
@@ -20566,7 +21562,9 @@ function OhhwellsBridge() {
|
|
|
20566
21562
|
const result = duplicateSectionInstance(instanceId, newId, window.location.pathname, currentEntries);
|
|
20567
21563
|
if (!result) return;
|
|
20568
21564
|
const { entries, keyRekeys } = result;
|
|
20569
|
-
const orderJson = JSON.stringify(
|
|
21565
|
+
const orderJson = JSON.stringify(
|
|
21566
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
21567
|
+
);
|
|
20570
21568
|
const nodes = [{ key: SECTION_ORDER_KEY, text: orderJson }];
|
|
20571
21569
|
for (const { from, to } of keyRekeys) {
|
|
20572
21570
|
const inherited = editContentRef.current[from];
|
|
@@ -20576,6 +21574,7 @@ function OhhwellsBridge() {
|
|
|
20576
21574
|
...editContentRef.current,
|
|
20577
21575
|
...Object.fromEntries(nodes.map(({ key, text }) => [key, text]))
|
|
20578
21576
|
};
|
|
21577
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
20579
21578
|
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20580
21579
|
postToParentRef.current({ type: "ow:change", nodes });
|
|
20581
21580
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20594,6 +21593,12 @@ function OhhwellsBridge() {
|
|
|
20594
21593
|
closeLinkPopoverRef.current();
|
|
20595
21594
|
return;
|
|
20596
21595
|
}
|
|
21596
|
+
if (floatingPanelOpenRef.current) {
|
|
21597
|
+
setFloatingPanelRef.current(null);
|
|
21598
|
+
deselectRef.current();
|
|
21599
|
+
deactivateRef.current();
|
|
21600
|
+
return;
|
|
21601
|
+
}
|
|
20597
21602
|
deselectRef.current();
|
|
20598
21603
|
deactivateRef.current();
|
|
20599
21604
|
clearMediaSelectionRef.current();
|
|
@@ -20826,7 +21831,12 @@ function OhhwellsBridge() {
|
|
|
20826
21831
|
}
|
|
20827
21832
|
if (navDragRef.current) {
|
|
20828
21833
|
const session = navDragRef.current;
|
|
20829
|
-
const slot = hitTestNavDropSlot(
|
|
21834
|
+
const slot = hitTestNavDropSlot(
|
|
21835
|
+
session.lastClientX,
|
|
21836
|
+
session.lastClientY,
|
|
21837
|
+
session.hrefKey,
|
|
21838
|
+
session.draggedEl
|
|
21839
|
+
);
|
|
20830
21840
|
refreshNavDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
|
|
20831
21841
|
}
|
|
20832
21842
|
if (hoveredImageRef.current) {
|
|
@@ -20839,6 +21849,10 @@ function OhhwellsBridge() {
|
|
|
20839
21849
|
};
|
|
20840
21850
|
const handleSave = (e) => {
|
|
20841
21851
|
if (e.data?.type !== "ow:save") return;
|
|
21852
|
+
const pendingUndo = pendingDeleteUndoRef.current;
|
|
21853
|
+
const reapExclude = /* @__PURE__ */ new Set();
|
|
21854
|
+
if (pendingUndo?.sectionInstanceId) reapExclude.add(pendingUndo.sectionInstanceId);
|
|
21855
|
+
const reapNodes = reapCommittedAiSections(reapExclude);
|
|
20842
21856
|
const nodes = collectEditableNodes(editContentRef.current);
|
|
20843
21857
|
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
20844
21858
|
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
@@ -20858,6 +21872,11 @@ function OhhwellsBridge() {
|
|
|
20858
21872
|
const text = specs.length ? JSON.stringify(specs) : editContentRef.current[fieldsKey(formKey)];
|
|
20859
21873
|
if (text) nodes.push({ key: fieldsKey(formKey), type: "text", text });
|
|
20860
21874
|
});
|
|
21875
|
+
for (const reapNode of reapNodes) {
|
|
21876
|
+
if (reapNode.key.startsWith(AI_SLOT_KEY_PREFIX) && !nodes.some((n) => n.key === reapNode.key)) {
|
|
21877
|
+
nodes.push({ key: reapNode.key, type: "text", text: reapNode.text });
|
|
21878
|
+
}
|
|
21879
|
+
}
|
|
20861
21880
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
20862
21881
|
};
|
|
20863
21882
|
const handleInsertSection = (e) => {
|
|
@@ -20868,8 +21887,12 @@ function OhhwellsBridge() {
|
|
|
20868
21887
|
if (inserted) {
|
|
20869
21888
|
const tracker = getSectionsTracker();
|
|
20870
21889
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
|
|
20871
|
-
const
|
|
20872
|
-
|
|
21890
|
+
const reportHeight = () => {
|
|
21891
|
+
const h = document.body.scrollHeight;
|
|
21892
|
+
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
21893
|
+
};
|
|
21894
|
+
reportHeight();
|
|
21895
|
+
setTimeout(reportHeight, 500);
|
|
20873
21896
|
}
|
|
20874
21897
|
};
|
|
20875
21898
|
const handleSwitchSchedule = (e) => {
|
|
@@ -21019,18 +22042,21 @@ function OhhwellsBridge() {
|
|
|
21019
22042
|
}
|
|
21020
22043
|
return null;
|
|
21021
22044
|
};
|
|
22045
|
+
const isPointInRect = (el, clientX, clientY) => {
|
|
22046
|
+
const r2 = el.getBoundingClientRect();
|
|
22047
|
+
return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
|
|
22048
|
+
};
|
|
21022
22049
|
const isPointOverEditable = (scope, clientX, clientY) => {
|
|
21023
22050
|
const editables = scope.querySelectorAll("[data-ohw-editable], [data-ohw-href-key]");
|
|
21024
22051
|
for (const el of editables) {
|
|
21025
|
-
|
|
21026
|
-
if (clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom) return true;
|
|
22052
|
+
if (isPointInRect(el, clientX, clientY)) return true;
|
|
21027
22053
|
}
|
|
21028
22054
|
return false;
|
|
21029
22055
|
};
|
|
21030
22056
|
const handleCarouselHover = (e) => {
|
|
21031
22057
|
const container = findCarouselAtPoint(e.clientX, e.clientY);
|
|
21032
22058
|
const scope = container?.closest("[data-ohw-section]") ?? container?.parentElement ?? null;
|
|
21033
|
-
if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY)) {
|
|
22059
|
+
if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY) || isPointOverNavigation(e.clientX, e.clientY) || isPointOverBridgeChrome(e.clientX, e.clientY)) {
|
|
21034
22060
|
setCarouselHover((prev) => prev ? null : prev);
|
|
21035
22061
|
return;
|
|
21036
22062
|
}
|
|
@@ -21268,15 +22294,17 @@ function OhhwellsBridge() {
|
|
|
21268
22294
|
window.removeEventListener("message", handleAiSetBrand);
|
|
21269
22295
|
window.removeEventListener("message", handleAiSetStyles);
|
|
21270
22296
|
window.removeEventListener("message", handleGetBrand);
|
|
22297
|
+
window.removeEventListener("message", handleGetTemplateFonts);
|
|
22298
|
+
window.removeEventListener("message", handleGetTemplateBrand);
|
|
21271
22299
|
window.removeEventListener("message", handleMoveSection);
|
|
21272
22300
|
window.removeEventListener("message", handlePanelDragging);
|
|
21273
22301
|
window.removeEventListener("message", handleDeleteSection);
|
|
21274
22302
|
window.removeEventListener("message", handleDuplicateSection);
|
|
21275
22303
|
window.removeEventListener("message", handleDeactivate);
|
|
21276
|
-
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
21277
22304
|
window.removeEventListener("message", handleToastAction);
|
|
21278
22305
|
window.removeEventListener("message", handleFormCount);
|
|
21279
22306
|
window.removeEventListener("message", handleUiEscape);
|
|
22307
|
+
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
21280
22308
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
21281
22309
|
autoSaveTimers.current.clear();
|
|
21282
22310
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
@@ -21479,7 +22507,7 @@ function OhhwellsBridge() {
|
|
|
21479
22507
|
postToParent2({
|
|
21480
22508
|
type: "ow:ready",
|
|
21481
22509
|
version: "1",
|
|
21482
|
-
bridgeVersion: "0.1.
|
|
22510
|
+
bridgeVersion: "0.1.93",
|
|
21483
22511
|
path: pathname,
|
|
21484
22512
|
nodes: collectEditableNodes(editContentRef.current),
|
|
21485
22513
|
sections
|
|
@@ -22095,7 +23123,7 @@ function OhhwellsBridge() {
|
|
|
22095
23123
|
"span",
|
|
22096
23124
|
{
|
|
22097
23125
|
"data-ohw-form-count": "",
|
|
22098
|
-
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",
|
|
23126
|
+
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",
|
|
22099
23127
|
children: formPickCount
|
|
22100
23128
|
}
|
|
22101
23129
|
)
|
|
@@ -22332,11 +23360,11 @@ function OhhwellsBridge() {
|
|
|
22332
23360
|
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
22333
23361
|
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
22334
23362
|
children: [
|
|
22335
|
-
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
23363
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } }),
|
|
22336
23364
|
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
22337
23365
|
Badge,
|
|
22338
23366
|
{
|
|
22339
|
-
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",
|
|
23367
|
+
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",
|
|
22340
23368
|
onClick: () => {
|
|
22341
23369
|
window.parent.postMessage(
|
|
22342
23370
|
{
|
|
@@ -22350,7 +23378,7 @@ function OhhwellsBridge() {
|
|
|
22350
23378
|
children: "Add Section"
|
|
22351
23379
|
}
|
|
22352
23380
|
),
|
|
22353
|
-
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
23381
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } })
|
|
22354
23382
|
]
|
|
22355
23383
|
}
|
|
22356
23384
|
),
|
|
@@ -22398,6 +23426,59 @@ function OhhwellsBridge() {
|
|
|
22398
23426
|
) : null
|
|
22399
23427
|
] });
|
|
22400
23428
|
}
|
|
23429
|
+
|
|
23430
|
+
// src/ui/EmptySection.tsx
|
|
23431
|
+
var import_link = __toESM(require("next/link"), 1);
|
|
23432
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
23433
|
+
function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
|
|
23434
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
23435
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
23436
|
+
"p",
|
|
23437
|
+
{
|
|
23438
|
+
style: {
|
|
23439
|
+
fontFamily: "var(--brand-font-body)",
|
|
23440
|
+
fontSize: "0.75rem",
|
|
23441
|
+
fontWeight: 500,
|
|
23442
|
+
letterSpacing: "0.15em",
|
|
23443
|
+
textTransform: "uppercase",
|
|
23444
|
+
color: "var(--brand-accent)",
|
|
23445
|
+
marginBottom: "1.5rem"
|
|
23446
|
+
},
|
|
23447
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_link.default, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
|
|
23448
|
+
}
|
|
23449
|
+
),
|
|
23450
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
23451
|
+
"h1",
|
|
23452
|
+
{
|
|
23453
|
+
style: {
|
|
23454
|
+
fontFamily: "var(--brand-font-heading)",
|
|
23455
|
+
fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
|
|
23456
|
+
lineHeight: 1.1,
|
|
23457
|
+
letterSpacing: "-0.025em",
|
|
23458
|
+
color: "var(--brand-text)",
|
|
23459
|
+
marginBottom: "1rem"
|
|
23460
|
+
},
|
|
23461
|
+
...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
|
|
23462
|
+
children: title
|
|
23463
|
+
}
|
|
23464
|
+
),
|
|
23465
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
23466
|
+
"p",
|
|
23467
|
+
{
|
|
23468
|
+
style: {
|
|
23469
|
+
fontFamily: "var(--brand-font-body)",
|
|
23470
|
+
fontSize: "1rem",
|
|
23471
|
+
lineHeight: 1.7,
|
|
23472
|
+
fontWeight: 300,
|
|
23473
|
+
color: "var(--brand-text-muted)",
|
|
23474
|
+
maxWidth: "340px"
|
|
23475
|
+
},
|
|
23476
|
+
...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
|
|
23477
|
+
children: "This page doesn't have any content yet."
|
|
23478
|
+
}
|
|
23479
|
+
)
|
|
23480
|
+
] });
|
|
23481
|
+
}
|
|
22401
23482
|
// Annotate the CommonJS export names for ESM import in node:
|
|
22402
23483
|
0 && (module.exports = {
|
|
22403
23484
|
AI_DEFAULT_BRAND,
|
|
@@ -22415,6 +23496,7 @@ function OhhwellsBridge() {
|
|
|
22415
23496
|
DropdownMenuItem,
|
|
22416
23497
|
DropdownMenuSeparator,
|
|
22417
23498
|
DropdownMenuTrigger,
|
|
23499
|
+
EmptySection,
|
|
22418
23500
|
ItemActionToolbar,
|
|
22419
23501
|
ItemInteractionLayer,
|
|
22420
23502
|
LinkEditorPanel,
|