@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.js
CHANGED
|
@@ -70,6 +70,9 @@ function isRenderableTree(value) {
|
|
|
70
70
|
// src/lib/ai-sections-store.ts
|
|
71
71
|
var AI_SECTIONS_KEY = "__ohw_ai_sections";
|
|
72
72
|
var AI_SLOT_KEY_PREFIX = "ai.";
|
|
73
|
+
function aiSlotKeyPrefixFor(sectionId) {
|
|
74
|
+
return `${AI_SLOT_KEY_PREFIX}${sectionId}.`;
|
|
75
|
+
}
|
|
73
76
|
var EMPTY_AI_SECTIONS = { v: 1, sections: [] };
|
|
74
77
|
function parseAiSectionsState(raw) {
|
|
75
78
|
if (!raw) return EMPTY_AI_SECTIONS;
|
|
@@ -181,6 +184,33 @@ function deleteSectionFromState(state, sectionId) {
|
|
|
181
184
|
if (removed.includes(sectionId)) return state;
|
|
182
185
|
return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
|
|
183
186
|
}
|
|
187
|
+
function reapRemovedAiSections(state, store, removedIds, excludeIds = /* @__PURE__ */ new Set()) {
|
|
188
|
+
const generated = new Set(state.sections.map((entry) => entry.id));
|
|
189
|
+
const reapedIds = [...new Set(removedIds)].filter((id) => generated.has(id) && !excludeIds.has(id));
|
|
190
|
+
if (reapedIds.length === 0) {
|
|
191
|
+
return { state, store, reapedIds: [], slotPrefixes: [], changed: false };
|
|
192
|
+
}
|
|
193
|
+
const reaped = new Set(reapedIds);
|
|
194
|
+
const slotPrefixes = reapedIds.map(aiSlotKeyPrefixFor);
|
|
195
|
+
const nextState = {
|
|
196
|
+
...state,
|
|
197
|
+
v: 1,
|
|
198
|
+
sections: state.sections.filter((entry) => !reaped.has(entry.id))
|
|
199
|
+
};
|
|
200
|
+
let nextStore = store;
|
|
201
|
+
if (store) {
|
|
202
|
+
const sections = {};
|
|
203
|
+
for (const [key, override] of Object.entries(store.sections)) {
|
|
204
|
+
if (!reaped.has(key)) sections[key] = override;
|
|
205
|
+
}
|
|
206
|
+
const nodes = {};
|
|
207
|
+
for (const [key, override] of Object.entries(store.nodes)) {
|
|
208
|
+
if (!slotPrefixes.some((prefix) => key.startsWith(prefix))) nodes[key] = override;
|
|
209
|
+
}
|
|
210
|
+
nextStore = { v: 1, sections, nodes };
|
|
211
|
+
}
|
|
212
|
+
return { state: nextState, store: nextStore, reapedIds, slotPrefixes, changed: true };
|
|
213
|
+
}
|
|
184
214
|
|
|
185
215
|
// src/lib/brand-chrome.ts
|
|
186
216
|
var BRAND_NAME_KEY = "__ohw_brand_name";
|
|
@@ -249,16 +279,17 @@ var LEGACY_BRAND_VAR_NAMES = [
|
|
|
249
279
|
"text-muted",
|
|
250
280
|
"surface",
|
|
251
281
|
"border",
|
|
252
|
-
"on-primary"
|
|
253
|
-
"navbar-background"
|
|
282
|
+
"on-primary"
|
|
254
283
|
].map((role) => `--brand-${role}`);
|
|
255
284
|
var FONT_VARS = {
|
|
256
285
|
heading: ["--font-heading", "--font-display", "--brand-font-heading"],
|
|
257
286
|
body: ["--font-body", "--brand-font-body"]
|
|
258
287
|
};
|
|
259
288
|
var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
|
|
260
|
-
|
|
261
|
-
|
|
289
|
+
var CUSTOM_FONT_STYLE_ID = "ohw-brand-custom-fonts";
|
|
290
|
+
var CUSTOM_FONT_FORMATS = /* @__PURE__ */ new Set(["woff2", "woff", "truetype", "opentype"]);
|
|
291
|
+
function brandColorVars(palette) {
|
|
292
|
+
const { dark, primary, accent, light } = palette;
|
|
262
293
|
const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
|
|
263
294
|
const surface = mix(light, 95, dark);
|
|
264
295
|
const border = mix(light, 85, dark);
|
|
@@ -281,22 +312,42 @@ function brandColorVars(kit) {
|
|
|
281
312
|
"--brand-border": border,
|
|
282
313
|
// Buttons/bands painted in the primary colour assume it's dark/saturated enough to need
|
|
283
314
|
// light text on top — the same assumption LOGO_IMAGE's light-on-dark navbar mark makes.
|
|
284
|
-
"--brand-on-primary": light
|
|
285
|
-
"--brand-navbar-background": dark
|
|
315
|
+
"--brand-on-primary": light
|
|
286
316
|
};
|
|
287
317
|
}
|
|
318
|
+
function parseCustomFontWeight(raw) {
|
|
319
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
320
|
+
const w = raw;
|
|
321
|
+
if (typeof w.weight !== "number" || !Number.isFinite(w.weight)) return null;
|
|
322
|
+
if (typeof w.url !== "string" || !w.url) return null;
|
|
323
|
+
if (typeof w.format !== "string" || !CUSTOM_FONT_FORMATS.has(w.format)) return null;
|
|
324
|
+
const weightEnd = typeof w.weightEnd === "number" && Number.isFinite(w.weightEnd) && w.weightEnd > w.weight ? w.weightEnd : void 0;
|
|
325
|
+
return { weight: w.weight, ...weightEnd !== void 0 ? { weightEnd } : {}, url: w.url, format: w.format };
|
|
326
|
+
}
|
|
327
|
+
function parseCustomFont(raw) {
|
|
328
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
329
|
+
const f = raw;
|
|
330
|
+
if (typeof f.family !== "string" || !f.family) return null;
|
|
331
|
+
if (typeof f.label !== "string" || !f.label) return null;
|
|
332
|
+
if (!Array.isArray(f.weights)) return null;
|
|
333
|
+
const weights = f.weights.map(parseCustomFontWeight).filter((w) => w !== null);
|
|
334
|
+
if (weights.length === 0) return null;
|
|
335
|
+
return { family: f.family, label: f.label, weights };
|
|
336
|
+
}
|
|
288
337
|
function parseBrandKit(raw) {
|
|
289
338
|
if (!raw) return null;
|
|
290
339
|
try {
|
|
291
340
|
const parsed = JSON.parse(raw);
|
|
292
341
|
const p = parsed?.palette;
|
|
293
342
|
const f = parsed?.fonts;
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
343
|
+
const palette = p && typeof p.dark === "string" && typeof p.primary === "string" && typeof p.accent === "string" && typeof p.light === "string" ? { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light } : void 0;
|
|
344
|
+
const fonts = f && typeof f.heading === "string" && typeof f.body === "string" ? { heading: f.heading, body: f.body } : void 0;
|
|
345
|
+
const customFonts = Array.isArray(parsed?.customFonts) ? parsed.customFonts.map(parseCustomFont).filter((c) => c !== null) : void 0;
|
|
346
|
+
if (!palette && !fonts && !customFonts) return null;
|
|
297
347
|
return {
|
|
298
|
-
palette
|
|
299
|
-
fonts
|
|
348
|
+
...palette ? { palette } : {},
|
|
349
|
+
...fonts ? { fonts } : {},
|
|
350
|
+
...customFonts ? { customFonts } : {}
|
|
300
351
|
};
|
|
301
352
|
} catch {
|
|
302
353
|
return null;
|
|
@@ -306,11 +357,16 @@ function familyOf(stack) {
|
|
|
306
357
|
const first = stack.split(",")[0]?.trim() ?? "";
|
|
307
358
|
return first.replace(/^['"]|['"]$/g, "");
|
|
308
359
|
}
|
|
360
|
+
function quoteFamily(family) {
|
|
361
|
+
return `'${family.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
362
|
+
}
|
|
363
|
+
var WEIGHT_SCALE = [100, 200, 300, 400, 500, 600, 700, 800, 900];
|
|
309
364
|
function loadBrandFonts(families) {
|
|
310
365
|
const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
|
|
311
366
|
if (unique.length === 0) return;
|
|
312
|
-
const
|
|
313
|
-
const
|
|
367
|
+
const weights = WEIGHT_SCALE.join(";");
|
|
368
|
+
const spec = unique.map((f) => `family=${f.replace(/ /g, "+")}:wght@${weights}`).join("&");
|
|
369
|
+
const href = `https://fonts.googleapis.com/css2?${spec}&display=swap`;
|
|
314
370
|
let link = document.getElementById(BRAND_FONT_LINK_ID);
|
|
315
371
|
if (!link) {
|
|
316
372
|
link = document.createElement("link");
|
|
@@ -320,18 +376,54 @@ function loadBrandFonts(families) {
|
|
|
320
376
|
}
|
|
321
377
|
if (link.href !== href) link.href = href;
|
|
322
378
|
}
|
|
379
|
+
function escapeCssString(value) {
|
|
380
|
+
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
381
|
+
}
|
|
382
|
+
function loadCustomFonts(fonts) {
|
|
383
|
+
const list = fonts ?? [];
|
|
384
|
+
let style = document.getElementById(CUSTOM_FONT_STYLE_ID);
|
|
385
|
+
if (list.length === 0) {
|
|
386
|
+
style?.remove();
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
if (!style) {
|
|
390
|
+
style = document.createElement("style");
|
|
391
|
+
style.id = CUSTOM_FONT_STYLE_ID;
|
|
392
|
+
document.head.appendChild(style);
|
|
393
|
+
}
|
|
394
|
+
style.textContent = list.flatMap(
|
|
395
|
+
(font) => font.weights.map((w) => {
|
|
396
|
+
const weightDescriptor = w.weightEnd ? `${w.weight} ${w.weightEnd}` : `${w.weight}`;
|
|
397
|
+
return `@font-face { font-family: '${escapeCssString(font.family)}'; src: url('${escapeCssString(w.url)}') format('${w.format}'); font-weight: ${weightDescriptor}; font-display: swap; }`;
|
|
398
|
+
})
|
|
399
|
+
).join("\n");
|
|
400
|
+
}
|
|
323
401
|
function applyBrandToDom(kit) {
|
|
324
402
|
const root = document.documentElement;
|
|
325
403
|
if (!kit) {
|
|
326
404
|
for (const name of [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES]) root.style.removeProperty(name);
|
|
327
405
|
for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
|
|
328
406
|
document.getElementById(BRAND_FONT_LINK_ID)?.remove();
|
|
407
|
+
document.getElementById(CUSTOM_FONT_STYLE_ID)?.remove();
|
|
329
408
|
return;
|
|
330
409
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
410
|
+
if (kit.palette) {
|
|
411
|
+
for (const [name, value] of Object.entries(brandColorVars(kit.palette))) root.style.setProperty(name, value);
|
|
412
|
+
}
|
|
413
|
+
if (kit.customFonts) {
|
|
414
|
+
loadCustomFonts(kit.customFonts);
|
|
415
|
+
}
|
|
416
|
+
if (kit.fonts) {
|
|
417
|
+
const heading = quoteFamily(kit.fonts.heading);
|
|
418
|
+
const body = quoteFamily(kit.fonts.body);
|
|
419
|
+
for (const name of FONT_VARS.heading) root.style.setProperty(name, heading);
|
|
420
|
+
for (const name of FONT_VARS.body) root.style.setProperty(name, body);
|
|
421
|
+
const customFamilies = new Set((kit.customFonts ?? []).map((f) => f.family));
|
|
422
|
+
const googleFamilies = [familyOf(kit.fonts.heading), familyOf(kit.fonts.body)].filter(
|
|
423
|
+
(f) => !customFamilies.has(f)
|
|
424
|
+
);
|
|
425
|
+
loadBrandFonts(googleFamilies);
|
|
426
|
+
}
|
|
335
427
|
}
|
|
336
428
|
|
|
337
429
|
// src/lib/section-styles.ts
|
|
@@ -388,6 +480,10 @@ function styleSheetCss() {
|
|
|
388
480
|
`[data-ohw-style-spacing="${spacing}"] { padding-top: ${px}px !important; padding-bottom: ${px}px !important; }`
|
|
389
481
|
);
|
|
390
482
|
}
|
|
483
|
+
rules.push(
|
|
484
|
+
`[data-ohw-style-corners="sharp"] :is(.card, [data-ohw-card], img, picture, figure, [data-ohw-editable="bg-image"]) { border-radius: 0 !important; }`,
|
|
485
|
+
`[data-ohw-style-corners="sharp"] :has(> img) { border-radius: 0 !important; }`
|
|
486
|
+
);
|
|
391
487
|
for (const align of ["left", "center", "right"]) {
|
|
392
488
|
rules.push(`[data-ohw-style-align="${align}"] { text-align: ${align} !important; }`);
|
|
393
489
|
}
|
|
@@ -418,6 +514,7 @@ var SECTION_ATTRS = {
|
|
|
418
514
|
headlineScale: "data-ohw-style-headline",
|
|
419
515
|
imageAspect: "data-ohw-style-aspect",
|
|
420
516
|
spacing: "data-ohw-style-spacing",
|
|
517
|
+
cornerStyle: "data-ohw-style-corners",
|
|
421
518
|
align: "data-ohw-style-align"
|
|
422
519
|
};
|
|
423
520
|
var NODE_WROTE_ATTR = "data-ohw-style-node";
|
|
@@ -559,9 +656,535 @@ function applyStylesToDom(store) {
|
|
|
559
656
|
import { flushSync } from "react-dom";
|
|
560
657
|
import { createRoot } from "react-dom/client";
|
|
561
658
|
|
|
659
|
+
// src/lib/sections.ts
|
|
660
|
+
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
661
|
+
function isChromeSection(el) {
|
|
662
|
+
return el.matches("header, nav, footer, aside");
|
|
663
|
+
}
|
|
664
|
+
function titleCaseSectionId(id) {
|
|
665
|
+
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
666
|
+
}
|
|
667
|
+
function parseSectionsFromRoot(root) {
|
|
668
|
+
const seen = /* @__PURE__ */ new Set();
|
|
669
|
+
const sections = [];
|
|
670
|
+
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
671
|
+
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
672
|
+
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
673
|
+
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
674
|
+
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
675
|
+
continue;
|
|
676
|
+
seen.add(id);
|
|
677
|
+
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
678
|
+
sections.push({ id, label });
|
|
679
|
+
}
|
|
680
|
+
return sections;
|
|
681
|
+
}
|
|
682
|
+
function collectSectionsFromDom() {
|
|
683
|
+
if (typeof document === "undefined") return [];
|
|
684
|
+
return parseSectionsFromRoot(document);
|
|
685
|
+
}
|
|
686
|
+
function parseSectionsFromHtml(html) {
|
|
687
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
688
|
+
return parseSectionsFromRoot(doc);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// src/lib/section-instances.ts
|
|
692
|
+
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
693
|
+
var REMOVED_ATTR = "data-ohw-section-removed";
|
|
694
|
+
function isRemovedSection(el) {
|
|
695
|
+
return el.hasAttribute(REMOVED_ATTR);
|
|
696
|
+
}
|
|
697
|
+
function movableUnit(el) {
|
|
698
|
+
return el.closest("[data-ohw-section-container]") ?? el;
|
|
699
|
+
}
|
|
700
|
+
function sectionTypeOf(el) {
|
|
701
|
+
return el.getAttribute("data-ohw-section") ?? el.querySelector("[data-ohw-section]")?.getAttribute("data-ohw-section") ?? "";
|
|
702
|
+
}
|
|
703
|
+
function sectionElementOf(el) {
|
|
704
|
+
return el.hasAttribute("data-ohw-section") ? el : el.querySelector("[data-ohw-section]") ?? el;
|
|
705
|
+
}
|
|
706
|
+
function collectTopLevelUnits(predicate) {
|
|
707
|
+
const seen = /* @__PURE__ */ new Set();
|
|
708
|
+
const result = [];
|
|
709
|
+
document.querySelectorAll("[data-ohw-section]").forEach((el) => {
|
|
710
|
+
if (!predicate(el)) return;
|
|
711
|
+
const unit = movableUnit(el);
|
|
712
|
+
if (unit.parentElement?.closest("[data-ohw-section],[data-ohw-section-container]")) return;
|
|
713
|
+
if (seen.has(unit)) return;
|
|
714
|
+
seen.add(unit);
|
|
715
|
+
result.push(unit);
|
|
716
|
+
});
|
|
717
|
+
return result;
|
|
718
|
+
}
|
|
719
|
+
function topLevelSections() {
|
|
720
|
+
return collectTopLevelUnits((el) => !isChromeSection(el) && !isRemovedSection(movableUnit(el)));
|
|
721
|
+
}
|
|
722
|
+
function instanceIdOf(el) {
|
|
723
|
+
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
724
|
+
}
|
|
725
|
+
function findByInstanceId(instanceId) {
|
|
726
|
+
const escapedId = CSS.escape(instanceId);
|
|
727
|
+
const direct = document.querySelector(`[data-ohw-instance="${escapedId}"]`);
|
|
728
|
+
if (direct) return movableUnit(direct);
|
|
729
|
+
const bare = document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
730
|
+
return bare ? movableUnit(bare) : null;
|
|
731
|
+
}
|
|
732
|
+
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
733
|
+
const sections = topLevelSections();
|
|
734
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
735
|
+
if (index === -1) return null;
|
|
736
|
+
const dragged = sections[index];
|
|
737
|
+
const others = sections.filter((_, i) => i !== index);
|
|
738
|
+
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
739
|
+
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
740
|
+
return reordered.map((el, order) => ({
|
|
741
|
+
instanceId: instanceIdOf(el),
|
|
742
|
+
type: sectionTypeOf(el),
|
|
743
|
+
order,
|
|
744
|
+
pagePath: currentPath
|
|
745
|
+
}));
|
|
746
|
+
}
|
|
747
|
+
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
748
|
+
const sections = topLevelSections();
|
|
749
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
750
|
+
if (index === -1) return null;
|
|
751
|
+
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
752
|
+
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
753
|
+
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
754
|
+
if (!entries) return null;
|
|
755
|
+
applyPersistedOrder(entries);
|
|
756
|
+
return entries;
|
|
757
|
+
}
|
|
758
|
+
function syncRemovedFlags(entries) {
|
|
759
|
+
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
760
|
+
document.querySelectorAll(`[${REMOVED_ATTR}]`).forEach((el) => {
|
|
761
|
+
if (!removedIds.has(instanceIdOf(el))) {
|
|
762
|
+
el.style.removeProperty("display");
|
|
763
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
for (const id of removedIds) {
|
|
767
|
+
const el = findByInstanceId(id);
|
|
768
|
+
if (el) {
|
|
769
|
+
el.style.display = "none";
|
|
770
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
function applyPersistedOrder(entries) {
|
|
775
|
+
syncRemovedFlags(entries);
|
|
776
|
+
if (entries.length === 0) return;
|
|
777
|
+
const sections = topLevelSections();
|
|
778
|
+
if (sections.length === 0) return;
|
|
779
|
+
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
780
|
+
const ordered = [...sections].sort((a, b) => {
|
|
781
|
+
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
782
|
+
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
783
|
+
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
784
|
+
if (aOrder === void 0) return 1;
|
|
785
|
+
if (bOrder === void 0) return -1;
|
|
786
|
+
return aOrder - bOrder;
|
|
787
|
+
});
|
|
788
|
+
let prev = null;
|
|
789
|
+
for (const el of ordered) {
|
|
790
|
+
if (prev) prev.after(el);
|
|
791
|
+
prev = el;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
795
|
+
if (!findByInstanceId(instanceId)) return null;
|
|
796
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
797
|
+
const allSections = collectTopLevelUnits((el) => !isChromeSection(el));
|
|
798
|
+
allSections.forEach((el, order) => {
|
|
799
|
+
const id = instanceIdOf(el);
|
|
800
|
+
if (!byId.has(id)) {
|
|
801
|
+
byId.set(id, { instanceId: id, type: sectionTypeOf(el), order, pagePath: currentPath });
|
|
802
|
+
}
|
|
803
|
+
});
|
|
804
|
+
const target = byId.get(instanceId);
|
|
805
|
+
if (!target) return null;
|
|
806
|
+
byId.set(instanceId, { ...target, removed });
|
|
807
|
+
const entries = Array.from(byId.values());
|
|
808
|
+
applyPersistedOrder(entries);
|
|
809
|
+
return entries;
|
|
810
|
+
}
|
|
811
|
+
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
812
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
813
|
+
}
|
|
814
|
+
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
815
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
816
|
+
}
|
|
817
|
+
function duplicateSectionInstance(instanceId, newId, currentPath, existingEntries) {
|
|
818
|
+
const original = findByInstanceId(instanceId);
|
|
819
|
+
if (!original) return null;
|
|
820
|
+
const clone = original.cloneNode(true);
|
|
821
|
+
clone.setAttribute("data-ohw-instance", newId);
|
|
822
|
+
const keyRekeys = rekeySectionSubtree(clone, newId);
|
|
823
|
+
original.insertAdjacentElement("afterend", clone);
|
|
824
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
825
|
+
const entries = topLevelSections().map((el, order) => {
|
|
826
|
+
const id = instanceIdOf(el);
|
|
827
|
+
return {
|
|
828
|
+
instanceId: id,
|
|
829
|
+
type: sectionTypeOf(el),
|
|
830
|
+
order,
|
|
831
|
+
pagePath: currentPath,
|
|
832
|
+
...byId.get(id)?.removed ? { removed: true } : {}
|
|
833
|
+
};
|
|
834
|
+
});
|
|
835
|
+
applyPersistedOrder(entries);
|
|
836
|
+
return { entries, keyRekeys };
|
|
837
|
+
}
|
|
838
|
+
function newInstanceId() {
|
|
839
|
+
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
840
|
+
}
|
|
841
|
+
function getPageSectionOrderEntries(raw, currentPath) {
|
|
842
|
+
if (!raw) return [];
|
|
843
|
+
try {
|
|
844
|
+
const entries = JSON.parse(raw);
|
|
845
|
+
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
846
|
+
} catch {
|
|
847
|
+
return [];
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
function mergePageSectionOrder(raw, currentPath, pageEntries) {
|
|
851
|
+
let all = [];
|
|
852
|
+
if (raw) {
|
|
853
|
+
try {
|
|
854
|
+
const parsed = JSON.parse(raw);
|
|
855
|
+
if (Array.isArray(parsed)) all = parsed;
|
|
856
|
+
} catch {
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
const otherPages = all.filter((e) => e && e.pagePath && e.pagePath !== currentPath);
|
|
860
|
+
const pageIds = new Set(pageEntries.map((e) => e.instanceId));
|
|
861
|
+
const removedHere = all.filter(
|
|
862
|
+
(e) => e && (!e.pagePath || e.pagePath === currentPath) && e.removed && !pageIds.has(e.instanceId)
|
|
863
|
+
);
|
|
864
|
+
return [...otherPages, ...removedHere, ...pageEntries];
|
|
865
|
+
}
|
|
866
|
+
function rekeySectionSubtree(root, instanceId) {
|
|
867
|
+
const suffix = `::${instanceId}`;
|
|
868
|
+
const pairs = [];
|
|
869
|
+
const rekey = (el, attr) => {
|
|
870
|
+
const current = el.getAttribute(attr);
|
|
871
|
+
if (!current) return;
|
|
872
|
+
const base = current.includes("::") ? current.slice(0, current.indexOf("::")) : current;
|
|
873
|
+
const next = `${base}${suffix}`;
|
|
874
|
+
el.setAttribute(attr, next);
|
|
875
|
+
pairs.push({ from: current, to: next });
|
|
876
|
+
};
|
|
877
|
+
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
878
|
+
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
879
|
+
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
880
|
+
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
881
|
+
return pairs;
|
|
882
|
+
}
|
|
883
|
+
function initSectionInstancesFromContent(content, currentPath) {
|
|
884
|
+
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
885
|
+
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
886
|
+
});
|
|
887
|
+
document.querySelectorAll("[data-ohw-section-container]:not([data-ohw-instance])").forEach((el) => {
|
|
888
|
+
const type = sectionTypeOf(el);
|
|
889
|
+
if (type) el.setAttribute("data-ohw-instance", type);
|
|
890
|
+
});
|
|
891
|
+
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
892
|
+
for (const entry of entries) {
|
|
893
|
+
if (entry.instanceId === entry.type) continue;
|
|
894
|
+
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
895
|
+
const original = document.querySelector(
|
|
896
|
+
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
897
|
+
);
|
|
898
|
+
if (!original) continue;
|
|
899
|
+
const clone = original.cloneNode(true);
|
|
900
|
+
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
901
|
+
rekeySectionSubtree(clone, entry.instanceId);
|
|
902
|
+
original.insertAdjacentElement("afterend", clone);
|
|
903
|
+
}
|
|
904
|
+
applyPersistedOrder(entries);
|
|
905
|
+
}
|
|
906
|
+
|
|
562
907
|
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
563
908
|
import React from "react";
|
|
564
909
|
import { ArrowLeft, ArrowRight, ChevronDown, icons as lucideIcons } from "lucide-react";
|
|
910
|
+
|
|
911
|
+
// src/lib/placeholder-imagery.ts
|
|
912
|
+
var U = (id) => `https://images.unsplash.com/photo-${id}?auto=format&fit=crop&w=1600&q=80`;
|
|
913
|
+
var GENERIC = [
|
|
914
|
+
U("1441986300917-64674bd600d8"),
|
|
915
|
+
U("1486406146926-c627a92ad1ab"),
|
|
916
|
+
U("1497032628192-86f99bcd76bc"),
|
|
917
|
+
U("1521737604893-d14cc237f11d"),
|
|
918
|
+
U("1522071820081-009f0129c71c"),
|
|
919
|
+
U("1519389950473-47ba0277781c"),
|
|
920
|
+
U("1460925895917-afdab827c52f"),
|
|
921
|
+
U("1504384308090-c894fdcc538d")
|
|
922
|
+
];
|
|
923
|
+
var PEOPLE = [
|
|
924
|
+
U("1500648767791-00dcc994a43e"),
|
|
925
|
+
U("1494790108377-be9c29b29330"),
|
|
926
|
+
U("1507003211169-0a1dd7228f2d"),
|
|
927
|
+
U("1438761681033-6461ffad8d80"),
|
|
928
|
+
U("1544005313-94ddf0286df2"),
|
|
929
|
+
U("1472099645785-5658abf4ff4e"),
|
|
930
|
+
U("1519085360753-af0119f7cbe7"),
|
|
931
|
+
U("1534528741775-53994a69daeb")
|
|
932
|
+
];
|
|
933
|
+
var THEMED = [
|
|
934
|
+
{
|
|
935
|
+
keywords: ["portrait", "headshot", "person", "people", "team", "staff", "avatar", "founder", "face"],
|
|
936
|
+
pool: PEOPLE
|
|
937
|
+
},
|
|
938
|
+
{
|
|
939
|
+
keywords: ["pet", "dog", "cat", "puppy", "kitten", "vet", "animal"],
|
|
940
|
+
pool: [
|
|
941
|
+
U("1548199973-03cce0bbc87b"),
|
|
942
|
+
U("1450778869180-41d0601e046e"),
|
|
943
|
+
U("1583511655857-d19b40a7a54e"),
|
|
944
|
+
U("1587300003388-59208cc962cb"),
|
|
945
|
+
U("1517849845537-4d257902454a"),
|
|
946
|
+
U("1601758228041-f3b2795255f1")
|
|
947
|
+
]
|
|
948
|
+
},
|
|
949
|
+
{
|
|
950
|
+
keywords: [
|
|
951
|
+
"baker",
|
|
952
|
+
"bakery",
|
|
953
|
+
"cafe",
|
|
954
|
+
"coffee",
|
|
955
|
+
"latte",
|
|
956
|
+
"restaurant",
|
|
957
|
+
"pastr",
|
|
958
|
+
"bread",
|
|
959
|
+
"cake",
|
|
960
|
+
"cater",
|
|
961
|
+
"chef",
|
|
962
|
+
"kitchen",
|
|
963
|
+
"food",
|
|
964
|
+
"pizza",
|
|
965
|
+
"dessert",
|
|
966
|
+
"brunch",
|
|
967
|
+
"bistro",
|
|
968
|
+
"deli",
|
|
969
|
+
"dish",
|
|
970
|
+
"menu"
|
|
971
|
+
],
|
|
972
|
+
pool: [
|
|
973
|
+
U("1509440159596-0249088772ff"),
|
|
974
|
+
U("1555507036-ab1f4038808a"),
|
|
975
|
+
U("1517433670267-08bbd4be890f"),
|
|
976
|
+
U("1486427944299-d1955d23e34d"),
|
|
977
|
+
U("1504754524776-8f4f37790ca0"),
|
|
978
|
+
U("1495474472287-4d71bcdd2085"),
|
|
979
|
+
U("1521017432531-fbd92d768814"),
|
|
980
|
+
U("1556909114-f6e7ad7d3136")
|
|
981
|
+
]
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
keywords: [
|
|
985
|
+
"shop",
|
|
986
|
+
"store",
|
|
987
|
+
"boutique",
|
|
988
|
+
"retail",
|
|
989
|
+
"clothing",
|
|
990
|
+
"fashion",
|
|
991
|
+
"jewel",
|
|
992
|
+
"gift",
|
|
993
|
+
"florist",
|
|
994
|
+
"market",
|
|
995
|
+
"grocer",
|
|
996
|
+
"product",
|
|
997
|
+
"storefront"
|
|
998
|
+
],
|
|
999
|
+
pool: [
|
|
1000
|
+
U("1441984904996-e0b6ba687e04"),
|
|
1001
|
+
U("1472851294608-062f824d29cc"),
|
|
1002
|
+
U("1523381210434-271e8be1f52b"),
|
|
1003
|
+
U("1534452203293-494d7ddbf7e0"),
|
|
1004
|
+
U("1445205170230-053b83016050"),
|
|
1005
|
+
U("1560243563-062bfc001d68")
|
|
1006
|
+
]
|
|
1007
|
+
},
|
|
1008
|
+
{
|
|
1009
|
+
keywords: [
|
|
1010
|
+
"yoga",
|
|
1011
|
+
"pilates",
|
|
1012
|
+
"fitness",
|
|
1013
|
+
"gym",
|
|
1014
|
+
"workout",
|
|
1015
|
+
"trainer",
|
|
1016
|
+
"wellness",
|
|
1017
|
+
"meditat",
|
|
1018
|
+
"massage",
|
|
1019
|
+
"therap",
|
|
1020
|
+
"physio",
|
|
1021
|
+
"chiro",
|
|
1022
|
+
"nutrition",
|
|
1023
|
+
"spa",
|
|
1024
|
+
"studio"
|
|
1025
|
+
],
|
|
1026
|
+
pool: [
|
|
1027
|
+
U("1544367567-0f2fcb009e0b"),
|
|
1028
|
+
U("1506126613408-eca07ce68773"),
|
|
1029
|
+
U("1545205597-3d9d02c29597"),
|
|
1030
|
+
U("1552196563-55cd4e45efb3"),
|
|
1031
|
+
U("1518611012118-696072aa579a"),
|
|
1032
|
+
U("1571019613454-1cb2f99b2d8b"),
|
|
1033
|
+
U("1540555700478-4be289fbecef"),
|
|
1034
|
+
U("1519824145371-296894a0daa9")
|
|
1035
|
+
]
|
|
1036
|
+
},
|
|
1037
|
+
{
|
|
1038
|
+
keywords: [
|
|
1039
|
+
"salon",
|
|
1040
|
+
"hairdress",
|
|
1041
|
+
"haircut",
|
|
1042
|
+
"barber",
|
|
1043
|
+
"manicure",
|
|
1044
|
+
"pedicure",
|
|
1045
|
+
"nails",
|
|
1046
|
+
"beauty",
|
|
1047
|
+
"makeup",
|
|
1048
|
+
"cosmetic",
|
|
1049
|
+
"eyelash",
|
|
1050
|
+
"eyebrow",
|
|
1051
|
+
"skincare",
|
|
1052
|
+
"esthetic",
|
|
1053
|
+
"waxing",
|
|
1054
|
+
"hair"
|
|
1055
|
+
],
|
|
1056
|
+
pool: [
|
|
1057
|
+
U("1560066984-138dadb4c035"),
|
|
1058
|
+
U("1522337660859-02fbefca4702"),
|
|
1059
|
+
U("1562322140-8baeececf3df"),
|
|
1060
|
+
U("1521590832167-7bcbfaa6381f"),
|
|
1061
|
+
U("1487412947147-5cebf100ffc2"),
|
|
1062
|
+
U("1526045478516-99145907023c")
|
|
1063
|
+
]
|
|
1064
|
+
},
|
|
1065
|
+
{
|
|
1066
|
+
keywords: [
|
|
1067
|
+
"cleaning",
|
|
1068
|
+
"plumb",
|
|
1069
|
+
"electric",
|
|
1070
|
+
"landscap",
|
|
1071
|
+
"contractor",
|
|
1072
|
+
"handyman",
|
|
1073
|
+
"renov",
|
|
1074
|
+
"hvac",
|
|
1075
|
+
"roofing",
|
|
1076
|
+
"painting",
|
|
1077
|
+
"carpentry",
|
|
1078
|
+
"flooring",
|
|
1079
|
+
"movers",
|
|
1080
|
+
"construction",
|
|
1081
|
+
"tools"
|
|
1082
|
+
],
|
|
1083
|
+
pool: [
|
|
1084
|
+
U("1581578731548-c64695cc6952"),
|
|
1085
|
+
U("1504307651254-35680f356dfd"),
|
|
1086
|
+
U("1581092160562-40aa08e78837"),
|
|
1087
|
+
U("1621905251189-08b45d6a269e"),
|
|
1088
|
+
U("1558618666-fcd25c85cd64"),
|
|
1089
|
+
U("1585128792020-803d29415281")
|
|
1090
|
+
]
|
|
1091
|
+
},
|
|
1092
|
+
{
|
|
1093
|
+
keywords: [
|
|
1094
|
+
"legal",
|
|
1095
|
+
"attorney",
|
|
1096
|
+
"lawyer",
|
|
1097
|
+
"account",
|
|
1098
|
+
"bookkeep",
|
|
1099
|
+
"consult",
|
|
1100
|
+
"coaching",
|
|
1101
|
+
"financ",
|
|
1102
|
+
"insurance",
|
|
1103
|
+
"realtor",
|
|
1104
|
+
"estate",
|
|
1105
|
+
"marketing",
|
|
1106
|
+
"agency",
|
|
1107
|
+
"office",
|
|
1108
|
+
"business",
|
|
1109
|
+
"desk"
|
|
1110
|
+
],
|
|
1111
|
+
pool: [
|
|
1112
|
+
U("1497366216548-37526070297c"),
|
|
1113
|
+
U("1497366811353-6870744d04b2"),
|
|
1114
|
+
U("1454165804606-c3d57bc86b40"),
|
|
1115
|
+
U("1521791136064-7986c2920216"),
|
|
1116
|
+
U("1556761175-b413da4baf72"),
|
|
1117
|
+
U("1542744173-8e7e53415bb0")
|
|
1118
|
+
]
|
|
1119
|
+
},
|
|
1120
|
+
{
|
|
1121
|
+
keywords: [
|
|
1122
|
+
"wedding",
|
|
1123
|
+
"event",
|
|
1124
|
+
"party",
|
|
1125
|
+
"celebrat",
|
|
1126
|
+
"venue",
|
|
1127
|
+
"community",
|
|
1128
|
+
"nonprofit",
|
|
1129
|
+
"charity",
|
|
1130
|
+
"workshop",
|
|
1131
|
+
"photograph",
|
|
1132
|
+
"concert"
|
|
1133
|
+
],
|
|
1134
|
+
pool: [
|
|
1135
|
+
U("1511578314322-379afb476865"),
|
|
1136
|
+
U("1501281668745-f7f57925c3b4"),
|
|
1137
|
+
U("1523580494863-6f3031224c94"),
|
|
1138
|
+
U("1540575467063-178a50c2df87"),
|
|
1139
|
+
U("1505236858219-8359eb29e329"),
|
|
1140
|
+
U("1528605248644-14dd04022da1")
|
|
1141
|
+
]
|
|
1142
|
+
}
|
|
1143
|
+
];
|
|
1144
|
+
function poolForSubject(subject) {
|
|
1145
|
+
for (const theme of THEMED) {
|
|
1146
|
+
if (theme.keywords.some((k) => subject.includes(k))) {
|
|
1147
|
+
return theme.pool;
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
return GENERIC;
|
|
1151
|
+
}
|
|
1152
|
+
function mixedHash(text) {
|
|
1153
|
+
let hash = 2166136261;
|
|
1154
|
+
for (let i = 0; i < text.length; i++) {
|
|
1155
|
+
hash ^= text.charCodeAt(i);
|
|
1156
|
+
hash = Math.imul(hash, 16777619);
|
|
1157
|
+
}
|
|
1158
|
+
return hash >>> 16 & 65535;
|
|
1159
|
+
}
|
|
1160
|
+
function resolvePlaceholderRef(ref) {
|
|
1161
|
+
const match = /^placeholder:([a-z0-9-]+)$/.exec(ref);
|
|
1162
|
+
if (!match) return null;
|
|
1163
|
+
const subject = match[1];
|
|
1164
|
+
const pool = poolForSubject(subject.replace(/-\d+$/, ""));
|
|
1165
|
+
return pool[mixedHash(ref) % pool.length];
|
|
1166
|
+
}
|
|
1167
|
+
function collectPlaceholderRefs(tree) {
|
|
1168
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1169
|
+
for (const match of JSON.stringify(tree ?? null).matchAll(/"(placeholder:[a-z0-9-]+)"/gu)) {
|
|
1170
|
+
seen.add(match[1]);
|
|
1171
|
+
}
|
|
1172
|
+
return [...seen];
|
|
1173
|
+
}
|
|
1174
|
+
function buildPlaceholderMap(tree) {
|
|
1175
|
+
const map = {};
|
|
1176
|
+
const cursor = /* @__PURE__ */ new Map();
|
|
1177
|
+
for (const ref of collectPlaceholderRefs(tree)) {
|
|
1178
|
+
const subject = ref.slice("placeholder:".length).replace(/-\d+$/, "");
|
|
1179
|
+
const pool = poolForSubject(subject);
|
|
1180
|
+
const start = cursor.get(pool) ?? mixedHash(ref) % pool.length;
|
|
1181
|
+
map[ref] = pool[start % pool.length];
|
|
1182
|
+
cursor.set(pool, start + 1);
|
|
1183
|
+
}
|
|
1184
|
+
return map;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
565
1188
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
566
1189
|
function lucideByName(name) {
|
|
567
1190
|
const pascal = name.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
@@ -575,6 +1198,7 @@ var typeStyle = (spec, font) => ({
|
|
|
575
1198
|
fontWeight: spec.weight
|
|
576
1199
|
});
|
|
577
1200
|
var str = (value) => typeof value === "string" ? value : "";
|
|
1201
|
+
var cardRadius = (slots) => slots.cornerStyle === "sharp" ? 0 : AI_TREE_TOKENS.radiusCard;
|
|
578
1202
|
var featureLines = (value) => value.split(/\n|<br\s*\/?>/i).map((line) => line.trim()).filter(Boolean);
|
|
579
1203
|
var CHECK_MASK = `data:image/svg+xml,${encodeURIComponent(
|
|
580
1204
|
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>'
|
|
@@ -601,6 +1225,25 @@ var FEATURE_LINE_CSS = [
|
|
|
601
1225
|
`background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
|
|
602
1226
|
`mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
|
|
603
1227
|
].join("");
|
|
1228
|
+
function buttonShellStyle(ctx, fullWidth) {
|
|
1229
|
+
const bs = ctx.buttonStyle;
|
|
1230
|
+
if (bs) {
|
|
1231
|
+
return {
|
|
1232
|
+
borderRadius: bs.radius,
|
|
1233
|
+
...bs.padding ? { padding: bs.padding } : {},
|
|
1234
|
+
...bs.fontFamily ? { fontFamily: bs.fontFamily } : { fontFamily: ctx.brand.fonts.body },
|
|
1235
|
+
...bs.fontSize ? { fontSize: bs.fontSize } : {},
|
|
1236
|
+
...bs.fontWeight ? { fontWeight: bs.fontWeight } : {},
|
|
1237
|
+
...bs.letterSpacing && bs.letterSpacing !== "normal" ? { letterSpacing: bs.letterSpacing } : {},
|
|
1238
|
+
...bs.textTransform && bs.textTransform !== "none" ? { textTransform: bs.textTransform } : {}
|
|
1239
|
+
};
|
|
1240
|
+
}
|
|
1241
|
+
return {
|
|
1242
|
+
borderRadius: AI_TREE_TOKENS.radiusButton,
|
|
1243
|
+
padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
|
|
1244
|
+
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
604
1247
|
function hexLuminance(color) {
|
|
605
1248
|
const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
|
|
606
1249
|
if (!m) return null;
|
|
@@ -617,6 +1260,12 @@ function hexContrast(a, b) {
|
|
|
617
1260
|
const [hi, lo] = la > lb ? [la, lb] : [lb, la];
|
|
618
1261
|
return (hi + 0.05) / (lo + 0.05);
|
|
619
1262
|
}
|
|
1263
|
+
function primaryButtonLabel(brand) {
|
|
1264
|
+
const darkC = hexContrast(brand.palette.primary, brand.palette.dark);
|
|
1265
|
+
const lightC = hexContrast(brand.palette.primary, AI_TREE_TOKENS.textPrimaryForeground);
|
|
1266
|
+
if (darkC === null || lightC === null) return AI_TREE_TOKENS.textPrimaryForeground;
|
|
1267
|
+
return darkC > lightC ? brand.palette.dark : AI_TREE_TOKENS.textPrimaryForeground;
|
|
1268
|
+
}
|
|
620
1269
|
function accentBandContext(brand) {
|
|
621
1270
|
const p = brand.palette;
|
|
622
1271
|
const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
|
|
@@ -634,6 +1283,22 @@ function accentBandContext(brand) {
|
|
|
634
1283
|
function textAttrs(ctx, path) {
|
|
635
1284
|
return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
|
|
636
1285
|
}
|
|
1286
|
+
var AI_RESPONSIVE_CSS = [
|
|
1287
|
+
"@media (max-width: 960px) {",
|
|
1288
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
|
|
1289
|
+
' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
|
|
1290
|
+
"}",
|
|
1291
|
+
"@media (max-width: 640px) {",
|
|
1292
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
|
|
1293
|
+
" [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
|
|
1294
|
+
// Group containers flatten to a column on phones; span placements come along for free.
|
|
1295
|
+
" [data-ai-responsive] [data-ai-group] { display: flex !important; flex-direction: column !important; }",
|
|
1296
|
+
" [data-ai-responsive] [data-ai-group] > * { grid-column: auto !important; }",
|
|
1297
|
+
" [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
|
|
1298
|
+
" [data-ai-responsive] { overflow-x: hidden; }",
|
|
1299
|
+
" [data-ai-responsive] img { max-width: 100%; }",
|
|
1300
|
+
"}"
|
|
1301
|
+
].join("\n");
|
|
637
1302
|
var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
638
1303
|
function MediaBox({
|
|
639
1304
|
refValue,
|
|
@@ -646,13 +1311,17 @@ function MediaBox({
|
|
|
646
1311
|
const url = refValue ? ctx.resolveMedia(refValue) : null;
|
|
647
1312
|
const isIcon = /^(lucide|simple):/.test(refValue);
|
|
648
1313
|
const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
|
|
649
|
-
const editAttrs = ctx.keyFor && editPath
|
|
1314
|
+
const editAttrs = ctx.keyFor && editPath ? {
|
|
1315
|
+
"data-ohw-key": ctx.keyFor(editPath),
|
|
1316
|
+
"data-ohw-editable": isIcon ? "icon" : "image"
|
|
1317
|
+
} : {};
|
|
650
1318
|
if (isIcon) {
|
|
651
1319
|
const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
|
|
652
1320
|
return /* @__PURE__ */ jsx(
|
|
653
1321
|
"span",
|
|
654
1322
|
{
|
|
655
1323
|
"data-ai-icon": refValue,
|
|
1324
|
+
...editAttrs,
|
|
656
1325
|
style: {
|
|
657
1326
|
display: "inline-flex",
|
|
658
1327
|
width: 48,
|
|
@@ -716,12 +1385,15 @@ function ButtonEl({
|
|
|
716
1385
|
width: fullWidth ? "100%" : void 0,
|
|
717
1386
|
alignItems: "center",
|
|
718
1387
|
justifyContent: "center",
|
|
719
|
-
padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
|
|
720
|
-
borderRadius: AI_TREE_TOKENS.radiusButton,
|
|
721
1388
|
textDecoration: "none",
|
|
722
1389
|
cursor: "pointer",
|
|
723
|
-
...
|
|
724
|
-
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } :
|
|
1390
|
+
...buttonShellStyle(ctx, fullWidth),
|
|
1391
|
+
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : (
|
|
1392
|
+
// Off-band, prefer the template button's measured fill/label pair — a template may
|
|
1393
|
+
// fill its CTAs with any token (hvac: accent bg, primary text). On an accent band
|
|
1394
|
+
// the flipped palette keeps contrast, so the brand-driven colours stay.
|
|
1395
|
+
!ctx.buttonLabel && ctx.buttonStyle?.background ? { background: ctx.buttonStyle.background, color: ctx.buttonStyle.color } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand) }
|
|
1396
|
+
)
|
|
725
1397
|
},
|
|
726
1398
|
children: /* @__PURE__ */ jsx("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
|
|
727
1399
|
}
|
|
@@ -897,10 +1569,11 @@ function PricingCard({ node, ctx, path }) {
|
|
|
897
1569
|
return /* @__PURE__ */ jsxs(
|
|
898
1570
|
"div",
|
|
899
1571
|
{
|
|
1572
|
+
"data-ohw-card": "",
|
|
900
1573
|
style: {
|
|
901
1574
|
background: hasBg ? ctx.brand.palette.light : "transparent",
|
|
902
1575
|
border: `1px solid ${dark}`,
|
|
903
|
-
borderRadius:
|
|
1576
|
+
borderRadius: cardRadius(slots),
|
|
904
1577
|
padding: AI_TREE_TOKENS.paddingBlock,
|
|
905
1578
|
display: "flex",
|
|
906
1579
|
flexDirection: "column",
|
|
@@ -1005,10 +1678,11 @@ function TestimonialCard({ node, ctx, path }) {
|
|
|
1005
1678
|
return /* @__PURE__ */ jsx(
|
|
1006
1679
|
"div",
|
|
1007
1680
|
{
|
|
1681
|
+
"data-ohw-card": "",
|
|
1008
1682
|
"data-ai-avatar-pos": avatarPos ?? void 0,
|
|
1009
1683
|
style: {
|
|
1010
1684
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1011
|
-
borderRadius: hasBg ?
|
|
1685
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1012
1686
|
overflow: "hidden",
|
|
1013
1687
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1014
1688
|
minWidth: 0
|
|
@@ -1043,10 +1717,11 @@ function TeamCard({ node, ctx, path }) {
|
|
|
1043
1717
|
return /* @__PURE__ */ jsxs(
|
|
1044
1718
|
"div",
|
|
1045
1719
|
{
|
|
1720
|
+
"data-ohw-card": "",
|
|
1046
1721
|
"data-ai-avatar-pos": avatarPos ?? void 0,
|
|
1047
1722
|
style: {
|
|
1048
1723
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1049
|
-
borderRadius: hasBg ?
|
|
1724
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1050
1725
|
overflow: "hidden",
|
|
1051
1726
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1052
1727
|
minWidth: 0,
|
|
@@ -1217,9 +1892,10 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1217
1892
|
return /* @__PURE__ */ jsxs(
|
|
1218
1893
|
"div",
|
|
1219
1894
|
{
|
|
1895
|
+
"data-ohw-card": "",
|
|
1220
1896
|
style: {
|
|
1221
1897
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1222
|
-
borderRadius: hasBg ?
|
|
1898
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1223
1899
|
overflow: "hidden",
|
|
1224
1900
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1225
1901
|
display: horizontal ? "flex" : "block",
|
|
@@ -1247,7 +1923,7 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1247
1923
|
) : /* @__PURE__ */ jsx(
|
|
1248
1924
|
"div",
|
|
1249
1925
|
{
|
|
1250
|
-
style: /^(lucide|simple):/.test(mediaRef) ? { padding: `${AI_TREE_TOKENS.paddingBlock}px ${AI_TREE_TOKENS.paddingBlock}px 0` } : hasBg ? void 0 : { borderRadius:
|
|
1926
|
+
style: /^(lucide|simple):/.test(mediaRef) ? { padding: `${AI_TREE_TOKENS.paddingBlock}px ${AI_TREE_TOKENS.paddingBlock}px 0` } : hasBg ? void 0 : { borderRadius: cardRadius(slots), overflow: "hidden" },
|
|
1251
1927
|
children: media
|
|
1252
1928
|
}
|
|
1253
1929
|
)),
|
|
@@ -1538,7 +2214,7 @@ function CollectionBlock({ node, ctx, path }) {
|
|
|
1538
2214
|
return /* @__PURE__ */ jsx(
|
|
1539
2215
|
"div",
|
|
1540
2216
|
{
|
|
1541
|
-
"data-ai-grid":
|
|
2217
|
+
"data-ai-grid": String(itemsPerRow),
|
|
1542
2218
|
style: {
|
|
1543
2219
|
display: "grid",
|
|
1544
2220
|
gridTemplateColumns: `repeat(${itemsPerRow}, 1fr)`,
|
|
@@ -1658,6 +2334,32 @@ function renderNode(node, ctx, path) {
|
|
|
1658
2334
|
if (child) {
|
|
1659
2335
|
return renderNode(child, ctx, `${path}.c0`);
|
|
1660
2336
|
}
|
|
2337
|
+
if (str(slots.provider) === "map" && str(slots.query)) {
|
|
2338
|
+
const query = str(slots.query);
|
|
2339
|
+
const mapAttrs = ctx.keyFor ? {
|
|
2340
|
+
"data-ohw-key": ctx.keyFor(`${path}.query`),
|
|
2341
|
+
"data-ohw-editable": "map",
|
|
2342
|
+
"data-ohw-map-query": query
|
|
2343
|
+
} : {};
|
|
2344
|
+
return /* @__PURE__ */ jsx(
|
|
2345
|
+
"iframe",
|
|
2346
|
+
{
|
|
2347
|
+
...mapAttrs,
|
|
2348
|
+
"data-ai-embed": "map",
|
|
2349
|
+
title: str(slots.title) || "Map",
|
|
2350
|
+
src: `https://www.google.com/maps?q=${encodeURIComponent(query)}&output=embed`,
|
|
2351
|
+
loading: "lazy",
|
|
2352
|
+
referrerPolicy: "no-referrer-when-downgrade",
|
|
2353
|
+
style: {
|
|
2354
|
+
width: "100%",
|
|
2355
|
+
minHeight: 320,
|
|
2356
|
+
border: 0,
|
|
2357
|
+
borderRadius: AI_TREE_TOKENS.radiusCard,
|
|
2358
|
+
display: "block"
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
);
|
|
2362
|
+
}
|
|
1661
2363
|
return /* @__PURE__ */ jsx(
|
|
1662
2364
|
"div",
|
|
1663
2365
|
{
|
|
@@ -1761,15 +2463,14 @@ function renderNode(node, ctx, path) {
|
|
|
1761
2463
|
alignSelf: submitAlign,
|
|
1762
2464
|
border: "none",
|
|
1763
2465
|
cursor: "pointer",
|
|
1764
|
-
padding
|
|
1765
|
-
|
|
1766
|
-
//
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
2466
|
+
// Shape/padding/typography follow the host template's own buttons.
|
|
2467
|
+
...buttonShellStyle(ctx),
|
|
2468
|
+
// Brand-styled: the template button's measured fill/label pair off-band, else
|
|
2469
|
+
// primary fill with a brand-derived label so it reads on custom palettes.
|
|
2470
|
+
...!ctx.buttonLabel && ctx.buttonStyle?.background ? { background: ctx.buttonStyle.background, color: ctx.buttonStyle.color } : {
|
|
2471
|
+
background: ctx.brand.palette.primary,
|
|
2472
|
+
color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand)
|
|
2473
|
+
}
|
|
1773
2474
|
},
|
|
1774
2475
|
children: /* @__PURE__ */ jsx("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
|
|
1775
2476
|
},
|
|
@@ -1804,7 +2505,7 @@ function renderNode(node, ctx, path) {
|
|
|
1804
2505
|
function AiTreeRenderer({
|
|
1805
2506
|
tree,
|
|
1806
2507
|
brand,
|
|
1807
|
-
|
|
2508
|
+
buttonStyle,
|
|
1808
2509
|
resolveMedia,
|
|
1809
2510
|
editKeyPrefix
|
|
1810
2511
|
}) {
|
|
@@ -1814,13 +2515,18 @@ function AiTreeRenderer({
|
|
|
1814
2515
|
const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
|
|
1815
2516
|
const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
|
|
1816
2517
|
const blockBrand = band?.brand ?? resolvedBrand;
|
|
2518
|
+
const placeholderMap = buildPlaceholderMap(tree);
|
|
1817
2519
|
const ctx = {
|
|
1818
2520
|
brand: blockBrand,
|
|
1819
|
-
|
|
2521
|
+
// An owner/library ref resolves through the host resolver; a `placeholder:<subject>` ref the
|
|
2522
|
+
// host cannot resolve falls back to real stock photography (the per-section map first, then a
|
|
2523
|
+
// standalone resolve), so generated galleries, image rows, and overlay backgrounds arrive with
|
|
2524
|
+
// photos instead of grey boxes.
|
|
2525
|
+
resolveMedia: (ref) => resolveMedia?.(ref) ?? placeholderMap[ref] ?? resolvePlaceholderRef(ref),
|
|
1820
2526
|
cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
|
|
1821
2527
|
keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
|
|
1822
2528
|
sectionAlignment: (tree.settings ?? {}).alignment === "center" ? "center" : "left",
|
|
1823
|
-
|
|
2529
|
+
buttonStyle,
|
|
1824
2530
|
...band ? { buttonLabel: band.buttonLabel } : {}
|
|
1825
2531
|
};
|
|
1826
2532
|
const settings = tree.settings ?? {};
|
|
@@ -1861,6 +2567,7 @@ function AiTreeRenderer({
|
|
|
1861
2567
|
{
|
|
1862
2568
|
"data-ai-section": tree.tag ?? "",
|
|
1863
2569
|
...bgAttrs,
|
|
2570
|
+
"data-ai-responsive": "",
|
|
1864
2571
|
style: {
|
|
1865
2572
|
position: "relative",
|
|
1866
2573
|
padding: `${pad}px 0`,
|
|
@@ -1871,12 +2578,13 @@ function AiTreeRenderer({
|
|
|
1871
2578
|
color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
|
|
1872
2579
|
},
|
|
1873
2580
|
children: [
|
|
1874
|
-
|
|
2581
|
+
/* @__PURE__ */ jsx("style", { children: AI_RESPONSIVE_CSS }),
|
|
1875
2582
|
/* @__PURE__ */ jsx("style", { children: AI_MOBILE_CSS }),
|
|
2583
|
+
isOverlay && backgroundUrl && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
|
|
1876
2584
|
/* @__PURE__ */ jsx(
|
|
1877
2585
|
"div",
|
|
1878
2586
|
{
|
|
1879
|
-
"data-ai-
|
|
2587
|
+
"data-ai-section-inner": "",
|
|
1880
2588
|
style: {
|
|
1881
2589
|
position: "relative",
|
|
1882
2590
|
maxWidth: AI_TREE_TOKENS.sectionMaxWidth,
|
|
@@ -1887,7 +2595,7 @@ function AiTreeRenderer({
|
|
|
1887
2595
|
children: tree.rows.map((row, r2) => /* @__PURE__ */ jsx(
|
|
1888
2596
|
"div",
|
|
1889
2597
|
{
|
|
1890
|
-
"data-ai-
|
|
2598
|
+
"data-ai-columns": "",
|
|
1891
2599
|
style: {
|
|
1892
2600
|
display: "grid",
|
|
1893
2601
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
@@ -1926,21 +2634,63 @@ function AiTreeRenderer({
|
|
|
1926
2634
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1927
2635
|
var CONTAINER_ATTR = "data-ohw-ai-generated";
|
|
1928
2636
|
var REPLACED_ATTR = "data-ohw-ai-replaced-by";
|
|
1929
|
-
var
|
|
2637
|
+
var REMOVED_ATTR2 = "data-ohw-ai-removed";
|
|
1930
2638
|
var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
|
|
1931
2639
|
var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
2640
|
+
function isChromeSection2(el) {
|
|
2641
|
+
if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) return true;
|
|
2642
|
+
return el.tagName === "HEADER" || el.tagName === "FOOTER";
|
|
2643
|
+
}
|
|
1932
2644
|
function readRootVar(name) {
|
|
1933
2645
|
if (typeof document === "undefined") return "";
|
|
1934
2646
|
return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
1935
2647
|
}
|
|
2648
|
+
function normalizeColorToHex(value) {
|
|
2649
|
+
if (!value || typeof document === "undefined") return value;
|
|
2650
|
+
const canvas = document.createElement("canvas");
|
|
2651
|
+
canvas.width = 1;
|
|
2652
|
+
canvas.height = 1;
|
|
2653
|
+
const ctx = canvas.getContext("2d");
|
|
2654
|
+
if (!ctx) return value;
|
|
2655
|
+
ctx.fillStyle = value;
|
|
2656
|
+
ctx.fillRect(0, 0, 1, 1);
|
|
2657
|
+
const [r2, g, b] = ctx.getImageData(0, 0, 1, 1).data;
|
|
2658
|
+
const toHex = (n) => n.toString(16).padStart(2, "0");
|
|
2659
|
+
return `#${toHex(r2)}${toHex(g)}${toHex(b)}`;
|
|
2660
|
+
}
|
|
2661
|
+
var GENERIC_FONT_KEYWORDS = /* @__PURE__ */ new Set([
|
|
2662
|
+
"serif",
|
|
2663
|
+
"sans-serif",
|
|
2664
|
+
"monospace",
|
|
2665
|
+
"cursive",
|
|
2666
|
+
"fantasy",
|
|
2667
|
+
"system-ui",
|
|
2668
|
+
"ui-serif",
|
|
2669
|
+
"ui-sans-serif",
|
|
2670
|
+
"ui-monospace",
|
|
2671
|
+
"ui-rounded",
|
|
2672
|
+
"math",
|
|
2673
|
+
"emoji",
|
|
2674
|
+
"fangsong"
|
|
2675
|
+
]);
|
|
2676
|
+
function primaryFontFamily(stack) {
|
|
2677
|
+
const first = stack.split(",").map((part) => part.trim().replace(/^["']|["']$/g, "")).find((part) => part && !GENERIC_FONT_KEYWORDS.has(part.toLowerCase()));
|
|
2678
|
+
return first ?? "";
|
|
2679
|
+
}
|
|
2680
|
+
function humanizeFontFamily(name) {
|
|
2681
|
+
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());
|
|
2682
|
+
}
|
|
2683
|
+
function readFontVar(name) {
|
|
2684
|
+
return humanizeFontFamily(primaryFontFamily(readRootVar(name)));
|
|
2685
|
+
}
|
|
1936
2686
|
function deriveBrandOverride() {
|
|
1937
2687
|
const dark = readRootVar("--ohw-brand-dark");
|
|
1938
2688
|
const primary = readRootVar("--ohw-brand-primary");
|
|
1939
2689
|
const light = readRootVar("--ohw-brand-light");
|
|
1940
2690
|
if (!dark || !primary || !light) return null;
|
|
1941
2691
|
const accent = readRootVar("--ohw-brand-accent");
|
|
1942
|
-
const heading =
|
|
1943
|
-
const body =
|
|
2692
|
+
const heading = readFontVar("--font-heading") || readFontVar("--font-display");
|
|
2693
|
+
const body = readFontVar("--font-body");
|
|
1944
2694
|
return {
|
|
1945
2695
|
palette: { dark, primary, accent: accent || dark, light },
|
|
1946
2696
|
fonts: {
|
|
@@ -1949,28 +2699,93 @@ function deriveBrandOverride() {
|
|
|
1949
2699
|
}
|
|
1950
2700
|
};
|
|
1951
2701
|
}
|
|
1952
|
-
function
|
|
1953
|
-
const dark = readRootVar("--color-dark");
|
|
1954
|
-
const primary = readRootVar("--color-primary");
|
|
1955
|
-
const light = readRootVar("--color-light");
|
|
2702
|
+
function deriveTemplateBrandLive() {
|
|
2703
|
+
const dark = readRootVar("--color-dark") || readRootVar("--brand-text");
|
|
2704
|
+
const primary = readRootVar("--color-primary") || readRootVar("--brand-primary");
|
|
2705
|
+
const light = readRootVar("--color-light") || readRootVar("--brand-background");
|
|
1956
2706
|
if (!dark || !primary || !light) return null;
|
|
1957
|
-
const accent = readRootVar("--color-accent");
|
|
1958
|
-
const heading =
|
|
1959
|
-
const body =
|
|
2707
|
+
const accent = readRootVar("--color-accent") || readRootVar("--brand-accent");
|
|
2708
|
+
const heading = readFontVar("--brand-font-heading") || readFontVar("--font-heading") || readFontVar("--font-display");
|
|
2709
|
+
const body = readFontVar("--brand-font-body") || readFontVar("--font-body");
|
|
1960
2710
|
return {
|
|
1961
|
-
palette: {
|
|
2711
|
+
palette: {
|
|
2712
|
+
dark: normalizeColorToHex(dark),
|
|
2713
|
+
primary: normalizeColorToHex(primary),
|
|
2714
|
+
accent: normalizeColorToHex(accent || dark),
|
|
2715
|
+
light: normalizeColorToHex(light)
|
|
2716
|
+
},
|
|
1962
2717
|
fonts: {
|
|
1963
2718
|
heading: heading || AI_DEFAULT_BRAND.fonts.heading,
|
|
1964
2719
|
body: body || AI_DEFAULT_BRAND.fonts.body
|
|
1965
2720
|
}
|
|
1966
2721
|
};
|
|
1967
2722
|
}
|
|
1968
|
-
function
|
|
2723
|
+
function deriveTemplateFontsLive() {
|
|
2724
|
+
const heading = readFontVar("--brand-font-heading") || readFontVar("--font-heading") || readFontVar("--font-display");
|
|
2725
|
+
const body = readFontVar("--brand-font-body") || readFontVar("--font-body");
|
|
2726
|
+
if (!heading && !body) return null;
|
|
2727
|
+
return {
|
|
2728
|
+
heading: heading || AI_DEFAULT_BRAND.fonts.heading,
|
|
2729
|
+
body: body || AI_DEFAULT_BRAND.fonts.body
|
|
2730
|
+
};
|
|
2731
|
+
}
|
|
2732
|
+
var OVERRIDE_VAR_NAMES = [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES, ...FONT_VARS.heading, ...FONT_VARS.body];
|
|
2733
|
+
function withOverrideStripped(read) {
|
|
2734
|
+
const root = document.documentElement;
|
|
2735
|
+
const restore = OVERRIDE_VAR_NAMES.map((name) => [name, root.style.getPropertyValue(name)]);
|
|
2736
|
+
for (const name of OVERRIDE_VAR_NAMES) root.style.removeProperty(name);
|
|
2737
|
+
try {
|
|
2738
|
+
return read();
|
|
2739
|
+
} finally {
|
|
2740
|
+
for (const [name, value] of restore) if (value) root.style.setProperty(name, value);
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
var TEMPLATE_BRAND_SNAPSHOT = typeof document === "undefined" ? null : withOverrideStripped(deriveTemplateBrandLive);
|
|
2744
|
+
var TEMPLATE_FONTS_SNAPSHOT = typeof document === "undefined" ? null : withOverrideStripped(deriveTemplateFontsLive);
|
|
2745
|
+
function deriveTemplateBrand() {
|
|
2746
|
+
return TEMPLATE_BRAND_SNAPSHOT;
|
|
2747
|
+
}
|
|
2748
|
+
function deriveTemplateFonts() {
|
|
2749
|
+
return TEMPLATE_FONTS_SNAPSHOT;
|
|
2750
|
+
}
|
|
2751
|
+
function deriveTemplateButtonStyle() {
|
|
1969
2752
|
if (typeof document === "undefined") return null;
|
|
1970
|
-
const
|
|
2753
|
+
const candidates = Array.from(
|
|
2754
|
+
document.querySelectorAll('[data-ohw-role="button"]')
|
|
2755
|
+
).filter((el) => !el.closest(`[${CONTAINER_ATTR}]`));
|
|
2756
|
+
const isFilled = (el) => {
|
|
2757
|
+
const bg = getComputedStyle(el).backgroundColor;
|
|
2758
|
+
if (!bg || bg === "transparent") return false;
|
|
2759
|
+
const alpha = bg.match(/rgba?\([^)]*,\s*([\d.]+)\)$/);
|
|
2760
|
+
return !alpha || parseFloat(alpha[1]) > 0;
|
|
2761
|
+
};
|
|
2762
|
+
const btn = candidates.find(isFilled) ?? candidates[0];
|
|
1971
2763
|
if (!btn) return null;
|
|
1972
|
-
const
|
|
1973
|
-
|
|
2764
|
+
const cs = getComputedStyle(btn);
|
|
2765
|
+
const filled = isFilled(btn);
|
|
2766
|
+
const corners = [
|
|
2767
|
+
cs.borderTopLeftRadius,
|
|
2768
|
+
cs.borderTopRightRadius,
|
|
2769
|
+
cs.borderBottomRightRadius,
|
|
2770
|
+
cs.borderBottomLeftRadius
|
|
2771
|
+
].map((v) => v || "0px");
|
|
2772
|
+
const radius = corners.every((v) => v === corners[0]) ? corners[0] : corners.join(" ");
|
|
2773
|
+
const px = (v) => parseFloat(v) || 0;
|
|
2774
|
+
const lineHeight = px(cs.lineHeight) || px(cs.fontSize) * 1.2;
|
|
2775
|
+
const contentH = btn.getBoundingClientRect().height - px(cs.borderTopWidth) - px(cs.borderBottomWidth);
|
|
2776
|
+
const impliedY = Math.round(Math.max(0, (contentH - lineHeight) / 2));
|
|
2777
|
+
const padY = Math.max(px(cs.paddingTop), px(cs.paddingBottom), impliedY);
|
|
2778
|
+
const padX = Math.max(px(cs.paddingLeft), px(cs.paddingRight));
|
|
2779
|
+
return {
|
|
2780
|
+
radius: radius || "10px",
|
|
2781
|
+
padding: `${padY}px ${padX}px`,
|
|
2782
|
+
...filled ? { background: cs.backgroundColor, color: cs.color } : {},
|
|
2783
|
+
fontFamily: cs.fontFamily || "",
|
|
2784
|
+
fontSize: cs.fontSize || "",
|
|
2785
|
+
fontWeight: cs.fontWeight || "",
|
|
2786
|
+
letterSpacing: cs.letterSpacing || "",
|
|
2787
|
+
textTransform: cs.textTransform || ""
|
|
2788
|
+
};
|
|
1974
2789
|
}
|
|
1975
2790
|
var mounted = /* @__PURE__ */ new Map();
|
|
1976
2791
|
function findTemplateSection(id) {
|
|
@@ -1986,6 +2801,19 @@ function findPlacementAnchor(id, exclude) {
|
|
|
1986
2801
|
for (const el of document.querySelectorAll(`[data-ohw-section="${CSS.escape(id)}"]`)) {
|
|
1987
2802
|
if (el === exclude) continue;
|
|
1988
2803
|
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
2804
|
+
if (isChromeSection2(el)) return null;
|
|
2805
|
+
return el;
|
|
2806
|
+
}
|
|
2807
|
+
return null;
|
|
2808
|
+
}
|
|
2809
|
+
function findFooterSection() {
|
|
2810
|
+
const byId = findTemplateSection("footer");
|
|
2811
|
+
if (byId) return byId;
|
|
2812
|
+
for (const el of Array.from(
|
|
2813
|
+
document.querySelectorAll("footer[data-ohw-section]")
|
|
2814
|
+
).reverse()) {
|
|
2815
|
+
if (el.hasAttribute(CONTAINER_ATTR)) continue;
|
|
2816
|
+
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
1989
2817
|
return el;
|
|
1990
2818
|
}
|
|
1991
2819
|
return null;
|
|
@@ -2012,7 +2840,7 @@ function placeContainer(container, entry) {
|
|
|
2012
2840
|
return;
|
|
2013
2841
|
}
|
|
2014
2842
|
}
|
|
2015
|
-
const footer =
|
|
2843
|
+
const footer = findFooterSection();
|
|
2016
2844
|
if (footer) {
|
|
2017
2845
|
footer.insertAdjacentElement("beforebegin", container);
|
|
2018
2846
|
} else {
|
|
@@ -2021,18 +2849,18 @@ function placeContainer(container, entry) {
|
|
|
2021
2849
|
}
|
|
2022
2850
|
function syncRemovedSections(state) {
|
|
2023
2851
|
const removed = new Set(state.removed ?? []);
|
|
2024
|
-
for (const el of document.querySelectorAll(`[${
|
|
2852
|
+
for (const el of document.querySelectorAll(`[${REMOVED_ATTR2}]`)) {
|
|
2025
2853
|
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
2026
2854
|
if (!removed.has(id)) {
|
|
2027
2855
|
el.style.removeProperty("display");
|
|
2028
|
-
el.removeAttribute(
|
|
2856
|
+
el.removeAttribute(REMOVED_ATTR2);
|
|
2029
2857
|
}
|
|
2030
2858
|
}
|
|
2031
2859
|
for (const id of removed) {
|
|
2032
2860
|
const section = findTemplateSection(id);
|
|
2033
2861
|
if (section && !section.hasAttribute(REPLACED_ATTR)) {
|
|
2034
2862
|
section.style.display = "none";
|
|
2035
|
-
section.setAttribute(
|
|
2863
|
+
section.setAttribute(REMOVED_ATTR2, "");
|
|
2036
2864
|
}
|
|
2037
2865
|
}
|
|
2038
2866
|
}
|
|
@@ -2047,9 +2875,9 @@ function syncTemplateHidden(state, pageHasSections) {
|
|
|
2047
2875
|
if (!hide) return;
|
|
2048
2876
|
for (const el of Array.from(document.querySelectorAll("[data-ohw-section]"))) {
|
|
2049
2877
|
if (el.hasAttribute(CONTAINER_ATTR)) continue;
|
|
2050
|
-
if (
|
|
2878
|
+
if (isChromeSection2(el)) continue;
|
|
2051
2879
|
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
2052
|
-
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(
|
|
2880
|
+
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR2)) continue;
|
|
2053
2881
|
el.style.display = "none";
|
|
2054
2882
|
el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
|
|
2055
2883
|
}
|
|
@@ -2073,18 +2901,23 @@ function syncReplacedOriginals(state) {
|
|
|
2073
2901
|
}
|
|
2074
2902
|
}
|
|
2075
2903
|
var sectionOrderIndex = /* @__PURE__ */ new Map();
|
|
2904
|
+
var removedSectionIds = /* @__PURE__ */ new Set();
|
|
2076
2905
|
function setAiSectionOrder(raw, currentPath) {
|
|
2077
2906
|
const next = /* @__PURE__ */ new Map();
|
|
2907
|
+
const removed = /* @__PURE__ */ new Set();
|
|
2078
2908
|
if (raw) {
|
|
2079
2909
|
try {
|
|
2080
2910
|
const entries = JSON.parse(raw);
|
|
2081
2911
|
for (const entry of entries) {
|
|
2082
|
-
if (
|
|
2912
|
+
if (entry.pagePath && entry.pagePath !== currentPath) continue;
|
|
2913
|
+
next.set(entry.instanceId, entry.order);
|
|
2914
|
+
if (entry.removed) removed.add(entry.instanceId);
|
|
2083
2915
|
}
|
|
2084
2916
|
} catch {
|
|
2085
2917
|
}
|
|
2086
2918
|
}
|
|
2087
2919
|
sectionOrderIndex = next;
|
|
2920
|
+
removedSectionIds = removed;
|
|
2088
2921
|
}
|
|
2089
2922
|
function applyExplicitOrder(entries) {
|
|
2090
2923
|
if (sectionOrderIndex.size === 0) return entries;
|
|
@@ -2120,11 +2953,23 @@ function orderByChain(sections) {
|
|
|
2120
2953
|
for (const root of roots) visit(root);
|
|
2121
2954
|
return out.length === sections.length ? out : sections;
|
|
2122
2955
|
}
|
|
2956
|
+
function syncSoftRemovedGenerated() {
|
|
2957
|
+
for (const [id, section] of mounted) {
|
|
2958
|
+
const el = section.container;
|
|
2959
|
+
if (removedSectionIds.has(id)) {
|
|
2960
|
+
el.style.display = "none";
|
|
2961
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
2962
|
+
} else if (el.hasAttribute(REMOVED_ATTR)) {
|
|
2963
|
+
el.style.removeProperty("display");
|
|
2964
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2123
2968
|
function applyAiSectionsToDom(state, options) {
|
|
2124
2969
|
if (typeof document === "undefined") return;
|
|
2125
2970
|
const brandOverride = deriveBrandOverride();
|
|
2126
2971
|
const templateBrand = deriveTemplateBrand();
|
|
2127
|
-
const
|
|
2972
|
+
const templateButtonStyle = deriveTemplateButtonStyle();
|
|
2128
2973
|
const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
|
|
2129
2974
|
const pagePath = window.location.pathname;
|
|
2130
2975
|
const pageSections = state.sections.filter((entry) => (entry.path ?? "/") === pagePath);
|
|
@@ -2164,7 +3009,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2164
3009
|
{
|
|
2165
3010
|
tree: entry.tree,
|
|
2166
3011
|
brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
|
|
2167
|
-
|
|
3012
|
+
buttonStyle: templateButtonStyle,
|
|
2168
3013
|
resolveMedia,
|
|
2169
3014
|
editKeyPrefix: `ai.${entry.id}`
|
|
2170
3015
|
}
|
|
@@ -2187,6 +3032,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2187
3032
|
syncReplacedOriginals(state);
|
|
2188
3033
|
syncRemovedSections(state);
|
|
2189
3034
|
syncTemplateHidden(state, pageSections.length > 0);
|
|
3035
|
+
syncSoftRemovedGenerated();
|
|
2190
3036
|
}
|
|
2191
3037
|
|
|
2192
3038
|
// src/useLinkHrefGuardian.ts
|
|
@@ -6378,12 +7224,12 @@ var cva = (base, config) => (props) => {
|
|
|
6378
7224
|
import { Toggle as TogglePrimitive } from "radix-ui";
|
|
6379
7225
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
6380
7226
|
var toggleVariants = cva(
|
|
6381
|
-
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
7227
|
+
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-bridge-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
6382
7228
|
{
|
|
6383
7229
|
variants: {
|
|
6384
7230
|
variant: {
|
|
6385
7231
|
default: "bg-transparent border-0",
|
|
6386
|
-
outline: "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground"
|
|
7232
|
+
outline: "border border-input bg-transparent shadow-xs hover:bg-bridge-accent hover:text-accent-foreground"
|
|
6387
7233
|
},
|
|
6388
7234
|
size: {
|
|
6389
7235
|
default: "px-2 py-1",
|
|
@@ -6476,10 +7322,10 @@ var DragHandle = React4.forwardRef(
|
|
|
6476
7322
|
type,
|
|
6477
7323
|
"data-slot": "drag-handle",
|
|
6478
7324
|
className: cn(
|
|
6479
|
-
"inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-
|
|
7325
|
+
"inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-7.5",
|
|
6480
7326
|
"bg-white border border-transparent text-stone-500 shadow-md cursor-grab",
|
|
6481
7327
|
"enabled:hover:border enabled:hover:border-stone-200 enabled:hover:text-stone-950",
|
|
6482
|
-
"enabled:active:border enabled:active:border-primary enabled:active:bg-primary-50 enabled:active:text-stone-950 enabled:active:shadow enabled:active:cursor-grabbing",
|
|
7328
|
+
"enabled:active:border enabled:active:border-bridge-primary enabled:active:bg-primary-50 enabled:active:text-stone-950 enabled:active:shadow enabled:active:cursor-grabbing",
|
|
6483
7329
|
"disabled:cursor-not-allowed disabled:opacity-40 disabled:text-stone-950 disabled:pointer-events-none",
|
|
6484
7330
|
className
|
|
6485
7331
|
),
|
|
@@ -6501,7 +7347,7 @@ var CustomToolbar = React5.forwardRef(({ className, onMouseDown, ...props }, ref
|
|
|
6501
7347
|
"data-ohw-toolbar": "",
|
|
6502
7348
|
className: cn(
|
|
6503
7349
|
// Figma: bg background, radius 8, gap-1, p-0.5, shadow-md — no border
|
|
6504
|
-
"inline-flex h-8 items-center gap-1 rounded-
|
|
7350
|
+
"inline-flex h-8 items-center gap-1 rounded-(--radius,0.5rem) bg-background p-0.5 font-sans whitespace-nowrap shadow-md",
|
|
6505
7351
|
className
|
|
6506
7352
|
),
|
|
6507
7353
|
onMouseDown: (e) => {
|
|
@@ -6530,7 +7376,7 @@ var CustomToolbarButton = React5.forwardRef(
|
|
|
6530
7376
|
type,
|
|
6531
7377
|
className: cn(
|
|
6532
7378
|
"inline-flex size-7 shrink-0 items-center justify-center rounded-[calc(var(--radius,0.5rem)-2px)] text-foreground transition-colors",
|
|
6533
|
-
active ? "bg-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
|
|
7379
|
+
active ? "bg-bridge-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
|
|
6534
7380
|
className
|
|
6535
7381
|
),
|
|
6536
7382
|
...props
|
|
@@ -6735,9 +7581,7 @@ function ItemActionToolbar({
|
|
|
6735
7581
|
ToggleGroup,
|
|
6736
7582
|
{
|
|
6737
7583
|
value: dropdownOpen ? "open" : "closed",
|
|
6738
|
-
onValueChange: (
|
|
6739
|
-
if (value !== "open" && value !== "closed") return;
|
|
6740
|
-
onDropdownOpenChange?.(value === "open");
|
|
7584
|
+
onValueChange: () => {
|
|
6741
7585
|
},
|
|
6742
7586
|
className: "h-7 gap-0.5 rounded-[calc(var(--radius,0.5rem)-2px)] bg-muted p-0.5",
|
|
6743
7587
|
onMouseDown: (e) => {
|
|
@@ -6752,6 +7596,11 @@ function ItemActionToolbar({
|
|
|
6752
7596
|
size: "sm",
|
|
6753
7597
|
"aria-label": "Closed",
|
|
6754
7598
|
className: "h-6 min-w-0 px-2 text-xs font-medium",
|
|
7599
|
+
onMouseDown: (e) => {
|
|
7600
|
+
e.preventDefault();
|
|
7601
|
+
e.stopPropagation();
|
|
7602
|
+
if (dropdownOpen !== false) onDropdownOpenChange?.(false);
|
|
7603
|
+
},
|
|
6755
7604
|
children: "Closed"
|
|
6756
7605
|
}
|
|
6757
7606
|
),
|
|
@@ -6762,6 +7611,11 @@ function ItemActionToolbar({
|
|
|
6762
7611
|
size: "sm",
|
|
6763
7612
|
"aria-label": "Open",
|
|
6764
7613
|
className: "h-6 min-w-0 px-2 text-xs font-medium",
|
|
7614
|
+
onMouseDown: (e) => {
|
|
7615
|
+
e.preventDefault();
|
|
7616
|
+
e.stopPropagation();
|
|
7617
|
+
if (dropdownOpen !== true) onDropdownOpenChange?.(true);
|
|
7618
|
+
},
|
|
6765
7619
|
children: "Open"
|
|
6766
7620
|
}
|
|
6767
7621
|
)
|
|
@@ -7724,13 +8578,13 @@ function FormFieldToolbar({
|
|
|
7724
8578
|
]
|
|
7725
8579
|
}
|
|
7726
8580
|
) }),
|
|
7727
|
-
/* @__PURE__ */ jsx13(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-
|
|
8581
|
+
/* @__PURE__ */ jsx13(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-47.5 p-1", children: FIELD_TYPES.map((entry) => {
|
|
7728
8582
|
const Icon = TYPE_ICONS[entry.type];
|
|
7729
8583
|
return /* @__PURE__ */ jsxs6(
|
|
7730
8584
|
DropdownMenuItem,
|
|
7731
8585
|
{
|
|
7732
8586
|
onSelect: () => onTypeChange(entry.type),
|
|
7733
|
-
className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-primary/10" : ""),
|
|
8587
|
+
className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-bridge-primary/10" : ""),
|
|
7734
8588
|
children: [
|
|
7735
8589
|
/* @__PURE__ */ jsx13(Icon, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
|
|
7736
8590
|
entry.label
|
|
@@ -7747,7 +8601,7 @@ function FormFieldToolbar({
|
|
|
7747
8601
|
type: "button",
|
|
7748
8602
|
"aria-pressed": required,
|
|
7749
8603
|
onClick: onRequiredToggle,
|
|
7750
|
-
className: "flex h-7 items-center gap-1.5 whitespace-nowrap rounded-md px-2 text-[13px] font-medium transition-colors " + (required ? "bg-primary/10 text-primary" : "text-foreground hover:bg-muted/70"),
|
|
8604
|
+
className: "flex h-7 items-center gap-1.5 whitespace-nowrap rounded-md px-2 text-[13px] font-medium transition-colors " + (required ? "bg-bridge-primary/10 text-bridge-primary" : "text-foreground hover:bg-muted/70"),
|
|
7751
8605
|
"data-ohw-field-required-toggle": "",
|
|
7752
8606
|
children: [
|
|
7753
8607
|
/* @__PURE__ */ jsx13(Asterisk, { size: 14, strokeWidth: 2, "aria-hidden": true }),
|
|
@@ -7767,7 +8621,7 @@ function FormFieldToolbar({
|
|
|
7767
8621
|
children: /* @__PURE__ */ jsx13(MoreHorizontal2, { size: 15, "aria-hidden": true })
|
|
7768
8622
|
}
|
|
7769
8623
|
) }),
|
|
7770
|
-
/* @__PURE__ */ jsxs6(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-
|
|
8624
|
+
/* @__PURE__ */ jsxs6(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-42.5 p-1", children: [
|
|
7771
8625
|
/* @__PURE__ */ jsxs6(DropdownMenuItem, { onSelect: onDuplicate, className: "rounded-md py-2 text-[13px]", children: [
|
|
7772
8626
|
/* @__PURE__ */ jsx13(Copy2, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
|
|
7773
8627
|
"Duplicate"
|
|
@@ -7787,7 +8641,7 @@ function FieldTypePicker({ onPick }) {
|
|
|
7787
8641
|
"div",
|
|
7788
8642
|
{
|
|
7789
8643
|
"data-ohw-field-type-picker": "",
|
|
7790
|
-
className: "pointer-events-auto grid w-
|
|
8644
|
+
className: "pointer-events-auto grid w-105 grid-cols-3 gap-3 rounded-xl border border-border bg-background p-4 shadow-lg",
|
|
7791
8645
|
children: FIELD_TYPES.map((entry) => {
|
|
7792
8646
|
const Icon = TYPE_ICONS[entry.type];
|
|
7793
8647
|
return /* @__PURE__ */ jsxs6(
|
|
@@ -7795,7 +8649,7 @@ function FieldTypePicker({ onPick }) {
|
|
|
7795
8649
|
{
|
|
7796
8650
|
type: "button",
|
|
7797
8651
|
onClick: () => onPick(entry.type),
|
|
7798
|
-
className: "flex h-
|
|
8652
|
+
className: "flex h-26 flex-col items-center justify-center gap-3 rounded-xl border border-border text-[15px] font-medium text-foreground transition-colors hover:border-bridge-primary hover:bg-bridge-primary/5",
|
|
7799
8653
|
children: [
|
|
7800
8654
|
/* @__PURE__ */ jsx13(Icon, { size: 26, strokeWidth: 1.5, "aria-hidden": true }),
|
|
7801
8655
|
entry.label
|
|
@@ -7821,7 +8675,7 @@ var buttonVariants = cva(
|
|
|
7821
8675
|
{
|
|
7822
8676
|
variants: {
|
|
7823
8677
|
variant: {
|
|
7824
|
-
default: "bg-primary text-primary-foreground hover:opacity-90",
|
|
8678
|
+
default: "bg-bridge-primary text-primary-foreground hover:opacity-90",
|
|
7825
8679
|
outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
|
|
7826
8680
|
ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
|
|
7827
8681
|
},
|
|
@@ -7916,6 +8770,7 @@ function MediaOverlay({
|
|
|
7916
8770
|
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
7917
8771
|
);
|
|
7918
8772
|
}, [isVideo]);
|
|
8773
|
+
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
7919
8774
|
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
7920
8775
|
const box = {
|
|
7921
8776
|
position: "fixed",
|
|
@@ -8021,8 +8876,8 @@ function MediaOverlay({
|
|
|
8021
8876
|
pointerEvents: hover.hasTextOverlap ? "none" : "auto",
|
|
8022
8877
|
// Selected: a firm component ring with no wash, so the image reads as chosen rather
|
|
8023
8878
|
// than hovered. Hover keeps the existing tinted preview.
|
|
8024
|
-
boxShadow: selected ? "inset 0 0 0 2px var(--color-primary)" : "inset 0 0 0 1.5px var(--color-primary)",
|
|
8025
|
-
background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
8879
|
+
boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
8880
|
+
background: selected ? "transparent" : "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
|
|
8026
8881
|
},
|
|
8027
8882
|
onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
|
|
8028
8883
|
children: [
|
|
@@ -8045,17 +8900,17 @@ function MediaOverlay({
|
|
|
8045
8900
|
},
|
|
8046
8901
|
children: [
|
|
8047
8902
|
isVideo ? /* @__PURE__ */ jsx15(Film, { size: 14 }) : /* @__PURE__ */ jsx15(ImageIcon, { size: 14 }),
|
|
8048
|
-
|
|
8903
|
+
replaceLabel
|
|
8049
8904
|
]
|
|
8050
8905
|
}
|
|
8051
8906
|
),
|
|
8052
|
-
replaceMode
|
|
8907
|
+
showChrome && replaceMode !== "none" && /* @__PURE__ */ jsxs7(
|
|
8053
8908
|
Button,
|
|
8054
8909
|
{
|
|
8055
8910
|
"data-ohw-media-overlay": "",
|
|
8056
8911
|
variant: "outline",
|
|
8057
8912
|
size: "sm",
|
|
8058
|
-
"aria-label":
|
|
8913
|
+
"aria-label": replaceLabel,
|
|
8059
8914
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
8060
8915
|
style: {
|
|
8061
8916
|
...OVERLAY_BUTTON_STYLE,
|
|
@@ -8078,7 +8933,7 @@ function MediaOverlay({
|
|
|
8078
8933
|
},
|
|
8079
8934
|
children: [
|
|
8080
8935
|
isVideo ? /* @__PURE__ */ jsx15(Film, { size: 14 }) : /* @__PURE__ */ jsx15(ImageIcon, { size: 14 }),
|
|
8081
|
-
replaceMode === "full" ?
|
|
8936
|
+
replaceMode === "full" ? replaceLabel : null
|
|
8082
8937
|
]
|
|
8083
8938
|
}
|
|
8084
8939
|
)
|
|
@@ -8113,253 +8968,41 @@ function CarouselOverlay({
|
|
|
8113
8968
|
top: rect.top,
|
|
8114
8969
|
left: rect.left,
|
|
8115
8970
|
width: rect.width,
|
|
8116
|
-
height: rect.height,
|
|
8117
|
-
zIndex: 2147483646,
|
|
8118
|
-
pointerEvents: "auto",
|
|
8119
|
-
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
8120
|
-
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
8121
|
-
},
|
|
8122
|
-
onClick: () => onEdit(hover.key),
|
|
8123
|
-
children: /* @__PURE__ */ jsxs8(
|
|
8124
|
-
Button,
|
|
8125
|
-
{
|
|
8126
|
-
"data-ohw-carousel-overlay": "",
|
|
8127
|
-
variant: "outline",
|
|
8128
|
-
size: "sm",
|
|
8129
|
-
className: "cursor-pointer gap-1.5 hover:bg-background",
|
|
8130
|
-
style: OVERLAY_BUTTON_STYLE2,
|
|
8131
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
8132
|
-
onClick: (e) => {
|
|
8133
|
-
e.stopPropagation();
|
|
8134
|
-
onEdit(hover.key);
|
|
8135
|
-
},
|
|
8136
|
-
children: [
|
|
8137
|
-
/* @__PURE__ */ jsx16(GalleryHorizontal, { size: 14 }),
|
|
8138
|
-
"Edit gallery"
|
|
8139
|
-
]
|
|
8140
|
-
}
|
|
8141
|
-
)
|
|
8142
|
-
}
|
|
8143
|
-
);
|
|
8144
|
-
}
|
|
8145
|
-
|
|
8146
|
-
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
8147
|
-
import { useCallback as useCallback2, useEffect as useEffect4, useRef as useRef4, useState as useState5 } from "react";
|
|
8148
|
-
import { Check, X } from "lucide-react";
|
|
8149
|
-
|
|
8150
|
-
// src/lib/sections.ts
|
|
8151
|
-
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
8152
|
-
function isChromeSection(el) {
|
|
8153
|
-
return el.matches("header, nav, footer, aside");
|
|
8154
|
-
}
|
|
8155
|
-
function titleCaseSectionId(id) {
|
|
8156
|
-
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
8157
|
-
}
|
|
8158
|
-
function parseSectionsFromRoot(root) {
|
|
8159
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8160
|
-
const sections = [];
|
|
8161
|
-
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
8162
|
-
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
8163
|
-
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
8164
|
-
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
8165
|
-
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
8166
|
-
continue;
|
|
8167
|
-
seen.add(id);
|
|
8168
|
-
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
8169
|
-
sections.push({ id, label });
|
|
8170
|
-
}
|
|
8171
|
-
return sections;
|
|
8172
|
-
}
|
|
8173
|
-
function collectSectionsFromDom() {
|
|
8174
|
-
if (typeof document === "undefined") return [];
|
|
8175
|
-
return parseSectionsFromRoot(document);
|
|
8176
|
-
}
|
|
8177
|
-
function parseSectionsFromHtml(html) {
|
|
8178
|
-
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
8179
|
-
return parseSectionsFromRoot(doc);
|
|
8180
|
-
}
|
|
8181
|
-
|
|
8182
|
-
// src/lib/section-instances.ts
|
|
8183
|
-
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
8184
|
-
var REMOVED_ATTR2 = "data-ohw-section-removed";
|
|
8185
|
-
function isRemovedSection(el) {
|
|
8186
|
-
return el.hasAttribute(REMOVED_ATTR2);
|
|
8187
|
-
}
|
|
8188
|
-
function topLevelSections() {
|
|
8189
|
-
return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
8190
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el) && !isRemovedSection(el)
|
|
8191
|
-
);
|
|
8192
|
-
}
|
|
8193
|
-
function instanceIdOf(el) {
|
|
8194
|
-
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
8195
|
-
}
|
|
8196
|
-
function findByInstanceId(instanceId) {
|
|
8197
|
-
const escapedId = CSS.escape(instanceId);
|
|
8198
|
-
return document.querySelector(`[data-ohw-instance="${escapedId}"]`) ?? document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
8199
|
-
}
|
|
8200
|
-
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
8201
|
-
const sections = topLevelSections();
|
|
8202
|
-
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8203
|
-
if (index === -1) return null;
|
|
8204
|
-
const dragged = sections[index];
|
|
8205
|
-
const others = sections.filter((_, i) => i !== index);
|
|
8206
|
-
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
8207
|
-
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
8208
|
-
return reordered.map((el, order) => ({
|
|
8209
|
-
instanceId: instanceIdOf(el),
|
|
8210
|
-
type: el.getAttribute("data-ohw-section") ?? "",
|
|
8211
|
-
order,
|
|
8212
|
-
pagePath: currentPath
|
|
8213
|
-
}));
|
|
8214
|
-
}
|
|
8215
|
-
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
8216
|
-
const sections = topLevelSections();
|
|
8217
|
-
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8218
|
-
if (index === -1) return null;
|
|
8219
|
-
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
8220
|
-
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
8221
|
-
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
8222
|
-
if (!entries) return null;
|
|
8223
|
-
applyPersistedOrder(entries);
|
|
8224
|
-
return entries;
|
|
8225
|
-
}
|
|
8226
|
-
function syncRemovedFlags(entries) {
|
|
8227
|
-
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
8228
|
-
document.querySelectorAll(`[${REMOVED_ATTR2}]`).forEach((el) => {
|
|
8229
|
-
if (!removedIds.has(instanceIdOf(el))) {
|
|
8230
|
-
el.style.removeProperty("display");
|
|
8231
|
-
el.removeAttribute(REMOVED_ATTR2);
|
|
8232
|
-
}
|
|
8233
|
-
});
|
|
8234
|
-
for (const id of removedIds) {
|
|
8235
|
-
const el = findByInstanceId(id);
|
|
8236
|
-
if (el) {
|
|
8237
|
-
el.style.display = "none";
|
|
8238
|
-
el.setAttribute(REMOVED_ATTR2, "");
|
|
8239
|
-
}
|
|
8240
|
-
}
|
|
8241
|
-
}
|
|
8242
|
-
function applyPersistedOrder(entries) {
|
|
8243
|
-
syncRemovedFlags(entries);
|
|
8244
|
-
if (entries.length === 0) return;
|
|
8245
|
-
const sections = topLevelSections();
|
|
8246
|
-
if (sections.length === 0) return;
|
|
8247
|
-
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
8248
|
-
const ordered = [...sections].sort((a, b) => {
|
|
8249
|
-
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
8250
|
-
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
8251
|
-
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
8252
|
-
if (aOrder === void 0) return 1;
|
|
8253
|
-
if (bOrder === void 0) return -1;
|
|
8254
|
-
return aOrder - bOrder;
|
|
8255
|
-
});
|
|
8256
|
-
let prev = null;
|
|
8257
|
-
for (const el of ordered) {
|
|
8258
|
-
if (prev) prev.after(el);
|
|
8259
|
-
prev = el;
|
|
8260
|
-
}
|
|
8261
|
-
}
|
|
8262
|
-
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
8263
|
-
if (!findByInstanceId(instanceId)) return null;
|
|
8264
|
-
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
8265
|
-
const allSections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
8266
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
|
|
8267
|
-
);
|
|
8268
|
-
allSections.forEach((el, order) => {
|
|
8269
|
-
const id = instanceIdOf(el);
|
|
8270
|
-
if (!byId.has(id)) {
|
|
8271
|
-
byId.set(id, { instanceId: id, type: el.getAttribute("data-ohw-section") ?? "", order, pagePath: currentPath });
|
|
8272
|
-
}
|
|
8273
|
-
});
|
|
8274
|
-
const target = byId.get(instanceId);
|
|
8275
|
-
if (!target) return null;
|
|
8276
|
-
byId.set(instanceId, { ...target, removed });
|
|
8277
|
-
const entries = Array.from(byId.values());
|
|
8278
|
-
applyPersistedOrder(entries);
|
|
8279
|
-
return entries;
|
|
8280
|
-
}
|
|
8281
|
-
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
8282
|
-
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
8283
|
-
}
|
|
8284
|
-
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
8285
|
-
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
8286
|
-
}
|
|
8287
|
-
function duplicateSectionInstance(instanceId, newId, currentPath, existingEntries) {
|
|
8288
|
-
const original = findByInstanceId(instanceId);
|
|
8289
|
-
if (!original) return null;
|
|
8290
|
-
const clone = original.cloneNode(true);
|
|
8291
|
-
clone.setAttribute("data-ohw-instance", newId);
|
|
8292
|
-
const keyRekeys = rekeySectionSubtree(clone, newId);
|
|
8293
|
-
original.insertAdjacentElement("afterend", clone);
|
|
8294
|
-
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
8295
|
-
const entries = topLevelSections().map((el, order) => {
|
|
8296
|
-
const id = instanceIdOf(el);
|
|
8297
|
-
return {
|
|
8298
|
-
instanceId: id,
|
|
8299
|
-
type: el.getAttribute("data-ohw-section") ?? "",
|
|
8300
|
-
order,
|
|
8301
|
-
pagePath: currentPath,
|
|
8302
|
-
...byId.get(id)?.removed ? { removed: true } : {}
|
|
8303
|
-
};
|
|
8304
|
-
});
|
|
8305
|
-
applyPersistedOrder(entries);
|
|
8306
|
-
return { entries, keyRekeys };
|
|
8307
|
-
}
|
|
8308
|
-
function newInstanceId() {
|
|
8309
|
-
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
8310
|
-
}
|
|
8311
|
-
function getPageSectionOrderEntries(raw, currentPath) {
|
|
8312
|
-
if (!raw) return [];
|
|
8313
|
-
try {
|
|
8314
|
-
const entries = JSON.parse(raw);
|
|
8315
|
-
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
8316
|
-
} catch {
|
|
8317
|
-
return [];
|
|
8318
|
-
}
|
|
8319
|
-
}
|
|
8320
|
-
function rekeySectionSubtree(root, instanceId) {
|
|
8321
|
-
const suffix = `::${instanceId}`;
|
|
8322
|
-
const pairs = [];
|
|
8323
|
-
const rekey = (el, attr) => {
|
|
8324
|
-
const current = el.getAttribute(attr);
|
|
8325
|
-
if (!current) return;
|
|
8326
|
-
const base = current.includes("::") ? current.slice(0, current.indexOf("::")) : current;
|
|
8327
|
-
const next = `${base}${suffix}`;
|
|
8328
|
-
el.setAttribute(attr, next);
|
|
8329
|
-
pairs.push({ from: current, to: next });
|
|
8330
|
-
};
|
|
8331
|
-
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
8332
|
-
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
8333
|
-
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
8334
|
-
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
8335
|
-
return pairs;
|
|
8336
|
-
}
|
|
8337
|
-
function initSectionInstancesFromContent(content, currentPath) {
|
|
8338
|
-
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
8339
|
-
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
8340
|
-
});
|
|
8341
|
-
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
8342
|
-
for (const entry of entries) {
|
|
8343
|
-
if (entry.instanceId === entry.type) continue;
|
|
8344
|
-
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
8345
|
-
const original = document.querySelector(
|
|
8346
|
-
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
8347
|
-
);
|
|
8348
|
-
if (!original) continue;
|
|
8349
|
-
const clone = original.cloneNode(true);
|
|
8350
|
-
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
8351
|
-
rekeySectionSubtree(clone, entry.instanceId);
|
|
8352
|
-
original.insertAdjacentElement("afterend", clone);
|
|
8353
|
-
}
|
|
8354
|
-
applyPersistedOrder(entries);
|
|
8971
|
+
height: rect.height,
|
|
8972
|
+
zIndex: 2147483646,
|
|
8973
|
+
pointerEvents: "auto",
|
|
8974
|
+
boxShadow: "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
8975
|
+
background: "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
|
|
8976
|
+
},
|
|
8977
|
+
onClick: () => onEdit(hover.key),
|
|
8978
|
+
children: /* @__PURE__ */ jsxs8(
|
|
8979
|
+
Button,
|
|
8980
|
+
{
|
|
8981
|
+
"data-ohw-carousel-overlay": "",
|
|
8982
|
+
variant: "outline",
|
|
8983
|
+
size: "sm",
|
|
8984
|
+
className: "cursor-pointer gap-1.5 hover:bg-background",
|
|
8985
|
+
style: OVERLAY_BUTTON_STYLE2,
|
|
8986
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
8987
|
+
onClick: (e) => {
|
|
8988
|
+
e.stopPropagation();
|
|
8989
|
+
onEdit(hover.key);
|
|
8990
|
+
},
|
|
8991
|
+
children: [
|
|
8992
|
+
/* @__PURE__ */ jsx16(GalleryHorizontal, { size: 14 }),
|
|
8993
|
+
"Edit gallery"
|
|
8994
|
+
]
|
|
8995
|
+
}
|
|
8996
|
+
)
|
|
8997
|
+
}
|
|
8998
|
+
);
|
|
8355
8999
|
}
|
|
8356
9000
|
|
|
8357
9001
|
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
9002
|
+
import { useCallback as useCallback2, useEffect as useEffect4, useRef as useRef4, useState as useState5 } from "react";
|
|
9003
|
+
import { Check, X } from "lucide-react";
|
|
8358
9004
|
import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
8359
|
-
|
|
8360
|
-
const escaped = CSS.escape(instanceId);
|
|
8361
|
-
return document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]:not([data-ohw-instance])`);
|
|
8362
|
-
}
|
|
9005
|
+
var findSectionElement = findByInstanceId;
|
|
8363
9006
|
function readRect(instanceId) {
|
|
8364
9007
|
const el = findSectionElement(instanceId);
|
|
8365
9008
|
if (!el) return null;
|
|
@@ -8399,7 +9042,7 @@ function useLiveSectionRect(sectionId) {
|
|
|
8399
9042
|
}
|
|
8400
9043
|
function computeSectionBoundaryFlags(instanceId) {
|
|
8401
9044
|
const topLevel = topLevelSections();
|
|
8402
|
-
const index = topLevel.findIndex((el) => (el
|
|
9045
|
+
const index = topLevel.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8403
9046
|
if (index === -1) return { isFirst: true, isLast: true };
|
|
8404
9047
|
return { isFirst: index === 0, isLast: index === topLevel.length - 1 };
|
|
8405
9048
|
}
|
|
@@ -8483,18 +9126,20 @@ function AiSectionOverlay({
|
|
|
8483
9126
|
selectedIdRef.current = selectedId;
|
|
8484
9127
|
const report = useCallback2(
|
|
8485
9128
|
(el) => {
|
|
9129
|
+
const labelSrc = el ? sectionElementOf(el) : null;
|
|
8486
9130
|
postToParent2({
|
|
8487
9131
|
type: "ow:section-selected",
|
|
8488
|
-
sectionId: el ? el
|
|
8489
|
-
sectionLabel:
|
|
9132
|
+
sectionId: el ? instanceIdOf(el) || null : null,
|
|
9133
|
+
sectionLabel: labelSrc ? labelSrc.dataset.ohwSectionLabel ?? titleCaseSectionId(labelSrc.dataset.ohwSection ?? "") : null
|
|
8490
9134
|
});
|
|
8491
9135
|
},
|
|
8492
9136
|
[postToParent2]
|
|
8493
9137
|
);
|
|
8494
9138
|
const selectFromElement = useCallback2(
|
|
8495
9139
|
(el, options) => {
|
|
8496
|
-
const
|
|
8497
|
-
const
|
|
9140
|
+
const inner = el?.closest("[data-ohw-section]") ?? null;
|
|
9141
|
+
const sectionEl = inner ? movableUnit(inner) : null;
|
|
9142
|
+
const id = sectionEl ? instanceIdOf(sectionEl) || null : null;
|
|
8498
9143
|
if (id === selectedIdRef.current) return;
|
|
8499
9144
|
setSelectedId(id);
|
|
8500
9145
|
if (options?.report !== false) report(sectionEl);
|
|
@@ -8560,7 +9205,8 @@ function AiSectionOverlay({
|
|
|
8560
9205
|
return;
|
|
8561
9206
|
}
|
|
8562
9207
|
const sec = t.closest("[data-ohw-section]");
|
|
8563
|
-
|
|
9208
|
+
const unit = sec ? movableUnit(sec) : null;
|
|
9209
|
+
setHoveredId(unit ? instanceIdOf(unit) || null : null);
|
|
8564
9210
|
};
|
|
8565
9211
|
const onLeave = () => setHoveredId(null);
|
|
8566
9212
|
document.addEventListener("mousemove", onMove, { passive: true });
|
|
@@ -9164,7 +9810,7 @@ function SectionTreeItem({
|
|
|
9164
9810
|
/* @__PURE__ */ jsx20(
|
|
9165
9811
|
"div",
|
|
9166
9812
|
{
|
|
9167
|
-
className: "mr-
|
|
9813
|
+
className: "-mr-px h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
|
|
9168
9814
|
"aria-hidden": true
|
|
9169
9815
|
}
|
|
9170
9816
|
),
|
|
@@ -9183,7 +9829,7 @@ function SectionTreeItem({
|
|
|
9183
9829
|
className: cn(
|
|
9184
9830
|
"flex h-9 min-w-0 flex-1 items-center gap-2 rounded-md border border-border bg-background p-3",
|
|
9185
9831
|
interactive && "cursor-pointer hover:bg-muted/30",
|
|
9186
|
-
interactive && selected && "border-primary"
|
|
9832
|
+
interactive && selected && "border-bridge-primary"
|
|
9187
9833
|
),
|
|
9188
9834
|
children: [
|
|
9189
9835
|
/* @__PURE__ */ jsx20(
|
|
@@ -9313,7 +9959,7 @@ function UrlOrPageInput({
|
|
|
9313
9959
|
};
|
|
9314
9960
|
const fieldClassName = cn(
|
|
9315
9961
|
"data-ohw-link-field flex h-[36px] w-full items-center overflow-hidden rounded-md border bg-background pl-3 pr-3 py-2 outline-none transition-[border-color,box-shadow]",
|
|
9316
|
-
urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
|
|
9962
|
+
urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-bridge-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
|
|
9317
9963
|
);
|
|
9318
9964
|
return /* @__PURE__ */ jsxs13("div", { className: "flex w-full flex-col gap-2 p-0", children: [
|
|
9319
9965
|
/* @__PURE__ */ jsx23(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
|
|
@@ -10357,6 +11003,32 @@ function getNavbarDesktopContainer() {
|
|
|
10357
11003
|
function getNavbarDrawerContainer() {
|
|
10358
11004
|
return document.querySelector("[data-ohw-nav-drawer]");
|
|
10359
11005
|
}
|
|
11006
|
+
function isNavbarListContainerVisible(el) {
|
|
11007
|
+
if (el.hasAttribute("hidden")) return false;
|
|
11008
|
+
if (el.getClientRects().length === 0) return false;
|
|
11009
|
+
const style = window.getComputedStyle(el);
|
|
11010
|
+
return style.display !== "none" && style.visibility !== "hidden";
|
|
11011
|
+
}
|
|
11012
|
+
function getActiveNavbarListContainer(draggedEl) {
|
|
11013
|
+
const desktop = getNavbarDesktopContainer();
|
|
11014
|
+
const drawer = getNavbarDrawerContainer();
|
|
11015
|
+
if (draggedEl) {
|
|
11016
|
+
if (drawer?.contains(draggedEl)) return drawer;
|
|
11017
|
+
if (desktop?.contains(draggedEl)) return desktop;
|
|
11018
|
+
}
|
|
11019
|
+
if (desktop && isNavbarListContainerVisible(desktop)) return desktop;
|
|
11020
|
+
if (drawer && isNavbarListContainerVisible(drawer)) return drawer;
|
|
11021
|
+
return desktop ?? drawer;
|
|
11022
|
+
}
|
|
11023
|
+
function listActiveNavbarItems(draggedEl) {
|
|
11024
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
11025
|
+
if (container) {
|
|
11026
|
+
return Array.from(container.querySelectorAll("[data-ohw-href-key]")).filter(
|
|
11027
|
+
isNavbarLinkItem
|
|
11028
|
+
);
|
|
11029
|
+
}
|
|
11030
|
+
return listNavbarItems();
|
|
11031
|
+
}
|
|
10360
11032
|
function listNavbarItems() {
|
|
10361
11033
|
const desktop = getNavbarDesktopContainer();
|
|
10362
11034
|
if (desktop) {
|
|
@@ -11469,20 +12141,23 @@ function isEmptyLabelValue(value) {
|
|
|
11469
12141
|
function applyStoredValues(item, content) {
|
|
11470
12142
|
const hrefKey = socialHrefKey(item);
|
|
11471
12143
|
const iconKey = socialIconKey(item);
|
|
12144
|
+
const baseKey = hrefKey?.replace(/-href$/, "");
|
|
11472
12145
|
if (hrefKey && content[hrefKey] !== void 0) item.setAttribute("href", content[hrefKey]);
|
|
11473
|
-
|
|
12146
|
+
const glyphKey = iconKey ?? baseKey ?? null;
|
|
12147
|
+
const glyphStored = glyphKey ? content[glyphKey]?.trim() : void 0;
|
|
12148
|
+
if (glyphStored) {
|
|
12149
|
+
ensureIconSlot(item);
|
|
11474
12150
|
const glyph = item.querySelector(ICON_SELECTOR);
|
|
11475
|
-
if (glyph
|
|
11476
|
-
applyIconMarkup(glyph,
|
|
12151
|
+
if (glyph) {
|
|
12152
|
+
applyIconMarkup(glyph, glyphStored);
|
|
11477
12153
|
glyph.removeAttribute(SOCIALS_ICON_PLACEHOLDER_ATTR);
|
|
11478
12154
|
}
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
|
|
11484
|
-
|
|
11485
|
-
}
|
|
12155
|
+
}
|
|
12156
|
+
const label = socialLabelElement(item);
|
|
12157
|
+
const labelKey = label?.getAttribute("data-ohw-key");
|
|
12158
|
+
if (label && labelKey && content[labelKey] !== void 0) {
|
|
12159
|
+
const words = isEmptyLabelValue(content[labelKey]) ? "" : content[labelKey];
|
|
12160
|
+
if (label.innerHTML !== words) label.innerHTML = words;
|
|
11486
12161
|
}
|
|
11487
12162
|
}
|
|
11488
12163
|
function socialPlatformKey(iconKey) {
|
|
@@ -11571,6 +12246,9 @@ function insertSocialItem(row, after, content = {}, { placeholder = true, keys }
|
|
|
11571
12246
|
if (placeholder) {
|
|
11572
12247
|
const label = socialLabelElement(item);
|
|
11573
12248
|
if (label) label.textContent = PLACEHOLDER_SOCIAL_LABEL;
|
|
12249
|
+
} else if (keys) {
|
|
12250
|
+
const label = socialLabelElement(item);
|
|
12251
|
+
if (label) label.textContent = "";
|
|
11574
12252
|
}
|
|
11575
12253
|
applySocialsDisplayToRow(row, display);
|
|
11576
12254
|
return { item, hrefKey, iconKey, order: getSocialsOrderFromDom(row.ownerDocument) };
|
|
@@ -13071,6 +13749,7 @@ function readLogoSizeState(content, placement) {
|
|
|
13071
13749
|
function getLogoElement(el) {
|
|
13072
13750
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
13073
13751
|
if (marked) return marked;
|
|
13752
|
+
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
13074
13753
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
13075
13754
|
if (!root) return null;
|
|
13076
13755
|
const anchor = el.closest("a");
|
|
@@ -13364,7 +14043,7 @@ function DisplaySwitch({
|
|
|
13364
14043
|
onClick: () => onChange(!checked),
|
|
13365
14044
|
className: cn(
|
|
13366
14045
|
"relative h-5 w-9 shrink-0 rounded-full transition-colors",
|
|
13367
|
-
checked ? "bg-primary" : "bg-primary-50",
|
|
14046
|
+
checked ? "bg-bridge-primary" : "bg-primary-50",
|
|
13368
14047
|
disabled ? "cursor-default opacity-50" : "cursor-pointer"
|
|
13369
14048
|
),
|
|
13370
14049
|
children: /* @__PURE__ */ jsx28(
|
|
@@ -13372,7 +14051,7 @@ function DisplaySwitch({
|
|
|
13372
14051
|
{
|
|
13373
14052
|
className: cn(
|
|
13374
14053
|
"absolute top-0.5 h-4 w-4 rounded-full bg-white transition-all",
|
|
13375
|
-
checked ? "left-
|
|
14054
|
+
checked ? "left-4.5" : "left-0.5"
|
|
13376
14055
|
)
|
|
13377
14056
|
}
|
|
13378
14057
|
)
|
|
@@ -13433,8 +14112,8 @@ var lockFooterDuringDrag = lockItemDuringDrag;
|
|
|
13433
14112
|
var unlockFooterDragInteraction = unlockItemDragInteraction;
|
|
13434
14113
|
|
|
13435
14114
|
// src/lib/nav-dnd.ts
|
|
13436
|
-
function listReorderableNavItems() {
|
|
13437
|
-
return
|
|
14115
|
+
function listReorderableNavItems(draggedEl) {
|
|
14116
|
+
return listActiveNavbarItems(draggedEl).filter((el) => {
|
|
13438
14117
|
const key = el.getAttribute("data-ohw-href-key");
|
|
13439
14118
|
return isNavbarHrefKey(key) && !isNestedNavChild(el);
|
|
13440
14119
|
});
|
|
@@ -13449,8 +14128,8 @@ function resolveParentNavHrefKey(child) {
|
|
|
13449
14128
|
const key = trigger?.getAttribute("data-ohw-href-key");
|
|
13450
14129
|
return key && isNavbarHrefKey(key) ? key : null;
|
|
13451
14130
|
}
|
|
13452
|
-
function listNavChildren(parentHrefKey) {
|
|
13453
|
-
const items =
|
|
14131
|
+
function listNavChildren(parentHrefKey, draggedEl) {
|
|
14132
|
+
const items = listActiveNavbarItems(draggedEl);
|
|
13454
14133
|
const parent = items.find((el) => el.getAttribute("data-ohw-href-key") === parentHrefKey);
|
|
13455
14134
|
if (!parent) return [];
|
|
13456
14135
|
const group = parent.closest("[data-ohw-nav-group]");
|
|
@@ -13460,20 +14139,83 @@ function listNavChildren(parentHrefKey) {
|
|
|
13460
14139
|
(el) => isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))
|
|
13461
14140
|
);
|
|
13462
14141
|
}
|
|
13463
|
-
function
|
|
13464
|
-
const
|
|
13465
|
-
if (
|
|
13466
|
-
const
|
|
13467
|
-
|
|
14142
|
+
function isVerticalNavLayout(items, draggedEl) {
|
|
14143
|
+
const visible = items.filter((el) => el.getClientRects().length > 0);
|
|
14144
|
+
if (visible.length >= 2) {
|
|
14145
|
+
const a = visible[0].getBoundingClientRect();
|
|
14146
|
+
const b = visible[1].getBoundingClientRect();
|
|
14147
|
+
const verticalGap = b.top - a.bottom;
|
|
14148
|
+
const horizontalGap = b.left - a.right;
|
|
14149
|
+
return verticalGap > horizontalGap;
|
|
14150
|
+
}
|
|
14151
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
14152
|
+
if (!container) return false;
|
|
14153
|
+
const style = window.getComputedStyle(container);
|
|
14154
|
+
return style.flexDirection === "column" || style.flexDirection === "column-reverse";
|
|
14155
|
+
}
|
|
14156
|
+
function buildVerticalRootNavDropSlots(items, draggedEl) {
|
|
14157
|
+
const slots = [];
|
|
14158
|
+
const barThickness = 3;
|
|
14159
|
+
if (items.length === 0) {
|
|
14160
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
14161
|
+
if (!container) return slots;
|
|
14162
|
+
const rect = container.getBoundingClientRect();
|
|
14163
|
+
slots.push({
|
|
14164
|
+
insertIndex: 0,
|
|
14165
|
+
parentId: null,
|
|
14166
|
+
left: rect.left,
|
|
14167
|
+
top: rect.top + rect.height / 2 - barThickness / 2,
|
|
14168
|
+
width: Math.max(rect.width, 40),
|
|
14169
|
+
height: barThickness,
|
|
14170
|
+
direction: "horizontal"
|
|
14171
|
+
});
|
|
14172
|
+
return slots;
|
|
14173
|
+
}
|
|
14174
|
+
const edgeGap = (() => {
|
|
14175
|
+
if (items.length < 2) return 16;
|
|
14176
|
+
const a = items[0].getBoundingClientRect();
|
|
14177
|
+
const b = items[1].getBoundingClientRect();
|
|
14178
|
+
return Math.max(0, b.top - a.bottom);
|
|
14179
|
+
})();
|
|
14180
|
+
for (let i = 0; i <= items.length; i++) {
|
|
14181
|
+
let top;
|
|
14182
|
+
let width;
|
|
14183
|
+
let left;
|
|
14184
|
+
if (i === 0) {
|
|
14185
|
+
const first = items[0].getBoundingClientRect();
|
|
14186
|
+
top = first.top - edgeGap / 2 - barThickness / 2;
|
|
14187
|
+
left = first.left;
|
|
14188
|
+
width = first.width;
|
|
14189
|
+
} else if (i === items.length) {
|
|
14190
|
+
const last = items[items.length - 1].getBoundingClientRect();
|
|
14191
|
+
const lastGap = items.length >= 2 ? Math.max(0, last.top - items[items.length - 2].getBoundingClientRect().bottom) : edgeGap;
|
|
14192
|
+
top = last.bottom + lastGap / 2 - barThickness / 2;
|
|
14193
|
+
left = last.left;
|
|
14194
|
+
width = last.width;
|
|
14195
|
+
} else {
|
|
14196
|
+
const prev = items[i - 1].getBoundingClientRect();
|
|
14197
|
+
const next = items[i].getBoundingClientRect();
|
|
14198
|
+
top = (prev.bottom + next.top) / 2 - barThickness / 2;
|
|
14199
|
+
left = Math.min(prev.left, next.left);
|
|
14200
|
+
width = Math.max(prev.right, next.right) - left;
|
|
14201
|
+
}
|
|
14202
|
+
slots.push({
|
|
14203
|
+
insertIndex: i,
|
|
14204
|
+
parentId: null,
|
|
14205
|
+
left,
|
|
14206
|
+
top,
|
|
14207
|
+
width: Math.max(width, 40),
|
|
14208
|
+
height: barThickness,
|
|
14209
|
+
direction: "horizontal"
|
|
14210
|
+
});
|
|
13468
14211
|
}
|
|
13469
|
-
return
|
|
14212
|
+
return slots;
|
|
13470
14213
|
}
|
|
13471
|
-
function
|
|
13472
|
-
const items = listReorderableNavItems();
|
|
14214
|
+
function buildHorizontalRootNavDropSlots(items, draggedEl) {
|
|
13473
14215
|
const slots = [];
|
|
13474
14216
|
const barThickness = 3;
|
|
13475
14217
|
if (items.length === 0) {
|
|
13476
|
-
const container =
|
|
14218
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
13477
14219
|
if (!container) return slots;
|
|
13478
14220
|
const rect = container.getBoundingClientRect();
|
|
13479
14221
|
slots.push({
|
|
@@ -13504,10 +14246,7 @@ function buildRootNavDropSlots() {
|
|
|
13504
14246
|
height = first.height;
|
|
13505
14247
|
} else if (i === items.length) {
|
|
13506
14248
|
const last = items[items.length - 1].getBoundingClientRect();
|
|
13507
|
-
const lastGap = items.length >= 2 ? Math.max(
|
|
13508
|
-
0,
|
|
13509
|
-
last.left - items[items.length - 2].getBoundingClientRect().right
|
|
13510
|
-
) : edgeGap;
|
|
14249
|
+
const lastGap = items.length >= 2 ? Math.max(0, last.left - items[items.length - 2].getBoundingClientRect().right) : edgeGap;
|
|
13511
14250
|
left = last.right + lastGap / 2 - barThickness / 2;
|
|
13512
14251
|
top = last.top;
|
|
13513
14252
|
height = last.height;
|
|
@@ -13530,8 +14269,15 @@ function buildRootNavDropSlots() {
|
|
|
13530
14269
|
}
|
|
13531
14270
|
return slots;
|
|
13532
14271
|
}
|
|
13533
|
-
function
|
|
13534
|
-
const
|
|
14272
|
+
function buildRootNavDropSlots(draggedEl) {
|
|
14273
|
+
const items = listReorderableNavItems(draggedEl);
|
|
14274
|
+
if (isVerticalNavLayout(items, draggedEl)) {
|
|
14275
|
+
return buildVerticalRootNavDropSlots(items, draggedEl);
|
|
14276
|
+
}
|
|
14277
|
+
return buildHorizontalRootNavDropSlots(items, draggedEl);
|
|
14278
|
+
}
|
|
14279
|
+
function buildChildNavDropSlots(parentHrefKey, draggedEl) {
|
|
14280
|
+
const children = listNavChildren(parentHrefKey, draggedEl);
|
|
13535
14281
|
const slots = [];
|
|
13536
14282
|
const barThickness = 3;
|
|
13537
14283
|
if (children.length === 0) return slots;
|
|
@@ -13552,10 +14298,7 @@ function buildChildNavDropSlots(parentHrefKey) {
|
|
|
13552
14298
|
width = first.width;
|
|
13553
14299
|
} else if (i === children.length) {
|
|
13554
14300
|
const last = children[children.length - 1].getBoundingClientRect();
|
|
13555
|
-
const lastGap = children.length >= 2 ? Math.max(
|
|
13556
|
-
0,
|
|
13557
|
-
last.top - children[children.length - 2].getBoundingClientRect().bottom
|
|
13558
|
-
) : edgeGap;
|
|
14301
|
+
const lastGap = children.length >= 2 ? Math.max(0, last.top - children[children.length - 2].getBoundingClientRect().bottom) : edgeGap;
|
|
13559
14302
|
top = last.bottom + lastGap / 2 - barThickness / 2;
|
|
13560
14303
|
left = last.left;
|
|
13561
14304
|
width = last.width;
|
|
@@ -13578,18 +14321,19 @@ function buildChildNavDropSlots(parentHrefKey) {
|
|
|
13578
14321
|
}
|
|
13579
14322
|
return slots;
|
|
13580
14323
|
}
|
|
13581
|
-
function buildAllNavDropSlots(draggedHrefKey) {
|
|
13582
|
-
const
|
|
13583
|
-
|
|
14324
|
+
function buildAllNavDropSlots(draggedHrefKey, draggedEl) {
|
|
14325
|
+
const activeItems = listActiveNavbarItems(draggedEl);
|
|
14326
|
+
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);
|
|
14327
|
+
if (!dragged) return buildRootNavDropSlots(draggedEl);
|
|
13584
14328
|
if (isNestedNavChild(dragged)) {
|
|
13585
14329
|
const parentKey = resolveParentNavHrefKey(dragged);
|
|
13586
14330
|
if (!parentKey) return [];
|
|
13587
|
-
return buildChildNavDropSlots(parentKey);
|
|
14331
|
+
return buildChildNavDropSlots(parentKey, draggedEl);
|
|
13588
14332
|
}
|
|
13589
|
-
return buildRootNavDropSlots();
|
|
14333
|
+
return buildRootNavDropSlots(draggedEl);
|
|
13590
14334
|
}
|
|
13591
|
-
function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
|
|
13592
|
-
const slots = buildAllNavDropSlots(draggedHrefKey);
|
|
14335
|
+
function hitTestNavDropSlot(clientX, clientY, draggedHrefKey, draggedEl) {
|
|
14336
|
+
const slots = buildAllNavDropSlots(draggedHrefKey, draggedEl);
|
|
13593
14337
|
let best = null;
|
|
13594
14338
|
for (const slot of slots) {
|
|
13595
14339
|
const cx2 = slot.left + slot.width / 2;
|
|
@@ -13640,6 +14384,12 @@ function useNavItemDrag({
|
|
|
13640
14384
|
setIsItemDragging(false);
|
|
13641
14385
|
if (keepOpenEl?.isConnected) {
|
|
13642
14386
|
setNavGroupForceOpen(keepOpenEl, true);
|
|
14387
|
+
requestAnimationFrame(() => {
|
|
14388
|
+
if (keepOpenEl.isConnected) setNavGroupForceOpen(keepOpenEl, true);
|
|
14389
|
+
requestAnimationFrame(() => {
|
|
14390
|
+
if (keepOpenEl.isConnected) setNavGroupForceOpen(keepOpenEl, true);
|
|
14391
|
+
});
|
|
14392
|
+
});
|
|
13643
14393
|
} else {
|
|
13644
14394
|
setNavGroupForceOpen(null, false);
|
|
13645
14395
|
}
|
|
@@ -13655,7 +14405,7 @@ function useNavItemDrag({
|
|
|
13655
14405
|
}
|
|
13656
14406
|
session.activeSlot = activeSlot;
|
|
13657
14407
|
setSiblingHintRects([]);
|
|
13658
|
-
const slots = buildAllNavDropSlots(session.hrefKey);
|
|
14408
|
+
const slots = buildAllNavDropSlots(session.hrefKey, session.draggedEl);
|
|
13659
14409
|
setNavDropSlots(slots);
|
|
13660
14410
|
const activeIdx = activeSlot ? slots.findIndex(
|
|
13661
14411
|
(s) => s.parentId === activeSlot.parentId && s.insertIndex === activeSlot.insertIndex
|
|
@@ -13691,7 +14441,12 @@ function useNavItemDrag({
|
|
|
13691
14441
|
if (session.wasSelected && selectedElRef.current === session.draggedEl) {
|
|
13692
14442
|
setToolbarRect(rect);
|
|
13693
14443
|
}
|
|
13694
|
-
const initialSlot = hitTestNavDropSlot(
|
|
14444
|
+
const initialSlot = hitTestNavDropSlot(
|
|
14445
|
+
session.lastClientX,
|
|
14446
|
+
session.lastClientY,
|
|
14447
|
+
session.hrefKey,
|
|
14448
|
+
session.draggedEl
|
|
14449
|
+
);
|
|
13695
14450
|
refreshNavDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
|
|
13696
14451
|
},
|
|
13697
14452
|
[
|
|
@@ -13713,10 +14468,11 @@ function useNavItemDrag({
|
|
|
13713
14468
|
}
|
|
13714
14469
|
const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
|
|
13715
14470
|
const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
|
|
13716
|
-
const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey);
|
|
14471
|
+
const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey, session.draggedEl);
|
|
13717
14472
|
const planned = slot != null ? planNavItemMove(session.hrefKey, slot.parentId, slot.insertIndex) : null;
|
|
13718
14473
|
const wasSelected = session.wasSelected;
|
|
13719
14474
|
const hrefKey = session.hrefKey;
|
|
14475
|
+
const keepDropdownOpen = Boolean(session.draggedEl.closest("[data-ohw-nav-children]"));
|
|
13720
14476
|
const applySelectionAfterDrop = () => {
|
|
13721
14477
|
if (!wasSelected) {
|
|
13722
14478
|
deselectRef.current();
|
|
@@ -13750,6 +14506,14 @@ function useNavItemDrag({
|
|
|
13750
14506
|
});
|
|
13751
14507
|
applySelectionAfterDrop();
|
|
13752
14508
|
clearNavDragVisuals();
|
|
14509
|
+
if (keepDropdownOpen) {
|
|
14510
|
+
requestAnimationFrame(() => {
|
|
14511
|
+
const desktop = document.querySelector("[data-ohw-nav-container]");
|
|
14512
|
+
const drawer = document.querySelector("[data-ohw-nav-drawer]");
|
|
14513
|
+
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)}"]`);
|
|
14514
|
+
if (link) setNavGroupForceOpen(link, true);
|
|
14515
|
+
});
|
|
14516
|
+
}
|
|
13753
14517
|
requestAnimationFrame(() => {
|
|
13754
14518
|
if (editContentRef.current[NAV_ORDER_KEY] === planned.orderJson) {
|
|
13755
14519
|
applyNavForest(planned.forest);
|
|
@@ -13789,7 +14553,7 @@ function useNavItemDrag({
|
|
|
13789
14553
|
if (!session) return false;
|
|
13790
14554
|
e.preventDefault();
|
|
13791
14555
|
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
13792
|
-
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
14556
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey, session.draggedEl);
|
|
13793
14557
|
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
13794
14558
|
return true;
|
|
13795
14559
|
},
|
|
@@ -13835,7 +14599,7 @@ function useNavItemDrag({
|
|
|
13835
14599
|
clearTextSelection();
|
|
13836
14600
|
const session = navDragRef.current;
|
|
13837
14601
|
if (!session) return;
|
|
13838
|
-
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
14602
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey, session.draggedEl);
|
|
13839
14603
|
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
13840
14604
|
return;
|
|
13841
14605
|
}
|
|
@@ -13851,7 +14615,8 @@ function useNavItemDrag({
|
|
|
13851
14615
|
} catch {
|
|
13852
14616
|
}
|
|
13853
14617
|
if (linkPopoverOpenRef.current) setLinkPopover(null);
|
|
13854
|
-
|
|
14618
|
+
const isNestedDrag = Boolean(pending.el.closest("[data-ohw-nav-children]"));
|
|
14619
|
+
if (activeElRef.current && !isNestedDrag) deactivateRef.current();
|
|
13855
14620
|
const key = pending.el.getAttribute("data-ohw-href-key");
|
|
13856
14621
|
if (!key) return;
|
|
13857
14622
|
beginNavDragRef.current({
|
|
@@ -13862,6 +14627,9 @@ function useNavItemDrag({
|
|
|
13862
14627
|
lastClientY: e.clientY,
|
|
13863
14628
|
activeSlot: null
|
|
13864
14629
|
});
|
|
14630
|
+
if (activeElRef.current && isNestedDrag) {
|
|
14631
|
+
deactivateRef.current();
|
|
14632
|
+
}
|
|
13865
14633
|
};
|
|
13866
14634
|
const endPointerDrag = (e) => {
|
|
13867
14635
|
const pending = navPointerDragRef.current;
|
|
@@ -13939,6 +14707,7 @@ function useNavItemDrag({
|
|
|
13939
14707
|
);
|
|
13940
14708
|
return {
|
|
13941
14709
|
navDragRef,
|
|
14710
|
+
navPointerDragRef,
|
|
13942
14711
|
navDropSlots,
|
|
13943
14712
|
activeNavDropIndex,
|
|
13944
14713
|
startNavLinkDrag,
|
|
@@ -14143,15 +14912,17 @@ function useSectionDrag({
|
|
|
14143
14912
|
clearSectionDragVisuals();
|
|
14144
14913
|
return;
|
|
14145
14914
|
}
|
|
14146
|
-
const orderJson = JSON.stringify(
|
|
14915
|
+
const orderJson = JSON.stringify(
|
|
14916
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
14917
|
+
);
|
|
14147
14918
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
14148
14919
|
setAiSectionOrder(orderJson, window.location.pathname);
|
|
14149
14920
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
14150
|
-
applyPersistedOrder(
|
|
14921
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
14151
14922
|
clearSectionDragVisuals();
|
|
14152
14923
|
requestAnimationFrame(() => {
|
|
14153
14924
|
if (editContentRef.current[SECTION_ORDER_KEY] === orderJson) {
|
|
14154
|
-
applyPersistedOrder(
|
|
14925
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
14155
14926
|
}
|
|
14156
14927
|
requestAnimationFrame(() => {
|
|
14157
14928
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -14184,8 +14955,9 @@ function useSectionDrag({
|
|
|
14184
14955
|
const target = e.target;
|
|
14185
14956
|
if (!(target instanceof HTMLElement)) return;
|
|
14186
14957
|
if (target.closest(SECTION_DRAG_EXCLUDED_SELECTOR)) return;
|
|
14187
|
-
const
|
|
14188
|
-
if (!
|
|
14958
|
+
const inner = target.closest("[data-ohw-section]");
|
|
14959
|
+
if (!inner || isChromeSection(inner) || inner.dataset.ohwSection === "footer") return;
|
|
14960
|
+
const sectionEl = movableUnit(inner);
|
|
14189
14961
|
if (!topLevelSections().includes(sectionEl)) return;
|
|
14190
14962
|
startSectionPressDrag(sectionEl, e.clientX, e.clientY, e.pointerId);
|
|
14191
14963
|
};
|
|
@@ -14452,6 +15224,9 @@ function collectEditableNodes(extraContent, root = document) {
|
|
|
14452
15224
|
if (el.dataset.ohwEditable === "link") {
|
|
14453
15225
|
return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref3(el) };
|
|
14454
15226
|
}
|
|
15227
|
+
if (el.dataset.ohwEditable === "map") {
|
|
15228
|
+
return { key: el.dataset.ohwKey ?? "", type: "map", text: el.dataset.ohwMapQuery ?? "" };
|
|
15229
|
+
}
|
|
14455
15230
|
return {
|
|
14456
15231
|
key: el.dataset.ohwKey ?? "",
|
|
14457
15232
|
type: el.dataset.ohwEditable ?? "text",
|
|
@@ -14892,7 +15667,7 @@ var badgeVariants = cva(
|
|
|
14892
15667
|
{
|
|
14893
15668
|
variants: {
|
|
14894
15669
|
variant: {
|
|
14895
|
-
default: "border-transparent bg-primary text-primary-foreground",
|
|
15670
|
+
default: "border-transparent bg-bridge-primary text-primary-foreground",
|
|
14896
15671
|
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
14897
15672
|
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
14898
15673
|
outline: "text-foreground"
|
|
@@ -15014,21 +15789,10 @@ function parseSchedulingInsertAfter(insertAfter) {
|
|
|
15014
15789
|
insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
|
|
15015
15790
|
};
|
|
15016
15791
|
}
|
|
15017
|
-
function
|
|
15018
|
-
|
|
15019
|
-
const
|
|
15020
|
-
|
|
15021
|
-
return { effectiveInsertAfter, insertBefore };
|
|
15022
|
-
}
|
|
15023
|
-
function getSchedulingMountPoint(insertAfter) {
|
|
15024
|
-
const { anchor } = parseSchedulingInsertAfter(insertAfter);
|
|
15025
|
-
let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
|
|
15026
|
-
if (!anchorEl && anchor === "scheduling") {
|
|
15027
|
-
const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
|
|
15028
|
-
anchorEl = widgets.at(-1) ?? null;
|
|
15029
|
-
}
|
|
15030
|
-
if (!anchorEl) return null;
|
|
15031
|
-
return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
15792
|
+
function resolveEntryAnchor(entry) {
|
|
15793
|
+
if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
|
|
15794
|
+
const parsed = parseSchedulingInsertAfter(entry.insertAfter);
|
|
15795
|
+
return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
|
|
15032
15796
|
}
|
|
15033
15797
|
function schedulingMountDepth(insertAfter) {
|
|
15034
15798
|
if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
|
|
@@ -15045,8 +15809,7 @@ function getPageSchedulingEntries(raw) {
|
|
|
15045
15809
|
}
|
|
15046
15810
|
}
|
|
15047
15811
|
function isSchedulingWidgetMissing(entry) {
|
|
15048
|
-
|
|
15049
|
-
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
|
|
15812
|
+
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
|
|
15050
15813
|
}
|
|
15051
15814
|
function hasMissingSchedulingWidgets(entries) {
|
|
15052
15815
|
return entries.some(isSchedulingWidgetMissing);
|
|
@@ -15084,18 +15847,18 @@ function initSectionsFromContent(content, removeExisting = false, currentPath =
|
|
|
15084
15847
|
} catch {
|
|
15085
15848
|
}
|
|
15086
15849
|
}
|
|
15087
|
-
function mountSchedulingWidget(
|
|
15088
|
-
const
|
|
15089
|
-
const sectionId = schedulingSectionId(
|
|
15850
|
+
function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
|
|
15851
|
+
const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
|
|
15852
|
+
const sectionId = schedulingSectionId(widgetId);
|
|
15090
15853
|
if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
|
|
15091
|
-
const
|
|
15092
|
-
if (!
|
|
15854
|
+
const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
|
|
15855
|
+
if (!anchorEl) return false;
|
|
15856
|
+
const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
15093
15857
|
const container = document.createElement("div");
|
|
15094
15858
|
container.dataset.ohwSectionContainer = "scheduling";
|
|
15095
|
-
container.dataset.ohwSection = sectionId;
|
|
15096
15859
|
container.dataset.ohwInstance = sectionId;
|
|
15097
|
-
if (
|
|
15098
|
-
const beforeAnchor = document.querySelector(`[data-ohw-section="${
|
|
15860
|
+
if (beforeId) {
|
|
15861
|
+
const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
|
|
15099
15862
|
const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
|
|
15100
15863
|
if (!beforePoint) return false;
|
|
15101
15864
|
beforePoint.insertAdjacentElement("beforebegin", container);
|
|
@@ -15106,20 +15869,26 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
15106
15869
|
}
|
|
15107
15870
|
tail.insertAdjacentElement("afterend", container);
|
|
15108
15871
|
}
|
|
15109
|
-
|
|
15110
|
-
|
|
15111
|
-
|
|
15112
|
-
|
|
15113
|
-
|
|
15114
|
-
|
|
15115
|
-
|
|
15116
|
-
|
|
15117
|
-
|
|
15118
|
-
|
|
15119
|
-
|
|
15120
|
-
|
|
15121
|
-
|
|
15122
|
-
|
|
15872
|
+
try {
|
|
15873
|
+
const root = createRoot2(container);
|
|
15874
|
+
schedulingRoots.set(container, root);
|
|
15875
|
+
flushSync2(() => {
|
|
15876
|
+
root.render(
|
|
15877
|
+
/* @__PURE__ */ jsx33(
|
|
15878
|
+
SchedulingWidget,
|
|
15879
|
+
{
|
|
15880
|
+
notifyOnConnect,
|
|
15881
|
+
initialScheduleId: scheduleId,
|
|
15882
|
+
insertAfter: widgetId
|
|
15883
|
+
}
|
|
15884
|
+
)
|
|
15885
|
+
);
|
|
15886
|
+
});
|
|
15887
|
+
} catch (err) {
|
|
15888
|
+
console.error("[ow:scheduling] render threw", err);
|
|
15889
|
+
container.remove();
|
|
15890
|
+
return false;
|
|
15891
|
+
}
|
|
15123
15892
|
const tracker = getSectionsTracker();
|
|
15124
15893
|
let sections = [];
|
|
15125
15894
|
try {
|
|
@@ -15127,10 +15896,12 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
15127
15896
|
} catch {
|
|
15128
15897
|
}
|
|
15129
15898
|
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
15130
|
-
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter ===
|
|
15899
|
+
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
|
|
15131
15900
|
sections.push({
|
|
15132
15901
|
type: "scheduling",
|
|
15133
|
-
insertAfter:
|
|
15902
|
+
insertAfter: widgetId,
|
|
15903
|
+
anchorId,
|
|
15904
|
+
beforeId: beforeId ?? null,
|
|
15134
15905
|
pagePath: window.location.pathname,
|
|
15135
15906
|
...scheduleId ? { scheduleId } : {}
|
|
15136
15907
|
});
|
|
@@ -15144,7 +15915,8 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
|
15144
15915
|
for (let i = pending.length - 1; i >= 0; i--) {
|
|
15145
15916
|
const entry = pending[i];
|
|
15146
15917
|
const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
|
|
15147
|
-
|
|
15918
|
+
const { anchorId, beforeId } = resolveEntryAnchor(entry);
|
|
15919
|
+
if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
|
|
15148
15920
|
pending.splice(i, 1);
|
|
15149
15921
|
}
|
|
15150
15922
|
}
|
|
@@ -15236,7 +16008,7 @@ var EDITOR_CHROME_SELECTOR = '[data-ohw-toolbar], [data-ohw-form-toolbar], [data
|
|
|
15236
16008
|
function isOverEditorChrome(x, y) {
|
|
15237
16009
|
return document.elementsFromPoint(x, y).some((el) => el instanceof HTMLElement && el.matches(EDITOR_CHROME_SELECTOR));
|
|
15238
16010
|
}
|
|
15239
|
-
var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]):not([data-ohw-editable="icon"]):not([data-ohw-editable="form"])';
|
|
16011
|
+
var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]):not([data-ohw-editable="icon"]):not([data-ohw-editable="form"]):not([data-ohw-editable="map"])';
|
|
15240
16012
|
function getVideoEl2(el) {
|
|
15241
16013
|
return el instanceof HTMLVideoElement ? el : el.querySelector("video");
|
|
15242
16014
|
}
|
|
@@ -15292,6 +16064,12 @@ function applyVideoSettingNode(key, val) {
|
|
|
15292
16064
|
});
|
|
15293
16065
|
return true;
|
|
15294
16066
|
}
|
|
16067
|
+
function applyMapQuery(el, val) {
|
|
16068
|
+
if (!(el instanceof HTMLIFrameElement)) return;
|
|
16069
|
+
const nextSrc = `https://www.google.com/maps?q=${encodeURIComponent(val)}&output=embed`;
|
|
16070
|
+
if (el.src !== nextSrc) el.src = nextSrc;
|
|
16071
|
+
el.setAttribute("data-ohw-map-query", val);
|
|
16072
|
+
}
|
|
15295
16073
|
function applyLinkByKey(key, val) {
|
|
15296
16074
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
15297
16075
|
if (el.dataset.ohwEditable === "link") applyLinkHref(el, val);
|
|
@@ -15302,6 +16080,11 @@ function applyLinkByKey(key, val) {
|
|
|
15302
16080
|
hrefAnchors.forEach((el) => applyLinkHref(el, val));
|
|
15303
16081
|
}
|
|
15304
16082
|
}
|
|
16083
|
+
function isInsideLinkEditor(target) {
|
|
16084
|
+
return Boolean(
|
|
16085
|
+
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"]')
|
|
16086
|
+
);
|
|
16087
|
+
}
|
|
15305
16088
|
function isInsideFloatingPanel(target) {
|
|
15306
16089
|
return Boolean(target.closest("[data-ohw-floating-panel]"));
|
|
15307
16090
|
}
|
|
@@ -15309,11 +16092,6 @@ function isPointOverFloatingPanel(clientX, clientY) {
|
|
|
15309
16092
|
const el = document.elementFromPoint(clientX, clientY);
|
|
15310
16093
|
return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
|
|
15311
16094
|
}
|
|
15312
|
-
function isInsideLinkEditor(target) {
|
|
15313
|
-
return Boolean(
|
|
15314
|
-
target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest("[data-ohw-footer-container-chrome]") || target.closest("[data-ohw-footer-add-button]") || target.closest("[data-ohw-more-menu]") || target.closest('[data-slot="dropdown-menu-content"]') || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
|
|
15315
|
-
);
|
|
15316
|
-
}
|
|
15317
16095
|
function getHrefKeyFromElement(el) {
|
|
15318
16096
|
if (!el) return null;
|
|
15319
16097
|
const anchor = el.closest("[data-ohw-href-key]");
|
|
@@ -15326,6 +16104,7 @@ function isNavDropdownPanelOpen(childrenRoot) {
|
|
|
15326
16104
|
if (childrenRoot.closest("[data-ohw-nav-drawer]")) return true;
|
|
15327
16105
|
const group = childrenRoot.closest("[data-ohw-nav-group]");
|
|
15328
16106
|
if (group?.hasAttribute("data-ohw-nav-force-open")) return true;
|
|
16107
|
+
if (navDropdownsOpenOnClick()) return false;
|
|
15329
16108
|
if (childrenRoot.clientHeight < 2 || childrenRoot.clientWidth < 2) return false;
|
|
15330
16109
|
const style = window.getComputedStyle(childrenRoot);
|
|
15331
16110
|
if (style.display === "none" || style.visibility === "hidden") return false;
|
|
@@ -15369,6 +16148,11 @@ function getNavigationItemAnchor(el) {
|
|
|
15369
16148
|
function isNavigationItem2(el) {
|
|
15370
16149
|
return getNavigationItemAnchor(el) !== null;
|
|
15371
16150
|
}
|
|
16151
|
+
function isNavFooterScopedNavigationItem(el) {
|
|
16152
|
+
return Boolean(
|
|
16153
|
+
el.closest("nav, footer, [data-ohw-nav-container], [data-ohw-nav-drawer]")
|
|
16154
|
+
);
|
|
16155
|
+
}
|
|
15372
16156
|
function socialWordsClicked(target, item) {
|
|
15373
16157
|
const text = target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
|
|
15374
16158
|
return Boolean(text && item.contains(text));
|
|
@@ -15572,13 +16356,14 @@ function getNavigationSelectionParent(el) {
|
|
|
15572
16356
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
15573
16357
|
return getFooterLinksContainer();
|
|
15574
16358
|
}
|
|
15575
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
16359
|
+
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isFooterLinksContainer(el) || isInferredFooterGroup2(el)) {
|
|
15576
16360
|
return getNavigationRoot(el);
|
|
15577
16361
|
}
|
|
15578
16362
|
return null;
|
|
15579
16363
|
}
|
|
15580
16364
|
function collectNavigationItemSiblingHintRects(selected) {
|
|
15581
16365
|
if (!isNavigationItem2(selected)) return [];
|
|
16366
|
+
if (!isNavFooterScopedNavigationItem(selected)) return [];
|
|
15582
16367
|
const socialsRow = findSocialsRow(selected);
|
|
15583
16368
|
if (socialsRow) {
|
|
15584
16369
|
return listSocialItems(socialsRow).filter((item) => item !== selected).map((item) => item.getBoundingClientRect());
|
|
@@ -15787,7 +16572,6 @@ var ICONS = {
|
|
|
15787
16572
|
insertUnorderedList: '<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>',
|
|
15788
16573
|
insertOrderedList: '<line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/>'
|
|
15789
16574
|
};
|
|
15790
|
-
var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
|
|
15791
16575
|
var SELECTION_CHROME_GAP2 = 4;
|
|
15792
16576
|
var TOOLBAR_STROKE_GAP2 = 4;
|
|
15793
16577
|
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
@@ -16167,6 +16951,7 @@ function StateToggle({
|
|
|
16167
16951
|
);
|
|
16168
16952
|
}
|
|
16169
16953
|
var contentCache = /* @__PURE__ */ new Map();
|
|
16954
|
+
var fetchedContentPaths = /* @__PURE__ */ new Set();
|
|
16170
16955
|
var brandingCache = /* @__PURE__ */ new Map();
|
|
16171
16956
|
var OHW_LOADER_STYLE = {
|
|
16172
16957
|
position: "fixed",
|
|
@@ -16696,13 +17481,6 @@ function OhhwellsBridge() {
|
|
|
16696
17481
|
const [isItemDragging, setIsItemDragging] = useState13(false);
|
|
16697
17482
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = useState13(false);
|
|
16698
17483
|
isFooterFrameSelectionRef.current = isFooterFrameSelection;
|
|
16699
|
-
const [floatingPanel, setFloatingPanel] = useState13(null);
|
|
16700
|
-
const floatingPanelOpenRef = useRef10(false);
|
|
16701
|
-
floatingPanelOpenRef.current = floatingPanel !== null;
|
|
16702
|
-
const [floatingPanelPos, setFloatingPanelPos] = useState13(null);
|
|
16703
|
-
const [logoSizeDraft, setLogoSizeDraft] = useState13(null);
|
|
16704
|
-
const [editorViewport, setEditorViewport] = useState13("desktop");
|
|
16705
|
-
const [parentScrollSnap, setParentScrollSnap] = useState13(null);
|
|
16706
17484
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState13(null);
|
|
16707
17485
|
const [footerHeadingVisible, setFooterHeadingVisible] = useState13(null);
|
|
16708
17486
|
const footerDragRef = useRef10(null);
|
|
@@ -16720,6 +17498,13 @@ function OhhwellsBridge() {
|
|
|
16720
17498
|
const brandKitRef = useRef10("");
|
|
16721
17499
|
const stylesRef = useRef10("");
|
|
16722
17500
|
const pendingDeleteUndoRef = useRef10(null);
|
|
17501
|
+
const [floatingPanel, setFloatingPanel] = useState13(null);
|
|
17502
|
+
const floatingPanelOpenRef = useRef10(false);
|
|
17503
|
+
const setFloatingPanelRef = useRef10(setFloatingPanel);
|
|
17504
|
+
const [floatingPanelPos, setFloatingPanelPos] = useState13(null);
|
|
17505
|
+
const [logoSizeDraft, setLogoSizeDraft] = useState13(null);
|
|
17506
|
+
const [editorViewport, setEditorViewport] = useState13("desktop");
|
|
17507
|
+
const [parentScrollSnap, setParentScrollSnap] = useState13(null);
|
|
16723
17508
|
const [sitePages, setSitePages] = useState13([]);
|
|
16724
17509
|
const [sectionsByPath, setSectionsByPath] = useState13({});
|
|
16725
17510
|
const sectionsPrefetchGenRef = useRef10(0);
|
|
@@ -16728,9 +17513,21 @@ function OhhwellsBridge() {
|
|
|
16728
17513
|
const linkPopoverOpenRef = useRef10(false);
|
|
16729
17514
|
const linkPopoverGraceUntilRef = useRef10(0);
|
|
16730
17515
|
setLinkPopoverRef.current = setLinkPopover;
|
|
17516
|
+
setFloatingPanelRef.current = setFloatingPanel;
|
|
16731
17517
|
linkPopoverSessionRef.current = linkPopover;
|
|
17518
|
+
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
17519
|
+
useEffect13(() => {
|
|
17520
|
+
const syncViewport = () => {
|
|
17521
|
+
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
17522
|
+
setEditorViewport((prev) => prev === next ? prev : next);
|
|
17523
|
+
};
|
|
17524
|
+
syncViewport();
|
|
17525
|
+
window.addEventListener("resize", syncViewport);
|
|
17526
|
+
return () => window.removeEventListener("resize", syncViewport);
|
|
17527
|
+
}, []);
|
|
16732
17528
|
const {
|
|
16733
17529
|
navDragRef,
|
|
17530
|
+
navPointerDragRef,
|
|
16734
17531
|
navDropSlots,
|
|
16735
17532
|
activeNavDropIndex,
|
|
16736
17533
|
startNavLinkDrag,
|
|
@@ -16933,7 +17730,12 @@ function OhhwellsBridge() {
|
|
|
16933
17730
|
if (owner) persistFieldsRef.current(owner);
|
|
16934
17731
|
}
|
|
16935
17732
|
activeElRef.current = null;
|
|
16936
|
-
|
|
17733
|
+
const preserveNavDropdown = Boolean(navPointerDragRef.current?.el?.closest("[data-ohw-nav-children]")) || Boolean(navDragRef.current?.draggedEl?.closest("[data-ohw-nav-children]")) || Boolean(
|
|
17734
|
+
selectedElRef.current?.closest("[data-ohw-nav-children]") && selectedElRef.current?.closest("[data-ohw-nav-group]")?.hasAttribute("data-ohw-nav-force-open")
|
|
17735
|
+
);
|
|
17736
|
+
if (!preserveNavDropdown) {
|
|
17737
|
+
setNavGroupForceOpen(null, false);
|
|
17738
|
+
}
|
|
16937
17739
|
setReorderHrefKey(null);
|
|
16938
17740
|
setReorderDragDisabled(false);
|
|
16939
17741
|
if (!selectedElRef.current) {
|
|
@@ -17055,7 +17857,10 @@ function OhhwellsBridge() {
|
|
|
17055
17857
|
setSelectedIsSocialsRow(false);
|
|
17056
17858
|
const isDropdownTrigger = !isNestedNavChild(navAnchor) && (navItemHasDropdownChildren(navAnchor) || navItemOwnsDropdownPanel(navAnchor));
|
|
17057
17859
|
if (isNestedNavChild(navAnchor)) {
|
|
17058
|
-
|
|
17860
|
+
const group = navAnchor.closest("[data-ohw-nav-group]");
|
|
17861
|
+
if (group?.hasAttribute("data-ohw-nav-force-open")) {
|
|
17862
|
+
setNavGroupForceOpen(navAnchor, true);
|
|
17863
|
+
}
|
|
17059
17864
|
setNavDropdownPreviewOpen(null);
|
|
17060
17865
|
} else if (isDropdownTrigger) {
|
|
17061
17866
|
const group = navAnchor.closest("[data-ohw-nav-group]");
|
|
@@ -17137,6 +17942,10 @@ function OhhwellsBridge() {
|
|
|
17137
17942
|
const handleNavDropdownOpenChange = useCallback8((open) => {
|
|
17138
17943
|
const selected = selectedElRef.current;
|
|
17139
17944
|
if (!selected || !isNavigationItem2(selected)) return;
|
|
17945
|
+
if (isNestedNavChild(selected)) return;
|
|
17946
|
+
const group = selected.closest("[data-ohw-nav-group]");
|
|
17947
|
+
const domOpen = Boolean(group?.hasAttribute("data-ohw-nav-force-open"));
|
|
17948
|
+
if (open === domOpen) return;
|
|
17140
17949
|
setNavGroupForceOpen(selected, open);
|
|
17141
17950
|
setNavDropdownPreviewOpen(open);
|
|
17142
17951
|
requestAnimationFrame(() => {
|
|
@@ -17666,7 +18475,10 @@ function OhhwellsBridge() {
|
|
|
17666
18475
|
clearHrefKeyHover(anchor);
|
|
17667
18476
|
const isDropdownTrigger = !isNestedNavChild(anchor) && (navItemHasDropdownChildren(anchor) || navItemOwnsDropdownPanel(anchor));
|
|
17668
18477
|
if (isNestedNavChild(anchor)) {
|
|
17669
|
-
|
|
18478
|
+
const group = anchor.closest("[data-ohw-nav-group]");
|
|
18479
|
+
if (group?.hasAttribute("data-ohw-nav-force-open")) {
|
|
18480
|
+
setNavGroupForceOpen(anchor, true);
|
|
18481
|
+
}
|
|
17670
18482
|
setNavDropdownPreviewOpen(null);
|
|
17671
18483
|
} else if (isDropdownTrigger) {
|
|
17672
18484
|
setNavGroupForceOpen(null, false);
|
|
@@ -18053,6 +18865,7 @@ function OhhwellsBridge() {
|
|
|
18053
18865
|
}
|
|
18054
18866
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
18055
18867
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
18868
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
18056
18869
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
18057
18870
|
}
|
|
18058
18871
|
applyBrandChrome(content);
|
|
@@ -18060,11 +18873,11 @@ function OhhwellsBridge() {
|
|
|
18060
18873
|
for (const [key, val] of Object.entries(content)) {
|
|
18061
18874
|
if (key === "__ohw_sections") continue;
|
|
18062
18875
|
if (key === AI_SECTIONS_KEY) continue;
|
|
18876
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18877
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18063
18878
|
if (key === BRAND_KIT_KEY) continue;
|
|
18064
18879
|
if (key === STYLE_STORE_KEY) continue;
|
|
18065
18880
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
18066
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18067
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18068
18881
|
if (applyVideoSettingNode(key, val)) continue;
|
|
18069
18882
|
if (applyCarouselNode(key, val)) continue;
|
|
18070
18883
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -18092,6 +18905,8 @@ function OhhwellsBridge() {
|
|
|
18092
18905
|
}
|
|
18093
18906
|
} else if (el.dataset.ohwEditable === "link") {
|
|
18094
18907
|
applyLinkHref(el, val);
|
|
18908
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
18909
|
+
applyMapQuery(el, val);
|
|
18095
18910
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
18096
18911
|
applyIconMarkup(el, val);
|
|
18097
18912
|
} else if (el.dataset.ohwEditable === "form") {
|
|
@@ -18130,7 +18945,9 @@ function OhhwellsBridge() {
|
|
|
18130
18945
|
let cancelled = false;
|
|
18131
18946
|
setFetchState("loading");
|
|
18132
18947
|
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
18133
|
-
|
|
18948
|
+
const initialPath = pathname;
|
|
18949
|
+
fetchedContentPaths.add(`${subdomain}::${initialPath}`);
|
|
18950
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
18134
18951
|
if (cancelled) return;
|
|
18135
18952
|
const content = data?.content ?? {};
|
|
18136
18953
|
const branding = Boolean(data?.showBranding);
|
|
@@ -18239,7 +19056,9 @@ function OhhwellsBridge() {
|
|
|
18239
19056
|
}, [isEditMode]);
|
|
18240
19057
|
useEffect13(() => {
|
|
18241
19058
|
if (isEditMode || fetchState !== "done") return;
|
|
19059
|
+
console.log("env", process.env.NEXT_PUBLIC_FLOWOPS_API_URL);
|
|
18242
19060
|
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
19061
|
+
console.log({ apiUrl, subdomain });
|
|
18243
19062
|
bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
|
|
18244
19063
|
}, [isEditMode, fetchState, subdomain]);
|
|
18245
19064
|
useEffect13(() => {
|
|
@@ -18249,10 +19068,10 @@ function OhhwellsBridge() {
|
|
|
18249
19068
|
const applyFromCache = () => {
|
|
18250
19069
|
const content = contentCache.get(subdomain);
|
|
18251
19070
|
if (!content) return;
|
|
18252
|
-
retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
|
|
18253
|
-
initSectionInstancesFromContent(content, window.location.pathname);
|
|
18254
19071
|
observer?.disconnect();
|
|
18255
19072
|
try {
|
|
19073
|
+
retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
|
|
19074
|
+
initSectionInstancesFromContent(content, window.location.pathname);
|
|
18256
19075
|
applyBrandChrome(content);
|
|
18257
19076
|
if (typeof content[BRAND_KIT_KEY] === "string") {
|
|
18258
19077
|
applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
|
|
@@ -18264,16 +19083,17 @@ function OhhwellsBridge() {
|
|
|
18264
19083
|
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
18265
19084
|
}
|
|
18266
19085
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
19086
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
18267
19087
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
18268
19088
|
}
|
|
18269
19089
|
for (const [key, val] of Object.entries(content)) {
|
|
18270
19090
|
if (key === "__ohw_sections") continue;
|
|
18271
19091
|
if (key === AI_SECTIONS_KEY) continue;
|
|
19092
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
19093
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18272
19094
|
if (key === BRAND_KIT_KEY) continue;
|
|
18273
19095
|
if (key === STYLE_STORE_KEY) continue;
|
|
18274
19096
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
18275
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18276
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18277
19097
|
if (applyVideoSettingNode(key, val)) continue;
|
|
18278
19098
|
if (applyCarouselNode(key, val)) continue;
|
|
18279
19099
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -18288,6 +19108,8 @@ function OhhwellsBridge() {
|
|
|
18288
19108
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
18289
19109
|
} else if (el.dataset.ohwEditable === "link") {
|
|
18290
19110
|
applyLinkHref(el, val);
|
|
19111
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
19112
|
+
applyMapQuery(el, val);
|
|
18291
19113
|
} else if (el.dataset.ohwEditable === "form") {
|
|
18292
19114
|
} else if (isIconMarkupValue(val)) {
|
|
18293
19115
|
} else if (el.innerHTML !== val) {
|
|
@@ -18319,6 +19141,17 @@ function OhhwellsBridge() {
|
|
|
18319
19141
|
debounceTimer = setTimeout(applyFromCache, 150);
|
|
18320
19142
|
};
|
|
18321
19143
|
applyFromCache();
|
|
19144
|
+
const pathCacheKey = `${subdomain}::${pathname}`;
|
|
19145
|
+
if (!fetchedContentPaths.has(pathCacheKey)) {
|
|
19146
|
+
fetchedContentPaths.add(pathCacheKey);
|
|
19147
|
+
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
19148
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
19149
|
+
if (!data?.content) return;
|
|
19150
|
+
contentCache.set(subdomain, data.content);
|
|
19151
|
+
applyFromCache();
|
|
19152
|
+
}).catch(() => {
|
|
19153
|
+
});
|
|
19154
|
+
}
|
|
18322
19155
|
observer = new MutationObserver(scheduleApply);
|
|
18323
19156
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
18324
19157
|
return () => {
|
|
@@ -18343,6 +19176,10 @@ function OhhwellsBridge() {
|
|
|
18343
19176
|
deselectRef.current();
|
|
18344
19177
|
deactivateRef.current();
|
|
18345
19178
|
}, [pathname, isEditMode]);
|
|
19179
|
+
useEffect13(() => {
|
|
19180
|
+
if (!isEditMode) return;
|
|
19181
|
+
initSectionInstancesFromContent(editContentRef.current, pathname);
|
|
19182
|
+
}, [pathname, isEditMode]);
|
|
18346
19183
|
useEffect13(() => {
|
|
18347
19184
|
const contentForNav = () => {
|
|
18348
19185
|
if (isEditMode) return editContentRef.current;
|
|
@@ -18434,26 +19271,11 @@ function OhhwellsBridge() {
|
|
|
18434
19271
|
const t2 = setTimeout(measure, 500);
|
|
18435
19272
|
const ro = new ResizeObserver(schedule);
|
|
18436
19273
|
ro.observe(document.body);
|
|
18437
|
-
let lastWidth = window.innerWidth;
|
|
18438
|
-
let resizeTimers = [];
|
|
18439
|
-
const clearResizeTimers = () => {
|
|
18440
|
-
resizeTimers.forEach(clearTimeout);
|
|
18441
|
-
resizeTimers = [];
|
|
18442
|
-
};
|
|
18443
|
-
const handleResize = () => {
|
|
18444
|
-
if (window.innerWidth === lastWidth) return;
|
|
18445
|
-
lastWidth = window.innerWidth;
|
|
18446
|
-
clearResizeTimers();
|
|
18447
|
-
resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
|
|
18448
|
-
};
|
|
18449
|
-
window.addEventListener("resize", handleResize);
|
|
18450
19274
|
return () => {
|
|
18451
19275
|
clearTimeout(t1);
|
|
18452
19276
|
clearTimeout(t2);
|
|
18453
19277
|
if (raf != null) cancelAnimationFrame(raf);
|
|
18454
19278
|
ro.disconnect();
|
|
18455
|
-
clearResizeTimers();
|
|
18456
|
-
window.removeEventListener("resize", handleResize);
|
|
18457
19279
|
};
|
|
18458
19280
|
}, [pathname, isEditMode, postToParent2]);
|
|
18459
19281
|
useEffect13(() => {
|
|
@@ -18484,28 +19306,19 @@ function OhhwellsBridge() {
|
|
|
18484
19306
|
return;
|
|
18485
19307
|
}
|
|
18486
19308
|
const existing = editStylesRef.current;
|
|
18487
|
-
|
|
18488
|
-
if (existing?.base.textContent) {
|
|
18489
|
-
const match = existing.base.textContent.match(/\.min-h-screen[^{]*\{[^}]*min-height:\s*(\d+)px/);
|
|
18490
|
-
if (match) initialVh = parseInt(match[1], 10);
|
|
18491
|
-
}
|
|
19309
|
+
const canvasHeight = "var(--ohw-canvas-h, 852px)";
|
|
18492
19310
|
const baseCss = `
|
|
18493
19311
|
html { height: auto !important; }
|
|
18494
19312
|
body { height: auto !important; min-height: 0 !important; overflow: hidden !important; }
|
|
18495
|
-
.min-h-screen, .min-h-svh, .min-h-dvh { min-height: ${
|
|
18496
|
-
.h-screen, .h-svh, .h-dvh { height: ${
|
|
18497
|
-
|
|
18498
|
-
|
|
18499
|
-
[style*="
|
|
18500
|
-
|
|
18501
|
-
|
|
18502
|
-
|
|
18503
|
-
|
|
18504
|
-
so content taller than one screen (a long mobile hero, say) overflows a centered flex
|
|
18505
|
-
column upward, under whatever sits above it. Only the min-height half belongs to it. */
|
|
18506
|
-
[style*="min-height"][style*="100vh"],
|
|
18507
|
-
[style*="min-height"][style*="100svh"],
|
|
18508
|
-
[style*="min-height"][style*="100dvh"] { height: auto !important; }
|
|
19313
|
+
.min-h-screen, .min-h-svh, .min-h-dvh { min-height: ${canvasHeight} !important; }
|
|
19314
|
+
.h-screen, .h-svh, .h-dvh { height: ${canvasHeight} !important; }
|
|
19315
|
+
/* Literal inline viewport units only \u2014 skip R11 sections that already reference --ohw-canvas-h
|
|
19316
|
+
(their style attribute contains "100svh" only as a var() fallback string). */
|
|
19317
|
+
[style*="100vh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
|
|
19318
|
+
[style*="100svh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
|
|
19319
|
+
[style*="100dvh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
|
|
19320
|
+
/* R11: min-height via --ohw-canvas-h; height must grow with content taller than one screen. */
|
|
19321
|
+
[style*="min-height"][style*="--ohw-canvas-h"] { height: auto !important; }
|
|
18509
19322
|
/* Emptied text keeps somewhere to click. A label typed down to nothing collapses to a
|
|
18510
19323
|
couple of pixels, and getting back into it meant hunting for the caret with the mouse.
|
|
18511
19324
|
Edit mode only \u2014 the published page shows nothing where there is nothing (OHH-736). */
|
|
@@ -18652,6 +19465,10 @@ function OhhwellsBridge() {
|
|
|
18652
19465
|
outline-offset: 0 !important;
|
|
18653
19466
|
box-shadow: none !important;
|
|
18654
19467
|
}
|
|
19468
|
+
/* Open nav dropdown panels paint above AI section selection chrome (2147483000). */
|
|
19469
|
+
[data-ohw-nav-group][data-ohw-nav-force-open] > [data-ohw-nav-children] {
|
|
19470
|
+
z-index: 2147483100 !important;
|
|
19471
|
+
}
|
|
18655
19472
|
/* Text edit wins over grab/default (must beat [data-ohw-can-drag] *). */
|
|
18656
19473
|
[data-ohw-editing],
|
|
18657
19474
|
[data-ohw-editing] *,
|
|
@@ -18708,9 +19525,6 @@ function OhhwellsBridge() {
|
|
|
18708
19525
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
18709
19526
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
18710
19527
|
if (isInsideLinkEditor(target)) return;
|
|
18711
|
-
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
18712
|
-
clearMediaSelectionRef.current();
|
|
18713
|
-
}
|
|
18714
19528
|
if (isInsideFloatingPanel(target)) return;
|
|
18715
19529
|
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
18716
19530
|
if (target.closest(
|
|
@@ -18718,6 +19532,9 @@ function OhhwellsBridge() {
|
|
|
18718
19532
|
)) {
|
|
18719
19533
|
return;
|
|
18720
19534
|
}
|
|
19535
|
+
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
19536
|
+
clearMediaSelectionRef.current();
|
|
19537
|
+
}
|
|
18721
19538
|
{
|
|
18722
19539
|
const formEl = getFormElement(target);
|
|
18723
19540
|
const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
|
|
@@ -18869,14 +19686,6 @@ function OhhwellsBridge() {
|
|
|
18869
19686
|
}
|
|
18870
19687
|
const clickedButton = findClosestButtonLike(target);
|
|
18871
19688
|
const buttonOnMedia = Boolean(clickedButton && isMediaEditable(editable) && editable.contains(clickedButton));
|
|
18872
|
-
console.log("[click-debug]", {
|
|
18873
|
-
editableType: editable.dataset.ohwEditable,
|
|
18874
|
-
editableTag: editable.tagName,
|
|
18875
|
-
targetTag: target.tagName,
|
|
18876
|
-
clickedButtonTag: clickedButton?.tagName ?? null,
|
|
18877
|
-
buttonOnMedia,
|
|
18878
|
-
isMediaEditableEditable: isMediaEditable(editable)
|
|
18879
|
-
});
|
|
18880
19689
|
if (isMediaEditable(editable) && !buttonOnMedia) {
|
|
18881
19690
|
e.preventDefault();
|
|
18882
19691
|
e.stopPropagation();
|
|
@@ -18903,11 +19712,6 @@ function OhhwellsBridge() {
|
|
|
18903
19712
|
const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
|
|
18904
19713
|
const hrefCtx = getHrefKeyFromElement(hrefLookupTarget);
|
|
18905
19714
|
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
18906
|
-
console.log("[click-debug 2]", {
|
|
18907
|
-
hrefLookupTargetTag: hrefLookupTarget.tagName,
|
|
18908
|
-
hrefCtx: hrefCtx ? { key: hrefCtx.key } : null,
|
|
18909
|
-
navAnchorTag: navAnchor?.tagName ?? null
|
|
18910
|
-
});
|
|
18911
19715
|
if (navAnchor) {
|
|
18912
19716
|
e.preventDefault();
|
|
18913
19717
|
e.stopPropagation();
|
|
@@ -19077,6 +19881,9 @@ function OhhwellsBridge() {
|
|
|
19077
19881
|
setHoveredItemRect(null);
|
|
19078
19882
|
hoveredNavContainerRef.current = null;
|
|
19079
19883
|
setHoveredNavContainerRect(null);
|
|
19884
|
+
siblingHintElRef.current = null;
|
|
19885
|
+
setSiblingHintRect(null);
|
|
19886
|
+
setSiblingHintRects([]);
|
|
19080
19887
|
return;
|
|
19081
19888
|
}
|
|
19082
19889
|
{
|
|
@@ -19195,7 +20002,6 @@ function OhhwellsBridge() {
|
|
|
19195
20002
|
hoveredNavContainerRef.current = null;
|
|
19196
20003
|
setHoveredNavContainerRect(null);
|
|
19197
20004
|
hoveredItemElRef.current = editable;
|
|
19198
|
-
setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
|
|
19199
20005
|
}
|
|
19200
20006
|
}
|
|
19201
20007
|
}
|
|
@@ -19492,7 +20298,7 @@ function OhhwellsBridge() {
|
|
|
19492
20298
|
}
|
|
19493
20299
|
};
|
|
19494
20300
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
19495
|
-
if (linkPopoverOpenRef.current) {
|
|
20301
|
+
if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
19496
20302
|
if (hoveredImageRef.current) {
|
|
19497
20303
|
hoveredImageRef.current = null;
|
|
19498
20304
|
hoveredImageHasTextOverlapRef.current = false;
|
|
@@ -19857,8 +20663,7 @@ function OhhwellsBridge() {
|
|
|
19857
20663
|
};
|
|
19858
20664
|
const handleMouseMove = (e) => {
|
|
19859
20665
|
const { clientX, clientY } = e;
|
|
19860
|
-
if (
|
|
19861
|
-
if (isOverEditorChrome(clientX, clientY)) {
|
|
20666
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
|
|
19862
20667
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
19863
20668
|
formHoverElRef.current = null;
|
|
19864
20669
|
setFormHoverRect(null);
|
|
@@ -19866,6 +20671,12 @@ function OhhwellsBridge() {
|
|
|
19866
20671
|
setHoveredItemRect(null);
|
|
19867
20672
|
hoveredNavContainerRef.current = null;
|
|
19868
20673
|
setHoveredNavContainerRect(null);
|
|
20674
|
+
siblingHintElRef.current = null;
|
|
20675
|
+
setSiblingHintRect(null);
|
|
20676
|
+
setSiblingHintRects([]);
|
|
20677
|
+
dismissImageHover();
|
|
20678
|
+
clearImageHover();
|
|
20679
|
+
setSectionGap(null);
|
|
19869
20680
|
return;
|
|
19870
20681
|
}
|
|
19871
20682
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
@@ -19877,7 +20688,11 @@ function OhhwellsBridge() {
|
|
|
19877
20688
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
19878
20689
|
const { clientX, clientY } = e.data;
|
|
19879
20690
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
19880
|
-
if (
|
|
20691
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
20692
|
+
dismissImageHover();
|
|
20693
|
+
clearImageHover();
|
|
20694
|
+
return;
|
|
20695
|
+
}
|
|
19881
20696
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
19882
20697
|
probeSectionGapAt(clientX, clientY);
|
|
19883
20698
|
probeImageAt(clientX, clientY);
|
|
@@ -19991,7 +20806,11 @@ function OhhwellsBridge() {
|
|
|
19991
20806
|
const slotFromItem = hrefKey ? findSocialByHrefKey(hrefKey)?.querySelector('[data-ohw-editable="icon"]') : null;
|
|
19992
20807
|
const requestedIsIconSlot = Boolean(requestedIconKey) && Boolean(document.querySelector(`[data-ohw-key="${requestedIconKey}"][data-ohw-editable="icon"]`));
|
|
19993
20808
|
const requestedIsFree = Boolean(requestedIconKey) && !document.querySelector(`[data-ohw-key="${requestedIconKey}"]`);
|
|
19994
|
-
|
|
20809
|
+
let iconKey = requestedIsIconSlot ? requestedIconKey : slotFromItem?.dataset.ohwKey ?? (requestedIsFree ? requestedIconKey : void 0);
|
|
20810
|
+
const item = hrefKey ? findSocialByHrefKey(hrefKey) : null;
|
|
20811
|
+
if (item && typeof iconMarkup === "string" && iconMarkup) {
|
|
20812
|
+
iconKey = ensureIconSlot(item) ?? iconKey;
|
|
20813
|
+
}
|
|
19995
20814
|
if (iconKey && typeof iconMarkup === "string" && iconMarkup) {
|
|
19996
20815
|
document.querySelectorAll(`[data-ohw-key="${iconKey}"][data-ohw-editable="icon"]`).forEach((el) => {
|
|
19997
20816
|
applyIconMarkup(el, iconMarkup);
|
|
@@ -20001,7 +20820,7 @@ function OhhwellsBridge() {
|
|
|
20001
20820
|
}
|
|
20002
20821
|
if (iconKey && platformId) nodes.push({ key: socialPlatformKey(iconKey), text: platformId });
|
|
20003
20822
|
if (iconKey && label) {
|
|
20004
|
-
const labelKey = socialLabelKey(iconKey);
|
|
20823
|
+
const labelKey = (item ? socialLabelElement(item)?.getAttribute("data-ohw-key") : null) ?? socialLabelKey(iconKey);
|
|
20005
20824
|
document.querySelectorAll(`[data-ohw-key="${labelKey}"]`).forEach((el) => {
|
|
20006
20825
|
if (keepLabel && el.textContent?.trim()) return;
|
|
20007
20826
|
el.textContent = label;
|
|
@@ -20156,6 +20975,44 @@ function OhhwellsBridge() {
|
|
|
20156
20975
|
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
20157
20976
|
}, 400));
|
|
20158
20977
|
};
|
|
20978
|
+
const reapCommittedAiSections = (excludeIds) => {
|
|
20979
|
+
const aiState = parseAiSectionsState(aiSectionsRef.current);
|
|
20980
|
+
if (aiState.sections.length === 0) return [];
|
|
20981
|
+
let orderEntries = [];
|
|
20982
|
+
try {
|
|
20983
|
+
const parsed = JSON.parse(editContentRef.current[SECTION_ORDER_KEY] ?? "[]");
|
|
20984
|
+
if (Array.isArray(parsed)) orderEntries = parsed;
|
|
20985
|
+
} catch {
|
|
20986
|
+
return [];
|
|
20987
|
+
}
|
|
20988
|
+
const removedIds = orderEntries.filter((entry) => entry && typeof entry.instanceId === "string" && entry.removed).map((entry) => entry.instanceId);
|
|
20989
|
+
if (removedIds.length === 0) return [];
|
|
20990
|
+
const result = reapRemovedAiSections(aiState, parseStyleStore(stylesRef.current), removedIds, excludeIds);
|
|
20991
|
+
if (!result.changed) return [];
|
|
20992
|
+
const nodes = [];
|
|
20993
|
+
aiSectionsRef.current = serializeAiSectionsState(result.state);
|
|
20994
|
+
nodes.push({ key: AI_SECTIONS_KEY, text: aiSectionsRef.current });
|
|
20995
|
+
const reaped = new Set(result.reapedIds);
|
|
20996
|
+
const nextOrderJson = JSON.stringify(orderEntries.filter((entry) => !reaped.has(entry.instanceId)));
|
|
20997
|
+
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: nextOrderJson };
|
|
20998
|
+
setAiSectionOrder(nextOrderJson, window.location.pathname);
|
|
20999
|
+
nodes.push({ key: SECTION_ORDER_KEY, text: nextOrderJson });
|
|
21000
|
+
if (result.store) {
|
|
21001
|
+
stylesRef.current = JSON.stringify(result.store);
|
|
21002
|
+
nodes.push({ key: STYLE_STORE_KEY, text: stylesRef.current });
|
|
21003
|
+
}
|
|
21004
|
+
const nextContent = { ...editContentRef.current };
|
|
21005
|
+
for (const key of Object.keys(nextContent)) {
|
|
21006
|
+
if (key.startsWith(AI_SLOT_KEY_PREFIX) && result.slotPrefixes.some((prefix) => key.startsWith(prefix)) && nextContent[key] !== "") {
|
|
21007
|
+
nextContent[key] = "";
|
|
21008
|
+
nodes.push({ key, text: "" });
|
|
21009
|
+
}
|
|
21010
|
+
}
|
|
21011
|
+
editContentRef.current = nextContent;
|
|
21012
|
+
applyAiSectionsToDom(result.state);
|
|
21013
|
+
applyStylesToDom(parseStyleStore(stylesRef.current));
|
|
21014
|
+
return nodes;
|
|
21015
|
+
};
|
|
20159
21016
|
const handleHydrate = (e) => {
|
|
20160
21017
|
if (e.data?.type !== "ow:hydrate") return;
|
|
20161
21018
|
const content = e.data.content;
|
|
@@ -20174,6 +21031,7 @@ function OhhwellsBridge() {
|
|
|
20174
21031
|
}
|
|
20175
21032
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
20176
21033
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
21034
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
20177
21035
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
20178
21036
|
}
|
|
20179
21037
|
applyBrandChrome(content);
|
|
@@ -20185,11 +21043,11 @@ function OhhwellsBridge() {
|
|
|
20185
21043
|
continue;
|
|
20186
21044
|
}
|
|
20187
21045
|
if (key === AI_SECTIONS_KEY) continue;
|
|
21046
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
21047
|
+
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
20188
21048
|
if (key === BRAND_KIT_KEY) continue;
|
|
20189
21049
|
if (key === STYLE_STORE_KEY) continue;
|
|
20190
21050
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
20191
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
20192
|
-
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
20193
21051
|
if (applyVideoSettingNode(key, val)) continue;
|
|
20194
21052
|
if (applyCarouselNode(key, val)) continue;
|
|
20195
21053
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -20203,6 +21061,8 @@ function OhhwellsBridge() {
|
|
|
20203
21061
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
20204
21062
|
} else if (el.dataset.ohwEditable === "link") {
|
|
20205
21063
|
applyLinkHref(el, val);
|
|
21064
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
21065
|
+
applyMapQuery(el, val);
|
|
20206
21066
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
20207
21067
|
applyIconMarkup(el, val);
|
|
20208
21068
|
} else if (isIconMarkupValue(val)) {
|
|
@@ -20224,8 +21084,16 @@ function OhhwellsBridge() {
|
|
|
20224
21084
|
reconcileFooterOrderFromContent(editContentRef.current);
|
|
20225
21085
|
syncNavigationDragCursorAttrs();
|
|
20226
21086
|
enforceLinkHrefs();
|
|
21087
|
+
const hydrateReapExclude = /* @__PURE__ */ new Set();
|
|
21088
|
+
const hydratePendingUndo = pendingDeleteUndoRef.current;
|
|
21089
|
+
if (hydratePendingUndo?.sectionInstanceId) hydrateReapExclude.add(hydratePendingUndo.sectionInstanceId);
|
|
21090
|
+
const reapNodes = reapCommittedAiSections(hydrateReapExclude);
|
|
21091
|
+
if (reapNodes.length > 0) postToParentRef.current({ type: "ow:change", nodes: reapNodes });
|
|
20227
21092
|
const hydratedHeight = document.body.scrollHeight;
|
|
20228
21093
|
if (hydratedHeight > 50) postToParentRef.current({ type: "ow:height", height: hydratedHeight });
|
|
21094
|
+
if (parseAiSectionsState(aiSectionsRef.current).sections.length > 0) {
|
|
21095
|
+
postAiSectionsChanged();
|
|
21096
|
+
}
|
|
20229
21097
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
20230
21098
|
};
|
|
20231
21099
|
const handleUpdateLogoIdentity = (e) => {
|
|
@@ -20397,10 +21265,26 @@ function OhhwellsBridge() {
|
|
|
20397
21265
|
const handleGetBrand = (e) => {
|
|
20398
21266
|
if (e.data?.type !== "ow:get-brand") return;
|
|
20399
21267
|
const template = deriveTemplateBrand();
|
|
20400
|
-
const
|
|
21268
|
+
const fallback = template ?? (() => {
|
|
21269
|
+
const fonts = deriveTemplateFonts();
|
|
21270
|
+
return fonts ? { palette: AI_DEFAULT_BRAND.palette, fonts } : null;
|
|
21271
|
+
})();
|
|
21272
|
+
const value = brandKitRef.current || (fallback ? JSON.stringify(fallback) : "");
|
|
20401
21273
|
postToParentRef.current({ type: "ow:brand-value", value });
|
|
20402
21274
|
};
|
|
20403
21275
|
window.addEventListener("message", handleGetBrand);
|
|
21276
|
+
const handleGetTemplateFonts = (e) => {
|
|
21277
|
+
if (e.data?.type !== "ow:get-template-fonts") return;
|
|
21278
|
+
const fonts = deriveTemplateFonts();
|
|
21279
|
+
postToParentRef.current({ type: "ow:template-fonts-value", value: fonts ? JSON.stringify(fonts) : "" });
|
|
21280
|
+
};
|
|
21281
|
+
window.addEventListener("message", handleGetTemplateFonts);
|
|
21282
|
+
const handleGetTemplateBrand = (e) => {
|
|
21283
|
+
if (e.data?.type !== "ow:get-template-brand") return;
|
|
21284
|
+
const brand = deriveTemplateBrand();
|
|
21285
|
+
postToParentRef.current({ type: "ow:template-brand-value", value: brand ? JSON.stringify(brand) : "" });
|
|
21286
|
+
};
|
|
21287
|
+
window.addEventListener("message", handleGetTemplateBrand);
|
|
20404
21288
|
const handleMoveSection = (e) => {
|
|
20405
21289
|
if (e.data?.type !== "ow:move-section") return;
|
|
20406
21290
|
const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
|
|
@@ -20408,8 +21292,11 @@ function OhhwellsBridge() {
|
|
|
20408
21292
|
if (!instanceId || !direction) return;
|
|
20409
21293
|
const entries = moveSectionInstance(instanceId, direction, window.location.pathname);
|
|
20410
21294
|
if (!entries) return;
|
|
20411
|
-
const orderJson = JSON.stringify(
|
|
21295
|
+
const orderJson = JSON.stringify(
|
|
21296
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
21297
|
+
);
|
|
20412
21298
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
21299
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
20413
21300
|
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20414
21301
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
20415
21302
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20455,8 +21342,11 @@ function OhhwellsBridge() {
|
|
|
20455
21342
|
const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname);
|
|
20456
21343
|
const entries = deleteSectionInstance(instanceId, window.location.pathname, currentEntries);
|
|
20457
21344
|
if (!entries) return;
|
|
20458
|
-
const orderJson = JSON.stringify(
|
|
21345
|
+
const orderJson = JSON.stringify(
|
|
21346
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
21347
|
+
);
|
|
20459
21348
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
21349
|
+
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20460
21350
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
20461
21351
|
aiSectionApiRef.current?.clear();
|
|
20462
21352
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20465,6 +21355,7 @@ function OhhwellsBridge() {
|
|
|
20465
21355
|
const actionId = newInstanceId();
|
|
20466
21356
|
pendingDeleteUndoRef.current = {
|
|
20467
21357
|
actionId,
|
|
21358
|
+
sectionInstanceId: instanceId,
|
|
20468
21359
|
restore: () => {
|
|
20469
21360
|
const restoredEntries = getPageSectionOrderEntries(
|
|
20470
21361
|
editContentRef.current[SECTION_ORDER_KEY],
|
|
@@ -20472,8 +21363,11 @@ function OhhwellsBridge() {
|
|
|
20472
21363
|
);
|
|
20473
21364
|
const restored = restoreSectionInstance(instanceId, window.location.pathname, restoredEntries);
|
|
20474
21365
|
if (!restored) return;
|
|
20475
|
-
const restoredJson = JSON.stringify(
|
|
21366
|
+
const restoredJson = JSON.stringify(
|
|
21367
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, restored)
|
|
21368
|
+
);
|
|
20476
21369
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: restoredJson };
|
|
21370
|
+
setAiSectionOrder(restoredJson, window.location.pathname);
|
|
20477
21371
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: restoredJson }] });
|
|
20478
21372
|
window.dispatchEvent(new Event("resize"));
|
|
20479
21373
|
const restoreHeight = document.body.scrollHeight;
|
|
@@ -20499,7 +21393,9 @@ function OhhwellsBridge() {
|
|
|
20499
21393
|
const result = duplicateSectionInstance(instanceId, newId, window.location.pathname, currentEntries);
|
|
20500
21394
|
if (!result) return;
|
|
20501
21395
|
const { entries, keyRekeys } = result;
|
|
20502
|
-
const orderJson = JSON.stringify(
|
|
21396
|
+
const orderJson = JSON.stringify(
|
|
21397
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
21398
|
+
);
|
|
20503
21399
|
const nodes = [{ key: SECTION_ORDER_KEY, text: orderJson }];
|
|
20504
21400
|
for (const { from, to } of keyRekeys) {
|
|
20505
21401
|
const inherited = editContentRef.current[from];
|
|
@@ -20509,6 +21405,7 @@ function OhhwellsBridge() {
|
|
|
20509
21405
|
...editContentRef.current,
|
|
20510
21406
|
...Object.fromEntries(nodes.map(({ key, text }) => [key, text]))
|
|
20511
21407
|
};
|
|
21408
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
20512
21409
|
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20513
21410
|
postToParentRef.current({ type: "ow:change", nodes });
|
|
20514
21411
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20527,6 +21424,12 @@ function OhhwellsBridge() {
|
|
|
20527
21424
|
closeLinkPopoverRef.current();
|
|
20528
21425
|
return;
|
|
20529
21426
|
}
|
|
21427
|
+
if (floatingPanelOpenRef.current) {
|
|
21428
|
+
setFloatingPanelRef.current(null);
|
|
21429
|
+
deselectRef.current();
|
|
21430
|
+
deactivateRef.current();
|
|
21431
|
+
return;
|
|
21432
|
+
}
|
|
20530
21433
|
deselectRef.current();
|
|
20531
21434
|
deactivateRef.current();
|
|
20532
21435
|
clearMediaSelectionRef.current();
|
|
@@ -20759,7 +21662,12 @@ function OhhwellsBridge() {
|
|
|
20759
21662
|
}
|
|
20760
21663
|
if (navDragRef.current) {
|
|
20761
21664
|
const session = navDragRef.current;
|
|
20762
|
-
const slot = hitTestNavDropSlot(
|
|
21665
|
+
const slot = hitTestNavDropSlot(
|
|
21666
|
+
session.lastClientX,
|
|
21667
|
+
session.lastClientY,
|
|
21668
|
+
session.hrefKey,
|
|
21669
|
+
session.draggedEl
|
|
21670
|
+
);
|
|
20763
21671
|
refreshNavDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
|
|
20764
21672
|
}
|
|
20765
21673
|
if (hoveredImageRef.current) {
|
|
@@ -20772,6 +21680,10 @@ function OhhwellsBridge() {
|
|
|
20772
21680
|
};
|
|
20773
21681
|
const handleSave = (e) => {
|
|
20774
21682
|
if (e.data?.type !== "ow:save") return;
|
|
21683
|
+
const pendingUndo = pendingDeleteUndoRef.current;
|
|
21684
|
+
const reapExclude = /* @__PURE__ */ new Set();
|
|
21685
|
+
if (pendingUndo?.sectionInstanceId) reapExclude.add(pendingUndo.sectionInstanceId);
|
|
21686
|
+
const reapNodes = reapCommittedAiSections(reapExclude);
|
|
20775
21687
|
const nodes = collectEditableNodes(editContentRef.current);
|
|
20776
21688
|
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
20777
21689
|
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
@@ -20791,6 +21703,11 @@ function OhhwellsBridge() {
|
|
|
20791
21703
|
const text = specs.length ? JSON.stringify(specs) : editContentRef.current[fieldsKey(formKey)];
|
|
20792
21704
|
if (text) nodes.push({ key: fieldsKey(formKey), type: "text", text });
|
|
20793
21705
|
});
|
|
21706
|
+
for (const reapNode of reapNodes) {
|
|
21707
|
+
if (reapNode.key.startsWith(AI_SLOT_KEY_PREFIX) && !nodes.some((n) => n.key === reapNode.key)) {
|
|
21708
|
+
nodes.push({ key: reapNode.key, type: "text", text: reapNode.text });
|
|
21709
|
+
}
|
|
21710
|
+
}
|
|
20794
21711
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
20795
21712
|
};
|
|
20796
21713
|
const handleInsertSection = (e) => {
|
|
@@ -20801,8 +21718,12 @@ function OhhwellsBridge() {
|
|
|
20801
21718
|
if (inserted) {
|
|
20802
21719
|
const tracker = getSectionsTracker();
|
|
20803
21720
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
|
|
20804
|
-
const
|
|
20805
|
-
|
|
21721
|
+
const reportHeight = () => {
|
|
21722
|
+
const h = document.body.scrollHeight;
|
|
21723
|
+
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
21724
|
+
};
|
|
21725
|
+
reportHeight();
|
|
21726
|
+
setTimeout(reportHeight, 500);
|
|
20806
21727
|
}
|
|
20807
21728
|
};
|
|
20808
21729
|
const handleSwitchSchedule = (e) => {
|
|
@@ -20952,18 +21873,21 @@ function OhhwellsBridge() {
|
|
|
20952
21873
|
}
|
|
20953
21874
|
return null;
|
|
20954
21875
|
};
|
|
21876
|
+
const isPointInRect = (el, clientX, clientY) => {
|
|
21877
|
+
const r2 = el.getBoundingClientRect();
|
|
21878
|
+
return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
|
|
21879
|
+
};
|
|
20955
21880
|
const isPointOverEditable = (scope, clientX, clientY) => {
|
|
20956
21881
|
const editables = scope.querySelectorAll("[data-ohw-editable], [data-ohw-href-key]");
|
|
20957
21882
|
for (const el of editables) {
|
|
20958
|
-
|
|
20959
|
-
if (clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom) return true;
|
|
21883
|
+
if (isPointInRect(el, clientX, clientY)) return true;
|
|
20960
21884
|
}
|
|
20961
21885
|
return false;
|
|
20962
21886
|
};
|
|
20963
21887
|
const handleCarouselHover = (e) => {
|
|
20964
21888
|
const container = findCarouselAtPoint(e.clientX, e.clientY);
|
|
20965
21889
|
const scope = container?.closest("[data-ohw-section]") ?? container?.parentElement ?? null;
|
|
20966
|
-
if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY)) {
|
|
21890
|
+
if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY) || isPointOverNavigation(e.clientX, e.clientY) || isPointOverBridgeChrome(e.clientX, e.clientY)) {
|
|
20967
21891
|
setCarouselHover((prev) => prev ? null : prev);
|
|
20968
21892
|
return;
|
|
20969
21893
|
}
|
|
@@ -21201,15 +22125,17 @@ function OhhwellsBridge() {
|
|
|
21201
22125
|
window.removeEventListener("message", handleAiSetBrand);
|
|
21202
22126
|
window.removeEventListener("message", handleAiSetStyles);
|
|
21203
22127
|
window.removeEventListener("message", handleGetBrand);
|
|
22128
|
+
window.removeEventListener("message", handleGetTemplateFonts);
|
|
22129
|
+
window.removeEventListener("message", handleGetTemplateBrand);
|
|
21204
22130
|
window.removeEventListener("message", handleMoveSection);
|
|
21205
22131
|
window.removeEventListener("message", handlePanelDragging);
|
|
21206
22132
|
window.removeEventListener("message", handleDeleteSection);
|
|
21207
22133
|
window.removeEventListener("message", handleDuplicateSection);
|
|
21208
22134
|
window.removeEventListener("message", handleDeactivate);
|
|
21209
|
-
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
21210
22135
|
window.removeEventListener("message", handleToastAction);
|
|
21211
22136
|
window.removeEventListener("message", handleFormCount);
|
|
21212
22137
|
window.removeEventListener("message", handleUiEscape);
|
|
22138
|
+
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
21213
22139
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
21214
22140
|
autoSaveTimers.current.clear();
|
|
21215
22141
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
@@ -21412,7 +22338,7 @@ function OhhwellsBridge() {
|
|
|
21412
22338
|
postToParent2({
|
|
21413
22339
|
type: "ow:ready",
|
|
21414
22340
|
version: "1",
|
|
21415
|
-
bridgeVersion: "0.1.
|
|
22341
|
+
bridgeVersion: "0.1.93",
|
|
21416
22342
|
path: pathname,
|
|
21417
22343
|
nodes: collectEditableNodes(editContentRef.current),
|
|
21418
22344
|
sections
|
|
@@ -22028,7 +22954,7 @@ function OhhwellsBridge() {
|
|
|
22028
22954
|
"span",
|
|
22029
22955
|
{
|
|
22030
22956
|
"data-ohw-form-count": "",
|
|
22031
|
-
className: "ml-0.5 inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-primary px-1.5 text-[11px] font-semibold text-primary-foreground",
|
|
22957
|
+
className: "ml-0.5 inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-bridge-primary px-1.5 text-[11px] font-semibold text-primary-foreground",
|
|
22032
22958
|
children: formPickCount
|
|
22033
22959
|
}
|
|
22034
22960
|
)
|
|
@@ -22265,11 +23191,11 @@ function OhhwellsBridge() {
|
|
|
22265
23191
|
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
22266
23192
|
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
22267
23193
|
children: [
|
|
22268
|
-
/* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
23194
|
+
/* @__PURE__ */ jsx33("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } }),
|
|
22269
23195
|
/* @__PURE__ */ jsx33(
|
|
22270
23196
|
Badge,
|
|
22271
23197
|
{
|
|
22272
|
-
className: "px-8 py-1 bg-primary hover:bg-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
|
|
23198
|
+
className: "px-8 py-1 bg-bridge-primary hover:bg-bridge-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
|
|
22273
23199
|
onClick: () => {
|
|
22274
23200
|
window.parent.postMessage(
|
|
22275
23201
|
{
|
|
@@ -22283,7 +23209,7 @@ function OhhwellsBridge() {
|
|
|
22283
23209
|
children: "Add Section"
|
|
22284
23210
|
}
|
|
22285
23211
|
),
|
|
22286
|
-
/* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
23212
|
+
/* @__PURE__ */ jsx33("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } })
|
|
22287
23213
|
]
|
|
22288
23214
|
}
|
|
22289
23215
|
),
|
|
@@ -22331,6 +23257,59 @@ function OhhwellsBridge() {
|
|
|
22331
23257
|
) : null
|
|
22332
23258
|
] });
|
|
22333
23259
|
}
|
|
23260
|
+
|
|
23261
|
+
// src/ui/EmptySection.tsx
|
|
23262
|
+
import Link3 from "next/link";
|
|
23263
|
+
import { Fragment as Fragment9, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
23264
|
+
function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
|
|
23265
|
+
return /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
23266
|
+
/* @__PURE__ */ jsx34(
|
|
23267
|
+
"p",
|
|
23268
|
+
{
|
|
23269
|
+
style: {
|
|
23270
|
+
fontFamily: "var(--brand-font-body)",
|
|
23271
|
+
fontSize: "0.75rem",
|
|
23272
|
+
fontWeight: 500,
|
|
23273
|
+
letterSpacing: "0.15em",
|
|
23274
|
+
textTransform: "uppercase",
|
|
23275
|
+
color: "var(--brand-accent)",
|
|
23276
|
+
marginBottom: "1.5rem"
|
|
23277
|
+
},
|
|
23278
|
+
children: /* @__PURE__ */ jsx34(Link3, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ jsx34("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
|
|
23279
|
+
}
|
|
23280
|
+
),
|
|
23281
|
+
/* @__PURE__ */ jsx34(
|
|
23282
|
+
"h1",
|
|
23283
|
+
{
|
|
23284
|
+
style: {
|
|
23285
|
+
fontFamily: "var(--brand-font-heading)",
|
|
23286
|
+
fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
|
|
23287
|
+
lineHeight: 1.1,
|
|
23288
|
+
letterSpacing: "-0.025em",
|
|
23289
|
+
color: "var(--brand-text)",
|
|
23290
|
+
marginBottom: "1rem"
|
|
23291
|
+
},
|
|
23292
|
+
...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
|
|
23293
|
+
children: title
|
|
23294
|
+
}
|
|
23295
|
+
),
|
|
23296
|
+
/* @__PURE__ */ jsx34(
|
|
23297
|
+
"p",
|
|
23298
|
+
{
|
|
23299
|
+
style: {
|
|
23300
|
+
fontFamily: "var(--brand-font-body)",
|
|
23301
|
+
fontSize: "1rem",
|
|
23302
|
+
lineHeight: 1.7,
|
|
23303
|
+
fontWeight: 300,
|
|
23304
|
+
color: "var(--brand-text-muted)",
|
|
23305
|
+
maxWidth: "340px"
|
|
23306
|
+
},
|
|
23307
|
+
...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
|
|
23308
|
+
children: "This page doesn't have any content yet."
|
|
23309
|
+
}
|
|
23310
|
+
)
|
|
23311
|
+
] });
|
|
23312
|
+
}
|
|
22334
23313
|
export {
|
|
22335
23314
|
AI_DEFAULT_BRAND,
|
|
22336
23315
|
AI_TREE_SCHEMA_VERSIONS,
|
|
@@ -22347,6 +23326,7 @@ export {
|
|
|
22347
23326
|
DropdownMenuItem,
|
|
22348
23327
|
DropdownMenuSeparator,
|
|
22349
23328
|
DropdownMenuTrigger,
|
|
23329
|
+
EmptySection,
|
|
22350
23330
|
ItemActionToolbar,
|
|
22351
23331
|
ItemInteractionLayer,
|
|
22352
23332
|
LinkEditorPanel,
|