@ohhwells/bridge 0.1.92 → 0.1.93-next.277
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 +1519 -538
- 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 +1518 -538
- 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,10 @@ 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
|
+
);
|
|
464
561
|
for (const align of ["left", "center", "right"]) {
|
|
465
562
|
rules.push(`[data-ohw-style-align="${align}"] { text-align: ${align} !important; }`);
|
|
466
563
|
}
|
|
@@ -491,6 +588,7 @@ var SECTION_ATTRS = {
|
|
|
491
588
|
headlineScale: "data-ohw-style-headline",
|
|
492
589
|
imageAspect: "data-ohw-style-aspect",
|
|
493
590
|
spacing: "data-ohw-style-spacing",
|
|
591
|
+
cornerStyle: "data-ohw-style-corners",
|
|
494
592
|
align: "data-ohw-style-align"
|
|
495
593
|
};
|
|
496
594
|
var NODE_WROTE_ATTR = "data-ohw-style-node";
|
|
@@ -632,9 +730,535 @@ function applyStylesToDom(store) {
|
|
|
632
730
|
var import_react_dom = require("react-dom");
|
|
633
731
|
var import_client = require("react-dom/client");
|
|
634
732
|
|
|
733
|
+
// src/lib/sections.ts
|
|
734
|
+
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
735
|
+
function isChromeSection(el) {
|
|
736
|
+
return el.matches("header, nav, footer, aside");
|
|
737
|
+
}
|
|
738
|
+
function titleCaseSectionId(id) {
|
|
739
|
+
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
740
|
+
}
|
|
741
|
+
function parseSectionsFromRoot(root) {
|
|
742
|
+
const seen = /* @__PURE__ */ new Set();
|
|
743
|
+
const sections = [];
|
|
744
|
+
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
745
|
+
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
746
|
+
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
747
|
+
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
748
|
+
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
749
|
+
continue;
|
|
750
|
+
seen.add(id);
|
|
751
|
+
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
752
|
+
sections.push({ id, label });
|
|
753
|
+
}
|
|
754
|
+
return sections;
|
|
755
|
+
}
|
|
756
|
+
function collectSectionsFromDom() {
|
|
757
|
+
if (typeof document === "undefined") return [];
|
|
758
|
+
return parseSectionsFromRoot(document);
|
|
759
|
+
}
|
|
760
|
+
function parseSectionsFromHtml(html) {
|
|
761
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
762
|
+
return parseSectionsFromRoot(doc);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// src/lib/section-instances.ts
|
|
766
|
+
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
767
|
+
var REMOVED_ATTR = "data-ohw-section-removed";
|
|
768
|
+
function isRemovedSection(el) {
|
|
769
|
+
return el.hasAttribute(REMOVED_ATTR);
|
|
770
|
+
}
|
|
771
|
+
function movableUnit(el) {
|
|
772
|
+
return el.closest("[data-ohw-section-container]") ?? el;
|
|
773
|
+
}
|
|
774
|
+
function sectionTypeOf(el) {
|
|
775
|
+
return el.getAttribute("data-ohw-section") ?? el.querySelector("[data-ohw-section]")?.getAttribute("data-ohw-section") ?? "";
|
|
776
|
+
}
|
|
777
|
+
function sectionElementOf(el) {
|
|
778
|
+
return el.hasAttribute("data-ohw-section") ? el : el.querySelector("[data-ohw-section]") ?? el;
|
|
779
|
+
}
|
|
780
|
+
function collectTopLevelUnits(predicate) {
|
|
781
|
+
const seen = /* @__PURE__ */ new Set();
|
|
782
|
+
const result = [];
|
|
783
|
+
document.querySelectorAll("[data-ohw-section]").forEach((el) => {
|
|
784
|
+
if (!predicate(el)) return;
|
|
785
|
+
const unit = movableUnit(el);
|
|
786
|
+
if (unit.parentElement?.closest("[data-ohw-section],[data-ohw-section-container]")) return;
|
|
787
|
+
if (seen.has(unit)) return;
|
|
788
|
+
seen.add(unit);
|
|
789
|
+
result.push(unit);
|
|
790
|
+
});
|
|
791
|
+
return result;
|
|
792
|
+
}
|
|
793
|
+
function topLevelSections() {
|
|
794
|
+
return collectTopLevelUnits((el) => !isChromeSection(el) && !isRemovedSection(movableUnit(el)));
|
|
795
|
+
}
|
|
796
|
+
function instanceIdOf(el) {
|
|
797
|
+
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
798
|
+
}
|
|
799
|
+
function findByInstanceId(instanceId) {
|
|
800
|
+
const escapedId = CSS.escape(instanceId);
|
|
801
|
+
const direct = document.querySelector(`[data-ohw-instance="${escapedId}"]`);
|
|
802
|
+
if (direct) return movableUnit(direct);
|
|
803
|
+
const bare = document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
804
|
+
return bare ? movableUnit(bare) : null;
|
|
805
|
+
}
|
|
806
|
+
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
807
|
+
const sections = topLevelSections();
|
|
808
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
809
|
+
if (index === -1) return null;
|
|
810
|
+
const dragged = sections[index];
|
|
811
|
+
const others = sections.filter((_, i) => i !== index);
|
|
812
|
+
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
813
|
+
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
814
|
+
return reordered.map((el, order) => ({
|
|
815
|
+
instanceId: instanceIdOf(el),
|
|
816
|
+
type: sectionTypeOf(el),
|
|
817
|
+
order,
|
|
818
|
+
pagePath: currentPath
|
|
819
|
+
}));
|
|
820
|
+
}
|
|
821
|
+
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
822
|
+
const sections = topLevelSections();
|
|
823
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
824
|
+
if (index === -1) return null;
|
|
825
|
+
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
826
|
+
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
827
|
+
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
828
|
+
if (!entries) return null;
|
|
829
|
+
applyPersistedOrder(entries);
|
|
830
|
+
return entries;
|
|
831
|
+
}
|
|
832
|
+
function syncRemovedFlags(entries) {
|
|
833
|
+
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
834
|
+
document.querySelectorAll(`[${REMOVED_ATTR}]`).forEach((el) => {
|
|
835
|
+
if (!removedIds.has(instanceIdOf(el))) {
|
|
836
|
+
el.style.removeProperty("display");
|
|
837
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
838
|
+
}
|
|
839
|
+
});
|
|
840
|
+
for (const id of removedIds) {
|
|
841
|
+
const el = findByInstanceId(id);
|
|
842
|
+
if (el) {
|
|
843
|
+
el.style.display = "none";
|
|
844
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
function applyPersistedOrder(entries) {
|
|
849
|
+
syncRemovedFlags(entries);
|
|
850
|
+
if (entries.length === 0) return;
|
|
851
|
+
const sections = topLevelSections();
|
|
852
|
+
if (sections.length === 0) return;
|
|
853
|
+
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
854
|
+
const ordered = [...sections].sort((a, b) => {
|
|
855
|
+
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
856
|
+
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
857
|
+
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
858
|
+
if (aOrder === void 0) return 1;
|
|
859
|
+
if (bOrder === void 0) return -1;
|
|
860
|
+
return aOrder - bOrder;
|
|
861
|
+
});
|
|
862
|
+
let prev = null;
|
|
863
|
+
for (const el of ordered) {
|
|
864
|
+
if (prev) prev.after(el);
|
|
865
|
+
prev = el;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
869
|
+
if (!findByInstanceId(instanceId)) return null;
|
|
870
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
871
|
+
const allSections = collectTopLevelUnits((el) => !isChromeSection(el));
|
|
872
|
+
allSections.forEach((el, order) => {
|
|
873
|
+
const id = instanceIdOf(el);
|
|
874
|
+
if (!byId.has(id)) {
|
|
875
|
+
byId.set(id, { instanceId: id, type: sectionTypeOf(el), order, pagePath: currentPath });
|
|
876
|
+
}
|
|
877
|
+
});
|
|
878
|
+
const target = byId.get(instanceId);
|
|
879
|
+
if (!target) return null;
|
|
880
|
+
byId.set(instanceId, { ...target, removed });
|
|
881
|
+
const entries = Array.from(byId.values());
|
|
882
|
+
applyPersistedOrder(entries);
|
|
883
|
+
return entries;
|
|
884
|
+
}
|
|
885
|
+
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
886
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
887
|
+
}
|
|
888
|
+
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
889
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
890
|
+
}
|
|
891
|
+
function duplicateSectionInstance(instanceId, newId, currentPath, existingEntries) {
|
|
892
|
+
const original = findByInstanceId(instanceId);
|
|
893
|
+
if (!original) return null;
|
|
894
|
+
const clone = original.cloneNode(true);
|
|
895
|
+
clone.setAttribute("data-ohw-instance", newId);
|
|
896
|
+
const keyRekeys = rekeySectionSubtree(clone, newId);
|
|
897
|
+
original.insertAdjacentElement("afterend", clone);
|
|
898
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
899
|
+
const entries = topLevelSections().map((el, order) => {
|
|
900
|
+
const id = instanceIdOf(el);
|
|
901
|
+
return {
|
|
902
|
+
instanceId: id,
|
|
903
|
+
type: sectionTypeOf(el),
|
|
904
|
+
order,
|
|
905
|
+
pagePath: currentPath,
|
|
906
|
+
...byId.get(id)?.removed ? { removed: true } : {}
|
|
907
|
+
};
|
|
908
|
+
});
|
|
909
|
+
applyPersistedOrder(entries);
|
|
910
|
+
return { entries, keyRekeys };
|
|
911
|
+
}
|
|
912
|
+
function newInstanceId() {
|
|
913
|
+
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
914
|
+
}
|
|
915
|
+
function getPageSectionOrderEntries(raw, currentPath) {
|
|
916
|
+
if (!raw) return [];
|
|
917
|
+
try {
|
|
918
|
+
const entries = JSON.parse(raw);
|
|
919
|
+
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
920
|
+
} catch {
|
|
921
|
+
return [];
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
function mergePageSectionOrder(raw, currentPath, pageEntries) {
|
|
925
|
+
let all = [];
|
|
926
|
+
if (raw) {
|
|
927
|
+
try {
|
|
928
|
+
const parsed = JSON.parse(raw);
|
|
929
|
+
if (Array.isArray(parsed)) all = parsed;
|
|
930
|
+
} catch {
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
const otherPages = all.filter((e) => e && e.pagePath && e.pagePath !== currentPath);
|
|
934
|
+
const pageIds = new Set(pageEntries.map((e) => e.instanceId));
|
|
935
|
+
const removedHere = all.filter(
|
|
936
|
+
(e) => e && (!e.pagePath || e.pagePath === currentPath) && e.removed && !pageIds.has(e.instanceId)
|
|
937
|
+
);
|
|
938
|
+
return [...otherPages, ...removedHere, ...pageEntries];
|
|
939
|
+
}
|
|
940
|
+
function rekeySectionSubtree(root, instanceId) {
|
|
941
|
+
const suffix = `::${instanceId}`;
|
|
942
|
+
const pairs = [];
|
|
943
|
+
const rekey = (el, attr) => {
|
|
944
|
+
const current = el.getAttribute(attr);
|
|
945
|
+
if (!current) return;
|
|
946
|
+
const base = current.includes("::") ? current.slice(0, current.indexOf("::")) : current;
|
|
947
|
+
const next = `${base}${suffix}`;
|
|
948
|
+
el.setAttribute(attr, next);
|
|
949
|
+
pairs.push({ from: current, to: next });
|
|
950
|
+
};
|
|
951
|
+
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
952
|
+
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
953
|
+
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
954
|
+
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
955
|
+
return pairs;
|
|
956
|
+
}
|
|
957
|
+
function initSectionInstancesFromContent(content, currentPath) {
|
|
958
|
+
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
959
|
+
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
960
|
+
});
|
|
961
|
+
document.querySelectorAll("[data-ohw-section-container]:not([data-ohw-instance])").forEach((el) => {
|
|
962
|
+
const type = sectionTypeOf(el);
|
|
963
|
+
if (type) el.setAttribute("data-ohw-instance", type);
|
|
964
|
+
});
|
|
965
|
+
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
966
|
+
for (const entry of entries) {
|
|
967
|
+
if (entry.instanceId === entry.type) continue;
|
|
968
|
+
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
969
|
+
const original = document.querySelector(
|
|
970
|
+
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
971
|
+
);
|
|
972
|
+
if (!original) continue;
|
|
973
|
+
const clone = original.cloneNode(true);
|
|
974
|
+
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
975
|
+
rekeySectionSubtree(clone, entry.instanceId);
|
|
976
|
+
original.insertAdjacentElement("afterend", clone);
|
|
977
|
+
}
|
|
978
|
+
applyPersistedOrder(entries);
|
|
979
|
+
}
|
|
980
|
+
|
|
635
981
|
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
636
982
|
var import_react = __toESM(require("react"), 1);
|
|
637
983
|
var import_lucide_react = require("lucide-react");
|
|
984
|
+
|
|
985
|
+
// src/lib/placeholder-imagery.ts
|
|
986
|
+
var U = (id) => `https://images.unsplash.com/photo-${id}?auto=format&fit=crop&w=1600&q=80`;
|
|
987
|
+
var GENERIC = [
|
|
988
|
+
U("1441986300917-64674bd600d8"),
|
|
989
|
+
U("1486406146926-c627a92ad1ab"),
|
|
990
|
+
U("1497032628192-86f99bcd76bc"),
|
|
991
|
+
U("1521737604893-d14cc237f11d"),
|
|
992
|
+
U("1522071820081-009f0129c71c"),
|
|
993
|
+
U("1519389950473-47ba0277781c"),
|
|
994
|
+
U("1460925895917-afdab827c52f"),
|
|
995
|
+
U("1504384308090-c894fdcc538d")
|
|
996
|
+
];
|
|
997
|
+
var PEOPLE = [
|
|
998
|
+
U("1500648767791-00dcc994a43e"),
|
|
999
|
+
U("1494790108377-be9c29b29330"),
|
|
1000
|
+
U("1507003211169-0a1dd7228f2d"),
|
|
1001
|
+
U("1438761681033-6461ffad8d80"),
|
|
1002
|
+
U("1544005313-94ddf0286df2"),
|
|
1003
|
+
U("1472099645785-5658abf4ff4e"),
|
|
1004
|
+
U("1519085360753-af0119f7cbe7"),
|
|
1005
|
+
U("1534528741775-53994a69daeb")
|
|
1006
|
+
];
|
|
1007
|
+
var THEMED = [
|
|
1008
|
+
{
|
|
1009
|
+
keywords: ["portrait", "headshot", "person", "people", "team", "staff", "avatar", "founder", "face"],
|
|
1010
|
+
pool: PEOPLE
|
|
1011
|
+
},
|
|
1012
|
+
{
|
|
1013
|
+
keywords: ["pet", "dog", "cat", "puppy", "kitten", "vet", "animal"],
|
|
1014
|
+
pool: [
|
|
1015
|
+
U("1548199973-03cce0bbc87b"),
|
|
1016
|
+
U("1450778869180-41d0601e046e"),
|
|
1017
|
+
U("1583511655857-d19b40a7a54e"),
|
|
1018
|
+
U("1587300003388-59208cc962cb"),
|
|
1019
|
+
U("1517849845537-4d257902454a"),
|
|
1020
|
+
U("1601758228041-f3b2795255f1")
|
|
1021
|
+
]
|
|
1022
|
+
},
|
|
1023
|
+
{
|
|
1024
|
+
keywords: [
|
|
1025
|
+
"baker",
|
|
1026
|
+
"bakery",
|
|
1027
|
+
"cafe",
|
|
1028
|
+
"coffee",
|
|
1029
|
+
"latte",
|
|
1030
|
+
"restaurant",
|
|
1031
|
+
"pastr",
|
|
1032
|
+
"bread",
|
|
1033
|
+
"cake",
|
|
1034
|
+
"cater",
|
|
1035
|
+
"chef",
|
|
1036
|
+
"kitchen",
|
|
1037
|
+
"food",
|
|
1038
|
+
"pizza",
|
|
1039
|
+
"dessert",
|
|
1040
|
+
"brunch",
|
|
1041
|
+
"bistro",
|
|
1042
|
+
"deli",
|
|
1043
|
+
"dish",
|
|
1044
|
+
"menu"
|
|
1045
|
+
],
|
|
1046
|
+
pool: [
|
|
1047
|
+
U("1509440159596-0249088772ff"),
|
|
1048
|
+
U("1555507036-ab1f4038808a"),
|
|
1049
|
+
U("1517433670267-08bbd4be890f"),
|
|
1050
|
+
U("1486427944299-d1955d23e34d"),
|
|
1051
|
+
U("1504754524776-8f4f37790ca0"),
|
|
1052
|
+
U("1495474472287-4d71bcdd2085"),
|
|
1053
|
+
U("1521017432531-fbd92d768814"),
|
|
1054
|
+
U("1556909114-f6e7ad7d3136")
|
|
1055
|
+
]
|
|
1056
|
+
},
|
|
1057
|
+
{
|
|
1058
|
+
keywords: [
|
|
1059
|
+
"shop",
|
|
1060
|
+
"store",
|
|
1061
|
+
"boutique",
|
|
1062
|
+
"retail",
|
|
1063
|
+
"clothing",
|
|
1064
|
+
"fashion",
|
|
1065
|
+
"jewel",
|
|
1066
|
+
"gift",
|
|
1067
|
+
"florist",
|
|
1068
|
+
"market",
|
|
1069
|
+
"grocer",
|
|
1070
|
+
"product",
|
|
1071
|
+
"storefront"
|
|
1072
|
+
],
|
|
1073
|
+
pool: [
|
|
1074
|
+
U("1441984904996-e0b6ba687e04"),
|
|
1075
|
+
U("1472851294608-062f824d29cc"),
|
|
1076
|
+
U("1523381210434-271e8be1f52b"),
|
|
1077
|
+
U("1534452203293-494d7ddbf7e0"),
|
|
1078
|
+
U("1445205170230-053b83016050"),
|
|
1079
|
+
U("1560243563-062bfc001d68")
|
|
1080
|
+
]
|
|
1081
|
+
},
|
|
1082
|
+
{
|
|
1083
|
+
keywords: [
|
|
1084
|
+
"yoga",
|
|
1085
|
+
"pilates",
|
|
1086
|
+
"fitness",
|
|
1087
|
+
"gym",
|
|
1088
|
+
"workout",
|
|
1089
|
+
"trainer",
|
|
1090
|
+
"wellness",
|
|
1091
|
+
"meditat",
|
|
1092
|
+
"massage",
|
|
1093
|
+
"therap",
|
|
1094
|
+
"physio",
|
|
1095
|
+
"chiro",
|
|
1096
|
+
"nutrition",
|
|
1097
|
+
"spa",
|
|
1098
|
+
"studio"
|
|
1099
|
+
],
|
|
1100
|
+
pool: [
|
|
1101
|
+
U("1544367567-0f2fcb009e0b"),
|
|
1102
|
+
U("1506126613408-eca07ce68773"),
|
|
1103
|
+
U("1545205597-3d9d02c29597"),
|
|
1104
|
+
U("1552196563-55cd4e45efb3"),
|
|
1105
|
+
U("1518611012118-696072aa579a"),
|
|
1106
|
+
U("1571019613454-1cb2f99b2d8b"),
|
|
1107
|
+
U("1540555700478-4be289fbecef"),
|
|
1108
|
+
U("1519824145371-296894a0daa9")
|
|
1109
|
+
]
|
|
1110
|
+
},
|
|
1111
|
+
{
|
|
1112
|
+
keywords: [
|
|
1113
|
+
"salon",
|
|
1114
|
+
"hairdress",
|
|
1115
|
+
"haircut",
|
|
1116
|
+
"barber",
|
|
1117
|
+
"manicure",
|
|
1118
|
+
"pedicure",
|
|
1119
|
+
"nails",
|
|
1120
|
+
"beauty",
|
|
1121
|
+
"makeup",
|
|
1122
|
+
"cosmetic",
|
|
1123
|
+
"eyelash",
|
|
1124
|
+
"eyebrow",
|
|
1125
|
+
"skincare",
|
|
1126
|
+
"esthetic",
|
|
1127
|
+
"waxing",
|
|
1128
|
+
"hair"
|
|
1129
|
+
],
|
|
1130
|
+
pool: [
|
|
1131
|
+
U("1560066984-138dadb4c035"),
|
|
1132
|
+
U("1522337660859-02fbefca4702"),
|
|
1133
|
+
U("1562322140-8baeececf3df"),
|
|
1134
|
+
U("1521590832167-7bcbfaa6381f"),
|
|
1135
|
+
U("1487412947147-5cebf100ffc2"),
|
|
1136
|
+
U("1526045478516-99145907023c")
|
|
1137
|
+
]
|
|
1138
|
+
},
|
|
1139
|
+
{
|
|
1140
|
+
keywords: [
|
|
1141
|
+
"cleaning",
|
|
1142
|
+
"plumb",
|
|
1143
|
+
"electric",
|
|
1144
|
+
"landscap",
|
|
1145
|
+
"contractor",
|
|
1146
|
+
"handyman",
|
|
1147
|
+
"renov",
|
|
1148
|
+
"hvac",
|
|
1149
|
+
"roofing",
|
|
1150
|
+
"painting",
|
|
1151
|
+
"carpentry",
|
|
1152
|
+
"flooring",
|
|
1153
|
+
"movers",
|
|
1154
|
+
"construction",
|
|
1155
|
+
"tools"
|
|
1156
|
+
],
|
|
1157
|
+
pool: [
|
|
1158
|
+
U("1581578731548-c64695cc6952"),
|
|
1159
|
+
U("1504307651254-35680f356dfd"),
|
|
1160
|
+
U("1581092160562-40aa08e78837"),
|
|
1161
|
+
U("1621905251189-08b45d6a269e"),
|
|
1162
|
+
U("1558618666-fcd25c85cd64"),
|
|
1163
|
+
U("1585128792020-803d29415281")
|
|
1164
|
+
]
|
|
1165
|
+
},
|
|
1166
|
+
{
|
|
1167
|
+
keywords: [
|
|
1168
|
+
"legal",
|
|
1169
|
+
"attorney",
|
|
1170
|
+
"lawyer",
|
|
1171
|
+
"account",
|
|
1172
|
+
"bookkeep",
|
|
1173
|
+
"consult",
|
|
1174
|
+
"coaching",
|
|
1175
|
+
"financ",
|
|
1176
|
+
"insurance",
|
|
1177
|
+
"realtor",
|
|
1178
|
+
"estate",
|
|
1179
|
+
"marketing",
|
|
1180
|
+
"agency",
|
|
1181
|
+
"office",
|
|
1182
|
+
"business",
|
|
1183
|
+
"desk"
|
|
1184
|
+
],
|
|
1185
|
+
pool: [
|
|
1186
|
+
U("1497366216548-37526070297c"),
|
|
1187
|
+
U("1497366811353-6870744d04b2"),
|
|
1188
|
+
U("1454165804606-c3d57bc86b40"),
|
|
1189
|
+
U("1521791136064-7986c2920216"),
|
|
1190
|
+
U("1556761175-b413da4baf72"),
|
|
1191
|
+
U("1542744173-8e7e53415bb0")
|
|
1192
|
+
]
|
|
1193
|
+
},
|
|
1194
|
+
{
|
|
1195
|
+
keywords: [
|
|
1196
|
+
"wedding",
|
|
1197
|
+
"event",
|
|
1198
|
+
"party",
|
|
1199
|
+
"celebrat",
|
|
1200
|
+
"venue",
|
|
1201
|
+
"community",
|
|
1202
|
+
"nonprofit",
|
|
1203
|
+
"charity",
|
|
1204
|
+
"workshop",
|
|
1205
|
+
"photograph",
|
|
1206
|
+
"concert"
|
|
1207
|
+
],
|
|
1208
|
+
pool: [
|
|
1209
|
+
U("1511578314322-379afb476865"),
|
|
1210
|
+
U("1501281668745-f7f57925c3b4"),
|
|
1211
|
+
U("1523580494863-6f3031224c94"),
|
|
1212
|
+
U("1540575467063-178a50c2df87"),
|
|
1213
|
+
U("1505236858219-8359eb29e329"),
|
|
1214
|
+
U("1528605248644-14dd04022da1")
|
|
1215
|
+
]
|
|
1216
|
+
}
|
|
1217
|
+
];
|
|
1218
|
+
function poolForSubject(subject) {
|
|
1219
|
+
for (const theme of THEMED) {
|
|
1220
|
+
if (theme.keywords.some((k) => subject.includes(k))) {
|
|
1221
|
+
return theme.pool;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
return GENERIC;
|
|
1225
|
+
}
|
|
1226
|
+
function mixedHash(text) {
|
|
1227
|
+
let hash = 2166136261;
|
|
1228
|
+
for (let i = 0; i < text.length; i++) {
|
|
1229
|
+
hash ^= text.charCodeAt(i);
|
|
1230
|
+
hash = Math.imul(hash, 16777619);
|
|
1231
|
+
}
|
|
1232
|
+
return hash >>> 16 & 65535;
|
|
1233
|
+
}
|
|
1234
|
+
function resolvePlaceholderRef(ref) {
|
|
1235
|
+
const match = /^placeholder:([a-z0-9-]+)$/.exec(ref);
|
|
1236
|
+
if (!match) return null;
|
|
1237
|
+
const subject = match[1];
|
|
1238
|
+
const pool = poolForSubject(subject.replace(/-\d+$/, ""));
|
|
1239
|
+
return pool[mixedHash(ref) % pool.length];
|
|
1240
|
+
}
|
|
1241
|
+
function collectPlaceholderRefs(tree) {
|
|
1242
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1243
|
+
for (const match of JSON.stringify(tree ?? null).matchAll(/"(placeholder:[a-z0-9-]+)"/gu)) {
|
|
1244
|
+
seen.add(match[1]);
|
|
1245
|
+
}
|
|
1246
|
+
return [...seen];
|
|
1247
|
+
}
|
|
1248
|
+
function buildPlaceholderMap(tree) {
|
|
1249
|
+
const map = {};
|
|
1250
|
+
const cursor = /* @__PURE__ */ new Map();
|
|
1251
|
+
for (const ref of collectPlaceholderRefs(tree)) {
|
|
1252
|
+
const subject = ref.slice("placeholder:".length).replace(/-\d+$/, "");
|
|
1253
|
+
const pool = poolForSubject(subject);
|
|
1254
|
+
const start = cursor.get(pool) ?? mixedHash(ref) % pool.length;
|
|
1255
|
+
map[ref] = pool[start % pool.length];
|
|
1256
|
+
cursor.set(pool, start + 1);
|
|
1257
|
+
}
|
|
1258
|
+
return map;
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
638
1262
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
639
1263
|
function lucideByName(name) {
|
|
640
1264
|
const pascal = name.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
@@ -648,6 +1272,7 @@ var typeStyle = (spec, font) => ({
|
|
|
648
1272
|
fontWeight: spec.weight
|
|
649
1273
|
});
|
|
650
1274
|
var str = (value) => typeof value === "string" ? value : "";
|
|
1275
|
+
var cardRadius = (slots) => slots.cornerStyle === "sharp" ? 0 : AI_TREE_TOKENS.radiusCard;
|
|
651
1276
|
var featureLines = (value) => value.split(/\n|<br\s*\/?>/i).map((line) => line.trim()).filter(Boolean);
|
|
652
1277
|
var CHECK_MASK = `data:image/svg+xml,${encodeURIComponent(
|
|
653
1278
|
'<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 +1299,25 @@ var FEATURE_LINE_CSS = [
|
|
|
674
1299
|
`background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
|
|
675
1300
|
`mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
|
|
676
1301
|
].join("");
|
|
1302
|
+
function buttonShellStyle(ctx, fullWidth) {
|
|
1303
|
+
const bs = ctx.buttonStyle;
|
|
1304
|
+
if (bs) {
|
|
1305
|
+
return {
|
|
1306
|
+
borderRadius: bs.radius,
|
|
1307
|
+
...bs.padding ? { padding: bs.padding } : {},
|
|
1308
|
+
...bs.fontFamily ? { fontFamily: bs.fontFamily } : { fontFamily: ctx.brand.fonts.body },
|
|
1309
|
+
...bs.fontSize ? { fontSize: bs.fontSize } : {},
|
|
1310
|
+
...bs.fontWeight ? { fontWeight: bs.fontWeight } : {},
|
|
1311
|
+
...bs.letterSpacing && bs.letterSpacing !== "normal" ? { letterSpacing: bs.letterSpacing } : {},
|
|
1312
|
+
...bs.textTransform && bs.textTransform !== "none" ? { textTransform: bs.textTransform } : {}
|
|
1313
|
+
};
|
|
1314
|
+
}
|
|
1315
|
+
return {
|
|
1316
|
+
borderRadius: AI_TREE_TOKENS.radiusButton,
|
|
1317
|
+
padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
|
|
1318
|
+
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
677
1321
|
function hexLuminance(color) {
|
|
678
1322
|
const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
|
|
679
1323
|
if (!m) return null;
|
|
@@ -690,6 +1334,12 @@ function hexContrast(a, b) {
|
|
|
690
1334
|
const [hi, lo] = la > lb ? [la, lb] : [lb, la];
|
|
691
1335
|
return (hi + 0.05) / (lo + 0.05);
|
|
692
1336
|
}
|
|
1337
|
+
function primaryButtonLabel(brand) {
|
|
1338
|
+
const darkC = hexContrast(brand.palette.primary, brand.palette.dark);
|
|
1339
|
+
const lightC = hexContrast(brand.palette.primary, AI_TREE_TOKENS.textPrimaryForeground);
|
|
1340
|
+
if (darkC === null || lightC === null) return AI_TREE_TOKENS.textPrimaryForeground;
|
|
1341
|
+
return darkC > lightC ? brand.palette.dark : AI_TREE_TOKENS.textPrimaryForeground;
|
|
1342
|
+
}
|
|
693
1343
|
function accentBandContext(brand) {
|
|
694
1344
|
const p = brand.palette;
|
|
695
1345
|
const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
|
|
@@ -707,6 +1357,22 @@ function accentBandContext(brand) {
|
|
|
707
1357
|
function textAttrs(ctx, path) {
|
|
708
1358
|
return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
|
|
709
1359
|
}
|
|
1360
|
+
var AI_RESPONSIVE_CSS = [
|
|
1361
|
+
"@media (max-width: 960px) {",
|
|
1362
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
|
|
1363
|
+
' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
|
|
1364
|
+
"}",
|
|
1365
|
+
"@media (max-width: 640px) {",
|
|
1366
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
|
|
1367
|
+
" [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
|
|
1368
|
+
// Group containers flatten to a column on phones; span placements come along for free.
|
|
1369
|
+
" [data-ai-responsive] [data-ai-group] { display: flex !important; flex-direction: column !important; }",
|
|
1370
|
+
" [data-ai-responsive] [data-ai-group] > * { grid-column: auto !important; }",
|
|
1371
|
+
" [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
|
|
1372
|
+
" [data-ai-responsive] { overflow-x: hidden; }",
|
|
1373
|
+
" [data-ai-responsive] img { max-width: 100%; }",
|
|
1374
|
+
"}"
|
|
1375
|
+
].join("\n");
|
|
710
1376
|
var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
711
1377
|
function MediaBox({
|
|
712
1378
|
refValue,
|
|
@@ -719,13 +1385,17 @@ function MediaBox({
|
|
|
719
1385
|
const url = refValue ? ctx.resolveMedia(refValue) : null;
|
|
720
1386
|
const isIcon = /^(lucide|simple):/.test(refValue);
|
|
721
1387
|
const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
|
|
722
|
-
const editAttrs = ctx.keyFor && editPath
|
|
1388
|
+
const editAttrs = ctx.keyFor && editPath ? {
|
|
1389
|
+
"data-ohw-key": ctx.keyFor(editPath),
|
|
1390
|
+
"data-ohw-editable": isIcon ? "icon" : "image"
|
|
1391
|
+
} : {};
|
|
723
1392
|
if (isIcon) {
|
|
724
1393
|
const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
|
|
725
1394
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
726
1395
|
"span",
|
|
727
1396
|
{
|
|
728
1397
|
"data-ai-icon": refValue,
|
|
1398
|
+
...editAttrs,
|
|
729
1399
|
style: {
|
|
730
1400
|
display: "inline-flex",
|
|
731
1401
|
width: 48,
|
|
@@ -789,12 +1459,15 @@ function ButtonEl({
|
|
|
789
1459
|
width: fullWidth ? "100%" : void 0,
|
|
790
1460
|
alignItems: "center",
|
|
791
1461
|
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
1462
|
textDecoration: "none",
|
|
795
1463
|
cursor: "pointer",
|
|
796
|
-
...
|
|
797
|
-
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } :
|
|
1464
|
+
...buttonShellStyle(ctx, fullWidth),
|
|
1465
|
+
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : (
|
|
1466
|
+
// Off-band, prefer the template button's measured fill/label pair — a template may
|
|
1467
|
+
// fill its CTAs with any token (hvac: accent bg, primary text). On an accent band
|
|
1468
|
+
// the flipped palette keeps contrast, so the brand-driven colours stay.
|
|
1469
|
+
!ctx.buttonLabel && ctx.buttonStyle?.background ? { background: ctx.buttonStyle.background, color: ctx.buttonStyle.color } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand) }
|
|
1470
|
+
)
|
|
798
1471
|
},
|
|
799
1472
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
|
|
800
1473
|
}
|
|
@@ -970,10 +1643,11 @@ function PricingCard({ node, ctx, path }) {
|
|
|
970
1643
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
971
1644
|
"div",
|
|
972
1645
|
{
|
|
1646
|
+
"data-ohw-card": "",
|
|
973
1647
|
style: {
|
|
974
1648
|
background: hasBg ? ctx.brand.palette.light : "transparent",
|
|
975
1649
|
border: `1px solid ${dark}`,
|
|
976
|
-
borderRadius:
|
|
1650
|
+
borderRadius: cardRadius(slots),
|
|
977
1651
|
padding: AI_TREE_TOKENS.paddingBlock,
|
|
978
1652
|
display: "flex",
|
|
979
1653
|
flexDirection: "column",
|
|
@@ -1078,10 +1752,11 @@ function TestimonialCard({ node, ctx, path }) {
|
|
|
1078
1752
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1079
1753
|
"div",
|
|
1080
1754
|
{
|
|
1755
|
+
"data-ohw-card": "",
|
|
1081
1756
|
"data-ai-avatar-pos": avatarPos ?? void 0,
|
|
1082
1757
|
style: {
|
|
1083
1758
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1084
|
-
borderRadius: hasBg ?
|
|
1759
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1085
1760
|
overflow: "hidden",
|
|
1086
1761
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1087
1762
|
minWidth: 0
|
|
@@ -1116,10 +1791,11 @@ function TeamCard({ node, ctx, path }) {
|
|
|
1116
1791
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1117
1792
|
"div",
|
|
1118
1793
|
{
|
|
1794
|
+
"data-ohw-card": "",
|
|
1119
1795
|
"data-ai-avatar-pos": avatarPos ?? void 0,
|
|
1120
1796
|
style: {
|
|
1121
1797
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1122
|
-
borderRadius: hasBg ?
|
|
1798
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1123
1799
|
overflow: "hidden",
|
|
1124
1800
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1125
1801
|
minWidth: 0,
|
|
@@ -1290,9 +1966,10 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1290
1966
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1291
1967
|
"div",
|
|
1292
1968
|
{
|
|
1969
|
+
"data-ohw-card": "",
|
|
1293
1970
|
style: {
|
|
1294
1971
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1295
|
-
borderRadius: hasBg ?
|
|
1972
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1296
1973
|
overflow: "hidden",
|
|
1297
1974
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1298
1975
|
display: horizontal ? "flex" : "block",
|
|
@@ -1320,7 +1997,7 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1320
1997
|
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1321
1998
|
"div",
|
|
1322
1999
|
{
|
|
1323
|
-
style: /^(lucide|simple):/.test(mediaRef) ? { padding: `${AI_TREE_TOKENS.paddingBlock}px ${AI_TREE_TOKENS.paddingBlock}px 0` } : hasBg ? void 0 : { borderRadius:
|
|
2000
|
+
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
2001
|
children: media
|
|
1325
2002
|
}
|
|
1326
2003
|
)),
|
|
@@ -1611,7 +2288,7 @@ function CollectionBlock({ node, ctx, path }) {
|
|
|
1611
2288
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1612
2289
|
"div",
|
|
1613
2290
|
{
|
|
1614
|
-
"data-ai-grid":
|
|
2291
|
+
"data-ai-grid": String(itemsPerRow),
|
|
1615
2292
|
style: {
|
|
1616
2293
|
display: "grid",
|
|
1617
2294
|
gridTemplateColumns: `repeat(${itemsPerRow}, 1fr)`,
|
|
@@ -1731,6 +2408,32 @@ function renderNode(node, ctx, path) {
|
|
|
1731
2408
|
if (child) {
|
|
1732
2409
|
return renderNode(child, ctx, `${path}.c0`);
|
|
1733
2410
|
}
|
|
2411
|
+
if (str(slots.provider) === "map" && str(slots.query)) {
|
|
2412
|
+
const query = str(slots.query);
|
|
2413
|
+
const mapAttrs = ctx.keyFor ? {
|
|
2414
|
+
"data-ohw-key": ctx.keyFor(`${path}.query`),
|
|
2415
|
+
"data-ohw-editable": "map",
|
|
2416
|
+
"data-ohw-map-query": query
|
|
2417
|
+
} : {};
|
|
2418
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2419
|
+
"iframe",
|
|
2420
|
+
{
|
|
2421
|
+
...mapAttrs,
|
|
2422
|
+
"data-ai-embed": "map",
|
|
2423
|
+
title: str(slots.title) || "Map",
|
|
2424
|
+
src: `https://www.google.com/maps?q=${encodeURIComponent(query)}&output=embed`,
|
|
2425
|
+
loading: "lazy",
|
|
2426
|
+
referrerPolicy: "no-referrer-when-downgrade",
|
|
2427
|
+
style: {
|
|
2428
|
+
width: "100%",
|
|
2429
|
+
minHeight: 320,
|
|
2430
|
+
border: 0,
|
|
2431
|
+
borderRadius: AI_TREE_TOKENS.radiusCard,
|
|
2432
|
+
display: "block"
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
);
|
|
2436
|
+
}
|
|
1734
2437
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1735
2438
|
"div",
|
|
1736
2439
|
{
|
|
@@ -1834,15 +2537,14 @@ function renderNode(node, ctx, path) {
|
|
|
1834
2537
|
alignSelf: submitAlign,
|
|
1835
2538
|
border: "none",
|
|
1836
2539
|
cursor: "pointer",
|
|
1837
|
-
padding
|
|
1838
|
-
|
|
1839
|
-
//
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
2540
|
+
// Shape/padding/typography follow the host template's own buttons.
|
|
2541
|
+
...buttonShellStyle(ctx),
|
|
2542
|
+
// Brand-styled: the template button's measured fill/label pair off-band, else
|
|
2543
|
+
// primary fill with a brand-derived label so it reads on custom palettes.
|
|
2544
|
+
...!ctx.buttonLabel && ctx.buttonStyle?.background ? { background: ctx.buttonStyle.background, color: ctx.buttonStyle.color } : {
|
|
2545
|
+
background: ctx.brand.palette.primary,
|
|
2546
|
+
color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand)
|
|
2547
|
+
}
|
|
1846
2548
|
},
|
|
1847
2549
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
|
|
1848
2550
|
},
|
|
@@ -1877,7 +2579,7 @@ function renderNode(node, ctx, path) {
|
|
|
1877
2579
|
function AiTreeRenderer({
|
|
1878
2580
|
tree,
|
|
1879
2581
|
brand,
|
|
1880
|
-
|
|
2582
|
+
buttonStyle,
|
|
1881
2583
|
resolveMedia,
|
|
1882
2584
|
editKeyPrefix
|
|
1883
2585
|
}) {
|
|
@@ -1887,13 +2589,18 @@ function AiTreeRenderer({
|
|
|
1887
2589
|
const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
|
|
1888
2590
|
const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
|
|
1889
2591
|
const blockBrand = band?.brand ?? resolvedBrand;
|
|
2592
|
+
const placeholderMap = buildPlaceholderMap(tree);
|
|
1890
2593
|
const ctx = {
|
|
1891
2594
|
brand: blockBrand,
|
|
1892
|
-
|
|
2595
|
+
// An owner/library ref resolves through the host resolver; a `placeholder:<subject>` ref the
|
|
2596
|
+
// host cannot resolve falls back to real stock photography (the per-section map first, then a
|
|
2597
|
+
// standalone resolve), so generated galleries, image rows, and overlay backgrounds arrive with
|
|
2598
|
+
// photos instead of grey boxes.
|
|
2599
|
+
resolveMedia: (ref) => resolveMedia?.(ref) ?? placeholderMap[ref] ?? resolvePlaceholderRef(ref),
|
|
1893
2600
|
cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
|
|
1894
2601
|
keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
|
|
1895
2602
|
sectionAlignment: (tree.settings ?? {}).alignment === "center" ? "center" : "left",
|
|
1896
|
-
|
|
2603
|
+
buttonStyle,
|
|
1897
2604
|
...band ? { buttonLabel: band.buttonLabel } : {}
|
|
1898
2605
|
};
|
|
1899
2606
|
const settings = tree.settings ?? {};
|
|
@@ -1934,6 +2641,7 @@ function AiTreeRenderer({
|
|
|
1934
2641
|
{
|
|
1935
2642
|
"data-ai-section": tree.tag ?? "",
|
|
1936
2643
|
...bgAttrs,
|
|
2644
|
+
"data-ai-responsive": "",
|
|
1937
2645
|
style: {
|
|
1938
2646
|
position: "relative",
|
|
1939
2647
|
padding: `${pad}px 0`,
|
|
@@ -1944,12 +2652,13 @@ function AiTreeRenderer({
|
|
|
1944
2652
|
color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
|
|
1945
2653
|
},
|
|
1946
2654
|
children: [
|
|
1947
|
-
|
|
2655
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
|
|
1948
2656
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
|
|
2657
|
+
isOverlay && backgroundUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
|
|
1949
2658
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1950
2659
|
"div",
|
|
1951
2660
|
{
|
|
1952
|
-
"data-ai-
|
|
2661
|
+
"data-ai-section-inner": "",
|
|
1953
2662
|
style: {
|
|
1954
2663
|
position: "relative",
|
|
1955
2664
|
maxWidth: AI_TREE_TOKENS.sectionMaxWidth,
|
|
@@ -1960,7 +2669,7 @@ function AiTreeRenderer({
|
|
|
1960
2669
|
children: tree.rows.map((row, r2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1961
2670
|
"div",
|
|
1962
2671
|
{
|
|
1963
|
-
"data-ai-
|
|
2672
|
+
"data-ai-columns": "",
|
|
1964
2673
|
style: {
|
|
1965
2674
|
display: "grid",
|
|
1966
2675
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
@@ -1999,21 +2708,63 @@ function AiTreeRenderer({
|
|
|
1999
2708
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
2000
2709
|
var CONTAINER_ATTR = "data-ohw-ai-generated";
|
|
2001
2710
|
var REPLACED_ATTR = "data-ohw-ai-replaced-by";
|
|
2002
|
-
var
|
|
2711
|
+
var REMOVED_ATTR2 = "data-ohw-ai-removed";
|
|
2003
2712
|
var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
|
|
2004
2713
|
var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
2714
|
+
function isChromeSection2(el) {
|
|
2715
|
+
if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) return true;
|
|
2716
|
+
return el.tagName === "HEADER" || el.tagName === "FOOTER";
|
|
2717
|
+
}
|
|
2005
2718
|
function readRootVar(name) {
|
|
2006
2719
|
if (typeof document === "undefined") return "";
|
|
2007
2720
|
return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
2008
2721
|
}
|
|
2722
|
+
function normalizeColorToHex(value) {
|
|
2723
|
+
if (!value || typeof document === "undefined") return value;
|
|
2724
|
+
const canvas = document.createElement("canvas");
|
|
2725
|
+
canvas.width = 1;
|
|
2726
|
+
canvas.height = 1;
|
|
2727
|
+
const ctx = canvas.getContext("2d");
|
|
2728
|
+
if (!ctx) return value;
|
|
2729
|
+
ctx.fillStyle = value;
|
|
2730
|
+
ctx.fillRect(0, 0, 1, 1);
|
|
2731
|
+
const [r2, g, b] = ctx.getImageData(0, 0, 1, 1).data;
|
|
2732
|
+
const toHex = (n) => n.toString(16).padStart(2, "0");
|
|
2733
|
+
return `#${toHex(r2)}${toHex(g)}${toHex(b)}`;
|
|
2734
|
+
}
|
|
2735
|
+
var GENERIC_FONT_KEYWORDS = /* @__PURE__ */ new Set([
|
|
2736
|
+
"serif",
|
|
2737
|
+
"sans-serif",
|
|
2738
|
+
"monospace",
|
|
2739
|
+
"cursive",
|
|
2740
|
+
"fantasy",
|
|
2741
|
+
"system-ui",
|
|
2742
|
+
"ui-serif",
|
|
2743
|
+
"ui-sans-serif",
|
|
2744
|
+
"ui-monospace",
|
|
2745
|
+
"ui-rounded",
|
|
2746
|
+
"math",
|
|
2747
|
+
"emoji",
|
|
2748
|
+
"fangsong"
|
|
2749
|
+
]);
|
|
2750
|
+
function primaryFontFamily(stack) {
|
|
2751
|
+
const first = stack.split(",").map((part) => part.trim().replace(/^["']|["']$/g, "")).find((part) => part && !GENERIC_FONT_KEYWORDS.has(part.toLowerCase()));
|
|
2752
|
+
return first ?? "";
|
|
2753
|
+
}
|
|
2754
|
+
function humanizeFontFamily(name) {
|
|
2755
|
+
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());
|
|
2756
|
+
}
|
|
2757
|
+
function readFontVar(name) {
|
|
2758
|
+
return humanizeFontFamily(primaryFontFamily(readRootVar(name)));
|
|
2759
|
+
}
|
|
2009
2760
|
function deriveBrandOverride() {
|
|
2010
2761
|
const dark = readRootVar("--ohw-brand-dark");
|
|
2011
2762
|
const primary = readRootVar("--ohw-brand-primary");
|
|
2012
2763
|
const light = readRootVar("--ohw-brand-light");
|
|
2013
2764
|
if (!dark || !primary || !light) return null;
|
|
2014
2765
|
const accent = readRootVar("--ohw-brand-accent");
|
|
2015
|
-
const heading =
|
|
2016
|
-
const body =
|
|
2766
|
+
const heading = readFontVar("--font-heading") || readFontVar("--font-display");
|
|
2767
|
+
const body = readFontVar("--font-body");
|
|
2017
2768
|
return {
|
|
2018
2769
|
palette: { dark, primary, accent: accent || dark, light },
|
|
2019
2770
|
fonts: {
|
|
@@ -2022,28 +2773,93 @@ function deriveBrandOverride() {
|
|
|
2022
2773
|
}
|
|
2023
2774
|
};
|
|
2024
2775
|
}
|
|
2025
|
-
function
|
|
2026
|
-
const dark = readRootVar("--color-dark");
|
|
2027
|
-
const primary = readRootVar("--color-primary");
|
|
2028
|
-
const light = readRootVar("--color-light");
|
|
2776
|
+
function deriveTemplateBrandLive() {
|
|
2777
|
+
const dark = readRootVar("--color-dark") || readRootVar("--brand-text");
|
|
2778
|
+
const primary = readRootVar("--color-primary") || readRootVar("--brand-primary");
|
|
2779
|
+
const light = readRootVar("--color-light") || readRootVar("--brand-background");
|
|
2029
2780
|
if (!dark || !primary || !light) return null;
|
|
2030
|
-
const accent = readRootVar("--color-accent");
|
|
2031
|
-
const heading =
|
|
2032
|
-
const body =
|
|
2781
|
+
const accent = readRootVar("--color-accent") || readRootVar("--brand-accent");
|
|
2782
|
+
const heading = readFontVar("--brand-font-heading") || readFontVar("--font-heading") || readFontVar("--font-display");
|
|
2783
|
+
const body = readFontVar("--brand-font-body") || readFontVar("--font-body");
|
|
2033
2784
|
return {
|
|
2034
|
-
palette: {
|
|
2785
|
+
palette: {
|
|
2786
|
+
dark: normalizeColorToHex(dark),
|
|
2787
|
+
primary: normalizeColorToHex(primary),
|
|
2788
|
+
accent: normalizeColorToHex(accent || dark),
|
|
2789
|
+
light: normalizeColorToHex(light)
|
|
2790
|
+
},
|
|
2035
2791
|
fonts: {
|
|
2036
2792
|
heading: heading || AI_DEFAULT_BRAND.fonts.heading,
|
|
2037
2793
|
body: body || AI_DEFAULT_BRAND.fonts.body
|
|
2038
2794
|
}
|
|
2039
2795
|
};
|
|
2040
2796
|
}
|
|
2041
|
-
function
|
|
2797
|
+
function deriveTemplateFontsLive() {
|
|
2798
|
+
const heading = readFontVar("--brand-font-heading") || readFontVar("--font-heading") || readFontVar("--font-display");
|
|
2799
|
+
const body = readFontVar("--brand-font-body") || readFontVar("--font-body");
|
|
2800
|
+
if (!heading && !body) return null;
|
|
2801
|
+
return {
|
|
2802
|
+
heading: heading || AI_DEFAULT_BRAND.fonts.heading,
|
|
2803
|
+
body: body || AI_DEFAULT_BRAND.fonts.body
|
|
2804
|
+
};
|
|
2805
|
+
}
|
|
2806
|
+
var OVERRIDE_VAR_NAMES = [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES, ...FONT_VARS.heading, ...FONT_VARS.body];
|
|
2807
|
+
function withOverrideStripped(read) {
|
|
2808
|
+
const root = document.documentElement;
|
|
2809
|
+
const restore = OVERRIDE_VAR_NAMES.map((name) => [name, root.style.getPropertyValue(name)]);
|
|
2810
|
+
for (const name of OVERRIDE_VAR_NAMES) root.style.removeProperty(name);
|
|
2811
|
+
try {
|
|
2812
|
+
return read();
|
|
2813
|
+
} finally {
|
|
2814
|
+
for (const [name, value] of restore) if (value) root.style.setProperty(name, value);
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
var TEMPLATE_BRAND_SNAPSHOT = typeof document === "undefined" ? null : withOverrideStripped(deriveTemplateBrandLive);
|
|
2818
|
+
var TEMPLATE_FONTS_SNAPSHOT = typeof document === "undefined" ? null : withOverrideStripped(deriveTemplateFontsLive);
|
|
2819
|
+
function deriveTemplateBrand() {
|
|
2820
|
+
return TEMPLATE_BRAND_SNAPSHOT;
|
|
2821
|
+
}
|
|
2822
|
+
function deriveTemplateFonts() {
|
|
2823
|
+
return TEMPLATE_FONTS_SNAPSHOT;
|
|
2824
|
+
}
|
|
2825
|
+
function deriveTemplateButtonStyle() {
|
|
2042
2826
|
if (typeof document === "undefined") return null;
|
|
2043
|
-
const
|
|
2827
|
+
const candidates = Array.from(
|
|
2828
|
+
document.querySelectorAll('[data-ohw-role="button"]')
|
|
2829
|
+
).filter((el) => !el.closest(`[${CONTAINER_ATTR}]`));
|
|
2830
|
+
const isFilled = (el) => {
|
|
2831
|
+
const bg = getComputedStyle(el).backgroundColor;
|
|
2832
|
+
if (!bg || bg === "transparent") return false;
|
|
2833
|
+
const alpha = bg.match(/rgba?\([^)]*,\s*([\d.]+)\)$/);
|
|
2834
|
+
return !alpha || parseFloat(alpha[1]) > 0;
|
|
2835
|
+
};
|
|
2836
|
+
const btn = candidates.find(isFilled) ?? candidates[0];
|
|
2044
2837
|
if (!btn) return null;
|
|
2045
|
-
const
|
|
2046
|
-
|
|
2838
|
+
const cs = getComputedStyle(btn);
|
|
2839
|
+
const filled = isFilled(btn);
|
|
2840
|
+
const corners = [
|
|
2841
|
+
cs.borderTopLeftRadius,
|
|
2842
|
+
cs.borderTopRightRadius,
|
|
2843
|
+
cs.borderBottomRightRadius,
|
|
2844
|
+
cs.borderBottomLeftRadius
|
|
2845
|
+
].map((v) => v || "0px");
|
|
2846
|
+
const radius = corners.every((v) => v === corners[0]) ? corners[0] : corners.join(" ");
|
|
2847
|
+
const px = (v) => parseFloat(v) || 0;
|
|
2848
|
+
const lineHeight = px(cs.lineHeight) || px(cs.fontSize) * 1.2;
|
|
2849
|
+
const contentH = btn.getBoundingClientRect().height - px(cs.borderTopWidth) - px(cs.borderBottomWidth);
|
|
2850
|
+
const impliedY = Math.round(Math.max(0, (contentH - lineHeight) / 2));
|
|
2851
|
+
const padY = Math.max(px(cs.paddingTop), px(cs.paddingBottom), impliedY);
|
|
2852
|
+
const padX = Math.max(px(cs.paddingLeft), px(cs.paddingRight));
|
|
2853
|
+
return {
|
|
2854
|
+
radius: radius || "10px",
|
|
2855
|
+
padding: `${padY}px ${padX}px`,
|
|
2856
|
+
...filled ? { background: cs.backgroundColor, color: cs.color } : {},
|
|
2857
|
+
fontFamily: cs.fontFamily || "",
|
|
2858
|
+
fontSize: cs.fontSize || "",
|
|
2859
|
+
fontWeight: cs.fontWeight || "",
|
|
2860
|
+
letterSpacing: cs.letterSpacing || "",
|
|
2861
|
+
textTransform: cs.textTransform || ""
|
|
2862
|
+
};
|
|
2047
2863
|
}
|
|
2048
2864
|
var mounted = /* @__PURE__ */ new Map();
|
|
2049
2865
|
function findTemplateSection(id) {
|
|
@@ -2059,6 +2875,19 @@ function findPlacementAnchor(id, exclude) {
|
|
|
2059
2875
|
for (const el of document.querySelectorAll(`[data-ohw-section="${CSS.escape(id)}"]`)) {
|
|
2060
2876
|
if (el === exclude) continue;
|
|
2061
2877
|
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
2878
|
+
if (isChromeSection2(el)) return null;
|
|
2879
|
+
return el;
|
|
2880
|
+
}
|
|
2881
|
+
return null;
|
|
2882
|
+
}
|
|
2883
|
+
function findFooterSection() {
|
|
2884
|
+
const byId = findTemplateSection("footer");
|
|
2885
|
+
if (byId) return byId;
|
|
2886
|
+
for (const el of Array.from(
|
|
2887
|
+
document.querySelectorAll("footer[data-ohw-section]")
|
|
2888
|
+
).reverse()) {
|
|
2889
|
+
if (el.hasAttribute(CONTAINER_ATTR)) continue;
|
|
2890
|
+
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
2062
2891
|
return el;
|
|
2063
2892
|
}
|
|
2064
2893
|
return null;
|
|
@@ -2085,7 +2914,7 @@ function placeContainer(container, entry) {
|
|
|
2085
2914
|
return;
|
|
2086
2915
|
}
|
|
2087
2916
|
}
|
|
2088
|
-
const footer =
|
|
2917
|
+
const footer = findFooterSection();
|
|
2089
2918
|
if (footer) {
|
|
2090
2919
|
footer.insertAdjacentElement("beforebegin", container);
|
|
2091
2920
|
} else {
|
|
@@ -2094,18 +2923,18 @@ function placeContainer(container, entry) {
|
|
|
2094
2923
|
}
|
|
2095
2924
|
function syncRemovedSections(state) {
|
|
2096
2925
|
const removed = new Set(state.removed ?? []);
|
|
2097
|
-
for (const el of document.querySelectorAll(`[${
|
|
2926
|
+
for (const el of document.querySelectorAll(`[${REMOVED_ATTR2}]`)) {
|
|
2098
2927
|
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
2099
2928
|
if (!removed.has(id)) {
|
|
2100
2929
|
el.style.removeProperty("display");
|
|
2101
|
-
el.removeAttribute(
|
|
2930
|
+
el.removeAttribute(REMOVED_ATTR2);
|
|
2102
2931
|
}
|
|
2103
2932
|
}
|
|
2104
2933
|
for (const id of removed) {
|
|
2105
2934
|
const section = findTemplateSection(id);
|
|
2106
2935
|
if (section && !section.hasAttribute(REPLACED_ATTR)) {
|
|
2107
2936
|
section.style.display = "none";
|
|
2108
|
-
section.setAttribute(
|
|
2937
|
+
section.setAttribute(REMOVED_ATTR2, "");
|
|
2109
2938
|
}
|
|
2110
2939
|
}
|
|
2111
2940
|
}
|
|
@@ -2120,9 +2949,9 @@ function syncTemplateHidden(state, pageHasSections) {
|
|
|
2120
2949
|
if (!hide) return;
|
|
2121
2950
|
for (const el of Array.from(document.querySelectorAll("[data-ohw-section]"))) {
|
|
2122
2951
|
if (el.hasAttribute(CONTAINER_ATTR)) continue;
|
|
2123
|
-
if (
|
|
2952
|
+
if (isChromeSection2(el)) continue;
|
|
2124
2953
|
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
2125
|
-
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(
|
|
2954
|
+
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR2)) continue;
|
|
2126
2955
|
el.style.display = "none";
|
|
2127
2956
|
el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
|
|
2128
2957
|
}
|
|
@@ -2146,18 +2975,23 @@ function syncReplacedOriginals(state) {
|
|
|
2146
2975
|
}
|
|
2147
2976
|
}
|
|
2148
2977
|
var sectionOrderIndex = /* @__PURE__ */ new Map();
|
|
2978
|
+
var removedSectionIds = /* @__PURE__ */ new Set();
|
|
2149
2979
|
function setAiSectionOrder(raw, currentPath) {
|
|
2150
2980
|
const next = /* @__PURE__ */ new Map();
|
|
2981
|
+
const removed = /* @__PURE__ */ new Set();
|
|
2151
2982
|
if (raw) {
|
|
2152
2983
|
try {
|
|
2153
2984
|
const entries = JSON.parse(raw);
|
|
2154
2985
|
for (const entry of entries) {
|
|
2155
|
-
if (
|
|
2986
|
+
if (entry.pagePath && entry.pagePath !== currentPath) continue;
|
|
2987
|
+
next.set(entry.instanceId, entry.order);
|
|
2988
|
+
if (entry.removed) removed.add(entry.instanceId);
|
|
2156
2989
|
}
|
|
2157
2990
|
} catch {
|
|
2158
2991
|
}
|
|
2159
2992
|
}
|
|
2160
2993
|
sectionOrderIndex = next;
|
|
2994
|
+
removedSectionIds = removed;
|
|
2161
2995
|
}
|
|
2162
2996
|
function applyExplicitOrder(entries) {
|
|
2163
2997
|
if (sectionOrderIndex.size === 0) return entries;
|
|
@@ -2193,11 +3027,23 @@ function orderByChain(sections) {
|
|
|
2193
3027
|
for (const root of roots) visit(root);
|
|
2194
3028
|
return out.length === sections.length ? out : sections;
|
|
2195
3029
|
}
|
|
3030
|
+
function syncSoftRemovedGenerated() {
|
|
3031
|
+
for (const [id, section] of mounted) {
|
|
3032
|
+
const el = section.container;
|
|
3033
|
+
if (removedSectionIds.has(id)) {
|
|
3034
|
+
el.style.display = "none";
|
|
3035
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
3036
|
+
} else if (el.hasAttribute(REMOVED_ATTR)) {
|
|
3037
|
+
el.style.removeProperty("display");
|
|
3038
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
3039
|
+
}
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
2196
3042
|
function applyAiSectionsToDom(state, options) {
|
|
2197
3043
|
if (typeof document === "undefined") return;
|
|
2198
3044
|
const brandOverride = deriveBrandOverride();
|
|
2199
3045
|
const templateBrand = deriveTemplateBrand();
|
|
2200
|
-
const
|
|
3046
|
+
const templateButtonStyle = deriveTemplateButtonStyle();
|
|
2201
3047
|
const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
|
|
2202
3048
|
const pagePath = window.location.pathname;
|
|
2203
3049
|
const pageSections = state.sections.filter((entry) => (entry.path ?? "/") === pagePath);
|
|
@@ -2237,7 +3083,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2237
3083
|
{
|
|
2238
3084
|
tree: entry.tree,
|
|
2239
3085
|
brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
|
|
2240
|
-
|
|
3086
|
+
buttonStyle: templateButtonStyle,
|
|
2241
3087
|
resolveMedia,
|
|
2242
3088
|
editKeyPrefix: `ai.${entry.id}`
|
|
2243
3089
|
}
|
|
@@ -2260,6 +3106,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2260
3106
|
syncReplacedOriginals(state);
|
|
2261
3107
|
syncRemovedSections(state);
|
|
2262
3108
|
syncTemplateHidden(state, pageSections.length > 0);
|
|
3109
|
+
syncSoftRemovedGenerated();
|
|
2263
3110
|
}
|
|
2264
3111
|
|
|
2265
3112
|
// src/useLinkHrefGuardian.ts
|
|
@@ -6451,12 +7298,12 @@ var cva = (base, config) => (props) => {
|
|
|
6451
7298
|
var import_radix_ui2 = require("radix-ui");
|
|
6452
7299
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
6453
7300
|
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",
|
|
7301
|
+
"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
7302
|
{
|
|
6456
7303
|
variants: {
|
|
6457
7304
|
variant: {
|
|
6458
7305
|
default: "bg-transparent border-0",
|
|
6459
|
-
outline: "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground"
|
|
7306
|
+
outline: "border border-input bg-transparent shadow-xs hover:bg-bridge-accent hover:text-accent-foreground"
|
|
6460
7307
|
},
|
|
6461
7308
|
size: {
|
|
6462
7309
|
default: "px-2 py-1",
|
|
@@ -6549,10 +7396,10 @@ var DragHandle = React4.forwardRef(
|
|
|
6549
7396
|
type,
|
|
6550
7397
|
"data-slot": "drag-handle",
|
|
6551
7398
|
className: cn(
|
|
6552
|
-
"inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-
|
|
7399
|
+
"inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-7.5",
|
|
6553
7400
|
"bg-white border border-transparent text-stone-500 shadow-md cursor-grab",
|
|
6554
7401
|
"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",
|
|
7402
|
+
"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
7403
|
"disabled:cursor-not-allowed disabled:opacity-40 disabled:text-stone-950 disabled:pointer-events-none",
|
|
6557
7404
|
className
|
|
6558
7405
|
),
|
|
@@ -6574,7 +7421,7 @@ var CustomToolbar = React5.forwardRef(({ className, onMouseDown, ...props }, ref
|
|
|
6574
7421
|
"data-ohw-toolbar": "",
|
|
6575
7422
|
className: cn(
|
|
6576
7423
|
// Figma: bg background, radius 8, gap-1, p-0.5, shadow-md — no border
|
|
6577
|
-
"inline-flex h-8 items-center gap-1 rounded-
|
|
7424
|
+
"inline-flex h-8 items-center gap-1 rounded-(--radius,0.5rem) bg-background p-0.5 font-sans whitespace-nowrap shadow-md",
|
|
6578
7425
|
className
|
|
6579
7426
|
),
|
|
6580
7427
|
onMouseDown: (e) => {
|
|
@@ -6603,7 +7450,7 @@ var CustomToolbarButton = React5.forwardRef(
|
|
|
6603
7450
|
type,
|
|
6604
7451
|
className: cn(
|
|
6605
7452
|
"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",
|
|
7453
|
+
active ? "bg-bridge-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
|
|
6607
7454
|
className
|
|
6608
7455
|
),
|
|
6609
7456
|
...props
|
|
@@ -6808,9 +7655,7 @@ function ItemActionToolbar({
|
|
|
6808
7655
|
ToggleGroup,
|
|
6809
7656
|
{
|
|
6810
7657
|
value: dropdownOpen ? "open" : "closed",
|
|
6811
|
-
onValueChange: (
|
|
6812
|
-
if (value !== "open" && value !== "closed") return;
|
|
6813
|
-
onDropdownOpenChange?.(value === "open");
|
|
7658
|
+
onValueChange: () => {
|
|
6814
7659
|
},
|
|
6815
7660
|
className: "h-7 gap-0.5 rounded-[calc(var(--radius,0.5rem)-2px)] bg-muted p-0.5",
|
|
6816
7661
|
onMouseDown: (e) => {
|
|
@@ -6825,6 +7670,11 @@ function ItemActionToolbar({
|
|
|
6825
7670
|
size: "sm",
|
|
6826
7671
|
"aria-label": "Closed",
|
|
6827
7672
|
className: "h-6 min-w-0 px-2 text-xs font-medium",
|
|
7673
|
+
onMouseDown: (e) => {
|
|
7674
|
+
e.preventDefault();
|
|
7675
|
+
e.stopPropagation();
|
|
7676
|
+
if (dropdownOpen !== false) onDropdownOpenChange?.(false);
|
|
7677
|
+
},
|
|
6828
7678
|
children: "Closed"
|
|
6829
7679
|
}
|
|
6830
7680
|
),
|
|
@@ -6835,6 +7685,11 @@ function ItemActionToolbar({
|
|
|
6835
7685
|
size: "sm",
|
|
6836
7686
|
"aria-label": "Open",
|
|
6837
7687
|
className: "h-6 min-w-0 px-2 text-xs font-medium",
|
|
7688
|
+
onMouseDown: (e) => {
|
|
7689
|
+
e.preventDefault();
|
|
7690
|
+
e.stopPropagation();
|
|
7691
|
+
if (dropdownOpen !== true) onDropdownOpenChange?.(true);
|
|
7692
|
+
},
|
|
6838
7693
|
children: "Open"
|
|
6839
7694
|
}
|
|
6840
7695
|
)
|
|
@@ -7797,13 +8652,13 @@ function FormFieldToolbar({
|
|
|
7797
8652
|
]
|
|
7798
8653
|
}
|
|
7799
8654
|
) }),
|
|
7800
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-
|
|
8655
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-47.5 p-1", children: FIELD_TYPES.map((entry) => {
|
|
7801
8656
|
const Icon = TYPE_ICONS[entry.type];
|
|
7802
8657
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
7803
8658
|
DropdownMenuItem,
|
|
7804
8659
|
{
|
|
7805
8660
|
onSelect: () => onTypeChange(entry.type),
|
|
7806
|
-
className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-primary/10" : ""),
|
|
8661
|
+
className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-bridge-primary/10" : ""),
|
|
7807
8662
|
children: [
|
|
7808
8663
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
|
|
7809
8664
|
entry.label
|
|
@@ -7820,7 +8675,7 @@ function FormFieldToolbar({
|
|
|
7820
8675
|
type: "button",
|
|
7821
8676
|
"aria-pressed": required,
|
|
7822
8677
|
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"),
|
|
8678
|
+
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
8679
|
"data-ohw-field-required-toggle": "",
|
|
7825
8680
|
children: [
|
|
7826
8681
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Asterisk, { size: 14, strokeWidth: 2, "aria-hidden": true }),
|
|
@@ -7840,7 +8695,7 @@ function FormFieldToolbar({
|
|
|
7840
8695
|
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.MoreHorizontal, { size: 15, "aria-hidden": true })
|
|
7841
8696
|
}
|
|
7842
8697
|
) }),
|
|
7843
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-
|
|
8698
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-42.5 p-1", children: [
|
|
7844
8699
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuItem, { onSelect: onDuplicate, className: "rounded-md py-2 text-[13px]", children: [
|
|
7845
8700
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Copy, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
|
|
7846
8701
|
"Duplicate"
|
|
@@ -7860,7 +8715,7 @@ function FieldTypePicker({ onPick }) {
|
|
|
7860
8715
|
"div",
|
|
7861
8716
|
{
|
|
7862
8717
|
"data-ohw-field-type-picker": "",
|
|
7863
|
-
className: "pointer-events-auto grid w-
|
|
8718
|
+
className: "pointer-events-auto grid w-105 grid-cols-3 gap-3 rounded-xl border border-border bg-background p-4 shadow-lg",
|
|
7864
8719
|
children: FIELD_TYPES.map((entry) => {
|
|
7865
8720
|
const Icon = TYPE_ICONS[entry.type];
|
|
7866
8721
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
@@ -7868,7 +8723,7 @@ function FieldTypePicker({ onPick }) {
|
|
|
7868
8723
|
{
|
|
7869
8724
|
type: "button",
|
|
7870
8725
|
onClick: () => onPick(entry.type),
|
|
7871
|
-
className: "flex h-
|
|
8726
|
+
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
8727
|
children: [
|
|
7873
8728
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 26, strokeWidth: 1.5, "aria-hidden": true }),
|
|
7874
8729
|
entry.label
|
|
@@ -7894,7 +8749,7 @@ var buttonVariants = cva(
|
|
|
7894
8749
|
{
|
|
7895
8750
|
variants: {
|
|
7896
8751
|
variant: {
|
|
7897
|
-
default: "bg-primary text-primary-foreground hover:opacity-90",
|
|
8752
|
+
default: "bg-bridge-primary text-primary-foreground hover:opacity-90",
|
|
7898
8753
|
outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
|
|
7899
8754
|
ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
|
|
7900
8755
|
},
|
|
@@ -7989,6 +8844,7 @@ function MediaOverlay({
|
|
|
7989
8844
|
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
7990
8845
|
);
|
|
7991
8846
|
}, [isVideo]);
|
|
8847
|
+
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
7992
8848
|
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
7993
8849
|
const box = {
|
|
7994
8850
|
position: "fixed",
|
|
@@ -8094,8 +8950,8 @@ function MediaOverlay({
|
|
|
8094
8950
|
pointerEvents: hover.hasTextOverlap ? "none" : "auto",
|
|
8095
8951
|
// Selected: a firm component ring with no wash, so the image reads as chosen rather
|
|
8096
8952
|
// 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)"
|
|
8953
|
+
boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
8954
|
+
background: selected ? "transparent" : "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
|
|
8099
8955
|
},
|
|
8100
8956
|
onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
|
|
8101
8957
|
children: [
|
|
@@ -8118,17 +8974,17 @@ function MediaOverlay({
|
|
|
8118
8974
|
},
|
|
8119
8975
|
children: [
|
|
8120
8976
|
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
|
-
|
|
8977
|
+
replaceLabel
|
|
8122
8978
|
]
|
|
8123
8979
|
}
|
|
8124
8980
|
),
|
|
8125
|
-
replaceMode
|
|
8981
|
+
showChrome && replaceMode !== "none" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
8126
8982
|
Button,
|
|
8127
8983
|
{
|
|
8128
8984
|
"data-ohw-media-overlay": "",
|
|
8129
8985
|
variant: "outline",
|
|
8130
8986
|
size: "sm",
|
|
8131
|
-
"aria-label":
|
|
8987
|
+
"aria-label": replaceLabel,
|
|
8132
8988
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
8133
8989
|
style: {
|
|
8134
8990
|
...OVERLAY_BUTTON_STYLE,
|
|
@@ -8151,7 +9007,7 @@ function MediaOverlay({
|
|
|
8151
9007
|
},
|
|
8152
9008
|
children: [
|
|
8153
9009
|
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" ?
|
|
9010
|
+
replaceMode === "full" ? replaceLabel : null
|
|
8155
9011
|
]
|
|
8156
9012
|
}
|
|
8157
9013
|
)
|
|
@@ -8186,253 +9042,41 @@ function CarouselOverlay({
|
|
|
8186
9042
|
top: rect.top,
|
|
8187
9043
|
left: rect.left,
|
|
8188
9044
|
width: rect.width,
|
|
8189
|
-
height: rect.height,
|
|
8190
|
-
zIndex: 2147483646,
|
|
8191
|
-
pointerEvents: "auto",
|
|
8192
|
-
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
8193
|
-
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
8194
|
-
},
|
|
8195
|
-
onClick: () => onEdit(hover.key),
|
|
8196
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
8197
|
-
Button,
|
|
8198
|
-
{
|
|
8199
|
-
"data-ohw-carousel-overlay": "",
|
|
8200
|
-
variant: "outline",
|
|
8201
|
-
size: "sm",
|
|
8202
|
-
className: "cursor-pointer gap-1.5 hover:bg-background",
|
|
8203
|
-
style: OVERLAY_BUTTON_STYLE2,
|
|
8204
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
8205
|
-
onClick: (e) => {
|
|
8206
|
-
e.stopPropagation();
|
|
8207
|
-
onEdit(hover.key);
|
|
8208
|
-
},
|
|
8209
|
-
children: [
|
|
8210
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react6.GalleryHorizontal, { size: 14 }),
|
|
8211
|
-
"Edit gallery"
|
|
8212
|
-
]
|
|
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);
|
|
9045
|
+
height: rect.height,
|
|
9046
|
+
zIndex: 2147483646,
|
|
9047
|
+
pointerEvents: "auto",
|
|
9048
|
+
boxShadow: "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
9049
|
+
background: "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
|
|
9050
|
+
},
|
|
9051
|
+
onClick: () => onEdit(hover.key),
|
|
9052
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
9053
|
+
Button,
|
|
9054
|
+
{
|
|
9055
|
+
"data-ohw-carousel-overlay": "",
|
|
9056
|
+
variant: "outline",
|
|
9057
|
+
size: "sm",
|
|
9058
|
+
className: "cursor-pointer gap-1.5 hover:bg-background",
|
|
9059
|
+
style: OVERLAY_BUTTON_STYLE2,
|
|
9060
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
9061
|
+
onClick: (e) => {
|
|
9062
|
+
e.stopPropagation();
|
|
9063
|
+
onEdit(hover.key);
|
|
9064
|
+
},
|
|
9065
|
+
children: [
|
|
9066
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react6.GalleryHorizontal, { size: 14 }),
|
|
9067
|
+
"Edit gallery"
|
|
9068
|
+
]
|
|
9069
|
+
}
|
|
9070
|
+
)
|
|
9071
|
+
}
|
|
9072
|
+
);
|
|
8428
9073
|
}
|
|
8429
9074
|
|
|
8430
9075
|
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
9076
|
+
var import_react8 = require("react");
|
|
9077
|
+
var import_lucide_react7 = require("lucide-react");
|
|
8431
9078
|
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
|
-
}
|
|
9079
|
+
var findSectionElement = findByInstanceId;
|
|
8436
9080
|
function readRect(instanceId) {
|
|
8437
9081
|
const el = findSectionElement(instanceId);
|
|
8438
9082
|
if (!el) return null;
|
|
@@ -8472,7 +9116,7 @@ function useLiveSectionRect(sectionId) {
|
|
|
8472
9116
|
}
|
|
8473
9117
|
function computeSectionBoundaryFlags(instanceId) {
|
|
8474
9118
|
const topLevel = topLevelSections();
|
|
8475
|
-
const index = topLevel.findIndex((el) => (el
|
|
9119
|
+
const index = topLevel.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8476
9120
|
if (index === -1) return { isFirst: true, isLast: true };
|
|
8477
9121
|
return { isFirst: index === 0, isLast: index === topLevel.length - 1 };
|
|
8478
9122
|
}
|
|
@@ -8556,18 +9200,20 @@ function AiSectionOverlay({
|
|
|
8556
9200
|
selectedIdRef.current = selectedId;
|
|
8557
9201
|
const report = (0, import_react8.useCallback)(
|
|
8558
9202
|
(el) => {
|
|
9203
|
+
const labelSrc = el ? sectionElementOf(el) : null;
|
|
8559
9204
|
postToParent2({
|
|
8560
9205
|
type: "ow:section-selected",
|
|
8561
|
-
sectionId: el ? el
|
|
8562
|
-
sectionLabel:
|
|
9206
|
+
sectionId: el ? instanceIdOf(el) || null : null,
|
|
9207
|
+
sectionLabel: labelSrc ? labelSrc.dataset.ohwSectionLabel ?? titleCaseSectionId(labelSrc.dataset.ohwSection ?? "") : null
|
|
8563
9208
|
});
|
|
8564
9209
|
},
|
|
8565
9210
|
[postToParent2]
|
|
8566
9211
|
);
|
|
8567
9212
|
const selectFromElement = (0, import_react8.useCallback)(
|
|
8568
9213
|
(el, options) => {
|
|
8569
|
-
const
|
|
8570
|
-
const
|
|
9214
|
+
const inner = el?.closest("[data-ohw-section]") ?? null;
|
|
9215
|
+
const sectionEl = inner ? movableUnit(inner) : null;
|
|
9216
|
+
const id = sectionEl ? instanceIdOf(sectionEl) || null : null;
|
|
8571
9217
|
if (id === selectedIdRef.current) return;
|
|
8572
9218
|
setSelectedId(id);
|
|
8573
9219
|
if (options?.report !== false) report(sectionEl);
|
|
@@ -8633,7 +9279,8 @@ function AiSectionOverlay({
|
|
|
8633
9279
|
return;
|
|
8634
9280
|
}
|
|
8635
9281
|
const sec = t.closest("[data-ohw-section]");
|
|
8636
|
-
|
|
9282
|
+
const unit = sec ? movableUnit(sec) : null;
|
|
9283
|
+
setHoveredId(unit ? instanceIdOf(unit) || null : null);
|
|
8637
9284
|
};
|
|
8638
9285
|
const onLeave = () => setHoveredId(null);
|
|
8639
9286
|
document.addEventListener("mousemove", onMove, { passive: true });
|
|
@@ -9237,7 +9884,7 @@ function SectionTreeItem({
|
|
|
9237
9884
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
9238
9885
|
"div",
|
|
9239
9886
|
{
|
|
9240
|
-
className: "mr-
|
|
9887
|
+
className: "-mr-px h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
|
|
9241
9888
|
"aria-hidden": true
|
|
9242
9889
|
}
|
|
9243
9890
|
),
|
|
@@ -9256,7 +9903,7 @@ function SectionTreeItem({
|
|
|
9256
9903
|
className: cn(
|
|
9257
9904
|
"flex h-9 min-w-0 flex-1 items-center gap-2 rounded-md border border-border bg-background p-3",
|
|
9258
9905
|
interactive && "cursor-pointer hover:bg-muted/30",
|
|
9259
|
-
interactive && selected && "border-primary"
|
|
9906
|
+
interactive && selected && "border-bridge-primary"
|
|
9260
9907
|
),
|
|
9261
9908
|
children: [
|
|
9262
9909
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
@@ -9386,7 +10033,7 @@ function UrlOrPageInput({
|
|
|
9386
10033
|
};
|
|
9387
10034
|
const fieldClassName = cn(
|
|
9388
10035
|
"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"
|
|
10036
|
+
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
10037
|
);
|
|
9391
10038
|
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
|
|
9392
10039
|
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
|
|
@@ -10430,6 +11077,32 @@ function getNavbarDesktopContainer() {
|
|
|
10430
11077
|
function getNavbarDrawerContainer() {
|
|
10431
11078
|
return document.querySelector("[data-ohw-nav-drawer]");
|
|
10432
11079
|
}
|
|
11080
|
+
function isNavbarListContainerVisible(el) {
|
|
11081
|
+
if (el.hasAttribute("hidden")) return false;
|
|
11082
|
+
if (el.getClientRects().length === 0) return false;
|
|
11083
|
+
const style = window.getComputedStyle(el);
|
|
11084
|
+
return style.display !== "none" && style.visibility !== "hidden";
|
|
11085
|
+
}
|
|
11086
|
+
function getActiveNavbarListContainer(draggedEl) {
|
|
11087
|
+
const desktop = getNavbarDesktopContainer();
|
|
11088
|
+
const drawer = getNavbarDrawerContainer();
|
|
11089
|
+
if (draggedEl) {
|
|
11090
|
+
if (drawer?.contains(draggedEl)) return drawer;
|
|
11091
|
+
if (desktop?.contains(draggedEl)) return desktop;
|
|
11092
|
+
}
|
|
11093
|
+
if (desktop && isNavbarListContainerVisible(desktop)) return desktop;
|
|
11094
|
+
if (drawer && isNavbarListContainerVisible(drawer)) return drawer;
|
|
11095
|
+
return desktop ?? drawer;
|
|
11096
|
+
}
|
|
11097
|
+
function listActiveNavbarItems(draggedEl) {
|
|
11098
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
11099
|
+
if (container) {
|
|
11100
|
+
return Array.from(container.querySelectorAll("[data-ohw-href-key]")).filter(
|
|
11101
|
+
isNavbarLinkItem
|
|
11102
|
+
);
|
|
11103
|
+
}
|
|
11104
|
+
return listNavbarItems();
|
|
11105
|
+
}
|
|
10433
11106
|
function listNavbarItems() {
|
|
10434
11107
|
const desktop = getNavbarDesktopContainer();
|
|
10435
11108
|
if (desktop) {
|
|
@@ -11542,20 +12215,23 @@ function isEmptyLabelValue(value) {
|
|
|
11542
12215
|
function applyStoredValues(item, content) {
|
|
11543
12216
|
const hrefKey = socialHrefKey(item);
|
|
11544
12217
|
const iconKey = socialIconKey(item);
|
|
12218
|
+
const baseKey = hrefKey?.replace(/-href$/, "");
|
|
11545
12219
|
if (hrefKey && content[hrefKey] !== void 0) item.setAttribute("href", content[hrefKey]);
|
|
11546
|
-
|
|
12220
|
+
const glyphKey = iconKey ?? baseKey ?? null;
|
|
12221
|
+
const glyphStored = glyphKey ? content[glyphKey]?.trim() : void 0;
|
|
12222
|
+
if (glyphStored) {
|
|
12223
|
+
ensureIconSlot(item);
|
|
11547
12224
|
const glyph = item.querySelector(ICON_SELECTOR);
|
|
11548
|
-
if (glyph
|
|
11549
|
-
applyIconMarkup(glyph,
|
|
12225
|
+
if (glyph) {
|
|
12226
|
+
applyIconMarkup(glyph, glyphStored);
|
|
11550
12227
|
glyph.removeAttribute(SOCIALS_ICON_PLACEHOLDER_ATTR);
|
|
11551
12228
|
}
|
|
11552
|
-
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
}
|
|
12229
|
+
}
|
|
12230
|
+
const label = socialLabelElement(item);
|
|
12231
|
+
const labelKey = label?.getAttribute("data-ohw-key");
|
|
12232
|
+
if (label && labelKey && content[labelKey] !== void 0) {
|
|
12233
|
+
const words = isEmptyLabelValue(content[labelKey]) ? "" : content[labelKey];
|
|
12234
|
+
if (label.innerHTML !== words) label.innerHTML = words;
|
|
11559
12235
|
}
|
|
11560
12236
|
}
|
|
11561
12237
|
function socialPlatformKey(iconKey) {
|
|
@@ -11644,6 +12320,9 @@ function insertSocialItem(row, after, content = {}, { placeholder = true, keys }
|
|
|
11644
12320
|
if (placeholder) {
|
|
11645
12321
|
const label = socialLabelElement(item);
|
|
11646
12322
|
if (label) label.textContent = PLACEHOLDER_SOCIAL_LABEL;
|
|
12323
|
+
} else if (keys) {
|
|
12324
|
+
const label = socialLabelElement(item);
|
|
12325
|
+
if (label) label.textContent = "";
|
|
11647
12326
|
}
|
|
11648
12327
|
applySocialsDisplayToRow(row, display);
|
|
11649
12328
|
return { item, hrefKey, iconKey, order: getSocialsOrderFromDom(row.ownerDocument) };
|
|
@@ -13144,6 +13823,7 @@ function readLogoSizeState(content, placement) {
|
|
|
13144
13823
|
function getLogoElement(el) {
|
|
13145
13824
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
13146
13825
|
if (marked) return marked;
|
|
13826
|
+
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
13147
13827
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
13148
13828
|
if (!root) return null;
|
|
13149
13829
|
const anchor = el.closest("a");
|
|
@@ -13431,7 +14111,7 @@ function DisplaySwitch({
|
|
|
13431
14111
|
onClick: () => onChange(!checked),
|
|
13432
14112
|
className: cn(
|
|
13433
14113
|
"relative h-5 w-9 shrink-0 rounded-full transition-colors",
|
|
13434
|
-
checked ? "bg-primary" : "bg-primary-50",
|
|
14114
|
+
checked ? "bg-bridge-primary" : "bg-primary-50",
|
|
13435
14115
|
disabled ? "cursor-default opacity-50" : "cursor-pointer"
|
|
13436
14116
|
),
|
|
13437
14117
|
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
@@ -13439,7 +14119,7 @@ function DisplaySwitch({
|
|
|
13439
14119
|
{
|
|
13440
14120
|
className: cn(
|
|
13441
14121
|
"absolute top-0.5 h-4 w-4 rounded-full bg-white transition-all",
|
|
13442
|
-
checked ? "left-
|
|
14122
|
+
checked ? "left-4.5" : "left-0.5"
|
|
13443
14123
|
)
|
|
13444
14124
|
}
|
|
13445
14125
|
)
|
|
@@ -13500,8 +14180,8 @@ var lockFooterDuringDrag = lockItemDuringDrag;
|
|
|
13500
14180
|
var unlockFooterDragInteraction = unlockItemDragInteraction;
|
|
13501
14181
|
|
|
13502
14182
|
// src/lib/nav-dnd.ts
|
|
13503
|
-
function listReorderableNavItems() {
|
|
13504
|
-
return
|
|
14183
|
+
function listReorderableNavItems(draggedEl) {
|
|
14184
|
+
return listActiveNavbarItems(draggedEl).filter((el) => {
|
|
13505
14185
|
const key = el.getAttribute("data-ohw-href-key");
|
|
13506
14186
|
return isNavbarHrefKey(key) && !isNestedNavChild(el);
|
|
13507
14187
|
});
|
|
@@ -13516,8 +14196,8 @@ function resolveParentNavHrefKey(child) {
|
|
|
13516
14196
|
const key = trigger?.getAttribute("data-ohw-href-key");
|
|
13517
14197
|
return key && isNavbarHrefKey(key) ? key : null;
|
|
13518
14198
|
}
|
|
13519
|
-
function listNavChildren(parentHrefKey) {
|
|
13520
|
-
const items =
|
|
14199
|
+
function listNavChildren(parentHrefKey, draggedEl) {
|
|
14200
|
+
const items = listActiveNavbarItems(draggedEl);
|
|
13521
14201
|
const parent = items.find((el) => el.getAttribute("data-ohw-href-key") === parentHrefKey);
|
|
13522
14202
|
if (!parent) return [];
|
|
13523
14203
|
const group = parent.closest("[data-ohw-nav-group]");
|
|
@@ -13527,20 +14207,83 @@ function listNavChildren(parentHrefKey) {
|
|
|
13527
14207
|
(el) => isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))
|
|
13528
14208
|
);
|
|
13529
14209
|
}
|
|
13530
|
-
function
|
|
13531
|
-
const
|
|
13532
|
-
if (
|
|
13533
|
-
const
|
|
13534
|
-
|
|
14210
|
+
function isVerticalNavLayout(items, draggedEl) {
|
|
14211
|
+
const visible = items.filter((el) => el.getClientRects().length > 0);
|
|
14212
|
+
if (visible.length >= 2) {
|
|
14213
|
+
const a = visible[0].getBoundingClientRect();
|
|
14214
|
+
const b = visible[1].getBoundingClientRect();
|
|
14215
|
+
const verticalGap = b.top - a.bottom;
|
|
14216
|
+
const horizontalGap = b.left - a.right;
|
|
14217
|
+
return verticalGap > horizontalGap;
|
|
14218
|
+
}
|
|
14219
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
14220
|
+
if (!container) return false;
|
|
14221
|
+
const style = window.getComputedStyle(container);
|
|
14222
|
+
return style.flexDirection === "column" || style.flexDirection === "column-reverse";
|
|
14223
|
+
}
|
|
14224
|
+
function buildVerticalRootNavDropSlots(items, draggedEl) {
|
|
14225
|
+
const slots = [];
|
|
14226
|
+
const barThickness = 3;
|
|
14227
|
+
if (items.length === 0) {
|
|
14228
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
14229
|
+
if (!container) return slots;
|
|
14230
|
+
const rect = container.getBoundingClientRect();
|
|
14231
|
+
slots.push({
|
|
14232
|
+
insertIndex: 0,
|
|
14233
|
+
parentId: null,
|
|
14234
|
+
left: rect.left,
|
|
14235
|
+
top: rect.top + rect.height / 2 - barThickness / 2,
|
|
14236
|
+
width: Math.max(rect.width, 40),
|
|
14237
|
+
height: barThickness,
|
|
14238
|
+
direction: "horizontal"
|
|
14239
|
+
});
|
|
14240
|
+
return slots;
|
|
14241
|
+
}
|
|
14242
|
+
const edgeGap = (() => {
|
|
14243
|
+
if (items.length < 2) return 16;
|
|
14244
|
+
const a = items[0].getBoundingClientRect();
|
|
14245
|
+
const b = items[1].getBoundingClientRect();
|
|
14246
|
+
return Math.max(0, b.top - a.bottom);
|
|
14247
|
+
})();
|
|
14248
|
+
for (let i = 0; i <= items.length; i++) {
|
|
14249
|
+
let top;
|
|
14250
|
+
let width;
|
|
14251
|
+
let left;
|
|
14252
|
+
if (i === 0) {
|
|
14253
|
+
const first = items[0].getBoundingClientRect();
|
|
14254
|
+
top = first.top - edgeGap / 2 - barThickness / 2;
|
|
14255
|
+
left = first.left;
|
|
14256
|
+
width = first.width;
|
|
14257
|
+
} else if (i === items.length) {
|
|
14258
|
+
const last = items[items.length - 1].getBoundingClientRect();
|
|
14259
|
+
const lastGap = items.length >= 2 ? Math.max(0, last.top - items[items.length - 2].getBoundingClientRect().bottom) : edgeGap;
|
|
14260
|
+
top = last.bottom + lastGap / 2 - barThickness / 2;
|
|
14261
|
+
left = last.left;
|
|
14262
|
+
width = last.width;
|
|
14263
|
+
} else {
|
|
14264
|
+
const prev = items[i - 1].getBoundingClientRect();
|
|
14265
|
+
const next = items[i].getBoundingClientRect();
|
|
14266
|
+
top = (prev.bottom + next.top) / 2 - barThickness / 2;
|
|
14267
|
+
left = Math.min(prev.left, next.left);
|
|
14268
|
+
width = Math.max(prev.right, next.right) - left;
|
|
14269
|
+
}
|
|
14270
|
+
slots.push({
|
|
14271
|
+
insertIndex: i,
|
|
14272
|
+
parentId: null,
|
|
14273
|
+
left,
|
|
14274
|
+
top,
|
|
14275
|
+
width: Math.max(width, 40),
|
|
14276
|
+
height: barThickness,
|
|
14277
|
+
direction: "horizontal"
|
|
14278
|
+
});
|
|
13535
14279
|
}
|
|
13536
|
-
return
|
|
14280
|
+
return slots;
|
|
13537
14281
|
}
|
|
13538
|
-
function
|
|
13539
|
-
const items = listReorderableNavItems();
|
|
14282
|
+
function buildHorizontalRootNavDropSlots(items, draggedEl) {
|
|
13540
14283
|
const slots = [];
|
|
13541
14284
|
const barThickness = 3;
|
|
13542
14285
|
if (items.length === 0) {
|
|
13543
|
-
const container =
|
|
14286
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
13544
14287
|
if (!container) return slots;
|
|
13545
14288
|
const rect = container.getBoundingClientRect();
|
|
13546
14289
|
slots.push({
|
|
@@ -13571,10 +14314,7 @@ function buildRootNavDropSlots() {
|
|
|
13571
14314
|
height = first.height;
|
|
13572
14315
|
} else if (i === items.length) {
|
|
13573
14316
|
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;
|
|
14317
|
+
const lastGap = items.length >= 2 ? Math.max(0, last.left - items[items.length - 2].getBoundingClientRect().right) : edgeGap;
|
|
13578
14318
|
left = last.right + lastGap / 2 - barThickness / 2;
|
|
13579
14319
|
top = last.top;
|
|
13580
14320
|
height = last.height;
|
|
@@ -13597,8 +14337,15 @@ function buildRootNavDropSlots() {
|
|
|
13597
14337
|
}
|
|
13598
14338
|
return slots;
|
|
13599
14339
|
}
|
|
13600
|
-
function
|
|
13601
|
-
const
|
|
14340
|
+
function buildRootNavDropSlots(draggedEl) {
|
|
14341
|
+
const items = listReorderableNavItems(draggedEl);
|
|
14342
|
+
if (isVerticalNavLayout(items, draggedEl)) {
|
|
14343
|
+
return buildVerticalRootNavDropSlots(items, draggedEl);
|
|
14344
|
+
}
|
|
14345
|
+
return buildHorizontalRootNavDropSlots(items, draggedEl);
|
|
14346
|
+
}
|
|
14347
|
+
function buildChildNavDropSlots(parentHrefKey, draggedEl) {
|
|
14348
|
+
const children = listNavChildren(parentHrefKey, draggedEl);
|
|
13602
14349
|
const slots = [];
|
|
13603
14350
|
const barThickness = 3;
|
|
13604
14351
|
if (children.length === 0) return slots;
|
|
@@ -13619,10 +14366,7 @@ function buildChildNavDropSlots(parentHrefKey) {
|
|
|
13619
14366
|
width = first.width;
|
|
13620
14367
|
} else if (i === children.length) {
|
|
13621
14368
|
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;
|
|
14369
|
+
const lastGap = children.length >= 2 ? Math.max(0, last.top - children[children.length - 2].getBoundingClientRect().bottom) : edgeGap;
|
|
13626
14370
|
top = last.bottom + lastGap / 2 - barThickness / 2;
|
|
13627
14371
|
left = last.left;
|
|
13628
14372
|
width = last.width;
|
|
@@ -13645,18 +14389,19 @@ function buildChildNavDropSlots(parentHrefKey) {
|
|
|
13645
14389
|
}
|
|
13646
14390
|
return slots;
|
|
13647
14391
|
}
|
|
13648
|
-
function buildAllNavDropSlots(draggedHrefKey) {
|
|
13649
|
-
const
|
|
13650
|
-
|
|
14392
|
+
function buildAllNavDropSlots(draggedHrefKey, draggedEl) {
|
|
14393
|
+
const activeItems = listActiveNavbarItems(draggedEl);
|
|
14394
|
+
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);
|
|
14395
|
+
if (!dragged) return buildRootNavDropSlots(draggedEl);
|
|
13651
14396
|
if (isNestedNavChild(dragged)) {
|
|
13652
14397
|
const parentKey = resolveParentNavHrefKey(dragged);
|
|
13653
14398
|
if (!parentKey) return [];
|
|
13654
|
-
return buildChildNavDropSlots(parentKey);
|
|
14399
|
+
return buildChildNavDropSlots(parentKey, draggedEl);
|
|
13655
14400
|
}
|
|
13656
|
-
return buildRootNavDropSlots();
|
|
14401
|
+
return buildRootNavDropSlots(draggedEl);
|
|
13657
14402
|
}
|
|
13658
|
-
function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
|
|
13659
|
-
const slots = buildAllNavDropSlots(draggedHrefKey);
|
|
14403
|
+
function hitTestNavDropSlot(clientX, clientY, draggedHrefKey, draggedEl) {
|
|
14404
|
+
const slots = buildAllNavDropSlots(draggedHrefKey, draggedEl);
|
|
13660
14405
|
let best = null;
|
|
13661
14406
|
for (const slot of slots) {
|
|
13662
14407
|
const cx2 = slot.left + slot.width / 2;
|
|
@@ -13707,6 +14452,12 @@ function useNavItemDrag({
|
|
|
13707
14452
|
setIsItemDragging(false);
|
|
13708
14453
|
if (keepOpenEl?.isConnected) {
|
|
13709
14454
|
setNavGroupForceOpen(keepOpenEl, true);
|
|
14455
|
+
requestAnimationFrame(() => {
|
|
14456
|
+
if (keepOpenEl.isConnected) setNavGroupForceOpen(keepOpenEl, true);
|
|
14457
|
+
requestAnimationFrame(() => {
|
|
14458
|
+
if (keepOpenEl.isConnected) setNavGroupForceOpen(keepOpenEl, true);
|
|
14459
|
+
});
|
|
14460
|
+
});
|
|
13710
14461
|
} else {
|
|
13711
14462
|
setNavGroupForceOpen(null, false);
|
|
13712
14463
|
}
|
|
@@ -13722,7 +14473,7 @@ function useNavItemDrag({
|
|
|
13722
14473
|
}
|
|
13723
14474
|
session.activeSlot = activeSlot;
|
|
13724
14475
|
setSiblingHintRects([]);
|
|
13725
|
-
const slots = buildAllNavDropSlots(session.hrefKey);
|
|
14476
|
+
const slots = buildAllNavDropSlots(session.hrefKey, session.draggedEl);
|
|
13726
14477
|
setNavDropSlots(slots);
|
|
13727
14478
|
const activeIdx = activeSlot ? slots.findIndex(
|
|
13728
14479
|
(s) => s.parentId === activeSlot.parentId && s.insertIndex === activeSlot.insertIndex
|
|
@@ -13758,7 +14509,12 @@ function useNavItemDrag({
|
|
|
13758
14509
|
if (session.wasSelected && selectedElRef.current === session.draggedEl) {
|
|
13759
14510
|
setToolbarRect(rect);
|
|
13760
14511
|
}
|
|
13761
|
-
const initialSlot = hitTestNavDropSlot(
|
|
14512
|
+
const initialSlot = hitTestNavDropSlot(
|
|
14513
|
+
session.lastClientX,
|
|
14514
|
+
session.lastClientY,
|
|
14515
|
+
session.hrefKey,
|
|
14516
|
+
session.draggedEl
|
|
14517
|
+
);
|
|
13762
14518
|
refreshNavDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
|
|
13763
14519
|
},
|
|
13764
14520
|
[
|
|
@@ -13780,10 +14536,11 @@ function useNavItemDrag({
|
|
|
13780
14536
|
}
|
|
13781
14537
|
const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
|
|
13782
14538
|
const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
|
|
13783
|
-
const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey);
|
|
14539
|
+
const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey, session.draggedEl);
|
|
13784
14540
|
const planned = slot != null ? planNavItemMove(session.hrefKey, slot.parentId, slot.insertIndex) : null;
|
|
13785
14541
|
const wasSelected = session.wasSelected;
|
|
13786
14542
|
const hrefKey = session.hrefKey;
|
|
14543
|
+
const keepDropdownOpen = Boolean(session.draggedEl.closest("[data-ohw-nav-children]"));
|
|
13787
14544
|
const applySelectionAfterDrop = () => {
|
|
13788
14545
|
if (!wasSelected) {
|
|
13789
14546
|
deselectRef.current();
|
|
@@ -13817,6 +14574,14 @@ function useNavItemDrag({
|
|
|
13817
14574
|
});
|
|
13818
14575
|
applySelectionAfterDrop();
|
|
13819
14576
|
clearNavDragVisuals();
|
|
14577
|
+
if (keepDropdownOpen) {
|
|
14578
|
+
requestAnimationFrame(() => {
|
|
14579
|
+
const desktop = document.querySelector("[data-ohw-nav-container]");
|
|
14580
|
+
const drawer = document.querySelector("[data-ohw-nav-drawer]");
|
|
14581
|
+
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)}"]`);
|
|
14582
|
+
if (link) setNavGroupForceOpen(link, true);
|
|
14583
|
+
});
|
|
14584
|
+
}
|
|
13820
14585
|
requestAnimationFrame(() => {
|
|
13821
14586
|
if (editContentRef.current[NAV_ORDER_KEY] === planned.orderJson) {
|
|
13822
14587
|
applyNavForest(planned.forest);
|
|
@@ -13856,7 +14621,7 @@ function useNavItemDrag({
|
|
|
13856
14621
|
if (!session) return false;
|
|
13857
14622
|
e.preventDefault();
|
|
13858
14623
|
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
13859
|
-
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
14624
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey, session.draggedEl);
|
|
13860
14625
|
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
13861
14626
|
return true;
|
|
13862
14627
|
},
|
|
@@ -13902,7 +14667,7 @@ function useNavItemDrag({
|
|
|
13902
14667
|
clearTextSelection();
|
|
13903
14668
|
const session = navDragRef.current;
|
|
13904
14669
|
if (!session) return;
|
|
13905
|
-
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
14670
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey, session.draggedEl);
|
|
13906
14671
|
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
13907
14672
|
return;
|
|
13908
14673
|
}
|
|
@@ -13918,7 +14683,8 @@ function useNavItemDrag({
|
|
|
13918
14683
|
} catch {
|
|
13919
14684
|
}
|
|
13920
14685
|
if (linkPopoverOpenRef.current) setLinkPopover(null);
|
|
13921
|
-
|
|
14686
|
+
const isNestedDrag = Boolean(pending.el.closest("[data-ohw-nav-children]"));
|
|
14687
|
+
if (activeElRef.current && !isNestedDrag) deactivateRef.current();
|
|
13922
14688
|
const key = pending.el.getAttribute("data-ohw-href-key");
|
|
13923
14689
|
if (!key) return;
|
|
13924
14690
|
beginNavDragRef.current({
|
|
@@ -13929,6 +14695,9 @@ function useNavItemDrag({
|
|
|
13929
14695
|
lastClientY: e.clientY,
|
|
13930
14696
|
activeSlot: null
|
|
13931
14697
|
});
|
|
14698
|
+
if (activeElRef.current && isNestedDrag) {
|
|
14699
|
+
deactivateRef.current();
|
|
14700
|
+
}
|
|
13932
14701
|
};
|
|
13933
14702
|
const endPointerDrag = (e) => {
|
|
13934
14703
|
const pending = navPointerDragRef.current;
|
|
@@ -14006,6 +14775,7 @@ function useNavItemDrag({
|
|
|
14006
14775
|
);
|
|
14007
14776
|
return {
|
|
14008
14777
|
navDragRef,
|
|
14778
|
+
navPointerDragRef,
|
|
14009
14779
|
navDropSlots,
|
|
14010
14780
|
activeNavDropIndex,
|
|
14011
14781
|
startNavLinkDrag,
|
|
@@ -14210,15 +14980,17 @@ function useSectionDrag({
|
|
|
14210
14980
|
clearSectionDragVisuals();
|
|
14211
14981
|
return;
|
|
14212
14982
|
}
|
|
14213
|
-
const orderJson = JSON.stringify(
|
|
14983
|
+
const orderJson = JSON.stringify(
|
|
14984
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
14985
|
+
);
|
|
14214
14986
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
14215
14987
|
setAiSectionOrder(orderJson, window.location.pathname);
|
|
14216
14988
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
14217
|
-
applyPersistedOrder(
|
|
14989
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
14218
14990
|
clearSectionDragVisuals();
|
|
14219
14991
|
requestAnimationFrame(() => {
|
|
14220
14992
|
if (editContentRef.current[SECTION_ORDER_KEY] === orderJson) {
|
|
14221
|
-
applyPersistedOrder(
|
|
14993
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
14222
14994
|
}
|
|
14223
14995
|
requestAnimationFrame(() => {
|
|
14224
14996
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -14251,8 +15023,9 @@ function useSectionDrag({
|
|
|
14251
15023
|
const target = e.target;
|
|
14252
15024
|
if (!(target instanceof HTMLElement)) return;
|
|
14253
15025
|
if (target.closest(SECTION_DRAG_EXCLUDED_SELECTOR)) return;
|
|
14254
|
-
const
|
|
14255
|
-
if (!
|
|
15026
|
+
const inner = target.closest("[data-ohw-section]");
|
|
15027
|
+
if (!inner || isChromeSection(inner) || inner.dataset.ohwSection === "footer") return;
|
|
15028
|
+
const sectionEl = movableUnit(inner);
|
|
14256
15029
|
if (!topLevelSections().includes(sectionEl)) return;
|
|
14257
15030
|
startSectionPressDrag(sectionEl, e.clientX, e.clientY, e.pointerId);
|
|
14258
15031
|
};
|
|
@@ -14519,6 +15292,9 @@ function collectEditableNodes(extraContent, root = document) {
|
|
|
14519
15292
|
if (el.dataset.ohwEditable === "link") {
|
|
14520
15293
|
return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref3(el) };
|
|
14521
15294
|
}
|
|
15295
|
+
if (el.dataset.ohwEditable === "map") {
|
|
15296
|
+
return { key: el.dataset.ohwKey ?? "", type: "map", text: el.dataset.ohwMapQuery ?? "" };
|
|
15297
|
+
}
|
|
14522
15298
|
return {
|
|
14523
15299
|
key: el.dataset.ohwKey ?? "",
|
|
14524
15300
|
type: el.dataset.ohwEditable ?? "text",
|
|
@@ -14959,7 +15735,7 @@ var badgeVariants = cva(
|
|
|
14959
15735
|
{
|
|
14960
15736
|
variants: {
|
|
14961
15737
|
variant: {
|
|
14962
|
-
default: "border-transparent bg-primary text-primary-foreground",
|
|
15738
|
+
default: "border-transparent bg-bridge-primary text-primary-foreground",
|
|
14963
15739
|
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
14964
15740
|
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
14965
15741
|
outline: "text-foreground"
|
|
@@ -15081,21 +15857,10 @@ function parseSchedulingInsertAfter(insertAfter) {
|
|
|
15081
15857
|
insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
|
|
15082
15858
|
};
|
|
15083
15859
|
}
|
|
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;
|
|
15860
|
+
function resolveEntryAnchor(entry) {
|
|
15861
|
+
if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
|
|
15862
|
+
const parsed = parseSchedulingInsertAfter(entry.insertAfter);
|
|
15863
|
+
return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
|
|
15099
15864
|
}
|
|
15100
15865
|
function schedulingMountDepth(insertAfter) {
|
|
15101
15866
|
if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
|
|
@@ -15112,8 +15877,7 @@ function getPageSchedulingEntries(raw) {
|
|
|
15112
15877
|
}
|
|
15113
15878
|
}
|
|
15114
15879
|
function isSchedulingWidgetMissing(entry) {
|
|
15115
|
-
|
|
15116
|
-
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
|
|
15880
|
+
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
|
|
15117
15881
|
}
|
|
15118
15882
|
function hasMissingSchedulingWidgets(entries) {
|
|
15119
15883
|
return entries.some(isSchedulingWidgetMissing);
|
|
@@ -15151,18 +15915,18 @@ function initSectionsFromContent(content, removeExisting = false, currentPath =
|
|
|
15151
15915
|
} catch {
|
|
15152
15916
|
}
|
|
15153
15917
|
}
|
|
15154
|
-
function mountSchedulingWidget(
|
|
15155
|
-
const
|
|
15156
|
-
const sectionId = schedulingSectionId(
|
|
15918
|
+
function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
|
|
15919
|
+
const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
|
|
15920
|
+
const sectionId = schedulingSectionId(widgetId);
|
|
15157
15921
|
if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
|
|
15158
|
-
const
|
|
15159
|
-
if (!
|
|
15922
|
+
const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
|
|
15923
|
+
if (!anchorEl) return false;
|
|
15924
|
+
const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
15160
15925
|
const container = document.createElement("div");
|
|
15161
15926
|
container.dataset.ohwSectionContainer = "scheduling";
|
|
15162
|
-
container.dataset.ohwSection = sectionId;
|
|
15163
15927
|
container.dataset.ohwInstance = sectionId;
|
|
15164
|
-
if (
|
|
15165
|
-
const beforeAnchor = document.querySelector(`[data-ohw-section="${
|
|
15928
|
+
if (beforeId) {
|
|
15929
|
+
const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
|
|
15166
15930
|
const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
|
|
15167
15931
|
if (!beforePoint) return false;
|
|
15168
15932
|
beforePoint.insertAdjacentElement("beforebegin", container);
|
|
@@ -15173,20 +15937,26 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
15173
15937
|
}
|
|
15174
15938
|
tail.insertAdjacentElement("afterend", container);
|
|
15175
15939
|
}
|
|
15176
|
-
|
|
15177
|
-
|
|
15178
|
-
|
|
15179
|
-
|
|
15180
|
-
|
|
15181
|
-
|
|
15182
|
-
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
|
|
15187
|
-
|
|
15188
|
-
|
|
15189
|
-
|
|
15940
|
+
try {
|
|
15941
|
+
const root = (0, import_client2.createRoot)(container);
|
|
15942
|
+
schedulingRoots.set(container, root);
|
|
15943
|
+
(0, import_react_dom3.flushSync)(() => {
|
|
15944
|
+
root.render(
|
|
15945
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
15946
|
+
SchedulingWidget,
|
|
15947
|
+
{
|
|
15948
|
+
notifyOnConnect,
|
|
15949
|
+
initialScheduleId: scheduleId,
|
|
15950
|
+
insertAfter: widgetId
|
|
15951
|
+
}
|
|
15952
|
+
)
|
|
15953
|
+
);
|
|
15954
|
+
});
|
|
15955
|
+
} catch (err) {
|
|
15956
|
+
console.error("[ow:scheduling] render threw", err);
|
|
15957
|
+
container.remove();
|
|
15958
|
+
return false;
|
|
15959
|
+
}
|
|
15190
15960
|
const tracker = getSectionsTracker();
|
|
15191
15961
|
let sections = [];
|
|
15192
15962
|
try {
|
|
@@ -15194,10 +15964,12 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
15194
15964
|
} catch {
|
|
15195
15965
|
}
|
|
15196
15966
|
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
15197
|
-
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter ===
|
|
15967
|
+
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
|
|
15198
15968
|
sections.push({
|
|
15199
15969
|
type: "scheduling",
|
|
15200
|
-
insertAfter:
|
|
15970
|
+
insertAfter: widgetId,
|
|
15971
|
+
anchorId,
|
|
15972
|
+
beforeId: beforeId ?? null,
|
|
15201
15973
|
pagePath: window.location.pathname,
|
|
15202
15974
|
...scheduleId ? { scheduleId } : {}
|
|
15203
15975
|
});
|
|
@@ -15211,7 +15983,8 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
|
15211
15983
|
for (let i = pending.length - 1; i >= 0; i--) {
|
|
15212
15984
|
const entry = pending[i];
|
|
15213
15985
|
const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
|
|
15214
|
-
|
|
15986
|
+
const { anchorId, beforeId } = resolveEntryAnchor(entry);
|
|
15987
|
+
if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
|
|
15215
15988
|
pending.splice(i, 1);
|
|
15216
15989
|
}
|
|
15217
15990
|
}
|
|
@@ -15303,7 +16076,7 @@ var EDITOR_CHROME_SELECTOR = '[data-ohw-toolbar], [data-ohw-form-toolbar], [data
|
|
|
15303
16076
|
function isOverEditorChrome(x, y) {
|
|
15304
16077
|
return document.elementsFromPoint(x, y).some((el) => el instanceof HTMLElement && el.matches(EDITOR_CHROME_SELECTOR));
|
|
15305
16078
|
}
|
|
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"])';
|
|
16079
|
+
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
16080
|
function getVideoEl2(el) {
|
|
15308
16081
|
return el instanceof HTMLVideoElement ? el : el.querySelector("video");
|
|
15309
16082
|
}
|
|
@@ -15359,6 +16132,12 @@ function applyVideoSettingNode(key, val) {
|
|
|
15359
16132
|
});
|
|
15360
16133
|
return true;
|
|
15361
16134
|
}
|
|
16135
|
+
function applyMapQuery(el, val) {
|
|
16136
|
+
if (!(el instanceof HTMLIFrameElement)) return;
|
|
16137
|
+
const nextSrc = `https://www.google.com/maps?q=${encodeURIComponent(val)}&output=embed`;
|
|
16138
|
+
if (el.src !== nextSrc) el.src = nextSrc;
|
|
16139
|
+
el.setAttribute("data-ohw-map-query", val);
|
|
16140
|
+
}
|
|
15362
16141
|
function applyLinkByKey(key, val) {
|
|
15363
16142
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
15364
16143
|
if (el.dataset.ohwEditable === "link") applyLinkHref(el, val);
|
|
@@ -15369,6 +16148,11 @@ function applyLinkByKey(key, val) {
|
|
|
15369
16148
|
hrefAnchors.forEach((el) => applyLinkHref(el, val));
|
|
15370
16149
|
}
|
|
15371
16150
|
}
|
|
16151
|
+
function isInsideLinkEditor(target) {
|
|
16152
|
+
return Boolean(
|
|
16153
|
+
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"]')
|
|
16154
|
+
);
|
|
16155
|
+
}
|
|
15372
16156
|
function isInsideFloatingPanel(target) {
|
|
15373
16157
|
return Boolean(target.closest("[data-ohw-floating-panel]"));
|
|
15374
16158
|
}
|
|
@@ -15376,11 +16160,6 @@ function isPointOverFloatingPanel(clientX, clientY) {
|
|
|
15376
16160
|
const el = document.elementFromPoint(clientX, clientY);
|
|
15377
16161
|
return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
|
|
15378
16162
|
}
|
|
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
16163
|
function getHrefKeyFromElement(el) {
|
|
15385
16164
|
if (!el) return null;
|
|
15386
16165
|
const anchor = el.closest("[data-ohw-href-key]");
|
|
@@ -15393,6 +16172,7 @@ function isNavDropdownPanelOpen(childrenRoot) {
|
|
|
15393
16172
|
if (childrenRoot.closest("[data-ohw-nav-drawer]")) return true;
|
|
15394
16173
|
const group = childrenRoot.closest("[data-ohw-nav-group]");
|
|
15395
16174
|
if (group?.hasAttribute("data-ohw-nav-force-open")) return true;
|
|
16175
|
+
if (navDropdownsOpenOnClick()) return false;
|
|
15396
16176
|
if (childrenRoot.clientHeight < 2 || childrenRoot.clientWidth < 2) return false;
|
|
15397
16177
|
const style = window.getComputedStyle(childrenRoot);
|
|
15398
16178
|
if (style.display === "none" || style.visibility === "hidden") return false;
|
|
@@ -15436,6 +16216,11 @@ function getNavigationItemAnchor(el) {
|
|
|
15436
16216
|
function isNavigationItem2(el) {
|
|
15437
16217
|
return getNavigationItemAnchor(el) !== null;
|
|
15438
16218
|
}
|
|
16219
|
+
function isNavFooterScopedNavigationItem(el) {
|
|
16220
|
+
return Boolean(
|
|
16221
|
+
el.closest("nav, footer, [data-ohw-nav-container], [data-ohw-nav-drawer]")
|
|
16222
|
+
);
|
|
16223
|
+
}
|
|
15439
16224
|
function socialWordsClicked(target, item) {
|
|
15440
16225
|
const text = target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
|
|
15441
16226
|
return Boolean(text && item.contains(text));
|
|
@@ -15639,13 +16424,14 @@ function getNavigationSelectionParent(el) {
|
|
|
15639
16424
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
15640
16425
|
return getFooterLinksContainer();
|
|
15641
16426
|
}
|
|
15642
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
16427
|
+
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
16428
|
return getNavigationRoot(el);
|
|
15644
16429
|
}
|
|
15645
16430
|
return null;
|
|
15646
16431
|
}
|
|
15647
16432
|
function collectNavigationItemSiblingHintRects(selected) {
|
|
15648
16433
|
if (!isNavigationItem2(selected)) return [];
|
|
16434
|
+
if (!isNavFooterScopedNavigationItem(selected)) return [];
|
|
15649
16435
|
const socialsRow = findSocialsRow(selected);
|
|
15650
16436
|
if (socialsRow) {
|
|
15651
16437
|
return listSocialItems(socialsRow).filter((item) => item !== selected).map((item) => item.getBoundingClientRect());
|
|
@@ -15854,7 +16640,6 @@ var ICONS = {
|
|
|
15854
16640
|
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
16641
|
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
16642
|
};
|
|
15857
|
-
var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
|
|
15858
16643
|
var SELECTION_CHROME_GAP2 = 4;
|
|
15859
16644
|
var TOOLBAR_STROKE_GAP2 = 4;
|
|
15860
16645
|
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
@@ -16234,6 +17019,7 @@ function StateToggle({
|
|
|
16234
17019
|
);
|
|
16235
17020
|
}
|
|
16236
17021
|
var contentCache = /* @__PURE__ */ new Map();
|
|
17022
|
+
var fetchedContentPaths = /* @__PURE__ */ new Set();
|
|
16237
17023
|
var brandingCache = /* @__PURE__ */ new Map();
|
|
16238
17024
|
var OHW_LOADER_STYLE = {
|
|
16239
17025
|
position: "fixed",
|
|
@@ -16763,13 +17549,6 @@ function OhhwellsBridge() {
|
|
|
16763
17549
|
const [isItemDragging, setIsItemDragging] = (0, import_react17.useState)(false);
|
|
16764
17550
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react17.useState)(false);
|
|
16765
17551
|
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
17552
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react17.useState)(null);
|
|
16774
17553
|
const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react17.useState)(null);
|
|
16775
17554
|
const footerDragRef = (0, import_react17.useRef)(null);
|
|
@@ -16787,6 +17566,13 @@ function OhhwellsBridge() {
|
|
|
16787
17566
|
const brandKitRef = (0, import_react17.useRef)("");
|
|
16788
17567
|
const stylesRef = (0, import_react17.useRef)("");
|
|
16789
17568
|
const pendingDeleteUndoRef = (0, import_react17.useRef)(null);
|
|
17569
|
+
const [floatingPanel, setFloatingPanel] = (0, import_react17.useState)(null);
|
|
17570
|
+
const floatingPanelOpenRef = (0, import_react17.useRef)(false);
|
|
17571
|
+
const setFloatingPanelRef = (0, import_react17.useRef)(setFloatingPanel);
|
|
17572
|
+
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react17.useState)(null);
|
|
17573
|
+
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react17.useState)(null);
|
|
17574
|
+
const [editorViewport, setEditorViewport] = (0, import_react17.useState)("desktop");
|
|
17575
|
+
const [parentScrollSnap, setParentScrollSnap] = (0, import_react17.useState)(null);
|
|
16790
17576
|
const [sitePages, setSitePages] = (0, import_react17.useState)([]);
|
|
16791
17577
|
const [sectionsByPath, setSectionsByPath] = (0, import_react17.useState)({});
|
|
16792
17578
|
const sectionsPrefetchGenRef = (0, import_react17.useRef)(0);
|
|
@@ -16795,9 +17581,21 @@ function OhhwellsBridge() {
|
|
|
16795
17581
|
const linkPopoverOpenRef = (0, import_react17.useRef)(false);
|
|
16796
17582
|
const linkPopoverGraceUntilRef = (0, import_react17.useRef)(0);
|
|
16797
17583
|
setLinkPopoverRef.current = setLinkPopover;
|
|
17584
|
+
setFloatingPanelRef.current = setFloatingPanel;
|
|
16798
17585
|
linkPopoverSessionRef.current = linkPopover;
|
|
17586
|
+
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
17587
|
+
(0, import_react17.useEffect)(() => {
|
|
17588
|
+
const syncViewport = () => {
|
|
17589
|
+
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
17590
|
+
setEditorViewport((prev) => prev === next ? prev : next);
|
|
17591
|
+
};
|
|
17592
|
+
syncViewport();
|
|
17593
|
+
window.addEventListener("resize", syncViewport);
|
|
17594
|
+
return () => window.removeEventListener("resize", syncViewport);
|
|
17595
|
+
}, []);
|
|
16799
17596
|
const {
|
|
16800
17597
|
navDragRef,
|
|
17598
|
+
navPointerDragRef,
|
|
16801
17599
|
navDropSlots,
|
|
16802
17600
|
activeNavDropIndex,
|
|
16803
17601
|
startNavLinkDrag,
|
|
@@ -17000,7 +17798,12 @@ function OhhwellsBridge() {
|
|
|
17000
17798
|
if (owner) persistFieldsRef.current(owner);
|
|
17001
17799
|
}
|
|
17002
17800
|
activeElRef.current = null;
|
|
17003
|
-
|
|
17801
|
+
const preserveNavDropdown = Boolean(navPointerDragRef.current?.el?.closest("[data-ohw-nav-children]")) || Boolean(navDragRef.current?.draggedEl?.closest("[data-ohw-nav-children]")) || Boolean(
|
|
17802
|
+
selectedElRef.current?.closest("[data-ohw-nav-children]") && selectedElRef.current?.closest("[data-ohw-nav-group]")?.hasAttribute("data-ohw-nav-force-open")
|
|
17803
|
+
);
|
|
17804
|
+
if (!preserveNavDropdown) {
|
|
17805
|
+
setNavGroupForceOpen(null, false);
|
|
17806
|
+
}
|
|
17004
17807
|
setReorderHrefKey(null);
|
|
17005
17808
|
setReorderDragDisabled(false);
|
|
17006
17809
|
if (!selectedElRef.current) {
|
|
@@ -17122,7 +17925,10 @@ function OhhwellsBridge() {
|
|
|
17122
17925
|
setSelectedIsSocialsRow(false);
|
|
17123
17926
|
const isDropdownTrigger = !isNestedNavChild(navAnchor) && (navItemHasDropdownChildren(navAnchor) || navItemOwnsDropdownPanel(navAnchor));
|
|
17124
17927
|
if (isNestedNavChild(navAnchor)) {
|
|
17125
|
-
|
|
17928
|
+
const group = navAnchor.closest("[data-ohw-nav-group]");
|
|
17929
|
+
if (group?.hasAttribute("data-ohw-nav-force-open")) {
|
|
17930
|
+
setNavGroupForceOpen(navAnchor, true);
|
|
17931
|
+
}
|
|
17126
17932
|
setNavDropdownPreviewOpen(null);
|
|
17127
17933
|
} else if (isDropdownTrigger) {
|
|
17128
17934
|
const group = navAnchor.closest("[data-ohw-nav-group]");
|
|
@@ -17204,6 +18010,10 @@ function OhhwellsBridge() {
|
|
|
17204
18010
|
const handleNavDropdownOpenChange = (0, import_react17.useCallback)((open) => {
|
|
17205
18011
|
const selected = selectedElRef.current;
|
|
17206
18012
|
if (!selected || !isNavigationItem2(selected)) return;
|
|
18013
|
+
if (isNestedNavChild(selected)) return;
|
|
18014
|
+
const group = selected.closest("[data-ohw-nav-group]");
|
|
18015
|
+
const domOpen = Boolean(group?.hasAttribute("data-ohw-nav-force-open"));
|
|
18016
|
+
if (open === domOpen) return;
|
|
17207
18017
|
setNavGroupForceOpen(selected, open);
|
|
17208
18018
|
setNavDropdownPreviewOpen(open);
|
|
17209
18019
|
requestAnimationFrame(() => {
|
|
@@ -17733,7 +18543,10 @@ function OhhwellsBridge() {
|
|
|
17733
18543
|
clearHrefKeyHover(anchor);
|
|
17734
18544
|
const isDropdownTrigger = !isNestedNavChild(anchor) && (navItemHasDropdownChildren(anchor) || navItemOwnsDropdownPanel(anchor));
|
|
17735
18545
|
if (isNestedNavChild(anchor)) {
|
|
17736
|
-
|
|
18546
|
+
const group = anchor.closest("[data-ohw-nav-group]");
|
|
18547
|
+
if (group?.hasAttribute("data-ohw-nav-force-open")) {
|
|
18548
|
+
setNavGroupForceOpen(anchor, true);
|
|
18549
|
+
}
|
|
17737
18550
|
setNavDropdownPreviewOpen(null);
|
|
17738
18551
|
} else if (isDropdownTrigger) {
|
|
17739
18552
|
setNavGroupForceOpen(null, false);
|
|
@@ -18120,6 +18933,7 @@ function OhhwellsBridge() {
|
|
|
18120
18933
|
}
|
|
18121
18934
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
18122
18935
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
18936
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
18123
18937
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
18124
18938
|
}
|
|
18125
18939
|
applyBrandChrome(content);
|
|
@@ -18127,11 +18941,11 @@ function OhhwellsBridge() {
|
|
|
18127
18941
|
for (const [key, val] of Object.entries(content)) {
|
|
18128
18942
|
if (key === "__ohw_sections") continue;
|
|
18129
18943
|
if (key === AI_SECTIONS_KEY) continue;
|
|
18944
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18945
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18130
18946
|
if (key === BRAND_KIT_KEY) continue;
|
|
18131
18947
|
if (key === STYLE_STORE_KEY) continue;
|
|
18132
18948
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
18133
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18134
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18135
18949
|
if (applyVideoSettingNode(key, val)) continue;
|
|
18136
18950
|
if (applyCarouselNode(key, val)) continue;
|
|
18137
18951
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -18159,6 +18973,8 @@ function OhhwellsBridge() {
|
|
|
18159
18973
|
}
|
|
18160
18974
|
} else if (el.dataset.ohwEditable === "link") {
|
|
18161
18975
|
applyLinkHref(el, val);
|
|
18976
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
18977
|
+
applyMapQuery(el, val);
|
|
18162
18978
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
18163
18979
|
applyIconMarkup(el, val);
|
|
18164
18980
|
} else if (el.dataset.ohwEditable === "form") {
|
|
@@ -18197,7 +19013,9 @@ function OhhwellsBridge() {
|
|
|
18197
19013
|
let cancelled = false;
|
|
18198
19014
|
setFetchState("loading");
|
|
18199
19015
|
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
18200
|
-
|
|
19016
|
+
const initialPath = pathname;
|
|
19017
|
+
fetchedContentPaths.add(`${subdomain}::${initialPath}`);
|
|
19018
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
18201
19019
|
if (cancelled) return;
|
|
18202
19020
|
const content = data?.content ?? {};
|
|
18203
19021
|
const branding = Boolean(data?.showBranding);
|
|
@@ -18306,7 +19124,9 @@ function OhhwellsBridge() {
|
|
|
18306
19124
|
}, [isEditMode]);
|
|
18307
19125
|
(0, import_react17.useEffect)(() => {
|
|
18308
19126
|
if (isEditMode || fetchState !== "done") return;
|
|
19127
|
+
console.log("env", process.env.NEXT_PUBLIC_FLOWOPS_API_URL);
|
|
18309
19128
|
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
19129
|
+
console.log({ apiUrl, subdomain });
|
|
18310
19130
|
bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
|
|
18311
19131
|
}, [isEditMode, fetchState, subdomain]);
|
|
18312
19132
|
(0, import_react17.useEffect)(() => {
|
|
@@ -18316,10 +19136,10 @@ function OhhwellsBridge() {
|
|
|
18316
19136
|
const applyFromCache = () => {
|
|
18317
19137
|
const content = contentCache.get(subdomain);
|
|
18318
19138
|
if (!content) return;
|
|
18319
|
-
retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
|
|
18320
|
-
initSectionInstancesFromContent(content, window.location.pathname);
|
|
18321
19139
|
observer?.disconnect();
|
|
18322
19140
|
try {
|
|
19141
|
+
retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
|
|
19142
|
+
initSectionInstancesFromContent(content, window.location.pathname);
|
|
18323
19143
|
applyBrandChrome(content);
|
|
18324
19144
|
if (typeof content[BRAND_KIT_KEY] === "string") {
|
|
18325
19145
|
applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
|
|
@@ -18331,16 +19151,17 @@ function OhhwellsBridge() {
|
|
|
18331
19151
|
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
18332
19152
|
}
|
|
18333
19153
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
19154
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
18334
19155
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
18335
19156
|
}
|
|
18336
19157
|
for (const [key, val] of Object.entries(content)) {
|
|
18337
19158
|
if (key === "__ohw_sections") continue;
|
|
18338
19159
|
if (key === AI_SECTIONS_KEY) continue;
|
|
19160
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
19161
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18339
19162
|
if (key === BRAND_KIT_KEY) continue;
|
|
18340
19163
|
if (key === STYLE_STORE_KEY) continue;
|
|
18341
19164
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
18342
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18343
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18344
19165
|
if (applyVideoSettingNode(key, val)) continue;
|
|
18345
19166
|
if (applyCarouselNode(key, val)) continue;
|
|
18346
19167
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -18355,6 +19176,8 @@ function OhhwellsBridge() {
|
|
|
18355
19176
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
18356
19177
|
} else if (el.dataset.ohwEditable === "link") {
|
|
18357
19178
|
applyLinkHref(el, val);
|
|
19179
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
19180
|
+
applyMapQuery(el, val);
|
|
18358
19181
|
} else if (el.dataset.ohwEditable === "form") {
|
|
18359
19182
|
} else if (isIconMarkupValue(val)) {
|
|
18360
19183
|
} else if (el.innerHTML !== val) {
|
|
@@ -18386,6 +19209,17 @@ function OhhwellsBridge() {
|
|
|
18386
19209
|
debounceTimer = setTimeout(applyFromCache, 150);
|
|
18387
19210
|
};
|
|
18388
19211
|
applyFromCache();
|
|
19212
|
+
const pathCacheKey = `${subdomain}::${pathname}`;
|
|
19213
|
+
if (!fetchedContentPaths.has(pathCacheKey)) {
|
|
19214
|
+
fetchedContentPaths.add(pathCacheKey);
|
|
19215
|
+
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
19216
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
19217
|
+
if (!data?.content) return;
|
|
19218
|
+
contentCache.set(subdomain, data.content);
|
|
19219
|
+
applyFromCache();
|
|
19220
|
+
}).catch(() => {
|
|
19221
|
+
});
|
|
19222
|
+
}
|
|
18389
19223
|
observer = new MutationObserver(scheduleApply);
|
|
18390
19224
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
18391
19225
|
return () => {
|
|
@@ -18410,6 +19244,10 @@ function OhhwellsBridge() {
|
|
|
18410
19244
|
deselectRef.current();
|
|
18411
19245
|
deactivateRef.current();
|
|
18412
19246
|
}, [pathname, isEditMode]);
|
|
19247
|
+
(0, import_react17.useEffect)(() => {
|
|
19248
|
+
if (!isEditMode) return;
|
|
19249
|
+
initSectionInstancesFromContent(editContentRef.current, pathname);
|
|
19250
|
+
}, [pathname, isEditMode]);
|
|
18413
19251
|
(0, import_react17.useEffect)(() => {
|
|
18414
19252
|
const contentForNav = () => {
|
|
18415
19253
|
if (isEditMode) return editContentRef.current;
|
|
@@ -18501,26 +19339,11 @@ function OhhwellsBridge() {
|
|
|
18501
19339
|
const t2 = setTimeout(measure, 500);
|
|
18502
19340
|
const ro = new ResizeObserver(schedule);
|
|
18503
19341
|
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
19342
|
return () => {
|
|
18518
19343
|
clearTimeout(t1);
|
|
18519
19344
|
clearTimeout(t2);
|
|
18520
19345
|
if (raf != null) cancelAnimationFrame(raf);
|
|
18521
19346
|
ro.disconnect();
|
|
18522
|
-
clearResizeTimers();
|
|
18523
|
-
window.removeEventListener("resize", handleResize);
|
|
18524
19347
|
};
|
|
18525
19348
|
}, [pathname, isEditMode, postToParent2]);
|
|
18526
19349
|
(0, import_react17.useEffect)(() => {
|
|
@@ -18551,28 +19374,19 @@ function OhhwellsBridge() {
|
|
|
18551
19374
|
return;
|
|
18552
19375
|
}
|
|
18553
19376
|
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
|
-
}
|
|
19377
|
+
const canvasHeight = "var(--ohw-canvas-h, 852px)";
|
|
18559
19378
|
const baseCss = `
|
|
18560
19379
|
html { height: auto !important; }
|
|
18561
19380
|
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; }
|
|
19381
|
+
.min-h-screen, .min-h-svh, .min-h-dvh { min-height: ${canvasHeight} !important; }
|
|
19382
|
+
.h-screen, .h-svh, .h-dvh { height: ${canvasHeight} !important; }
|
|
19383
|
+
/* Literal inline viewport units only \u2014 skip R11 sections that already reference --ohw-canvas-h
|
|
19384
|
+
(their style attribute contains "100svh" only as a var() fallback string). */
|
|
19385
|
+
[style*="100vh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
|
|
19386
|
+
[style*="100svh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
|
|
19387
|
+
[style*="100dvh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
|
|
19388
|
+
/* R11: min-height via --ohw-canvas-h; height must grow with content taller than one screen. */
|
|
19389
|
+
[style*="min-height"][style*="--ohw-canvas-h"] { height: auto !important; }
|
|
18576
19390
|
/* Emptied text keeps somewhere to click. A label typed down to nothing collapses to a
|
|
18577
19391
|
couple of pixels, and getting back into it meant hunting for the caret with the mouse.
|
|
18578
19392
|
Edit mode only \u2014 the published page shows nothing where there is nothing (OHH-736). */
|
|
@@ -18719,6 +19533,10 @@ function OhhwellsBridge() {
|
|
|
18719
19533
|
outline-offset: 0 !important;
|
|
18720
19534
|
box-shadow: none !important;
|
|
18721
19535
|
}
|
|
19536
|
+
/* Open nav dropdown panels paint above AI section selection chrome (2147483000). */
|
|
19537
|
+
[data-ohw-nav-group][data-ohw-nav-force-open] > [data-ohw-nav-children] {
|
|
19538
|
+
z-index: 2147483100 !important;
|
|
19539
|
+
}
|
|
18722
19540
|
/* Text edit wins over grab/default (must beat [data-ohw-can-drag] *). */
|
|
18723
19541
|
[data-ohw-editing],
|
|
18724
19542
|
[data-ohw-editing] *,
|
|
@@ -18775,9 +19593,6 @@ function OhhwellsBridge() {
|
|
|
18775
19593
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
18776
19594
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
18777
19595
|
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
19596
|
if (isInsideFloatingPanel(target)) return;
|
|
18782
19597
|
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
18783
19598
|
if (target.closest(
|
|
@@ -18785,6 +19600,9 @@ function OhhwellsBridge() {
|
|
|
18785
19600
|
)) {
|
|
18786
19601
|
return;
|
|
18787
19602
|
}
|
|
19603
|
+
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
19604
|
+
clearMediaSelectionRef.current();
|
|
19605
|
+
}
|
|
18788
19606
|
{
|
|
18789
19607
|
const formEl = getFormElement(target);
|
|
18790
19608
|
const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
|
|
@@ -18936,14 +19754,6 @@ function OhhwellsBridge() {
|
|
|
18936
19754
|
}
|
|
18937
19755
|
const clickedButton = findClosestButtonLike(target);
|
|
18938
19756
|
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
19757
|
if (isMediaEditable(editable) && !buttonOnMedia) {
|
|
18948
19758
|
e.preventDefault();
|
|
18949
19759
|
e.stopPropagation();
|
|
@@ -18970,11 +19780,6 @@ function OhhwellsBridge() {
|
|
|
18970
19780
|
const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
|
|
18971
19781
|
const hrefCtx = getHrefKeyFromElement(hrefLookupTarget);
|
|
18972
19782
|
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
19783
|
if (navAnchor) {
|
|
18979
19784
|
e.preventDefault();
|
|
18980
19785
|
e.stopPropagation();
|
|
@@ -19144,6 +19949,9 @@ function OhhwellsBridge() {
|
|
|
19144
19949
|
setHoveredItemRect(null);
|
|
19145
19950
|
hoveredNavContainerRef.current = null;
|
|
19146
19951
|
setHoveredNavContainerRect(null);
|
|
19952
|
+
siblingHintElRef.current = null;
|
|
19953
|
+
setSiblingHintRect(null);
|
|
19954
|
+
setSiblingHintRects([]);
|
|
19147
19955
|
return;
|
|
19148
19956
|
}
|
|
19149
19957
|
{
|
|
@@ -19262,7 +20070,6 @@ function OhhwellsBridge() {
|
|
|
19262
20070
|
hoveredNavContainerRef.current = null;
|
|
19263
20071
|
setHoveredNavContainerRect(null);
|
|
19264
20072
|
hoveredItemElRef.current = editable;
|
|
19265
|
-
setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
|
|
19266
20073
|
}
|
|
19267
20074
|
}
|
|
19268
20075
|
}
|
|
@@ -19559,7 +20366,7 @@ function OhhwellsBridge() {
|
|
|
19559
20366
|
}
|
|
19560
20367
|
};
|
|
19561
20368
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
19562
|
-
if (linkPopoverOpenRef.current) {
|
|
20369
|
+
if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
19563
20370
|
if (hoveredImageRef.current) {
|
|
19564
20371
|
hoveredImageRef.current = null;
|
|
19565
20372
|
hoveredImageHasTextOverlapRef.current = false;
|
|
@@ -19924,8 +20731,7 @@ function OhhwellsBridge() {
|
|
|
19924
20731
|
};
|
|
19925
20732
|
const handleMouseMove = (e) => {
|
|
19926
20733
|
const { clientX, clientY } = e;
|
|
19927
|
-
if (
|
|
19928
|
-
if (isOverEditorChrome(clientX, clientY)) {
|
|
20734
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
|
|
19929
20735
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
19930
20736
|
formHoverElRef.current = null;
|
|
19931
20737
|
setFormHoverRect(null);
|
|
@@ -19933,6 +20739,12 @@ function OhhwellsBridge() {
|
|
|
19933
20739
|
setHoveredItemRect(null);
|
|
19934
20740
|
hoveredNavContainerRef.current = null;
|
|
19935
20741
|
setHoveredNavContainerRect(null);
|
|
20742
|
+
siblingHintElRef.current = null;
|
|
20743
|
+
setSiblingHintRect(null);
|
|
20744
|
+
setSiblingHintRects([]);
|
|
20745
|
+
dismissImageHover();
|
|
20746
|
+
clearImageHover();
|
|
20747
|
+
setSectionGap(null);
|
|
19936
20748
|
return;
|
|
19937
20749
|
}
|
|
19938
20750
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
@@ -19944,7 +20756,11 @@ function OhhwellsBridge() {
|
|
|
19944
20756
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
19945
20757
|
const { clientX, clientY } = e.data;
|
|
19946
20758
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
19947
|
-
if (
|
|
20759
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
20760
|
+
dismissImageHover();
|
|
20761
|
+
clearImageHover();
|
|
20762
|
+
return;
|
|
20763
|
+
}
|
|
19948
20764
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
19949
20765
|
probeSectionGapAt(clientX, clientY);
|
|
19950
20766
|
probeImageAt(clientX, clientY);
|
|
@@ -20058,7 +20874,11 @@ function OhhwellsBridge() {
|
|
|
20058
20874
|
const slotFromItem = hrefKey ? findSocialByHrefKey(hrefKey)?.querySelector('[data-ohw-editable="icon"]') : null;
|
|
20059
20875
|
const requestedIsIconSlot = Boolean(requestedIconKey) && Boolean(document.querySelector(`[data-ohw-key="${requestedIconKey}"][data-ohw-editable="icon"]`));
|
|
20060
20876
|
const requestedIsFree = Boolean(requestedIconKey) && !document.querySelector(`[data-ohw-key="${requestedIconKey}"]`);
|
|
20061
|
-
|
|
20877
|
+
let iconKey = requestedIsIconSlot ? requestedIconKey : slotFromItem?.dataset.ohwKey ?? (requestedIsFree ? requestedIconKey : void 0);
|
|
20878
|
+
const item = hrefKey ? findSocialByHrefKey(hrefKey) : null;
|
|
20879
|
+
if (item && typeof iconMarkup === "string" && iconMarkup) {
|
|
20880
|
+
iconKey = ensureIconSlot(item) ?? iconKey;
|
|
20881
|
+
}
|
|
20062
20882
|
if (iconKey && typeof iconMarkup === "string" && iconMarkup) {
|
|
20063
20883
|
document.querySelectorAll(`[data-ohw-key="${iconKey}"][data-ohw-editable="icon"]`).forEach((el) => {
|
|
20064
20884
|
applyIconMarkup(el, iconMarkup);
|
|
@@ -20068,7 +20888,7 @@ function OhhwellsBridge() {
|
|
|
20068
20888
|
}
|
|
20069
20889
|
if (iconKey && platformId) nodes.push({ key: socialPlatformKey(iconKey), text: platformId });
|
|
20070
20890
|
if (iconKey && label) {
|
|
20071
|
-
const labelKey = socialLabelKey(iconKey);
|
|
20891
|
+
const labelKey = (item ? socialLabelElement(item)?.getAttribute("data-ohw-key") : null) ?? socialLabelKey(iconKey);
|
|
20072
20892
|
document.querySelectorAll(`[data-ohw-key="${labelKey}"]`).forEach((el) => {
|
|
20073
20893
|
if (keepLabel && el.textContent?.trim()) return;
|
|
20074
20894
|
el.textContent = label;
|
|
@@ -20223,6 +21043,44 @@ function OhhwellsBridge() {
|
|
|
20223
21043
|
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
20224
21044
|
}, 400));
|
|
20225
21045
|
};
|
|
21046
|
+
const reapCommittedAiSections = (excludeIds) => {
|
|
21047
|
+
const aiState = parseAiSectionsState(aiSectionsRef.current);
|
|
21048
|
+
if (aiState.sections.length === 0) return [];
|
|
21049
|
+
let orderEntries = [];
|
|
21050
|
+
try {
|
|
21051
|
+
const parsed = JSON.parse(editContentRef.current[SECTION_ORDER_KEY] ?? "[]");
|
|
21052
|
+
if (Array.isArray(parsed)) orderEntries = parsed;
|
|
21053
|
+
} catch {
|
|
21054
|
+
return [];
|
|
21055
|
+
}
|
|
21056
|
+
const removedIds = orderEntries.filter((entry) => entry && typeof entry.instanceId === "string" && entry.removed).map((entry) => entry.instanceId);
|
|
21057
|
+
if (removedIds.length === 0) return [];
|
|
21058
|
+
const result = reapRemovedAiSections(aiState, parseStyleStore(stylesRef.current), removedIds, excludeIds);
|
|
21059
|
+
if (!result.changed) return [];
|
|
21060
|
+
const nodes = [];
|
|
21061
|
+
aiSectionsRef.current = serializeAiSectionsState(result.state);
|
|
21062
|
+
nodes.push({ key: AI_SECTIONS_KEY, text: aiSectionsRef.current });
|
|
21063
|
+
const reaped = new Set(result.reapedIds);
|
|
21064
|
+
const nextOrderJson = JSON.stringify(orderEntries.filter((entry) => !reaped.has(entry.instanceId)));
|
|
21065
|
+
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: nextOrderJson };
|
|
21066
|
+
setAiSectionOrder(nextOrderJson, window.location.pathname);
|
|
21067
|
+
nodes.push({ key: SECTION_ORDER_KEY, text: nextOrderJson });
|
|
21068
|
+
if (result.store) {
|
|
21069
|
+
stylesRef.current = JSON.stringify(result.store);
|
|
21070
|
+
nodes.push({ key: STYLE_STORE_KEY, text: stylesRef.current });
|
|
21071
|
+
}
|
|
21072
|
+
const nextContent = { ...editContentRef.current };
|
|
21073
|
+
for (const key of Object.keys(nextContent)) {
|
|
21074
|
+
if (key.startsWith(AI_SLOT_KEY_PREFIX) && result.slotPrefixes.some((prefix) => key.startsWith(prefix)) && nextContent[key] !== "") {
|
|
21075
|
+
nextContent[key] = "";
|
|
21076
|
+
nodes.push({ key, text: "" });
|
|
21077
|
+
}
|
|
21078
|
+
}
|
|
21079
|
+
editContentRef.current = nextContent;
|
|
21080
|
+
applyAiSectionsToDom(result.state);
|
|
21081
|
+
applyStylesToDom(parseStyleStore(stylesRef.current));
|
|
21082
|
+
return nodes;
|
|
21083
|
+
};
|
|
20226
21084
|
const handleHydrate = (e) => {
|
|
20227
21085
|
if (e.data?.type !== "ow:hydrate") return;
|
|
20228
21086
|
const content = e.data.content;
|
|
@@ -20241,6 +21099,7 @@ function OhhwellsBridge() {
|
|
|
20241
21099
|
}
|
|
20242
21100
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
20243
21101
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
21102
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
20244
21103
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
20245
21104
|
}
|
|
20246
21105
|
applyBrandChrome(content);
|
|
@@ -20252,11 +21111,11 @@ function OhhwellsBridge() {
|
|
|
20252
21111
|
continue;
|
|
20253
21112
|
}
|
|
20254
21113
|
if (key === AI_SECTIONS_KEY) continue;
|
|
21114
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
21115
|
+
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
20255
21116
|
if (key === BRAND_KIT_KEY) continue;
|
|
20256
21117
|
if (key === STYLE_STORE_KEY) continue;
|
|
20257
21118
|
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
21119
|
if (applyVideoSettingNode(key, val)) continue;
|
|
20261
21120
|
if (applyCarouselNode(key, val)) continue;
|
|
20262
21121
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -20270,6 +21129,8 @@ function OhhwellsBridge() {
|
|
|
20270
21129
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
20271
21130
|
} else if (el.dataset.ohwEditable === "link") {
|
|
20272
21131
|
applyLinkHref(el, val);
|
|
21132
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
21133
|
+
applyMapQuery(el, val);
|
|
20273
21134
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
20274
21135
|
applyIconMarkup(el, val);
|
|
20275
21136
|
} else if (isIconMarkupValue(val)) {
|
|
@@ -20291,8 +21152,16 @@ function OhhwellsBridge() {
|
|
|
20291
21152
|
reconcileFooterOrderFromContent(editContentRef.current);
|
|
20292
21153
|
syncNavigationDragCursorAttrs();
|
|
20293
21154
|
enforceLinkHrefs();
|
|
21155
|
+
const hydrateReapExclude = /* @__PURE__ */ new Set();
|
|
21156
|
+
const hydratePendingUndo = pendingDeleteUndoRef.current;
|
|
21157
|
+
if (hydratePendingUndo?.sectionInstanceId) hydrateReapExclude.add(hydratePendingUndo.sectionInstanceId);
|
|
21158
|
+
const reapNodes = reapCommittedAiSections(hydrateReapExclude);
|
|
21159
|
+
if (reapNodes.length > 0) postToParentRef.current({ type: "ow:change", nodes: reapNodes });
|
|
20294
21160
|
const hydratedHeight = document.body.scrollHeight;
|
|
20295
21161
|
if (hydratedHeight > 50) postToParentRef.current({ type: "ow:height", height: hydratedHeight });
|
|
21162
|
+
if (parseAiSectionsState(aiSectionsRef.current).sections.length > 0) {
|
|
21163
|
+
postAiSectionsChanged();
|
|
21164
|
+
}
|
|
20296
21165
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
20297
21166
|
};
|
|
20298
21167
|
const handleUpdateLogoIdentity = (e) => {
|
|
@@ -20464,10 +21333,26 @@ function OhhwellsBridge() {
|
|
|
20464
21333
|
const handleGetBrand = (e) => {
|
|
20465
21334
|
if (e.data?.type !== "ow:get-brand") return;
|
|
20466
21335
|
const template = deriveTemplateBrand();
|
|
20467
|
-
const
|
|
21336
|
+
const fallback = template ?? (() => {
|
|
21337
|
+
const fonts = deriveTemplateFonts();
|
|
21338
|
+
return fonts ? { palette: AI_DEFAULT_BRAND.palette, fonts } : null;
|
|
21339
|
+
})();
|
|
21340
|
+
const value = brandKitRef.current || (fallback ? JSON.stringify(fallback) : "");
|
|
20468
21341
|
postToParentRef.current({ type: "ow:brand-value", value });
|
|
20469
21342
|
};
|
|
20470
21343
|
window.addEventListener("message", handleGetBrand);
|
|
21344
|
+
const handleGetTemplateFonts = (e) => {
|
|
21345
|
+
if (e.data?.type !== "ow:get-template-fonts") return;
|
|
21346
|
+
const fonts = deriveTemplateFonts();
|
|
21347
|
+
postToParentRef.current({ type: "ow:template-fonts-value", value: fonts ? JSON.stringify(fonts) : "" });
|
|
21348
|
+
};
|
|
21349
|
+
window.addEventListener("message", handleGetTemplateFonts);
|
|
21350
|
+
const handleGetTemplateBrand = (e) => {
|
|
21351
|
+
if (e.data?.type !== "ow:get-template-brand") return;
|
|
21352
|
+
const brand = deriveTemplateBrand();
|
|
21353
|
+
postToParentRef.current({ type: "ow:template-brand-value", value: brand ? JSON.stringify(brand) : "" });
|
|
21354
|
+
};
|
|
21355
|
+
window.addEventListener("message", handleGetTemplateBrand);
|
|
20471
21356
|
const handleMoveSection = (e) => {
|
|
20472
21357
|
if (e.data?.type !== "ow:move-section") return;
|
|
20473
21358
|
const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
|
|
@@ -20475,8 +21360,11 @@ function OhhwellsBridge() {
|
|
|
20475
21360
|
if (!instanceId || !direction) return;
|
|
20476
21361
|
const entries = moveSectionInstance(instanceId, direction, window.location.pathname);
|
|
20477
21362
|
if (!entries) return;
|
|
20478
|
-
const orderJson = JSON.stringify(
|
|
21363
|
+
const orderJson = JSON.stringify(
|
|
21364
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
21365
|
+
);
|
|
20479
21366
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
21367
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
20480
21368
|
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20481
21369
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
20482
21370
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20522,8 +21410,11 @@ function OhhwellsBridge() {
|
|
|
20522
21410
|
const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname);
|
|
20523
21411
|
const entries = deleteSectionInstance(instanceId, window.location.pathname, currentEntries);
|
|
20524
21412
|
if (!entries) return;
|
|
20525
|
-
const orderJson = JSON.stringify(
|
|
21413
|
+
const orderJson = JSON.stringify(
|
|
21414
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
21415
|
+
);
|
|
20526
21416
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
21417
|
+
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20527
21418
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
20528
21419
|
aiSectionApiRef.current?.clear();
|
|
20529
21420
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20532,6 +21423,7 @@ function OhhwellsBridge() {
|
|
|
20532
21423
|
const actionId = newInstanceId();
|
|
20533
21424
|
pendingDeleteUndoRef.current = {
|
|
20534
21425
|
actionId,
|
|
21426
|
+
sectionInstanceId: instanceId,
|
|
20535
21427
|
restore: () => {
|
|
20536
21428
|
const restoredEntries = getPageSectionOrderEntries(
|
|
20537
21429
|
editContentRef.current[SECTION_ORDER_KEY],
|
|
@@ -20539,8 +21431,11 @@ function OhhwellsBridge() {
|
|
|
20539
21431
|
);
|
|
20540
21432
|
const restored = restoreSectionInstance(instanceId, window.location.pathname, restoredEntries);
|
|
20541
21433
|
if (!restored) return;
|
|
20542
|
-
const restoredJson = JSON.stringify(
|
|
21434
|
+
const restoredJson = JSON.stringify(
|
|
21435
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, restored)
|
|
21436
|
+
);
|
|
20543
21437
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: restoredJson };
|
|
21438
|
+
setAiSectionOrder(restoredJson, window.location.pathname);
|
|
20544
21439
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: restoredJson }] });
|
|
20545
21440
|
window.dispatchEvent(new Event("resize"));
|
|
20546
21441
|
const restoreHeight = document.body.scrollHeight;
|
|
@@ -20566,7 +21461,9 @@ function OhhwellsBridge() {
|
|
|
20566
21461
|
const result = duplicateSectionInstance(instanceId, newId, window.location.pathname, currentEntries);
|
|
20567
21462
|
if (!result) return;
|
|
20568
21463
|
const { entries, keyRekeys } = result;
|
|
20569
|
-
const orderJson = JSON.stringify(
|
|
21464
|
+
const orderJson = JSON.stringify(
|
|
21465
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
21466
|
+
);
|
|
20570
21467
|
const nodes = [{ key: SECTION_ORDER_KEY, text: orderJson }];
|
|
20571
21468
|
for (const { from, to } of keyRekeys) {
|
|
20572
21469
|
const inherited = editContentRef.current[from];
|
|
@@ -20576,6 +21473,7 @@ function OhhwellsBridge() {
|
|
|
20576
21473
|
...editContentRef.current,
|
|
20577
21474
|
...Object.fromEntries(nodes.map(({ key, text }) => [key, text]))
|
|
20578
21475
|
};
|
|
21476
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
20579
21477
|
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20580
21478
|
postToParentRef.current({ type: "ow:change", nodes });
|
|
20581
21479
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20594,6 +21492,12 @@ function OhhwellsBridge() {
|
|
|
20594
21492
|
closeLinkPopoverRef.current();
|
|
20595
21493
|
return;
|
|
20596
21494
|
}
|
|
21495
|
+
if (floatingPanelOpenRef.current) {
|
|
21496
|
+
setFloatingPanelRef.current(null);
|
|
21497
|
+
deselectRef.current();
|
|
21498
|
+
deactivateRef.current();
|
|
21499
|
+
return;
|
|
21500
|
+
}
|
|
20597
21501
|
deselectRef.current();
|
|
20598
21502
|
deactivateRef.current();
|
|
20599
21503
|
clearMediaSelectionRef.current();
|
|
@@ -20826,7 +21730,12 @@ function OhhwellsBridge() {
|
|
|
20826
21730
|
}
|
|
20827
21731
|
if (navDragRef.current) {
|
|
20828
21732
|
const session = navDragRef.current;
|
|
20829
|
-
const slot = hitTestNavDropSlot(
|
|
21733
|
+
const slot = hitTestNavDropSlot(
|
|
21734
|
+
session.lastClientX,
|
|
21735
|
+
session.lastClientY,
|
|
21736
|
+
session.hrefKey,
|
|
21737
|
+
session.draggedEl
|
|
21738
|
+
);
|
|
20830
21739
|
refreshNavDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
|
|
20831
21740
|
}
|
|
20832
21741
|
if (hoveredImageRef.current) {
|
|
@@ -20839,6 +21748,10 @@ function OhhwellsBridge() {
|
|
|
20839
21748
|
};
|
|
20840
21749
|
const handleSave = (e) => {
|
|
20841
21750
|
if (e.data?.type !== "ow:save") return;
|
|
21751
|
+
const pendingUndo = pendingDeleteUndoRef.current;
|
|
21752
|
+
const reapExclude = /* @__PURE__ */ new Set();
|
|
21753
|
+
if (pendingUndo?.sectionInstanceId) reapExclude.add(pendingUndo.sectionInstanceId);
|
|
21754
|
+
const reapNodes = reapCommittedAiSections(reapExclude);
|
|
20842
21755
|
const nodes = collectEditableNodes(editContentRef.current);
|
|
20843
21756
|
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
20844
21757
|
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
@@ -20858,6 +21771,11 @@ function OhhwellsBridge() {
|
|
|
20858
21771
|
const text = specs.length ? JSON.stringify(specs) : editContentRef.current[fieldsKey(formKey)];
|
|
20859
21772
|
if (text) nodes.push({ key: fieldsKey(formKey), type: "text", text });
|
|
20860
21773
|
});
|
|
21774
|
+
for (const reapNode of reapNodes) {
|
|
21775
|
+
if (reapNode.key.startsWith(AI_SLOT_KEY_PREFIX) && !nodes.some((n) => n.key === reapNode.key)) {
|
|
21776
|
+
nodes.push({ key: reapNode.key, type: "text", text: reapNode.text });
|
|
21777
|
+
}
|
|
21778
|
+
}
|
|
20861
21779
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
20862
21780
|
};
|
|
20863
21781
|
const handleInsertSection = (e) => {
|
|
@@ -20868,8 +21786,12 @@ function OhhwellsBridge() {
|
|
|
20868
21786
|
if (inserted) {
|
|
20869
21787
|
const tracker = getSectionsTracker();
|
|
20870
21788
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
|
|
20871
|
-
const
|
|
20872
|
-
|
|
21789
|
+
const reportHeight = () => {
|
|
21790
|
+
const h = document.body.scrollHeight;
|
|
21791
|
+
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
21792
|
+
};
|
|
21793
|
+
reportHeight();
|
|
21794
|
+
setTimeout(reportHeight, 500);
|
|
20873
21795
|
}
|
|
20874
21796
|
};
|
|
20875
21797
|
const handleSwitchSchedule = (e) => {
|
|
@@ -21019,18 +21941,21 @@ function OhhwellsBridge() {
|
|
|
21019
21941
|
}
|
|
21020
21942
|
return null;
|
|
21021
21943
|
};
|
|
21944
|
+
const isPointInRect = (el, clientX, clientY) => {
|
|
21945
|
+
const r2 = el.getBoundingClientRect();
|
|
21946
|
+
return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
|
|
21947
|
+
};
|
|
21022
21948
|
const isPointOverEditable = (scope, clientX, clientY) => {
|
|
21023
21949
|
const editables = scope.querySelectorAll("[data-ohw-editable], [data-ohw-href-key]");
|
|
21024
21950
|
for (const el of editables) {
|
|
21025
|
-
|
|
21026
|
-
if (clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom) return true;
|
|
21951
|
+
if (isPointInRect(el, clientX, clientY)) return true;
|
|
21027
21952
|
}
|
|
21028
21953
|
return false;
|
|
21029
21954
|
};
|
|
21030
21955
|
const handleCarouselHover = (e) => {
|
|
21031
21956
|
const container = findCarouselAtPoint(e.clientX, e.clientY);
|
|
21032
21957
|
const scope = container?.closest("[data-ohw-section]") ?? container?.parentElement ?? null;
|
|
21033
|
-
if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY)) {
|
|
21958
|
+
if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY) || isPointOverNavigation(e.clientX, e.clientY) || isPointOverBridgeChrome(e.clientX, e.clientY)) {
|
|
21034
21959
|
setCarouselHover((prev) => prev ? null : prev);
|
|
21035
21960
|
return;
|
|
21036
21961
|
}
|
|
@@ -21268,15 +22193,17 @@ function OhhwellsBridge() {
|
|
|
21268
22193
|
window.removeEventListener("message", handleAiSetBrand);
|
|
21269
22194
|
window.removeEventListener("message", handleAiSetStyles);
|
|
21270
22195
|
window.removeEventListener("message", handleGetBrand);
|
|
22196
|
+
window.removeEventListener("message", handleGetTemplateFonts);
|
|
22197
|
+
window.removeEventListener("message", handleGetTemplateBrand);
|
|
21271
22198
|
window.removeEventListener("message", handleMoveSection);
|
|
21272
22199
|
window.removeEventListener("message", handlePanelDragging);
|
|
21273
22200
|
window.removeEventListener("message", handleDeleteSection);
|
|
21274
22201
|
window.removeEventListener("message", handleDuplicateSection);
|
|
21275
22202
|
window.removeEventListener("message", handleDeactivate);
|
|
21276
|
-
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
21277
22203
|
window.removeEventListener("message", handleToastAction);
|
|
21278
22204
|
window.removeEventListener("message", handleFormCount);
|
|
21279
22205
|
window.removeEventListener("message", handleUiEscape);
|
|
22206
|
+
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
21280
22207
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
21281
22208
|
autoSaveTimers.current.clear();
|
|
21282
22209
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
@@ -21479,7 +22406,7 @@ function OhhwellsBridge() {
|
|
|
21479
22406
|
postToParent2({
|
|
21480
22407
|
type: "ow:ready",
|
|
21481
22408
|
version: "1",
|
|
21482
|
-
bridgeVersion: "0.1.
|
|
22409
|
+
bridgeVersion: "0.1.93",
|
|
21483
22410
|
path: pathname,
|
|
21484
22411
|
nodes: collectEditableNodes(editContentRef.current),
|
|
21485
22412
|
sections
|
|
@@ -22095,7 +23022,7 @@ function OhhwellsBridge() {
|
|
|
22095
23022
|
"span",
|
|
22096
23023
|
{
|
|
22097
23024
|
"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",
|
|
23025
|
+
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
23026
|
children: formPickCount
|
|
22100
23027
|
}
|
|
22101
23028
|
)
|
|
@@ -22332,11 +23259,11 @@ function OhhwellsBridge() {
|
|
|
22332
23259
|
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
22333
23260
|
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
22334
23261
|
children: [
|
|
22335
|
-
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
23262
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } }),
|
|
22336
23263
|
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
22337
23264
|
Badge,
|
|
22338
23265
|
{
|
|
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",
|
|
23266
|
+
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
23267
|
onClick: () => {
|
|
22341
23268
|
window.parent.postMessage(
|
|
22342
23269
|
{
|
|
@@ -22350,7 +23277,7 @@ function OhhwellsBridge() {
|
|
|
22350
23277
|
children: "Add Section"
|
|
22351
23278
|
}
|
|
22352
23279
|
),
|
|
22353
|
-
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
23280
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } })
|
|
22354
23281
|
]
|
|
22355
23282
|
}
|
|
22356
23283
|
),
|
|
@@ -22398,6 +23325,59 @@ function OhhwellsBridge() {
|
|
|
22398
23325
|
) : null
|
|
22399
23326
|
] });
|
|
22400
23327
|
}
|
|
23328
|
+
|
|
23329
|
+
// src/ui/EmptySection.tsx
|
|
23330
|
+
var import_link = __toESM(require("next/link"), 1);
|
|
23331
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
23332
|
+
function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
|
|
23333
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
23334
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
23335
|
+
"p",
|
|
23336
|
+
{
|
|
23337
|
+
style: {
|
|
23338
|
+
fontFamily: "var(--brand-font-body)",
|
|
23339
|
+
fontSize: "0.75rem",
|
|
23340
|
+
fontWeight: 500,
|
|
23341
|
+
letterSpacing: "0.15em",
|
|
23342
|
+
textTransform: "uppercase",
|
|
23343
|
+
color: "var(--brand-accent)",
|
|
23344
|
+
marginBottom: "1.5rem"
|
|
23345
|
+
},
|
|
23346
|
+
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" }) })
|
|
23347
|
+
}
|
|
23348
|
+
),
|
|
23349
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
23350
|
+
"h1",
|
|
23351
|
+
{
|
|
23352
|
+
style: {
|
|
23353
|
+
fontFamily: "var(--brand-font-heading)",
|
|
23354
|
+
fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
|
|
23355
|
+
lineHeight: 1.1,
|
|
23356
|
+
letterSpacing: "-0.025em",
|
|
23357
|
+
color: "var(--brand-text)",
|
|
23358
|
+
marginBottom: "1rem"
|
|
23359
|
+
},
|
|
23360
|
+
...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
|
|
23361
|
+
children: title
|
|
23362
|
+
}
|
|
23363
|
+
),
|
|
23364
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
23365
|
+
"p",
|
|
23366
|
+
{
|
|
23367
|
+
style: {
|
|
23368
|
+
fontFamily: "var(--brand-font-body)",
|
|
23369
|
+
fontSize: "1rem",
|
|
23370
|
+
lineHeight: 1.7,
|
|
23371
|
+
fontWeight: 300,
|
|
23372
|
+
color: "var(--brand-text-muted)",
|
|
23373
|
+
maxWidth: "340px"
|
|
23374
|
+
},
|
|
23375
|
+
...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
|
|
23376
|
+
children: "This page doesn't have any content yet."
|
|
23377
|
+
}
|
|
23378
|
+
)
|
|
23379
|
+
] });
|
|
23380
|
+
}
|
|
22401
23381
|
// Annotate the CommonJS export names for ESM import in node:
|
|
22402
23382
|
0 && (module.exports = {
|
|
22403
23383
|
AI_DEFAULT_BRAND,
|
|
@@ -22415,6 +23395,7 @@ function OhhwellsBridge() {
|
|
|
22415
23395
|
DropdownMenuItem,
|
|
22416
23396
|
DropdownMenuSeparator,
|
|
22417
23397
|
DropdownMenuTrigger,
|
|
23398
|
+
EmptySection,
|
|
22418
23399
|
ItemActionToolbar,
|
|
22419
23400
|
ItemInteractionLayer,
|
|
22420
23401
|
LinkEditorPanel,
|