@ohhwells/bridge 0.1.85 → 0.1.86-next.256
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 +1121 -365
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -4
- package/dist/index.d.ts +32 -4
- package/dist/index.js +1120 -365
- 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 +55 -0
- package/package.json +8 -3
package/dist/index.js
CHANGED
|
@@ -69,6 +69,10 @@ function isRenderableTree(value) {
|
|
|
69
69
|
|
|
70
70
|
// src/lib/ai-sections-store.ts
|
|
71
71
|
var AI_SECTIONS_KEY = "__ohw_ai_sections";
|
|
72
|
+
var AI_SLOT_KEY_PREFIX = "ai.";
|
|
73
|
+
function aiSlotKeyPrefixFor(sectionId) {
|
|
74
|
+
return `${AI_SLOT_KEY_PREFIX}${sectionId}.`;
|
|
75
|
+
}
|
|
72
76
|
var EMPTY_AI_SECTIONS = { v: 1, sections: [] };
|
|
73
77
|
function parseAiSectionsState(raw) {
|
|
74
78
|
if (!raw) return EMPTY_AI_SECTIONS;
|
|
@@ -112,6 +116,63 @@ function applyTreeToState(state, payload) {
|
|
|
112
116
|
const others = state.sections.filter((existing) => existing.id !== entry.id);
|
|
113
117
|
return { ...state, v: 1, sections: [...others, entry] };
|
|
114
118
|
}
|
|
119
|
+
function foldAlignIntoTrees(state, store) {
|
|
120
|
+
const byId = new Map(state.sections.map((entry) => [entry.id, entry]));
|
|
121
|
+
const nextTrees = /* @__PURE__ */ new Map();
|
|
122
|
+
const treeFor = (id) => {
|
|
123
|
+
const cloned = nextTrees.get(id);
|
|
124
|
+
if (cloned) return cloned;
|
|
125
|
+
const entry = byId.get(id);
|
|
126
|
+
if (!entry) return void 0;
|
|
127
|
+
const fresh = {
|
|
128
|
+
...entry.tree,
|
|
129
|
+
rows: entry.tree.rows.map((row) => ({ ...row, blocks: row.blocks.map((block) => ({ ...block })) }))
|
|
130
|
+
};
|
|
131
|
+
nextTrees.set(id, fresh);
|
|
132
|
+
return fresh;
|
|
133
|
+
};
|
|
134
|
+
const nodes = {};
|
|
135
|
+
for (const [key, override] of Object.entries(store.nodes)) {
|
|
136
|
+
const match = override.align !== void 0 && key.startsWith(AI_SLOT_KEY_PREFIX) ? key.match(/^ai\.(.+?)\.r(\d+)\.b(\d+)(?:\.|$)/) : null;
|
|
137
|
+
const tree = match ? treeFor(match[1]) : void 0;
|
|
138
|
+
const block = match && tree ? tree.rows[Number(match[2])]?.blocks[Number(match[3])] : void 0;
|
|
139
|
+
if (!block) {
|
|
140
|
+
nodes[key] = override;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
block.align = override.align;
|
|
144
|
+
const rest = { ...override };
|
|
145
|
+
delete rest.align;
|
|
146
|
+
if (Object.keys(rest).length > 0) nodes[key] = rest;
|
|
147
|
+
}
|
|
148
|
+
const sections = {};
|
|
149
|
+
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
150
|
+
const tree = override.align !== void 0 ? treeFor(sectionId) : void 0;
|
|
151
|
+
if (!tree) {
|
|
152
|
+
sections[sectionId] = override;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
for (const row of tree.rows) {
|
|
156
|
+
for (const block of row.blocks) block.align = override.align;
|
|
157
|
+
}
|
|
158
|
+
const rest = { ...override };
|
|
159
|
+
delete rest.align;
|
|
160
|
+
if (Object.keys(rest).length > 0) sections[sectionId] = rest;
|
|
161
|
+
}
|
|
162
|
+
if (nextTrees.size === 0) return { state, store, changed: false };
|
|
163
|
+
return {
|
|
164
|
+
state: {
|
|
165
|
+
...state,
|
|
166
|
+
v: 1,
|
|
167
|
+
sections: state.sections.map((entry) => {
|
|
168
|
+
const tree = nextTrees.get(entry.id);
|
|
169
|
+
return tree ? { ...entry, tree } : entry;
|
|
170
|
+
})
|
|
171
|
+
},
|
|
172
|
+
store: { v: 1, sections, nodes },
|
|
173
|
+
changed: true
|
|
174
|
+
};
|
|
175
|
+
}
|
|
115
176
|
function removeFromState(state, id) {
|
|
116
177
|
return { ...state, v: 1, sections: state.sections.filter((entry) => entry.id !== id) };
|
|
117
178
|
}
|
|
@@ -123,6 +184,33 @@ function deleteSectionFromState(state, sectionId) {
|
|
|
123
184
|
if (removed.includes(sectionId)) return state;
|
|
124
185
|
return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
|
|
125
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
|
+
}
|
|
126
214
|
|
|
127
215
|
// src/lib/brand-chrome.ts
|
|
128
216
|
var BRAND_NAME_KEY = "__ohw_brand_name";
|
|
@@ -330,6 +418,12 @@ function styleSheetCss() {
|
|
|
330
418
|
`[data-ohw-style-spacing="${spacing}"] { padding-top: ${px}px !important; padding-bottom: ${px}px !important; }`
|
|
331
419
|
);
|
|
332
420
|
}
|
|
421
|
+
rules.push(
|
|
422
|
+
`[data-ohw-style-corners="sharp"] :is(.card, [data-ohw-card]) { border-radius: 0 !important; }`
|
|
423
|
+
);
|
|
424
|
+
for (const align of ["left", "center", "right"]) {
|
|
425
|
+
rules.push(`[data-ohw-style-align="${align}"] { text-align: ${align} !important; }`);
|
|
426
|
+
}
|
|
333
427
|
return rules.join("\n");
|
|
334
428
|
}
|
|
335
429
|
var STYLE_FONT_LINK_ID = "ohw-style-fonts";
|
|
@@ -356,10 +450,25 @@ var SECTION_ATTRS = {
|
|
|
356
450
|
textDistribution: "data-ohw-style-distribution",
|
|
357
451
|
headlineScale: "data-ohw-style-headline",
|
|
358
452
|
imageAspect: "data-ohw-style-aspect",
|
|
359
|
-
spacing: "data-ohw-style-spacing"
|
|
453
|
+
spacing: "data-ohw-style-spacing",
|
|
454
|
+
cornerStyle: "data-ohw-style-corners",
|
|
455
|
+
align: "data-ohw-style-align"
|
|
360
456
|
};
|
|
361
457
|
var NODE_WROTE_ATTR = "data-ohw-style-node";
|
|
362
|
-
var NODE_PROPS = [
|
|
458
|
+
var NODE_PROPS = [
|
|
459
|
+
"color",
|
|
460
|
+
"font-family",
|
|
461
|
+
"font-size",
|
|
462
|
+
"background",
|
|
463
|
+
"text-align",
|
|
464
|
+
"justify-content",
|
|
465
|
+
"align-items"
|
|
466
|
+
];
|
|
467
|
+
var ALIGN_JUSTIFY = {
|
|
468
|
+
left: "flex-start",
|
|
469
|
+
center: "center",
|
|
470
|
+
right: "flex-end"
|
|
471
|
+
};
|
|
363
472
|
function saveInline(el, prop) {
|
|
364
473
|
const attr = `data-ohw-style-prev-${prop}`;
|
|
365
474
|
if (el.hasAttribute(attr)) return;
|
|
@@ -403,6 +512,10 @@ function clearNodeProps(root) {
|
|
|
403
512
|
function buttonSurfaceOf(el) {
|
|
404
513
|
return el.closest("a, button") ?? el;
|
|
405
514
|
}
|
|
515
|
+
function alignSubjectOf(el) {
|
|
516
|
+
const button = el.closest('[data-ohw-role="button"]');
|
|
517
|
+
return button?.parentElement ?? el;
|
|
518
|
+
}
|
|
406
519
|
function applyStylesToDom(store) {
|
|
407
520
|
ensureStyleSheet();
|
|
408
521
|
clearSectionAttrs(document);
|
|
@@ -448,6 +561,18 @@ function applyStylesToDom(store) {
|
|
|
448
561
|
el.style.setProperty("font-size", `${override.fontSize}px`, "important");
|
|
449
562
|
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
450
563
|
}
|
|
564
|
+
if (override.align !== void 0) {
|
|
565
|
+
const subject = alignSubjectOf(el);
|
|
566
|
+
saveInline(subject, "text-align");
|
|
567
|
+
saveInline(subject, "justify-content");
|
|
568
|
+
subject.style.setProperty("text-align", override.align, "important");
|
|
569
|
+
subject.style.setProperty(
|
|
570
|
+
"justify-content",
|
|
571
|
+
ALIGN_JUSTIFY[override.align] ?? "flex-start",
|
|
572
|
+
"important"
|
|
573
|
+
);
|
|
574
|
+
subject.setAttribute(NODE_WROTE_ATTR, "");
|
|
575
|
+
}
|
|
451
576
|
if (override.buttonBackground !== void 0 || override.buttonText !== void 0) {
|
|
452
577
|
const surface = buttonSurfaceOf(el);
|
|
453
578
|
if (override.buttonBackground !== void 0) {
|
|
@@ -468,9 +593,494 @@ function applyStylesToDom(store) {
|
|
|
468
593
|
import { flushSync } from "react-dom";
|
|
469
594
|
import { createRoot } from "react-dom/client";
|
|
470
595
|
|
|
596
|
+
// src/lib/sections.ts
|
|
597
|
+
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
598
|
+
function isChromeSection(el) {
|
|
599
|
+
return el.matches("header, nav, footer, aside");
|
|
600
|
+
}
|
|
601
|
+
function titleCaseSectionId(id) {
|
|
602
|
+
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
603
|
+
}
|
|
604
|
+
function parseSectionsFromRoot(root) {
|
|
605
|
+
const seen = /* @__PURE__ */ new Set();
|
|
606
|
+
const sections = [];
|
|
607
|
+
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
608
|
+
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
609
|
+
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
610
|
+
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
611
|
+
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
612
|
+
continue;
|
|
613
|
+
seen.add(id);
|
|
614
|
+
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
615
|
+
sections.push({ id, label });
|
|
616
|
+
}
|
|
617
|
+
return sections;
|
|
618
|
+
}
|
|
619
|
+
function collectSectionsFromDom() {
|
|
620
|
+
if (typeof document === "undefined") return [];
|
|
621
|
+
return parseSectionsFromRoot(document);
|
|
622
|
+
}
|
|
623
|
+
function parseSectionsFromHtml(html) {
|
|
624
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
625
|
+
return parseSectionsFromRoot(doc);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// src/lib/section-instances.ts
|
|
629
|
+
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
630
|
+
var REMOVED_ATTR = "data-ohw-section-removed";
|
|
631
|
+
function isRemovedSection(el) {
|
|
632
|
+
return el.hasAttribute(REMOVED_ATTR);
|
|
633
|
+
}
|
|
634
|
+
function topLevelSections() {
|
|
635
|
+
return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
636
|
+
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el) && !isRemovedSection(el)
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
function instanceIdOf(el) {
|
|
640
|
+
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
641
|
+
}
|
|
642
|
+
function findByInstanceId(instanceId) {
|
|
643
|
+
const escapedId = CSS.escape(instanceId);
|
|
644
|
+
return document.querySelector(`[data-ohw-instance="${escapedId}"]`) ?? document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
645
|
+
}
|
|
646
|
+
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
647
|
+
const sections = topLevelSections();
|
|
648
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
649
|
+
if (index === -1) return null;
|
|
650
|
+
const dragged = sections[index];
|
|
651
|
+
const others = sections.filter((_, i) => i !== index);
|
|
652
|
+
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
653
|
+
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
654
|
+
return reordered.map((el, order) => ({
|
|
655
|
+
instanceId: instanceIdOf(el),
|
|
656
|
+
type: el.getAttribute("data-ohw-section") ?? "",
|
|
657
|
+
order,
|
|
658
|
+
pagePath: currentPath
|
|
659
|
+
}));
|
|
660
|
+
}
|
|
661
|
+
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
662
|
+
const sections = topLevelSections();
|
|
663
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
664
|
+
if (index === -1) return null;
|
|
665
|
+
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
666
|
+
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
667
|
+
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
668
|
+
if (!entries) return null;
|
|
669
|
+
applyPersistedOrder(entries);
|
|
670
|
+
return entries;
|
|
671
|
+
}
|
|
672
|
+
function syncRemovedFlags(entries) {
|
|
673
|
+
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
674
|
+
document.querySelectorAll(`[${REMOVED_ATTR}]`).forEach((el) => {
|
|
675
|
+
if (!removedIds.has(instanceIdOf(el))) {
|
|
676
|
+
el.style.removeProperty("display");
|
|
677
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
678
|
+
}
|
|
679
|
+
});
|
|
680
|
+
for (const id of removedIds) {
|
|
681
|
+
const el = findByInstanceId(id);
|
|
682
|
+
if (el) {
|
|
683
|
+
el.style.display = "none";
|
|
684
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
function applyPersistedOrder(entries) {
|
|
689
|
+
syncRemovedFlags(entries);
|
|
690
|
+
if (entries.length === 0) return;
|
|
691
|
+
const sections = topLevelSections();
|
|
692
|
+
if (sections.length === 0) return;
|
|
693
|
+
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
694
|
+
const ordered = [...sections].sort((a, b) => {
|
|
695
|
+
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
696
|
+
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
697
|
+
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
698
|
+
if (aOrder === void 0) return 1;
|
|
699
|
+
if (bOrder === void 0) return -1;
|
|
700
|
+
return aOrder - bOrder;
|
|
701
|
+
});
|
|
702
|
+
let prev = null;
|
|
703
|
+
for (const el of ordered) {
|
|
704
|
+
if (prev) prev.after(el);
|
|
705
|
+
prev = el;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
709
|
+
if (!findByInstanceId(instanceId)) return null;
|
|
710
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
711
|
+
const allSections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
712
|
+
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
|
|
713
|
+
);
|
|
714
|
+
allSections.forEach((el, order) => {
|
|
715
|
+
const id = instanceIdOf(el);
|
|
716
|
+
if (!byId.has(id)) {
|
|
717
|
+
byId.set(id, { instanceId: id, type: el.getAttribute("data-ohw-section") ?? "", order, pagePath: currentPath });
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
const target = byId.get(instanceId);
|
|
721
|
+
if (!target) return null;
|
|
722
|
+
byId.set(instanceId, { ...target, removed });
|
|
723
|
+
const entries = Array.from(byId.values());
|
|
724
|
+
applyPersistedOrder(entries);
|
|
725
|
+
return entries;
|
|
726
|
+
}
|
|
727
|
+
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
728
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
729
|
+
}
|
|
730
|
+
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
731
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
732
|
+
}
|
|
733
|
+
function duplicateSectionInstance(instanceId, newId, currentPath, existingEntries) {
|
|
734
|
+
const original = findByInstanceId(instanceId);
|
|
735
|
+
if (!original) return null;
|
|
736
|
+
const clone = original.cloneNode(true);
|
|
737
|
+
clone.setAttribute("data-ohw-instance", newId);
|
|
738
|
+
const keyRekeys = rekeySectionSubtree(clone, newId);
|
|
739
|
+
original.insertAdjacentElement("afterend", clone);
|
|
740
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
741
|
+
const entries = topLevelSections().map((el, order) => {
|
|
742
|
+
const id = instanceIdOf(el);
|
|
743
|
+
return {
|
|
744
|
+
instanceId: id,
|
|
745
|
+
type: el.getAttribute("data-ohw-section") ?? "",
|
|
746
|
+
order,
|
|
747
|
+
pagePath: currentPath,
|
|
748
|
+
...byId.get(id)?.removed ? { removed: true } : {}
|
|
749
|
+
};
|
|
750
|
+
});
|
|
751
|
+
applyPersistedOrder(entries);
|
|
752
|
+
return { entries, keyRekeys };
|
|
753
|
+
}
|
|
754
|
+
function newInstanceId() {
|
|
755
|
+
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
756
|
+
}
|
|
757
|
+
function getPageSectionOrderEntries(raw, currentPath) {
|
|
758
|
+
if (!raw) return [];
|
|
759
|
+
try {
|
|
760
|
+
const entries = JSON.parse(raw);
|
|
761
|
+
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
762
|
+
} catch {
|
|
763
|
+
return [];
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
function rekeySectionSubtree(root, instanceId) {
|
|
767
|
+
const suffix = `::${instanceId}`;
|
|
768
|
+
const pairs = [];
|
|
769
|
+
const rekey = (el, attr) => {
|
|
770
|
+
const current = el.getAttribute(attr);
|
|
771
|
+
if (!current) return;
|
|
772
|
+
const base = current.includes("::") ? current.slice(0, current.indexOf("::")) : current;
|
|
773
|
+
const next = `${base}${suffix}`;
|
|
774
|
+
el.setAttribute(attr, next);
|
|
775
|
+
pairs.push({ from: current, to: next });
|
|
776
|
+
};
|
|
777
|
+
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
778
|
+
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
779
|
+
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
780
|
+
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
781
|
+
return pairs;
|
|
782
|
+
}
|
|
783
|
+
function initSectionInstancesFromContent(content, currentPath) {
|
|
784
|
+
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
785
|
+
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
786
|
+
});
|
|
787
|
+
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
788
|
+
for (const entry of entries) {
|
|
789
|
+
if (entry.instanceId === entry.type) continue;
|
|
790
|
+
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
791
|
+
const original = document.querySelector(
|
|
792
|
+
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
793
|
+
);
|
|
794
|
+
if (!original) continue;
|
|
795
|
+
const clone = original.cloneNode(true);
|
|
796
|
+
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
797
|
+
rekeySectionSubtree(clone, entry.instanceId);
|
|
798
|
+
original.insertAdjacentElement("afterend", clone);
|
|
799
|
+
}
|
|
800
|
+
applyPersistedOrder(entries);
|
|
801
|
+
}
|
|
802
|
+
|
|
471
803
|
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
472
804
|
import React from "react";
|
|
473
805
|
import { ArrowLeft, ArrowRight, ChevronDown, icons as lucideIcons } from "lucide-react";
|
|
806
|
+
|
|
807
|
+
// src/lib/placeholder-imagery.ts
|
|
808
|
+
var U = (id) => `https://images.unsplash.com/photo-${id}?auto=format&fit=crop&w=1600&q=80`;
|
|
809
|
+
var GENERIC = [
|
|
810
|
+
U("1441986300917-64674bd600d8"),
|
|
811
|
+
U("1486406146926-c627a92ad1ab"),
|
|
812
|
+
U("1497032628192-86f99bcd76bc"),
|
|
813
|
+
U("1521737604893-d14cc237f11d"),
|
|
814
|
+
U("1522071820081-009f0129c71c"),
|
|
815
|
+
U("1519389950473-47ba0277781c"),
|
|
816
|
+
U("1460925895917-afdab827c52f"),
|
|
817
|
+
U("1504384308090-c894fdcc538d")
|
|
818
|
+
];
|
|
819
|
+
var PEOPLE = [
|
|
820
|
+
U("1500648767791-00dcc994a43e"),
|
|
821
|
+
U("1494790108377-be9c29b29330"),
|
|
822
|
+
U("1507003211169-0a1dd7228f2d"),
|
|
823
|
+
U("1438761681033-6461ffad8d80"),
|
|
824
|
+
U("1544005313-94ddf0286df2"),
|
|
825
|
+
U("1472099645785-5658abf4ff4e"),
|
|
826
|
+
U("1519085360753-af0119f7cbe7"),
|
|
827
|
+
U("1534528741775-53994a69daeb")
|
|
828
|
+
];
|
|
829
|
+
var THEMED = [
|
|
830
|
+
{
|
|
831
|
+
keywords: ["portrait", "headshot", "person", "people", "team", "staff", "avatar", "founder", "face"],
|
|
832
|
+
pool: PEOPLE
|
|
833
|
+
},
|
|
834
|
+
{
|
|
835
|
+
keywords: ["pet", "dog", "cat", "puppy", "kitten", "vet", "animal"],
|
|
836
|
+
pool: [
|
|
837
|
+
U("1548199973-03cce0bbc87b"),
|
|
838
|
+
U("1450778869180-41d0601e046e"),
|
|
839
|
+
U("1583511655857-d19b40a7a54e"),
|
|
840
|
+
U("1587300003388-59208cc962cb"),
|
|
841
|
+
U("1517849845537-4d257902454a"),
|
|
842
|
+
U("1601758228041-f3b2795255f1")
|
|
843
|
+
]
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
keywords: [
|
|
847
|
+
"baker",
|
|
848
|
+
"bakery",
|
|
849
|
+
"cafe",
|
|
850
|
+
"coffee",
|
|
851
|
+
"latte",
|
|
852
|
+
"restaurant",
|
|
853
|
+
"pastr",
|
|
854
|
+
"bread",
|
|
855
|
+
"cake",
|
|
856
|
+
"cater",
|
|
857
|
+
"chef",
|
|
858
|
+
"kitchen",
|
|
859
|
+
"food",
|
|
860
|
+
"pizza",
|
|
861
|
+
"dessert",
|
|
862
|
+
"brunch",
|
|
863
|
+
"bistro",
|
|
864
|
+
"deli",
|
|
865
|
+
"dish",
|
|
866
|
+
"menu"
|
|
867
|
+
],
|
|
868
|
+
pool: [
|
|
869
|
+
U("1509440159596-0249088772ff"),
|
|
870
|
+
U("1555507036-ab1f4038808a"),
|
|
871
|
+
U("1517433670267-08bbd4be890f"),
|
|
872
|
+
U("1486427944299-d1955d23e34d"),
|
|
873
|
+
U("1504754524776-8f4f37790ca0"),
|
|
874
|
+
U("1495474472287-4d71bcdd2085"),
|
|
875
|
+
U("1521017432531-fbd92d768814"),
|
|
876
|
+
U("1556909114-f6e7ad7d3136")
|
|
877
|
+
]
|
|
878
|
+
},
|
|
879
|
+
{
|
|
880
|
+
keywords: [
|
|
881
|
+
"shop",
|
|
882
|
+
"store",
|
|
883
|
+
"boutique",
|
|
884
|
+
"retail",
|
|
885
|
+
"clothing",
|
|
886
|
+
"fashion",
|
|
887
|
+
"jewel",
|
|
888
|
+
"gift",
|
|
889
|
+
"florist",
|
|
890
|
+
"market",
|
|
891
|
+
"grocer",
|
|
892
|
+
"product",
|
|
893
|
+
"storefront"
|
|
894
|
+
],
|
|
895
|
+
pool: [
|
|
896
|
+
U("1441984904996-e0b6ba687e04"),
|
|
897
|
+
U("1472851294608-062f824d29cc"),
|
|
898
|
+
U("1523381210434-271e8be1f52b"),
|
|
899
|
+
U("1534452203293-494d7ddbf7e0"),
|
|
900
|
+
U("1445205170230-053b83016050"),
|
|
901
|
+
U("1560243563-062bfc001d68")
|
|
902
|
+
]
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
keywords: [
|
|
906
|
+
"yoga",
|
|
907
|
+
"pilates",
|
|
908
|
+
"fitness",
|
|
909
|
+
"gym",
|
|
910
|
+
"workout",
|
|
911
|
+
"trainer",
|
|
912
|
+
"wellness",
|
|
913
|
+
"meditat",
|
|
914
|
+
"massage",
|
|
915
|
+
"therap",
|
|
916
|
+
"physio",
|
|
917
|
+
"chiro",
|
|
918
|
+
"nutrition",
|
|
919
|
+
"spa",
|
|
920
|
+
"studio"
|
|
921
|
+
],
|
|
922
|
+
pool: [
|
|
923
|
+
U("1544367567-0f2fcb009e0b"),
|
|
924
|
+
U("1506126613408-eca07ce68773"),
|
|
925
|
+
U("1545205597-3d9d02c29597"),
|
|
926
|
+
U("1552196563-55cd4e45efb3"),
|
|
927
|
+
U("1518611012118-696072aa579a"),
|
|
928
|
+
U("1571019613454-1cb2f99b2d8b"),
|
|
929
|
+
U("1540555700478-4be289fbecef"),
|
|
930
|
+
U("1519824145371-296894a0daa9")
|
|
931
|
+
]
|
|
932
|
+
},
|
|
933
|
+
{
|
|
934
|
+
keywords: [
|
|
935
|
+
"salon",
|
|
936
|
+
"hairdress",
|
|
937
|
+
"haircut",
|
|
938
|
+
"barber",
|
|
939
|
+
"manicure",
|
|
940
|
+
"pedicure",
|
|
941
|
+
"nails",
|
|
942
|
+
"beauty",
|
|
943
|
+
"makeup",
|
|
944
|
+
"cosmetic",
|
|
945
|
+
"eyelash",
|
|
946
|
+
"eyebrow",
|
|
947
|
+
"skincare",
|
|
948
|
+
"esthetic",
|
|
949
|
+
"waxing",
|
|
950
|
+
"hair"
|
|
951
|
+
],
|
|
952
|
+
pool: [
|
|
953
|
+
U("1560066984-138dadb4c035"),
|
|
954
|
+
U("1522337660859-02fbefca4702"),
|
|
955
|
+
U("1562322140-8baeececf3df"),
|
|
956
|
+
U("1521590832167-7bcbfaa6381f"),
|
|
957
|
+
U("1487412947147-5cebf100ffc2"),
|
|
958
|
+
U("1526045478516-99145907023c")
|
|
959
|
+
]
|
|
960
|
+
},
|
|
961
|
+
{
|
|
962
|
+
keywords: [
|
|
963
|
+
"cleaning",
|
|
964
|
+
"plumb",
|
|
965
|
+
"electric",
|
|
966
|
+
"landscap",
|
|
967
|
+
"contractor",
|
|
968
|
+
"handyman",
|
|
969
|
+
"renov",
|
|
970
|
+
"hvac",
|
|
971
|
+
"roofing",
|
|
972
|
+
"painting",
|
|
973
|
+
"carpentry",
|
|
974
|
+
"flooring",
|
|
975
|
+
"movers",
|
|
976
|
+
"construction",
|
|
977
|
+
"tools"
|
|
978
|
+
],
|
|
979
|
+
pool: [
|
|
980
|
+
U("1581578731548-c64695cc6952"),
|
|
981
|
+
U("1504307651254-35680f356dfd"),
|
|
982
|
+
U("1581092160562-40aa08e78837"),
|
|
983
|
+
U("1621905251189-08b45d6a269e"),
|
|
984
|
+
U("1558618666-fcd25c85cd64"),
|
|
985
|
+
U("1585128792020-803d29415281")
|
|
986
|
+
]
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
keywords: [
|
|
990
|
+
"legal",
|
|
991
|
+
"attorney",
|
|
992
|
+
"lawyer",
|
|
993
|
+
"account",
|
|
994
|
+
"bookkeep",
|
|
995
|
+
"consult",
|
|
996
|
+
"coaching",
|
|
997
|
+
"financ",
|
|
998
|
+
"insurance",
|
|
999
|
+
"realtor",
|
|
1000
|
+
"estate",
|
|
1001
|
+
"marketing",
|
|
1002
|
+
"agency",
|
|
1003
|
+
"office",
|
|
1004
|
+
"business",
|
|
1005
|
+
"desk"
|
|
1006
|
+
],
|
|
1007
|
+
pool: [
|
|
1008
|
+
U("1497366216548-37526070297c"),
|
|
1009
|
+
U("1497366811353-6870744d04b2"),
|
|
1010
|
+
U("1454165804606-c3d57bc86b40"),
|
|
1011
|
+
U("1521791136064-7986c2920216"),
|
|
1012
|
+
U("1556761175-b413da4baf72"),
|
|
1013
|
+
U("1542744173-8e7e53415bb0")
|
|
1014
|
+
]
|
|
1015
|
+
},
|
|
1016
|
+
{
|
|
1017
|
+
keywords: [
|
|
1018
|
+
"wedding",
|
|
1019
|
+
"event",
|
|
1020
|
+
"party",
|
|
1021
|
+
"celebrat",
|
|
1022
|
+
"venue",
|
|
1023
|
+
"community",
|
|
1024
|
+
"nonprofit",
|
|
1025
|
+
"charity",
|
|
1026
|
+
"workshop",
|
|
1027
|
+
"photograph",
|
|
1028
|
+
"concert"
|
|
1029
|
+
],
|
|
1030
|
+
pool: [
|
|
1031
|
+
U("1511578314322-379afb476865"),
|
|
1032
|
+
U("1501281668745-f7f57925c3b4"),
|
|
1033
|
+
U("1523580494863-6f3031224c94"),
|
|
1034
|
+
U("1540575467063-178a50c2df87"),
|
|
1035
|
+
U("1505236858219-8359eb29e329"),
|
|
1036
|
+
U("1528605248644-14dd04022da1")
|
|
1037
|
+
]
|
|
1038
|
+
}
|
|
1039
|
+
];
|
|
1040
|
+
function poolForSubject(subject) {
|
|
1041
|
+
for (const theme of THEMED) {
|
|
1042
|
+
if (theme.keywords.some((k) => subject.includes(k))) {
|
|
1043
|
+
return theme.pool;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
return GENERIC;
|
|
1047
|
+
}
|
|
1048
|
+
function mixedHash(text) {
|
|
1049
|
+
let hash = 2166136261;
|
|
1050
|
+
for (let i = 0; i < text.length; i++) {
|
|
1051
|
+
hash ^= text.charCodeAt(i);
|
|
1052
|
+
hash = Math.imul(hash, 16777619);
|
|
1053
|
+
}
|
|
1054
|
+
return hash >>> 16 & 65535;
|
|
1055
|
+
}
|
|
1056
|
+
function resolvePlaceholderRef(ref) {
|
|
1057
|
+
const match = /^placeholder:([a-z0-9-]+)$/.exec(ref);
|
|
1058
|
+
if (!match) return null;
|
|
1059
|
+
const subject = match[1];
|
|
1060
|
+
const pool = poolForSubject(subject.replace(/-\d+$/, ""));
|
|
1061
|
+
return pool[mixedHash(ref) % pool.length];
|
|
1062
|
+
}
|
|
1063
|
+
function collectPlaceholderRefs(tree) {
|
|
1064
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1065
|
+
for (const match of JSON.stringify(tree ?? null).matchAll(/"(placeholder:[a-z0-9-]+)"/gu)) {
|
|
1066
|
+
seen.add(match[1]);
|
|
1067
|
+
}
|
|
1068
|
+
return [...seen];
|
|
1069
|
+
}
|
|
1070
|
+
function buildPlaceholderMap(tree) {
|
|
1071
|
+
const map = {};
|
|
1072
|
+
const cursor = /* @__PURE__ */ new Map();
|
|
1073
|
+
for (const ref of collectPlaceholderRefs(tree)) {
|
|
1074
|
+
const subject = ref.slice("placeholder:".length).replace(/-\d+$/, "");
|
|
1075
|
+
const pool = poolForSubject(subject);
|
|
1076
|
+
const start = cursor.get(pool) ?? mixedHash(ref) % pool.length;
|
|
1077
|
+
map[ref] = pool[start % pool.length];
|
|
1078
|
+
cursor.set(pool, start + 1);
|
|
1079
|
+
}
|
|
1080
|
+
return map;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
474
1084
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
475
1085
|
function lucideByName(name) {
|
|
476
1086
|
const pascal = name.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
@@ -484,6 +1094,7 @@ var typeStyle = (spec, font) => ({
|
|
|
484
1094
|
fontWeight: spec.weight
|
|
485
1095
|
});
|
|
486
1096
|
var str = (value) => typeof value === "string" ? value : "";
|
|
1097
|
+
var cardRadius = (slots) => slots.cornerStyle === "sharp" ? 0 : AI_TREE_TOKENS.radiusCard;
|
|
487
1098
|
var featureLines = (value) => value.split(/\n|<br\s*\/?>/i).map((line) => line.trim()).filter(Boolean);
|
|
488
1099
|
var CHECK_MASK = `data:image/svg+xml,${encodeURIComponent(
|
|
489
1100
|
'<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>'
|
|
@@ -510,6 +1121,25 @@ var FEATURE_LINE_CSS = [
|
|
|
510
1121
|
`background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
|
|
511
1122
|
`mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
|
|
512
1123
|
].join("");
|
|
1124
|
+
function buttonShellStyle(ctx, fullWidth) {
|
|
1125
|
+
const bs = ctx.buttonStyle;
|
|
1126
|
+
if (bs) {
|
|
1127
|
+
return {
|
|
1128
|
+
borderRadius: bs.radius,
|
|
1129
|
+
...bs.padding ? { padding: bs.padding } : {},
|
|
1130
|
+
...bs.fontFamily ? { fontFamily: bs.fontFamily } : { fontFamily: ctx.brand.fonts.body },
|
|
1131
|
+
...bs.fontSize ? { fontSize: bs.fontSize } : {},
|
|
1132
|
+
...bs.fontWeight ? { fontWeight: bs.fontWeight } : {},
|
|
1133
|
+
...bs.letterSpacing && bs.letterSpacing !== "normal" ? { letterSpacing: bs.letterSpacing } : {},
|
|
1134
|
+
...bs.textTransform && bs.textTransform !== "none" ? { textTransform: bs.textTransform } : {}
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
return {
|
|
1138
|
+
borderRadius: AI_TREE_TOKENS.radiusButton,
|
|
1139
|
+
padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
|
|
1140
|
+
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
513
1143
|
function hexLuminance(color) {
|
|
514
1144
|
const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
|
|
515
1145
|
if (!m) return null;
|
|
@@ -526,6 +1156,12 @@ function hexContrast(a, b) {
|
|
|
526
1156
|
const [hi, lo] = la > lb ? [la, lb] : [lb, la];
|
|
527
1157
|
return (hi + 0.05) / (lo + 0.05);
|
|
528
1158
|
}
|
|
1159
|
+
function primaryButtonLabel(brand) {
|
|
1160
|
+
const darkC = hexContrast(brand.palette.primary, brand.palette.dark);
|
|
1161
|
+
const lightC = hexContrast(brand.palette.primary, AI_TREE_TOKENS.textPrimaryForeground);
|
|
1162
|
+
if (darkC === null || lightC === null) return AI_TREE_TOKENS.textPrimaryForeground;
|
|
1163
|
+
return darkC > lightC ? brand.palette.dark : AI_TREE_TOKENS.textPrimaryForeground;
|
|
1164
|
+
}
|
|
529
1165
|
function accentBandContext(brand) {
|
|
530
1166
|
const p = brand.palette;
|
|
531
1167
|
const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
|
|
@@ -543,6 +1179,22 @@ function accentBandContext(brand) {
|
|
|
543
1179
|
function textAttrs(ctx, path) {
|
|
544
1180
|
return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
|
|
545
1181
|
}
|
|
1182
|
+
var AI_RESPONSIVE_CSS = [
|
|
1183
|
+
"@media (max-width: 960px) {",
|
|
1184
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
|
|
1185
|
+
' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
|
|
1186
|
+
"}",
|
|
1187
|
+
"@media (max-width: 640px) {",
|
|
1188
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
|
|
1189
|
+
" [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
|
|
1190
|
+
// Group containers flatten to a column on phones; span placements come along for free.
|
|
1191
|
+
" [data-ai-responsive] [data-ai-group] { display: flex !important; flex-direction: column !important; }",
|
|
1192
|
+
" [data-ai-responsive] [data-ai-group] > * { grid-column: auto !important; }",
|
|
1193
|
+
" [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
|
|
1194
|
+
" [data-ai-responsive] { overflow-x: hidden; }",
|
|
1195
|
+
" [data-ai-responsive] img { max-width: 100%; }",
|
|
1196
|
+
"}"
|
|
1197
|
+
].join("\n");
|
|
546
1198
|
var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
547
1199
|
function MediaBox({
|
|
548
1200
|
refValue,
|
|
@@ -555,13 +1207,17 @@ function MediaBox({
|
|
|
555
1207
|
const url = refValue ? ctx.resolveMedia(refValue) : null;
|
|
556
1208
|
const isIcon = /^(lucide|simple):/.test(refValue);
|
|
557
1209
|
const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
|
|
558
|
-
const editAttrs = ctx.keyFor && editPath
|
|
1210
|
+
const editAttrs = ctx.keyFor && editPath ? {
|
|
1211
|
+
"data-ohw-key": ctx.keyFor(editPath),
|
|
1212
|
+
"data-ohw-editable": isIcon ? "icon" : "image"
|
|
1213
|
+
} : {};
|
|
559
1214
|
if (isIcon) {
|
|
560
1215
|
const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
|
|
561
1216
|
return /* @__PURE__ */ jsx(
|
|
562
1217
|
"span",
|
|
563
1218
|
{
|
|
564
1219
|
"data-ai-icon": refValue,
|
|
1220
|
+
...editAttrs,
|
|
565
1221
|
style: {
|
|
566
1222
|
display: "inline-flex",
|
|
567
1223
|
width: 48,
|
|
@@ -625,12 +1281,10 @@ function ButtonEl({
|
|
|
625
1281
|
width: fullWidth ? "100%" : void 0,
|
|
626
1282
|
alignItems: "center",
|
|
627
1283
|
justifyContent: "center",
|
|
628
|
-
padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
|
|
629
|
-
borderRadius: AI_TREE_TOKENS.radiusButton,
|
|
630
1284
|
textDecoration: "none",
|
|
631
1285
|
cursor: "pointer",
|
|
632
|
-
...
|
|
633
|
-
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ??
|
|
1286
|
+
...buttonShellStyle(ctx, fullWidth),
|
|
1287
|
+
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand) }
|
|
634
1288
|
},
|
|
635
1289
|
children: /* @__PURE__ */ jsx("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
|
|
636
1290
|
}
|
|
@@ -656,7 +1310,7 @@ function TextBlock({ slots, ctx, path }) {
|
|
|
656
1310
|
}
|
|
657
1311
|
function SectionHeaderBlock({ node, ctx, path }) {
|
|
658
1312
|
const slots = node.slots ?? {};
|
|
659
|
-
const align = slots.alignment === "center" ? "center" : "left";
|
|
1313
|
+
const align = node.align ?? (slots.alignment === "center" ? "center" : "left");
|
|
660
1314
|
const children = node.children ?? [];
|
|
661
1315
|
const buttonRowIdx = children.findIndex((c) => c.type === "button-row");
|
|
662
1316
|
const buttonRow = buttonRowIdx >= 0 ? children[buttonRowIdx] : void 0;
|
|
@@ -700,7 +1354,7 @@ function SectionHeaderBlock({ node, ctx, path }) {
|
|
|
700
1354
|
display: "flex",
|
|
701
1355
|
gap: AI_TREE_TOKENS.spacing6,
|
|
702
1356
|
marginTop: AI_TREE_TOKENS.spacing8,
|
|
703
|
-
justifyContent: align === "center" ? "center" : "flex-start"
|
|
1357
|
+
justifyContent: align === "center" ? "center" : align === "right" ? "flex-end" : "flex-start"
|
|
704
1358
|
},
|
|
705
1359
|
children: (buttonRow.children ?? []).map((button, i) => /* @__PURE__ */ jsx(
|
|
706
1360
|
ButtonEl,
|
|
@@ -806,10 +1460,11 @@ function PricingCard({ node, ctx, path }) {
|
|
|
806
1460
|
return /* @__PURE__ */ jsxs(
|
|
807
1461
|
"div",
|
|
808
1462
|
{
|
|
1463
|
+
"data-ohw-card": "",
|
|
809
1464
|
style: {
|
|
810
1465
|
background: hasBg ? ctx.brand.palette.light : "transparent",
|
|
811
1466
|
border: `1px solid ${dark}`,
|
|
812
|
-
borderRadius:
|
|
1467
|
+
borderRadius: cardRadius(slots),
|
|
813
1468
|
padding: AI_TREE_TOKENS.paddingBlock,
|
|
814
1469
|
display: "flex",
|
|
815
1470
|
flexDirection: "column",
|
|
@@ -914,10 +1569,11 @@ function TestimonialCard({ node, ctx, path }) {
|
|
|
914
1569
|
return /* @__PURE__ */ jsx(
|
|
915
1570
|
"div",
|
|
916
1571
|
{
|
|
1572
|
+
"data-ohw-card": "",
|
|
917
1573
|
"data-ai-avatar-pos": avatarPos ?? void 0,
|
|
918
1574
|
style: {
|
|
919
1575
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
920
|
-
borderRadius: hasBg ?
|
|
1576
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
921
1577
|
overflow: "hidden",
|
|
922
1578
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
923
1579
|
minWidth: 0
|
|
@@ -952,10 +1608,11 @@ function TeamCard({ node, ctx, path }) {
|
|
|
952
1608
|
return /* @__PURE__ */ jsxs(
|
|
953
1609
|
"div",
|
|
954
1610
|
{
|
|
1611
|
+
"data-ohw-card": "",
|
|
955
1612
|
"data-ai-avatar-pos": avatarPos ?? void 0,
|
|
956
1613
|
style: {
|
|
957
1614
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
958
|
-
borderRadius: hasBg ?
|
|
1615
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
959
1616
|
overflow: "hidden",
|
|
960
1617
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
961
1618
|
minWidth: 0,
|
|
@@ -1033,7 +1690,7 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1033
1690
|
editPath: `${path}.media`
|
|
1034
1691
|
}
|
|
1035
1692
|
) : null;
|
|
1036
|
-
const centered = slots.alignment === "center";
|
|
1693
|
+
const centered = (node.align ?? slots.alignment) === "center";
|
|
1037
1694
|
const content = /* @__PURE__ */ jsxs(
|
|
1038
1695
|
"div",
|
|
1039
1696
|
{
|
|
@@ -1126,9 +1783,10 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1126
1783
|
return /* @__PURE__ */ jsxs(
|
|
1127
1784
|
"div",
|
|
1128
1785
|
{
|
|
1786
|
+
"data-ohw-card": "",
|
|
1129
1787
|
style: {
|
|
1130
1788
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1131
|
-
borderRadius: hasBg ?
|
|
1789
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1132
1790
|
overflow: "hidden",
|
|
1133
1791
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1134
1792
|
display: horizontal ? "flex" : "block",
|
|
@@ -1156,7 +1814,7 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1156
1814
|
) : /* @__PURE__ */ jsx(
|
|
1157
1815
|
"div",
|
|
1158
1816
|
{
|
|
1159
|
-
style: /^(lucide|simple):/.test(mediaRef) ? { padding: `${AI_TREE_TOKENS.paddingBlock}px ${AI_TREE_TOKENS.paddingBlock}px 0` } : hasBg ? void 0 : { borderRadius:
|
|
1817
|
+
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" },
|
|
1160
1818
|
children: media
|
|
1161
1819
|
}
|
|
1162
1820
|
)),
|
|
@@ -1447,7 +2105,7 @@ function CollectionBlock({ node, ctx, path }) {
|
|
|
1447
2105
|
return /* @__PURE__ */ jsx(
|
|
1448
2106
|
"div",
|
|
1449
2107
|
{
|
|
1450
|
-
"data-ai-grid":
|
|
2108
|
+
"data-ai-grid": String(itemsPerRow),
|
|
1451
2109
|
style: {
|
|
1452
2110
|
display: "grid",
|
|
1453
2111
|
gridTemplateColumns: `repeat(${itemsPerRow}, 1fr)`,
|
|
@@ -1567,6 +2225,32 @@ function renderNode(node, ctx, path) {
|
|
|
1567
2225
|
if (child) {
|
|
1568
2226
|
return renderNode(child, ctx, `${path}.c0`);
|
|
1569
2227
|
}
|
|
2228
|
+
if (str(slots.provider) === "map" && str(slots.query)) {
|
|
2229
|
+
const query = str(slots.query);
|
|
2230
|
+
const mapAttrs = ctx.keyFor ? {
|
|
2231
|
+
"data-ohw-key": ctx.keyFor(`${path}.query`),
|
|
2232
|
+
"data-ohw-editable": "map",
|
|
2233
|
+
"data-ohw-map-query": query
|
|
2234
|
+
} : {};
|
|
2235
|
+
return /* @__PURE__ */ jsx(
|
|
2236
|
+
"iframe",
|
|
2237
|
+
{
|
|
2238
|
+
...mapAttrs,
|
|
2239
|
+
"data-ai-embed": "map",
|
|
2240
|
+
title: str(slots.title) || "Map",
|
|
2241
|
+
src: `https://www.google.com/maps?q=${encodeURIComponent(query)}&output=embed`,
|
|
2242
|
+
loading: "lazy",
|
|
2243
|
+
referrerPolicy: "no-referrer-when-downgrade",
|
|
2244
|
+
style: {
|
|
2245
|
+
width: "100%",
|
|
2246
|
+
minHeight: 320,
|
|
2247
|
+
border: 0,
|
|
2248
|
+
borderRadius: AI_TREE_TOKENS.radiusCard,
|
|
2249
|
+
display: "block"
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
);
|
|
2253
|
+
}
|
|
1570
2254
|
return /* @__PURE__ */ jsx(
|
|
1571
2255
|
"div",
|
|
1572
2256
|
{
|
|
@@ -1670,15 +2354,12 @@ function renderNode(node, ctx, path) {
|
|
|
1670
2354
|
alignSelf: submitAlign,
|
|
1671
2355
|
border: "none",
|
|
1672
2356
|
cursor: "pointer",
|
|
1673
|
-
padding
|
|
1674
|
-
|
|
1675
|
-
// CTA); 8px only when the page has no template button to match.
|
|
1676
|
-
borderRadius: ctx.buttonRadius ?? 8,
|
|
2357
|
+
// Shape/padding/typography follow the host template's own buttons.
|
|
2358
|
+
...buttonShellStyle(ctx),
|
|
1677
2359
|
// Brand-styled: primary fill, brand-derived label colour (not a fixed token) so it
|
|
1678
2360
|
// reads correctly on custom palettes.
|
|
1679
2361
|
background: ctx.brand.palette.primary,
|
|
1680
|
-
color: ctx.buttonLabel ?? ctx.brand
|
|
1681
|
-
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
2362
|
+
color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand)
|
|
1682
2363
|
},
|
|
1683
2364
|
children: /* @__PURE__ */ jsx("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
|
|
1684
2365
|
},
|
|
@@ -1713,7 +2394,7 @@ function renderNode(node, ctx, path) {
|
|
|
1713
2394
|
function AiTreeRenderer({
|
|
1714
2395
|
tree,
|
|
1715
2396
|
brand,
|
|
1716
|
-
|
|
2397
|
+
buttonStyle,
|
|
1717
2398
|
resolveMedia,
|
|
1718
2399
|
editKeyPrefix
|
|
1719
2400
|
}) {
|
|
@@ -1723,13 +2404,18 @@ function AiTreeRenderer({
|
|
|
1723
2404
|
const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
|
|
1724
2405
|
const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
|
|
1725
2406
|
const blockBrand = band?.brand ?? resolvedBrand;
|
|
2407
|
+
const placeholderMap = buildPlaceholderMap(tree);
|
|
1726
2408
|
const ctx = {
|
|
1727
2409
|
brand: blockBrand,
|
|
1728
|
-
|
|
2410
|
+
// An owner/library ref resolves through the host resolver; a `placeholder:<subject>` ref the
|
|
2411
|
+
// host cannot resolve falls back to real stock photography (the per-section map first, then a
|
|
2412
|
+
// standalone resolve), so generated galleries, image rows, and overlay backgrounds arrive with
|
|
2413
|
+
// photos instead of grey boxes.
|
|
2414
|
+
resolveMedia: (ref) => resolveMedia?.(ref) ?? placeholderMap[ref] ?? resolvePlaceholderRef(ref),
|
|
1729
2415
|
cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
|
|
1730
2416
|
keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
|
|
1731
2417
|
sectionAlignment: (tree.settings ?? {}).alignment === "center" ? "center" : "left",
|
|
1732
|
-
|
|
2418
|
+
buttonStyle,
|
|
1733
2419
|
...band ? { buttonLabel: band.buttonLabel } : {}
|
|
1734
2420
|
};
|
|
1735
2421
|
const settings = tree.settings ?? {};
|
|
@@ -1752,11 +2438,25 @@ function AiTreeRenderer({
|
|
|
1752
2438
|
}
|
|
1753
2439
|
})();
|
|
1754
2440
|
const distributed = !isOverlay && settings.textDistribution;
|
|
2441
|
+
const rowAlignItems = (rowAlign) => {
|
|
2442
|
+
if (rowAlign === "top") return "start";
|
|
2443
|
+
if (rowAlign === "bottom") return "end";
|
|
2444
|
+
if (rowAlign === "center" || rowAlign === "stretch") return rowAlign;
|
|
2445
|
+
if (distributed === "space-between") return "stretch";
|
|
2446
|
+
return (distributed ?? settings.verticalPosition) === "top" ? "start" : "center";
|
|
2447
|
+
};
|
|
2448
|
+
const cellAlignStyle = (blockAlign) => blockAlign ? {
|
|
2449
|
+
display: "flex",
|
|
2450
|
+
flexDirection: "column",
|
|
2451
|
+
alignItems: blockAlign === "left" ? "flex-start" : blockAlign === "right" ? "flex-end" : "center",
|
|
2452
|
+
textAlign: blockAlign
|
|
2453
|
+
} : {};
|
|
1755
2454
|
return /* @__PURE__ */ jsxs(
|
|
1756
2455
|
"section",
|
|
1757
2456
|
{
|
|
1758
2457
|
"data-ai-section": tree.tag ?? "",
|
|
1759
2458
|
...bgAttrs,
|
|
2459
|
+
"data-ai-responsive": "",
|
|
1760
2460
|
style: {
|
|
1761
2461
|
position: "relative",
|
|
1762
2462
|
padding: `${pad}px 0`,
|
|
@@ -1767,12 +2467,13 @@ function AiTreeRenderer({
|
|
|
1767
2467
|
color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
|
|
1768
2468
|
},
|
|
1769
2469
|
children: [
|
|
1770
|
-
|
|
2470
|
+
/* @__PURE__ */ jsx("style", { children: AI_RESPONSIVE_CSS }),
|
|
1771
2471
|
/* @__PURE__ */ jsx("style", { children: AI_MOBILE_CSS }),
|
|
2472
|
+
isOverlay && backgroundUrl && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
|
|
1772
2473
|
/* @__PURE__ */ jsx(
|
|
1773
2474
|
"div",
|
|
1774
2475
|
{
|
|
1775
|
-
"data-ai-
|
|
2476
|
+
"data-ai-section-inner": "",
|
|
1776
2477
|
style: {
|
|
1777
2478
|
position: "relative",
|
|
1778
2479
|
maxWidth: AI_TREE_TOKENS.sectionMaxWidth,
|
|
@@ -1783,12 +2484,12 @@ function AiTreeRenderer({
|
|
|
1783
2484
|
children: tree.rows.map((row, r2) => /* @__PURE__ */ jsx(
|
|
1784
2485
|
"div",
|
|
1785
2486
|
{
|
|
1786
|
-
"data-ai-
|
|
2487
|
+
"data-ai-columns": "",
|
|
1787
2488
|
style: {
|
|
1788
2489
|
display: "grid",
|
|
1789
2490
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
1790
2491
|
gap: AI_TREE_TOKENS.spacing6,
|
|
1791
|
-
alignItems:
|
|
2492
|
+
alignItems: rowAlignItems(row.align),
|
|
1792
2493
|
marginTop: r2 > 0 ? AI_TREE_TOKENS.spacing8 : 0
|
|
1793
2494
|
},
|
|
1794
2495
|
children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ jsx(
|
|
@@ -1798,6 +2499,8 @@ function AiTreeRenderer({
|
|
|
1798
2499
|
style: {
|
|
1799
2500
|
gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`,
|
|
1800
2501
|
minWidth: 0,
|
|
2502
|
+
// Horizontal placement of the block's content within its column.
|
|
2503
|
+
...cellAlignStyle(block.align),
|
|
1801
2504
|
// space-between: each column becomes a flex column whose content spreads over
|
|
1802
2505
|
// the full row height instead of clumping at the top.
|
|
1803
2506
|
...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
|
|
@@ -1820,7 +2523,7 @@ function AiTreeRenderer({
|
|
|
1820
2523
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1821
2524
|
var CONTAINER_ATTR = "data-ohw-ai-generated";
|
|
1822
2525
|
var REPLACED_ATTR = "data-ohw-ai-replaced-by";
|
|
1823
|
-
var
|
|
2526
|
+
var REMOVED_ATTR2 = "data-ohw-ai-removed";
|
|
1824
2527
|
var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
|
|
1825
2528
|
var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
1826
2529
|
function readRootVar(name) {
|
|
@@ -1844,13 +2547,13 @@ function deriveBrandOverride() {
|
|
|
1844
2547
|
};
|
|
1845
2548
|
}
|
|
1846
2549
|
function deriveTemplateBrand() {
|
|
1847
|
-
const
|
|
1848
|
-
const
|
|
1849
|
-
const light = readRootVar("--color-light");
|
|
2550
|
+
const primary = readRootVar("--brand-primary") || readRootVar("--color-primary");
|
|
2551
|
+
const dark = readRootVar("--brand-text") || readRootVar("--color-dark");
|
|
2552
|
+
const light = readRootVar("--brand-background") || readRootVar("--color-light");
|
|
1850
2553
|
if (!dark || !primary || !light) return null;
|
|
1851
|
-
const accent = readRootVar("--color-accent");
|
|
1852
|
-
const heading = readRootVar("--font-heading") || readRootVar("--font-display");
|
|
1853
|
-
const body = readRootVar("--font-body");
|
|
2554
|
+
const accent = readRootVar("--brand-accent") || readRootVar("--color-accent");
|
|
2555
|
+
const heading = readRootVar("--brand-font-heading") || readRootVar("--font-heading") || readRootVar("--font-display");
|
|
2556
|
+
const body = readRootVar("--brand-font-body") || readRootVar("--font-body");
|
|
1854
2557
|
return {
|
|
1855
2558
|
palette: { dark, primary, accent: accent || dark, light },
|
|
1856
2559
|
fonts: {
|
|
@@ -1859,12 +2562,32 @@ function deriveTemplateBrand() {
|
|
|
1859
2562
|
}
|
|
1860
2563
|
};
|
|
1861
2564
|
}
|
|
1862
|
-
function
|
|
2565
|
+
function deriveTemplateButtonStyle() {
|
|
1863
2566
|
if (typeof document === "undefined") return null;
|
|
1864
|
-
const btn = document.
|
|
2567
|
+
const btn = Array.from(document.querySelectorAll('[data-ohw-role="button"]')).find(
|
|
2568
|
+
(el) => !el.closest(`[${CONTAINER_ATTR}]`)
|
|
2569
|
+
);
|
|
1865
2570
|
if (!btn) return null;
|
|
1866
|
-
const
|
|
1867
|
-
|
|
2571
|
+
const cs = getComputedStyle(btn);
|
|
2572
|
+
const corners = [
|
|
2573
|
+
cs.borderTopLeftRadius,
|
|
2574
|
+
cs.borderTopRightRadius,
|
|
2575
|
+
cs.borderBottomRightRadius,
|
|
2576
|
+
cs.borderBottomLeftRadius
|
|
2577
|
+
].map((v) => v || "0px");
|
|
2578
|
+
const radius = corners.every((v) => v === corners[0]) ? corners[0] : corners.join(" ");
|
|
2579
|
+
const px = (v) => parseFloat(v) || 0;
|
|
2580
|
+
const padY = Math.max(px(cs.paddingTop), px(cs.paddingBottom));
|
|
2581
|
+
const padX = Math.max(px(cs.paddingLeft), px(cs.paddingRight));
|
|
2582
|
+
return {
|
|
2583
|
+
radius: radius || "10px",
|
|
2584
|
+
padding: `${padY}px ${padX}px`,
|
|
2585
|
+
fontFamily: cs.fontFamily || "",
|
|
2586
|
+
fontSize: cs.fontSize || "",
|
|
2587
|
+
fontWeight: cs.fontWeight || "",
|
|
2588
|
+
letterSpacing: cs.letterSpacing || "",
|
|
2589
|
+
textTransform: cs.textTransform || ""
|
|
2590
|
+
};
|
|
1868
2591
|
}
|
|
1869
2592
|
var mounted = /* @__PURE__ */ new Map();
|
|
1870
2593
|
function findTemplateSection(id) {
|
|
@@ -1914,18 +2637,18 @@ function placeContainer(container, entry) {
|
|
|
1914
2637
|
}
|
|
1915
2638
|
function syncRemovedSections(state) {
|
|
1916
2639
|
const removed = new Set(state.removed ?? []);
|
|
1917
|
-
for (const el of document.querySelectorAll(`[${
|
|
2640
|
+
for (const el of document.querySelectorAll(`[${REMOVED_ATTR2}]`)) {
|
|
1918
2641
|
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
1919
2642
|
if (!removed.has(id)) {
|
|
1920
2643
|
el.style.removeProperty("display");
|
|
1921
|
-
el.removeAttribute(
|
|
2644
|
+
el.removeAttribute(REMOVED_ATTR2);
|
|
1922
2645
|
}
|
|
1923
2646
|
}
|
|
1924
2647
|
for (const id of removed) {
|
|
1925
2648
|
const section = findTemplateSection(id);
|
|
1926
2649
|
if (section && !section.hasAttribute(REPLACED_ATTR)) {
|
|
1927
2650
|
section.style.display = "none";
|
|
1928
|
-
section.setAttribute(
|
|
2651
|
+
section.setAttribute(REMOVED_ATTR2, "");
|
|
1929
2652
|
}
|
|
1930
2653
|
}
|
|
1931
2654
|
}
|
|
@@ -1942,7 +2665,7 @@ function syncTemplateHidden(state, pageHasSections) {
|
|
|
1942
2665
|
if (el.hasAttribute(CONTAINER_ATTR)) continue;
|
|
1943
2666
|
if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
|
|
1944
2667
|
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
1945
|
-
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(
|
|
2668
|
+
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR2)) continue;
|
|
1946
2669
|
el.style.display = "none";
|
|
1947
2670
|
el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
|
|
1948
2671
|
}
|
|
@@ -1966,18 +2689,23 @@ function syncReplacedOriginals(state) {
|
|
|
1966
2689
|
}
|
|
1967
2690
|
}
|
|
1968
2691
|
var sectionOrderIndex = /* @__PURE__ */ new Map();
|
|
2692
|
+
var removedSectionIds = /* @__PURE__ */ new Set();
|
|
1969
2693
|
function setAiSectionOrder(raw, currentPath) {
|
|
1970
2694
|
const next = /* @__PURE__ */ new Map();
|
|
2695
|
+
const removed = /* @__PURE__ */ new Set();
|
|
1971
2696
|
if (raw) {
|
|
1972
2697
|
try {
|
|
1973
2698
|
const entries = JSON.parse(raw);
|
|
1974
2699
|
for (const entry of entries) {
|
|
1975
|
-
if (
|
|
2700
|
+
if (entry.pagePath && entry.pagePath !== currentPath) continue;
|
|
2701
|
+
next.set(entry.instanceId, entry.order);
|
|
2702
|
+
if (entry.removed) removed.add(entry.instanceId);
|
|
1976
2703
|
}
|
|
1977
2704
|
} catch {
|
|
1978
2705
|
}
|
|
1979
2706
|
}
|
|
1980
2707
|
sectionOrderIndex = next;
|
|
2708
|
+
removedSectionIds = removed;
|
|
1981
2709
|
}
|
|
1982
2710
|
function applyExplicitOrder(entries) {
|
|
1983
2711
|
if (sectionOrderIndex.size === 0) return entries;
|
|
@@ -2013,11 +2741,23 @@ function orderByChain(sections) {
|
|
|
2013
2741
|
for (const root of roots) visit(root);
|
|
2014
2742
|
return out.length === sections.length ? out : sections;
|
|
2015
2743
|
}
|
|
2744
|
+
function syncSoftRemovedGenerated() {
|
|
2745
|
+
for (const [id, section] of mounted) {
|
|
2746
|
+
const el = section.container;
|
|
2747
|
+
if (removedSectionIds.has(id)) {
|
|
2748
|
+
el.style.display = "none";
|
|
2749
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
2750
|
+
} else if (el.hasAttribute(REMOVED_ATTR)) {
|
|
2751
|
+
el.style.removeProperty("display");
|
|
2752
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2016
2756
|
function applyAiSectionsToDom(state, options) {
|
|
2017
2757
|
if (typeof document === "undefined") return;
|
|
2018
2758
|
const brandOverride = deriveBrandOverride();
|
|
2019
2759
|
const templateBrand = deriveTemplateBrand();
|
|
2020
|
-
const
|
|
2760
|
+
const templateButtonStyle = deriveTemplateButtonStyle();
|
|
2021
2761
|
const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
|
|
2022
2762
|
const pagePath = window.location.pathname;
|
|
2023
2763
|
const pageSections = state.sections.filter((entry) => (entry.path ?? "/") === pagePath);
|
|
@@ -2057,7 +2797,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2057
2797
|
{
|
|
2058
2798
|
tree: entry.tree,
|
|
2059
2799
|
brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
|
|
2060
|
-
|
|
2800
|
+
buttonStyle: templateButtonStyle,
|
|
2061
2801
|
resolveMedia,
|
|
2062
2802
|
editKeyPrefix: `ai.${entry.id}`
|
|
2063
2803
|
}
|
|
@@ -2080,6 +2820,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2080
2820
|
syncReplacedOriginals(state);
|
|
2081
2821
|
syncRemovedSections(state);
|
|
2082
2822
|
syncTemplateHidden(state, pageSections.length > 0);
|
|
2823
|
+
syncSoftRemovedGenerated();
|
|
2083
2824
|
}
|
|
2084
2825
|
|
|
2085
2826
|
// src/useLinkHrefGuardian.ts
|
|
@@ -7809,6 +8550,7 @@ function MediaOverlay({
|
|
|
7809
8550
|
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
7810
8551
|
);
|
|
7811
8552
|
}, [isVideo]);
|
|
8553
|
+
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
7812
8554
|
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
7813
8555
|
const box = {
|
|
7814
8556
|
position: "fixed",
|
|
@@ -7938,17 +8680,17 @@ function MediaOverlay({
|
|
|
7938
8680
|
},
|
|
7939
8681
|
children: [
|
|
7940
8682
|
isVideo ? /* @__PURE__ */ jsx15(Film, { size: 14 }) : /* @__PURE__ */ jsx15(ImageIcon, { size: 14 }),
|
|
7941
|
-
|
|
8683
|
+
replaceLabel
|
|
7942
8684
|
]
|
|
7943
8685
|
}
|
|
7944
8686
|
),
|
|
7945
|
-
replaceMode
|
|
8687
|
+
showChrome && replaceMode !== "none" && /* @__PURE__ */ jsxs7(
|
|
7946
8688
|
Button,
|
|
7947
8689
|
{
|
|
7948
8690
|
"data-ohw-media-overlay": "",
|
|
7949
8691
|
variant: "outline",
|
|
7950
8692
|
size: "sm",
|
|
7951
|
-
"aria-label":
|
|
8693
|
+
"aria-label": replaceLabel,
|
|
7952
8694
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
7953
8695
|
style: {
|
|
7954
8696
|
...OVERLAY_BUTTON_STYLE,
|
|
@@ -7971,7 +8713,7 @@ function MediaOverlay({
|
|
|
7971
8713
|
},
|
|
7972
8714
|
children: [
|
|
7973
8715
|
isVideo ? /* @__PURE__ */ jsx15(Film, { size: 14 }) : /* @__PURE__ */ jsx15(ImageIcon, { size: 14 }),
|
|
7974
|
-
replaceMode === "full" ?
|
|
8716
|
+
replaceMode === "full" ? replaceLabel : null
|
|
7975
8717
|
]
|
|
7976
8718
|
}
|
|
7977
8719
|
)
|
|
@@ -8008,219 +8750,37 @@ function CarouselOverlay({
|
|
|
8008
8750
|
width: rect.width,
|
|
8009
8751
|
height: rect.height,
|
|
8010
8752
|
zIndex: 2147483646,
|
|
8011
|
-
pointerEvents: "auto",
|
|
8012
|
-
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
8013
|
-
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
8014
|
-
},
|
|
8015
|
-
onClick: () => onEdit(hover.key),
|
|
8016
|
-
children: /* @__PURE__ */ jsxs8(
|
|
8017
|
-
Button,
|
|
8018
|
-
{
|
|
8019
|
-
"data-ohw-carousel-overlay": "",
|
|
8020
|
-
variant: "outline",
|
|
8021
|
-
size: "sm",
|
|
8022
|
-
className: "cursor-pointer gap-1.5 hover:bg-background",
|
|
8023
|
-
style: OVERLAY_BUTTON_STYLE2,
|
|
8024
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
8025
|
-
onClick: (e) => {
|
|
8026
|
-
e.stopPropagation();
|
|
8027
|
-
onEdit(hover.key);
|
|
8028
|
-
},
|
|
8029
|
-
children: [
|
|
8030
|
-
/* @__PURE__ */ jsx16(GalleryHorizontal, { size: 14 }),
|
|
8031
|
-
"Edit gallery"
|
|
8032
|
-
]
|
|
8033
|
-
}
|
|
8034
|
-
)
|
|
8035
|
-
}
|
|
8036
|
-
);
|
|
8037
|
-
}
|
|
8038
|
-
|
|
8039
|
-
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
8040
|
-
import { useCallback as useCallback2, useEffect as useEffect4, useRef as useRef4, useState as useState5 } from "react";
|
|
8041
|
-
import { Check, X } from "lucide-react";
|
|
8042
|
-
|
|
8043
|
-
// src/lib/sections.ts
|
|
8044
|
-
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
8045
|
-
function isChromeSection(el) {
|
|
8046
|
-
return el.matches("header, nav, footer, aside");
|
|
8047
|
-
}
|
|
8048
|
-
function titleCaseSectionId(id) {
|
|
8049
|
-
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
8050
|
-
}
|
|
8051
|
-
function parseSectionsFromRoot(root) {
|
|
8052
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8053
|
-
const sections = [];
|
|
8054
|
-
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
8055
|
-
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
8056
|
-
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
8057
|
-
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
8058
|
-
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
8059
|
-
continue;
|
|
8060
|
-
seen.add(id);
|
|
8061
|
-
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
8062
|
-
sections.push({ id, label });
|
|
8063
|
-
}
|
|
8064
|
-
return sections;
|
|
8065
|
-
}
|
|
8066
|
-
function collectSectionsFromDom() {
|
|
8067
|
-
if (typeof document === "undefined") return [];
|
|
8068
|
-
return parseSectionsFromRoot(document);
|
|
8069
|
-
}
|
|
8070
|
-
function parseSectionsFromHtml(html) {
|
|
8071
|
-
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
8072
|
-
return parseSectionsFromRoot(doc);
|
|
8073
|
-
}
|
|
8074
|
-
|
|
8075
|
-
// src/lib/section-instances.ts
|
|
8076
|
-
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
8077
|
-
var REMOVED_ATTR2 = "data-ohw-section-removed";
|
|
8078
|
-
function isRemovedSection(el) {
|
|
8079
|
-
return el.hasAttribute(REMOVED_ATTR2);
|
|
8080
|
-
}
|
|
8081
|
-
function topLevelSections() {
|
|
8082
|
-
return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
8083
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el) && !isRemovedSection(el)
|
|
8084
|
-
);
|
|
8085
|
-
}
|
|
8086
|
-
function instanceIdOf(el) {
|
|
8087
|
-
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
8088
|
-
}
|
|
8089
|
-
function findByInstanceId(instanceId) {
|
|
8090
|
-
const escapedId = CSS.escape(instanceId);
|
|
8091
|
-
return document.querySelector(`[data-ohw-instance="${escapedId}"]`) ?? document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
8092
|
-
}
|
|
8093
|
-
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
8094
|
-
const sections = topLevelSections();
|
|
8095
|
-
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8096
|
-
if (index === -1) return null;
|
|
8097
|
-
const dragged = sections[index];
|
|
8098
|
-
const others = sections.filter((_, i) => i !== index);
|
|
8099
|
-
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
8100
|
-
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
8101
|
-
return reordered.map((el, order) => ({
|
|
8102
|
-
instanceId: instanceIdOf(el),
|
|
8103
|
-
type: el.getAttribute("data-ohw-section") ?? "",
|
|
8104
|
-
order,
|
|
8105
|
-
pagePath: currentPath
|
|
8106
|
-
}));
|
|
8107
|
-
}
|
|
8108
|
-
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
8109
|
-
const sections = topLevelSections();
|
|
8110
|
-
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8111
|
-
if (index === -1) return null;
|
|
8112
|
-
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
8113
|
-
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
8114
|
-
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
8115
|
-
if (!entries) return null;
|
|
8116
|
-
applyPersistedOrder(entries);
|
|
8117
|
-
return entries;
|
|
8118
|
-
}
|
|
8119
|
-
function syncRemovedFlags(entries) {
|
|
8120
|
-
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
8121
|
-
document.querySelectorAll(`[${REMOVED_ATTR2}]`).forEach((el) => {
|
|
8122
|
-
if (!removedIds.has(instanceIdOf(el))) {
|
|
8123
|
-
el.style.removeProperty("display");
|
|
8124
|
-
el.removeAttribute(REMOVED_ATTR2);
|
|
8125
|
-
}
|
|
8126
|
-
});
|
|
8127
|
-
for (const id of removedIds) {
|
|
8128
|
-
const el = findByInstanceId(id);
|
|
8129
|
-
if (el) {
|
|
8130
|
-
el.style.display = "none";
|
|
8131
|
-
el.setAttribute(REMOVED_ATTR2, "");
|
|
8753
|
+
pointerEvents: "auto",
|
|
8754
|
+
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
8755
|
+
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
8756
|
+
},
|
|
8757
|
+
onClick: () => onEdit(hover.key),
|
|
8758
|
+
children: /* @__PURE__ */ jsxs8(
|
|
8759
|
+
Button,
|
|
8760
|
+
{
|
|
8761
|
+
"data-ohw-carousel-overlay": "",
|
|
8762
|
+
variant: "outline",
|
|
8763
|
+
size: "sm",
|
|
8764
|
+
className: "cursor-pointer gap-1.5 hover:bg-background",
|
|
8765
|
+
style: OVERLAY_BUTTON_STYLE2,
|
|
8766
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
8767
|
+
onClick: (e) => {
|
|
8768
|
+
e.stopPropagation();
|
|
8769
|
+
onEdit(hover.key);
|
|
8770
|
+
},
|
|
8771
|
+
children: [
|
|
8772
|
+
/* @__PURE__ */ jsx16(GalleryHorizontal, { size: 14 }),
|
|
8773
|
+
"Edit gallery"
|
|
8774
|
+
]
|
|
8775
|
+
}
|
|
8776
|
+
)
|
|
8132
8777
|
}
|
|
8133
|
-
}
|
|
8134
|
-
}
|
|
8135
|
-
function applyPersistedOrder(entries) {
|
|
8136
|
-
syncRemovedFlags(entries);
|
|
8137
|
-
if (entries.length === 0) return;
|
|
8138
|
-
const sections = topLevelSections();
|
|
8139
|
-
if (sections.length === 0) return;
|
|
8140
|
-
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
8141
|
-
const ordered = [...sections].sort((a, b) => {
|
|
8142
|
-
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
8143
|
-
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
8144
|
-
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
8145
|
-
if (aOrder === void 0) return 1;
|
|
8146
|
-
if (bOrder === void 0) return -1;
|
|
8147
|
-
return aOrder - bOrder;
|
|
8148
|
-
});
|
|
8149
|
-
let prev = null;
|
|
8150
|
-
for (const el of ordered) {
|
|
8151
|
-
if (prev) prev.after(el);
|
|
8152
|
-
prev = el;
|
|
8153
|
-
}
|
|
8154
|
-
}
|
|
8155
|
-
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
8156
|
-
if (!findByInstanceId(instanceId)) return null;
|
|
8157
|
-
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
8158
|
-
const allSections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
8159
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
|
|
8160
8778
|
);
|
|
8161
|
-
allSections.forEach((el, order) => {
|
|
8162
|
-
const id = instanceIdOf(el);
|
|
8163
|
-
if (!byId.has(id)) {
|
|
8164
|
-
byId.set(id, { instanceId: id, type: el.getAttribute("data-ohw-section") ?? "", order, pagePath: currentPath });
|
|
8165
|
-
}
|
|
8166
|
-
});
|
|
8167
|
-
const target = byId.get(instanceId);
|
|
8168
|
-
if (!target) return null;
|
|
8169
|
-
byId.set(instanceId, { ...target, removed });
|
|
8170
|
-
const entries = Array.from(byId.values());
|
|
8171
|
-
applyPersistedOrder(entries);
|
|
8172
|
-
return entries;
|
|
8173
|
-
}
|
|
8174
|
-
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
8175
|
-
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
8176
|
-
}
|
|
8177
|
-
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
8178
|
-
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
8179
|
-
}
|
|
8180
|
-
function newInstanceId() {
|
|
8181
|
-
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
8182
|
-
}
|
|
8183
|
-
function getPageSectionOrderEntries(raw, currentPath) {
|
|
8184
|
-
if (!raw) return [];
|
|
8185
|
-
try {
|
|
8186
|
-
const entries = JSON.parse(raw);
|
|
8187
|
-
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
8188
|
-
} catch {
|
|
8189
|
-
return [];
|
|
8190
|
-
}
|
|
8191
|
-
}
|
|
8192
|
-
function rekeySectionSubtree(root, instanceId) {
|
|
8193
|
-
const suffix = `::${instanceId}`;
|
|
8194
|
-
const rekey = (el, attr) => {
|
|
8195
|
-
const current = el.getAttribute(attr);
|
|
8196
|
-
if (current) el.setAttribute(attr, `${current}${suffix}`);
|
|
8197
|
-
};
|
|
8198
|
-
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
8199
|
-
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
8200
|
-
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
8201
|
-
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
8202
|
-
}
|
|
8203
|
-
function initSectionInstancesFromContent(content, currentPath) {
|
|
8204
|
-
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
8205
|
-
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
8206
|
-
});
|
|
8207
|
-
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
8208
|
-
for (const entry of entries) {
|
|
8209
|
-
if (entry.instanceId === entry.type) continue;
|
|
8210
|
-
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
8211
|
-
const original = document.querySelector(
|
|
8212
|
-
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
8213
|
-
);
|
|
8214
|
-
if (!original) continue;
|
|
8215
|
-
const clone = original.cloneNode(true);
|
|
8216
|
-
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
8217
|
-
rekeySectionSubtree(clone, entry.instanceId);
|
|
8218
|
-
original.insertAdjacentElement("afterend", clone);
|
|
8219
|
-
}
|
|
8220
|
-
applyPersistedOrder(entries);
|
|
8221
8779
|
}
|
|
8222
8780
|
|
|
8223
8781
|
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
8782
|
+
import { useCallback as useCallback2, useEffect as useEffect4, useRef as useRef4, useState as useState5 } from "react";
|
|
8783
|
+
import { Check, X } from "lucide-react";
|
|
8224
8784
|
import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
8225
8785
|
function findSectionElement(instanceId) {
|
|
8226
8786
|
const escaped = CSS.escape(instanceId);
|
|
@@ -12936,6 +13496,7 @@ function readLogoSizeState(content, placement) {
|
|
|
12936
13496
|
function getLogoElement(el) {
|
|
12937
13497
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
12938
13498
|
if (marked) return marked;
|
|
13499
|
+
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
12939
13500
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
12940
13501
|
if (!root) return null;
|
|
12941
13502
|
const anchor = el.closest("a");
|
|
@@ -14317,6 +14878,9 @@ function collectEditableNodes(extraContent, root = document) {
|
|
|
14317
14878
|
if (el.dataset.ohwEditable === "link") {
|
|
14318
14879
|
return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref3(el) };
|
|
14319
14880
|
}
|
|
14881
|
+
if (el.dataset.ohwEditable === "map") {
|
|
14882
|
+
return { key: el.dataset.ohwKey ?? "", type: "map", text: el.dataset.ohwMapQuery ?? "" };
|
|
14883
|
+
}
|
|
14320
14884
|
return {
|
|
14321
14885
|
key: el.dataset.ohwKey ?? "",
|
|
14322
14886
|
type: el.dataset.ohwEditable ?? "text",
|
|
@@ -14870,21 +15434,10 @@ function parseSchedulingInsertAfter(insertAfter) {
|
|
|
14870
15434
|
insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
|
|
14871
15435
|
};
|
|
14872
15436
|
}
|
|
14873
|
-
function
|
|
14874
|
-
|
|
14875
|
-
const
|
|
14876
|
-
|
|
14877
|
-
return { effectiveInsertAfter, insertBefore };
|
|
14878
|
-
}
|
|
14879
|
-
function getSchedulingMountPoint(insertAfter) {
|
|
14880
|
-
const { anchor } = parseSchedulingInsertAfter(insertAfter);
|
|
14881
|
-
let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
|
|
14882
|
-
if (!anchorEl && anchor === "scheduling") {
|
|
14883
|
-
const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
|
|
14884
|
-
anchorEl = widgets.at(-1) ?? null;
|
|
14885
|
-
}
|
|
14886
|
-
if (!anchorEl) return null;
|
|
14887
|
-
return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
15437
|
+
function resolveEntryAnchor(entry) {
|
|
15438
|
+
if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
|
|
15439
|
+
const parsed = parseSchedulingInsertAfter(entry.insertAfter);
|
|
15440
|
+
return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
|
|
14888
15441
|
}
|
|
14889
15442
|
function schedulingMountDepth(insertAfter) {
|
|
14890
15443
|
if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
|
|
@@ -14901,8 +15454,7 @@ function getPageSchedulingEntries(raw) {
|
|
|
14901
15454
|
}
|
|
14902
15455
|
}
|
|
14903
15456
|
function isSchedulingWidgetMissing(entry) {
|
|
14904
|
-
|
|
14905
|
-
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
|
|
15457
|
+
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
|
|
14906
15458
|
}
|
|
14907
15459
|
function hasMissingSchedulingWidgets(entries) {
|
|
14908
15460
|
return entries.some(isSchedulingWidgetMissing);
|
|
@@ -14932,16 +15484,17 @@ function initSectionsFromContent(content, removeExisting = false) {
|
|
|
14932
15484
|
} catch {
|
|
14933
15485
|
}
|
|
14934
15486
|
}
|
|
14935
|
-
function mountSchedulingWidget(
|
|
14936
|
-
const
|
|
14937
|
-
const sectionId = schedulingSectionId(
|
|
15487
|
+
function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
|
|
15488
|
+
const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
|
|
15489
|
+
const sectionId = schedulingSectionId(widgetId);
|
|
14938
15490
|
if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
|
|
14939
|
-
const
|
|
14940
|
-
if (!
|
|
15491
|
+
const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
|
|
15492
|
+
if (!anchorEl) return false;
|
|
15493
|
+
const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
14941
15494
|
const container = document.createElement("div");
|
|
14942
15495
|
container.dataset.ohwSectionContainer = "scheduling";
|
|
14943
|
-
if (
|
|
14944
|
-
const beforeAnchor = document.querySelector(`[data-ohw-section="${
|
|
15496
|
+
if (beforeId) {
|
|
15497
|
+
const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
|
|
14945
15498
|
const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
|
|
14946
15499
|
if (!beforePoint) return false;
|
|
14947
15500
|
beforePoint.insertAdjacentElement("beforebegin", container);
|
|
@@ -14952,19 +15505,25 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
14952
15505
|
}
|
|
14953
15506
|
tail.insertAdjacentElement("afterend", container);
|
|
14954
15507
|
}
|
|
14955
|
-
|
|
14956
|
-
|
|
14957
|
-
|
|
14958
|
-
|
|
14959
|
-
|
|
14960
|
-
|
|
14961
|
-
|
|
14962
|
-
|
|
14963
|
-
|
|
14964
|
-
|
|
14965
|
-
|
|
14966
|
-
|
|
14967
|
-
|
|
15508
|
+
try {
|
|
15509
|
+
const root = createRoot2(container);
|
|
15510
|
+
flushSync2(() => {
|
|
15511
|
+
root.render(
|
|
15512
|
+
/* @__PURE__ */ jsx33(
|
|
15513
|
+
SchedulingWidget,
|
|
15514
|
+
{
|
|
15515
|
+
notifyOnConnect,
|
|
15516
|
+
initialScheduleId: scheduleId,
|
|
15517
|
+
insertAfter: widgetId
|
|
15518
|
+
}
|
|
15519
|
+
)
|
|
15520
|
+
);
|
|
15521
|
+
});
|
|
15522
|
+
} catch (err) {
|
|
15523
|
+
console.error("[ow:scheduling] render threw", err);
|
|
15524
|
+
container.remove();
|
|
15525
|
+
return false;
|
|
15526
|
+
}
|
|
14968
15527
|
const tracker = getSectionsTracker();
|
|
14969
15528
|
let sections = [];
|
|
14970
15529
|
try {
|
|
@@ -14972,10 +15531,12 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
14972
15531
|
} catch {
|
|
14973
15532
|
}
|
|
14974
15533
|
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
14975
|
-
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter ===
|
|
15534
|
+
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
|
|
14976
15535
|
sections.push({
|
|
14977
15536
|
type: "scheduling",
|
|
14978
|
-
insertAfter:
|
|
15537
|
+
insertAfter: widgetId,
|
|
15538
|
+
anchorId,
|
|
15539
|
+
beforeId: beforeId ?? null,
|
|
14979
15540
|
pagePath: window.location.pathname,
|
|
14980
15541
|
...scheduleId ? { scheduleId } : {}
|
|
14981
15542
|
});
|
|
@@ -14989,7 +15550,8 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
|
14989
15550
|
for (let i = pending.length - 1; i >= 0; i--) {
|
|
14990
15551
|
const entry = pending[i];
|
|
14991
15552
|
const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
|
|
14992
|
-
|
|
15553
|
+
const { anchorId, beforeId } = resolveEntryAnchor(entry);
|
|
15554
|
+
if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
|
|
14993
15555
|
pending.splice(i, 1);
|
|
14994
15556
|
}
|
|
14995
15557
|
}
|
|
@@ -15081,7 +15643,7 @@ var EDITOR_CHROME_SELECTOR = '[data-ohw-toolbar], [data-ohw-form-toolbar], [data
|
|
|
15081
15643
|
function isOverEditorChrome(x, y) {
|
|
15082
15644
|
return document.elementsFromPoint(x, y).some((el) => el instanceof HTMLElement && el.matches(EDITOR_CHROME_SELECTOR));
|
|
15083
15645
|
}
|
|
15084
|
-
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"])';
|
|
15646
|
+
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"])';
|
|
15085
15647
|
function getVideoEl2(el) {
|
|
15086
15648
|
return el instanceof HTMLVideoElement ? el : el.querySelector("video");
|
|
15087
15649
|
}
|
|
@@ -15137,6 +15699,12 @@ function applyVideoSettingNode(key, val) {
|
|
|
15137
15699
|
});
|
|
15138
15700
|
return true;
|
|
15139
15701
|
}
|
|
15702
|
+
function applyMapQuery(el, val) {
|
|
15703
|
+
if (!(el instanceof HTMLIFrameElement)) return;
|
|
15704
|
+
const nextSrc = `https://www.google.com/maps?q=${encodeURIComponent(val)}&output=embed`;
|
|
15705
|
+
if (el.src !== nextSrc) el.src = nextSrc;
|
|
15706
|
+
el.setAttribute("data-ohw-map-query", val);
|
|
15707
|
+
}
|
|
15140
15708
|
function applyLinkByKey(key, val) {
|
|
15141
15709
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
15142
15710
|
if (el.dataset.ohwEditable === "link") applyLinkHref(el, val);
|
|
@@ -15147,6 +15715,11 @@ function applyLinkByKey(key, val) {
|
|
|
15147
15715
|
hrefAnchors.forEach((el) => applyLinkHref(el, val));
|
|
15148
15716
|
}
|
|
15149
15717
|
}
|
|
15718
|
+
function isInsideLinkEditor(target) {
|
|
15719
|
+
return Boolean(
|
|
15720
|
+
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"]')
|
|
15721
|
+
);
|
|
15722
|
+
}
|
|
15150
15723
|
function isInsideFloatingPanel(target) {
|
|
15151
15724
|
return Boolean(target.closest("[data-ohw-floating-panel]"));
|
|
15152
15725
|
}
|
|
@@ -15154,11 +15727,6 @@ function isPointOverFloatingPanel(clientX, clientY) {
|
|
|
15154
15727
|
const el = document.elementFromPoint(clientX, clientY);
|
|
15155
15728
|
return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
|
|
15156
15729
|
}
|
|
15157
|
-
function isInsideLinkEditor(target) {
|
|
15158
|
-
return Boolean(
|
|
15159
|
-
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"]')
|
|
15160
|
-
);
|
|
15161
|
-
}
|
|
15162
15730
|
function getHrefKeyFromElement(el) {
|
|
15163
15731
|
if (!el) return null;
|
|
15164
15732
|
const anchor = el.closest("[data-ohw-href-key]");
|
|
@@ -15417,7 +15985,7 @@ function getNavigationSelectionParent(el) {
|
|
|
15417
15985
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
15418
15986
|
return getFooterLinksContainer();
|
|
15419
15987
|
}
|
|
15420
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
15988
|
+
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)) {
|
|
15421
15989
|
return getNavigationRoot(el);
|
|
15422
15990
|
}
|
|
15423
15991
|
return null;
|
|
@@ -15632,7 +16200,6 @@ var ICONS = {
|
|
|
15632
16200
|
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"/>',
|
|
15633
16201
|
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"/>'
|
|
15634
16202
|
};
|
|
15635
|
-
var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
|
|
15636
16203
|
var SELECTION_CHROME_GAP2 = 4;
|
|
15637
16204
|
var TOOLBAR_STROKE_GAP2 = 4;
|
|
15638
16205
|
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
@@ -16012,6 +16579,7 @@ function StateToggle({
|
|
|
16012
16579
|
);
|
|
16013
16580
|
}
|
|
16014
16581
|
var contentCache = /* @__PURE__ */ new Map();
|
|
16582
|
+
var fetchedContentPaths = /* @__PURE__ */ new Set();
|
|
16015
16583
|
var brandingCache = /* @__PURE__ */ new Map();
|
|
16016
16584
|
var OHW_LOADER_STYLE = {
|
|
16017
16585
|
position: "fixed",
|
|
@@ -16541,13 +17109,6 @@ function OhhwellsBridge() {
|
|
|
16541
17109
|
const [isItemDragging, setIsItemDragging] = useState13(false);
|
|
16542
17110
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = useState13(false);
|
|
16543
17111
|
isFooterFrameSelectionRef.current = isFooterFrameSelection;
|
|
16544
|
-
const [floatingPanel, setFloatingPanel] = useState13(null);
|
|
16545
|
-
const floatingPanelOpenRef = useRef10(false);
|
|
16546
|
-
floatingPanelOpenRef.current = floatingPanel !== null;
|
|
16547
|
-
const [floatingPanelPos, setFloatingPanelPos] = useState13(null);
|
|
16548
|
-
const [logoSizeDraft, setLogoSizeDraft] = useState13(null);
|
|
16549
|
-
const [editorViewport, setEditorViewport] = useState13("desktop");
|
|
16550
|
-
const [parentScrollSnap, setParentScrollSnap] = useState13(null);
|
|
16551
17112
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState13(null);
|
|
16552
17113
|
const [footerHeadingVisible, setFooterHeadingVisible] = useState13(null);
|
|
16553
17114
|
const footerDragRef = useRef10(null);
|
|
@@ -16565,6 +17126,13 @@ function OhhwellsBridge() {
|
|
|
16565
17126
|
const brandKitRef = useRef10("");
|
|
16566
17127
|
const stylesRef = useRef10("");
|
|
16567
17128
|
const pendingDeleteUndoRef = useRef10(null);
|
|
17129
|
+
const [floatingPanel, setFloatingPanel] = useState13(null);
|
|
17130
|
+
const floatingPanelOpenRef = useRef10(false);
|
|
17131
|
+
const setFloatingPanelRef = useRef10(setFloatingPanel);
|
|
17132
|
+
const [floatingPanelPos, setFloatingPanelPos] = useState13(null);
|
|
17133
|
+
const [logoSizeDraft, setLogoSizeDraft] = useState13(null);
|
|
17134
|
+
const [editorViewport, setEditorViewport] = useState13("desktop");
|
|
17135
|
+
const [parentScrollSnap, setParentScrollSnap] = useState13(null);
|
|
16568
17136
|
const [sitePages, setSitePages] = useState13([]);
|
|
16569
17137
|
const [sectionsByPath, setSectionsByPath] = useState13({});
|
|
16570
17138
|
const sectionsPrefetchGenRef = useRef10(0);
|
|
@@ -16573,7 +17141,18 @@ function OhhwellsBridge() {
|
|
|
16573
17141
|
const linkPopoverOpenRef = useRef10(false);
|
|
16574
17142
|
const linkPopoverGraceUntilRef = useRef10(0);
|
|
16575
17143
|
setLinkPopoverRef.current = setLinkPopover;
|
|
17144
|
+
setFloatingPanelRef.current = setFloatingPanel;
|
|
16576
17145
|
linkPopoverSessionRef.current = linkPopover;
|
|
17146
|
+
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
17147
|
+
useEffect13(() => {
|
|
17148
|
+
const syncViewport = () => {
|
|
17149
|
+
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
17150
|
+
setEditorViewport((prev) => prev === next ? prev : next);
|
|
17151
|
+
};
|
|
17152
|
+
syncViewport();
|
|
17153
|
+
window.addEventListener("resize", syncViewport);
|
|
17154
|
+
return () => window.removeEventListener("resize", syncViewport);
|
|
17155
|
+
}, []);
|
|
16577
17156
|
const {
|
|
16578
17157
|
navDragRef,
|
|
16579
17158
|
navDropSlots,
|
|
@@ -17898,17 +18477,19 @@ function OhhwellsBridge() {
|
|
|
17898
18477
|
}
|
|
17899
18478
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
17900
18479
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
18480
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
17901
18481
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
17902
18482
|
}
|
|
17903
18483
|
applyBrandChrome(content);
|
|
18484
|
+
initSectionInstancesFromContent(content, window.location.pathname);
|
|
17904
18485
|
for (const [key, val] of Object.entries(content)) {
|
|
17905
18486
|
if (key === "__ohw_sections") continue;
|
|
17906
18487
|
if (key === AI_SECTIONS_KEY) continue;
|
|
18488
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18489
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
17907
18490
|
if (key === BRAND_KIT_KEY) continue;
|
|
17908
18491
|
if (key === STYLE_STORE_KEY) continue;
|
|
17909
18492
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
17910
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
17911
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
17912
18493
|
if (applyVideoSettingNode(key, val)) continue;
|
|
17913
18494
|
if (applyCarouselNode(key, val)) continue;
|
|
17914
18495
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -17936,6 +18517,8 @@ function OhhwellsBridge() {
|
|
|
17936
18517
|
}
|
|
17937
18518
|
} else if (el.dataset.ohwEditable === "link") {
|
|
17938
18519
|
applyLinkHref(el, val);
|
|
18520
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
18521
|
+
applyMapQuery(el, val);
|
|
17939
18522
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
17940
18523
|
applyIconMarkup(el, val);
|
|
17941
18524
|
} else if (el.dataset.ohwEditable === "form") {
|
|
@@ -17956,7 +18539,6 @@ function OhhwellsBridge() {
|
|
|
17956
18539
|
if (isEditModeRef.current) requestMissingSocialIconsRef.current();
|
|
17957
18540
|
enforceLinkHrefs();
|
|
17958
18541
|
initSectionsFromContent(content, true);
|
|
17959
|
-
initSectionInstancesFromContent(content, window.location.pathname);
|
|
17960
18542
|
sectionsLoadedRef.current = true;
|
|
17961
18543
|
pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
|
|
17962
18544
|
if (imageLoads.length === 0) return Promise.resolve();
|
|
@@ -17975,7 +18557,9 @@ function OhhwellsBridge() {
|
|
|
17975
18557
|
let cancelled = false;
|
|
17976
18558
|
setFetchState("loading");
|
|
17977
18559
|
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
17978
|
-
|
|
18560
|
+
const initialPath = pathname;
|
|
18561
|
+
fetchedContentPaths.add(`${subdomain}::${initialPath}`);
|
|
18562
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
17979
18563
|
if (cancelled) return;
|
|
17980
18564
|
const content = data?.content ?? {};
|
|
17981
18565
|
const branding = Boolean(data?.showBranding);
|
|
@@ -18109,16 +18693,17 @@ function OhhwellsBridge() {
|
|
|
18109
18693
|
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
18110
18694
|
}
|
|
18111
18695
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
18696
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
18112
18697
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
18113
18698
|
}
|
|
18114
18699
|
for (const [key, val] of Object.entries(content)) {
|
|
18115
18700
|
if (key === "__ohw_sections") continue;
|
|
18116
18701
|
if (key === AI_SECTIONS_KEY) continue;
|
|
18702
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18703
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18117
18704
|
if (key === BRAND_KIT_KEY) continue;
|
|
18118
18705
|
if (key === STYLE_STORE_KEY) continue;
|
|
18119
18706
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
18120
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18121
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18122
18707
|
if (applyVideoSettingNode(key, val)) continue;
|
|
18123
18708
|
if (applyCarouselNode(key, val)) continue;
|
|
18124
18709
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -18133,6 +18718,8 @@ function OhhwellsBridge() {
|
|
|
18133
18718
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
18134
18719
|
} else if (el.dataset.ohwEditable === "link") {
|
|
18135
18720
|
applyLinkHref(el, val);
|
|
18721
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
18722
|
+
applyMapQuery(el, val);
|
|
18136
18723
|
} else if (el.dataset.ohwEditable === "form") {
|
|
18137
18724
|
} else if (isIconMarkupValue(val)) {
|
|
18138
18725
|
} else if (el.innerHTML !== val) {
|
|
@@ -18164,6 +18751,17 @@ function OhhwellsBridge() {
|
|
|
18164
18751
|
debounceTimer = setTimeout(applyFromCache, 150);
|
|
18165
18752
|
};
|
|
18166
18753
|
applyFromCache();
|
|
18754
|
+
const pathCacheKey = `${subdomain}::${pathname}`;
|
|
18755
|
+
if (!fetchedContentPaths.has(pathCacheKey)) {
|
|
18756
|
+
fetchedContentPaths.add(pathCacheKey);
|
|
18757
|
+
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
18758
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
18759
|
+
if (!data?.content) return;
|
|
18760
|
+
contentCache.set(subdomain, data.content);
|
|
18761
|
+
applyFromCache();
|
|
18762
|
+
}).catch(() => {
|
|
18763
|
+
});
|
|
18764
|
+
}
|
|
18167
18765
|
observer = new MutationObserver(scheduleApply);
|
|
18168
18766
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
18169
18767
|
return () => {
|
|
@@ -18279,26 +18877,11 @@ function OhhwellsBridge() {
|
|
|
18279
18877
|
const t2 = setTimeout(measure, 500);
|
|
18280
18878
|
const ro = new ResizeObserver(schedule);
|
|
18281
18879
|
ro.observe(document.body);
|
|
18282
|
-
let lastWidth = window.innerWidth;
|
|
18283
|
-
let resizeTimers = [];
|
|
18284
|
-
const clearResizeTimers = () => {
|
|
18285
|
-
resizeTimers.forEach(clearTimeout);
|
|
18286
|
-
resizeTimers = [];
|
|
18287
|
-
};
|
|
18288
|
-
const handleResize = () => {
|
|
18289
|
-
if (window.innerWidth === lastWidth) return;
|
|
18290
|
-
lastWidth = window.innerWidth;
|
|
18291
|
-
clearResizeTimers();
|
|
18292
|
-
resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
|
|
18293
|
-
};
|
|
18294
|
-
window.addEventListener("resize", handleResize);
|
|
18295
18880
|
return () => {
|
|
18296
18881
|
clearTimeout(t1);
|
|
18297
18882
|
clearTimeout(t2);
|
|
18298
18883
|
if (raf != null) cancelAnimationFrame(raf);
|
|
18299
18884
|
ro.disconnect();
|
|
18300
|
-
clearResizeTimers();
|
|
18301
|
-
window.removeEventListener("resize", handleResize);
|
|
18302
18885
|
};
|
|
18303
18886
|
}, [pathname, isEditMode, postToParent2]);
|
|
18304
18887
|
useEffect13(() => {
|
|
@@ -18544,9 +19127,6 @@ function OhhwellsBridge() {
|
|
|
18544
19127
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
18545
19128
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
18546
19129
|
if (isInsideLinkEditor(target)) return;
|
|
18547
|
-
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
18548
|
-
clearMediaSelectionRef.current();
|
|
18549
|
-
}
|
|
18550
19130
|
if (isInsideFloatingPanel(target)) return;
|
|
18551
19131
|
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
18552
19132
|
if (target.closest(
|
|
@@ -18554,6 +19134,9 @@ function OhhwellsBridge() {
|
|
|
18554
19134
|
)) {
|
|
18555
19135
|
return;
|
|
18556
19136
|
}
|
|
19137
|
+
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
19138
|
+
clearMediaSelectionRef.current();
|
|
19139
|
+
}
|
|
18557
19140
|
{
|
|
18558
19141
|
const formEl = getFormElement(target);
|
|
18559
19142
|
const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
|
|
@@ -18705,14 +19288,6 @@ function OhhwellsBridge() {
|
|
|
18705
19288
|
}
|
|
18706
19289
|
const clickedButton = findClosestButtonLike(target);
|
|
18707
19290
|
const buttonOnMedia = Boolean(clickedButton && isMediaEditable(editable) && editable.contains(clickedButton));
|
|
18708
|
-
console.log("[click-debug]", {
|
|
18709
|
-
editableType: editable.dataset.ohwEditable,
|
|
18710
|
-
editableTag: editable.tagName,
|
|
18711
|
-
targetTag: target.tagName,
|
|
18712
|
-
clickedButtonTag: clickedButton?.tagName ?? null,
|
|
18713
|
-
buttonOnMedia,
|
|
18714
|
-
isMediaEditableEditable: isMediaEditable(editable)
|
|
18715
|
-
});
|
|
18716
19291
|
if (isMediaEditable(editable) && !buttonOnMedia) {
|
|
18717
19292
|
e.preventDefault();
|
|
18718
19293
|
e.stopPropagation();
|
|
@@ -18739,11 +19314,6 @@ function OhhwellsBridge() {
|
|
|
18739
19314
|
const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
|
|
18740
19315
|
const hrefCtx = getHrefKeyFromElement(hrefLookupTarget);
|
|
18741
19316
|
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
18742
|
-
console.log("[click-debug 2]", {
|
|
18743
|
-
hrefLookupTargetTag: hrefLookupTarget.tagName,
|
|
18744
|
-
hrefCtx: hrefCtx ? { key: hrefCtx.key } : null,
|
|
18745
|
-
navAnchorTag: navAnchor?.tagName ?? null
|
|
18746
|
-
});
|
|
18747
19317
|
if (navAnchor) {
|
|
18748
19318
|
e.preventDefault();
|
|
18749
19319
|
e.stopPropagation();
|
|
@@ -18913,6 +19483,9 @@ function OhhwellsBridge() {
|
|
|
18913
19483
|
setHoveredItemRect(null);
|
|
18914
19484
|
hoveredNavContainerRef.current = null;
|
|
18915
19485
|
setHoveredNavContainerRect(null);
|
|
19486
|
+
siblingHintElRef.current = null;
|
|
19487
|
+
setSiblingHintRect(null);
|
|
19488
|
+
setSiblingHintRects([]);
|
|
18916
19489
|
return;
|
|
18917
19490
|
}
|
|
18918
19491
|
{
|
|
@@ -19031,7 +19604,6 @@ function OhhwellsBridge() {
|
|
|
19031
19604
|
hoveredNavContainerRef.current = null;
|
|
19032
19605
|
setHoveredNavContainerRect(null);
|
|
19033
19606
|
hoveredItemElRef.current = editable;
|
|
19034
|
-
setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
|
|
19035
19607
|
}
|
|
19036
19608
|
}
|
|
19037
19609
|
}
|
|
@@ -19328,7 +19900,7 @@ function OhhwellsBridge() {
|
|
|
19328
19900
|
}
|
|
19329
19901
|
};
|
|
19330
19902
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
19331
|
-
if (linkPopoverOpenRef.current) {
|
|
19903
|
+
if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
19332
19904
|
if (hoveredImageRef.current) {
|
|
19333
19905
|
hoveredImageRef.current = null;
|
|
19334
19906
|
hoveredImageHasTextOverlapRef.current = false;
|
|
@@ -19693,8 +20265,7 @@ function OhhwellsBridge() {
|
|
|
19693
20265
|
};
|
|
19694
20266
|
const handleMouseMove = (e) => {
|
|
19695
20267
|
const { clientX, clientY } = e;
|
|
19696
|
-
if (
|
|
19697
|
-
if (isOverEditorChrome(clientX, clientY)) {
|
|
20268
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
|
|
19698
20269
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
19699
20270
|
formHoverElRef.current = null;
|
|
19700
20271
|
setFormHoverRect(null);
|
|
@@ -19702,6 +20273,12 @@ function OhhwellsBridge() {
|
|
|
19702
20273
|
setHoveredItemRect(null);
|
|
19703
20274
|
hoveredNavContainerRef.current = null;
|
|
19704
20275
|
setHoveredNavContainerRect(null);
|
|
20276
|
+
siblingHintElRef.current = null;
|
|
20277
|
+
setSiblingHintRect(null);
|
|
20278
|
+
setSiblingHintRects([]);
|
|
20279
|
+
dismissImageHover();
|
|
20280
|
+
clearImageHover();
|
|
20281
|
+
setSectionGap(null);
|
|
19705
20282
|
return;
|
|
19706
20283
|
}
|
|
19707
20284
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
@@ -19713,7 +20290,11 @@ function OhhwellsBridge() {
|
|
|
19713
20290
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
19714
20291
|
const { clientX, clientY } = e.data;
|
|
19715
20292
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
19716
|
-
if (
|
|
20293
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
20294
|
+
dismissImageHover();
|
|
20295
|
+
clearImageHover();
|
|
20296
|
+
return;
|
|
20297
|
+
}
|
|
19717
20298
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
19718
20299
|
probeSectionGapAt(clientX, clientY);
|
|
19719
20300
|
probeImageAt(clientX, clientY);
|
|
@@ -19992,6 +20573,44 @@ function OhhwellsBridge() {
|
|
|
19992
20573
|
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
19993
20574
|
}, 400));
|
|
19994
20575
|
};
|
|
20576
|
+
const reapCommittedAiSections = (excludeIds) => {
|
|
20577
|
+
const aiState = parseAiSectionsState(aiSectionsRef.current);
|
|
20578
|
+
if (aiState.sections.length === 0) return [];
|
|
20579
|
+
let orderEntries = [];
|
|
20580
|
+
try {
|
|
20581
|
+
const parsed = JSON.parse(editContentRef.current[SECTION_ORDER_KEY] ?? "[]");
|
|
20582
|
+
if (Array.isArray(parsed)) orderEntries = parsed;
|
|
20583
|
+
} catch {
|
|
20584
|
+
return [];
|
|
20585
|
+
}
|
|
20586
|
+
const removedIds = orderEntries.filter((entry) => entry && typeof entry.instanceId === "string" && entry.removed).map((entry) => entry.instanceId);
|
|
20587
|
+
if (removedIds.length === 0) return [];
|
|
20588
|
+
const result = reapRemovedAiSections(aiState, parseStyleStore(stylesRef.current), removedIds, excludeIds);
|
|
20589
|
+
if (!result.changed) return [];
|
|
20590
|
+
const nodes = [];
|
|
20591
|
+
aiSectionsRef.current = serializeAiSectionsState(result.state);
|
|
20592
|
+
nodes.push({ key: AI_SECTIONS_KEY, text: aiSectionsRef.current });
|
|
20593
|
+
const reaped = new Set(result.reapedIds);
|
|
20594
|
+
const nextOrderJson = JSON.stringify(orderEntries.filter((entry) => !reaped.has(entry.instanceId)));
|
|
20595
|
+
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: nextOrderJson };
|
|
20596
|
+
setAiSectionOrder(nextOrderJson, window.location.pathname);
|
|
20597
|
+
nodes.push({ key: SECTION_ORDER_KEY, text: nextOrderJson });
|
|
20598
|
+
if (result.store) {
|
|
20599
|
+
stylesRef.current = JSON.stringify(result.store);
|
|
20600
|
+
nodes.push({ key: STYLE_STORE_KEY, text: stylesRef.current });
|
|
20601
|
+
}
|
|
20602
|
+
const nextContent = { ...editContentRef.current };
|
|
20603
|
+
for (const key of Object.keys(nextContent)) {
|
|
20604
|
+
if (key.startsWith(AI_SLOT_KEY_PREFIX) && result.slotPrefixes.some((prefix) => key.startsWith(prefix)) && nextContent[key] !== "") {
|
|
20605
|
+
nextContent[key] = "";
|
|
20606
|
+
nodes.push({ key, text: "" });
|
|
20607
|
+
}
|
|
20608
|
+
}
|
|
20609
|
+
editContentRef.current = nextContent;
|
|
20610
|
+
applyAiSectionsToDom(result.state);
|
|
20611
|
+
applyStylesToDom(parseStyleStore(stylesRef.current));
|
|
20612
|
+
return nodes;
|
|
20613
|
+
};
|
|
19995
20614
|
const handleHydrate = (e) => {
|
|
19996
20615
|
if (e.data?.type !== "ow:hydrate") return;
|
|
19997
20616
|
const content = e.data.content;
|
|
@@ -20010,9 +20629,11 @@ function OhhwellsBridge() {
|
|
|
20010
20629
|
}
|
|
20011
20630
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
20012
20631
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
20632
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
20013
20633
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
20014
20634
|
}
|
|
20015
20635
|
applyBrandChrome(content);
|
|
20636
|
+
initSectionInstancesFromContent(content, window.location.pathname);
|
|
20016
20637
|
let sectionsJson = null;
|
|
20017
20638
|
for (const [key, val] of Object.entries(content)) {
|
|
20018
20639
|
if (key === "__ohw_sections") {
|
|
@@ -20020,11 +20641,11 @@ function OhhwellsBridge() {
|
|
|
20020
20641
|
continue;
|
|
20021
20642
|
}
|
|
20022
20643
|
if (key === AI_SECTIONS_KEY) continue;
|
|
20644
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
20645
|
+
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
20023
20646
|
if (key === BRAND_KIT_KEY) continue;
|
|
20024
20647
|
if (key === STYLE_STORE_KEY) continue;
|
|
20025
20648
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
20026
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
20027
|
-
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
20028
20649
|
if (applyVideoSettingNode(key, val)) continue;
|
|
20029
20650
|
if (applyCarouselNode(key, val)) continue;
|
|
20030
20651
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -20038,6 +20659,8 @@ function OhhwellsBridge() {
|
|
|
20038
20659
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
20039
20660
|
} else if (el.dataset.ohwEditable === "link") {
|
|
20040
20661
|
applyLinkHref(el, val);
|
|
20662
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
20663
|
+
applyMapQuery(el, val);
|
|
20041
20664
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
20042
20665
|
applyIconMarkup(el, val);
|
|
20043
20666
|
} else if (isIconMarkupValue(val)) {
|
|
@@ -20054,12 +20677,16 @@ function OhhwellsBridge() {
|
|
|
20054
20677
|
sectionsLoadedRef.current = true;
|
|
20055
20678
|
pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
|
|
20056
20679
|
}
|
|
20057
|
-
initSectionInstancesFromContent(content, window.location.pathname);
|
|
20058
20680
|
editContentRef.current = { ...editContentRef.current, ...content };
|
|
20059
20681
|
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
20060
20682
|
reconcileFooterOrderFromContent(editContentRef.current);
|
|
20061
20683
|
syncNavigationDragCursorAttrs();
|
|
20062
20684
|
enforceLinkHrefs();
|
|
20685
|
+
const hydrateReapExclude = /* @__PURE__ */ new Set();
|
|
20686
|
+
const hydratePendingUndo = pendingDeleteUndoRef.current;
|
|
20687
|
+
if (hydratePendingUndo?.sectionInstanceId) hydrateReapExclude.add(hydratePendingUndo.sectionInstanceId);
|
|
20688
|
+
const reapNodes = reapCommittedAiSections(hydrateReapExclude);
|
|
20689
|
+
if (reapNodes.length > 0) postToParentRef.current({ type: "ow:change", nodes: reapNodes });
|
|
20063
20690
|
const hydratedHeight = document.body.scrollHeight;
|
|
20064
20691
|
if (hydratedHeight > 50) postToParentRef.current({ type: "ow:height", height: hydratedHeight });
|
|
20065
20692
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
@@ -20199,12 +20826,35 @@ function OhhwellsBridge() {
|
|
|
20199
20826
|
window.addEventListener("message", handleAiSetBrand);
|
|
20200
20827
|
const handleAiSetStyles = (e) => {
|
|
20201
20828
|
if (e.data?.type !== "ow:ai-set-styles") return;
|
|
20202
|
-
|
|
20829
|
+
let value = typeof e.data.value === "string" ? e.data.value : "";
|
|
20203
20830
|
const previous = stylesRef.current;
|
|
20831
|
+
let previousSections;
|
|
20832
|
+
const store = parseStyleStore(value);
|
|
20833
|
+
if (store) {
|
|
20834
|
+
const folded = foldAlignIntoTrees(parseAiSectionsState(aiSectionsRef.current), store);
|
|
20835
|
+
if (folded.changed) {
|
|
20836
|
+
const nextSections = serializeAiSectionsState(folded.state);
|
|
20837
|
+
if (nextSections !== aiSectionsRef.current) {
|
|
20838
|
+
previousSections = aiSectionsRef.current;
|
|
20839
|
+
aiSectionsRef.current = nextSections;
|
|
20840
|
+
applyAiSectionsToDom(folded.state);
|
|
20841
|
+
postToParentRef.current({
|
|
20842
|
+
type: "ow:change",
|
|
20843
|
+
nodes: [{ key: AI_SECTIONS_KEY, text: nextSections }]
|
|
20844
|
+
});
|
|
20845
|
+
}
|
|
20846
|
+
value = JSON.stringify(folded.store);
|
|
20847
|
+
}
|
|
20848
|
+
}
|
|
20204
20849
|
stylesRef.current = value;
|
|
20205
20850
|
applyStylesToDom(parseStyleStore(value));
|
|
20206
20851
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: STYLE_STORE_KEY, text: value }] });
|
|
20207
|
-
postToParentRef.current({
|
|
20852
|
+
postToParentRef.current({
|
|
20853
|
+
type: "ow:ai-styles-applied",
|
|
20854
|
+
previous,
|
|
20855
|
+
value,
|
|
20856
|
+
...previousSections !== void 0 ? { previousSections } : {}
|
|
20857
|
+
});
|
|
20208
20858
|
};
|
|
20209
20859
|
window.addEventListener("message", handleAiSetStyles);
|
|
20210
20860
|
const handleGetBrand = (e) => {
|
|
@@ -20243,6 +20893,7 @@ function OhhwellsBridge() {
|
|
|
20243
20893
|
if (!entries) return;
|
|
20244
20894
|
const orderJson = JSON.stringify(entries);
|
|
20245
20895
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
20896
|
+
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20246
20897
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
20247
20898
|
aiSectionApiRef.current?.clear();
|
|
20248
20899
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20251,6 +20902,7 @@ function OhhwellsBridge() {
|
|
|
20251
20902
|
const actionId = newInstanceId();
|
|
20252
20903
|
pendingDeleteUndoRef.current = {
|
|
20253
20904
|
actionId,
|
|
20905
|
+
sectionInstanceId: instanceId,
|
|
20254
20906
|
restore: () => {
|
|
20255
20907
|
const restoredEntries = getPageSectionOrderEntries(
|
|
20256
20908
|
editContentRef.current[SECTION_ORDER_KEY],
|
|
@@ -20260,6 +20912,7 @@ function OhhwellsBridge() {
|
|
|
20260
20912
|
if (!restored) return;
|
|
20261
20913
|
const restoredJson = JSON.stringify(restored);
|
|
20262
20914
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: restoredJson };
|
|
20915
|
+
setAiSectionOrder(restoredJson, window.location.pathname);
|
|
20263
20916
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: restoredJson }] });
|
|
20264
20917
|
window.dispatchEvent(new Event("resize"));
|
|
20265
20918
|
const restoreHeight = document.body.scrollHeight;
|
|
@@ -20276,6 +20929,34 @@ function OhhwellsBridge() {
|
|
|
20276
20929
|
});
|
|
20277
20930
|
};
|
|
20278
20931
|
window.addEventListener("message", handleDeleteSection);
|
|
20932
|
+
const handleDuplicateSection = (e) => {
|
|
20933
|
+
if (e.data?.type !== "ow:duplicate-section") return;
|
|
20934
|
+
const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
|
|
20935
|
+
if (!instanceId) return;
|
|
20936
|
+
const newId = newInstanceId();
|
|
20937
|
+
const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname);
|
|
20938
|
+
const result = duplicateSectionInstance(instanceId, newId, window.location.pathname, currentEntries);
|
|
20939
|
+
if (!result) return;
|
|
20940
|
+
const { entries, keyRekeys } = result;
|
|
20941
|
+
const orderJson = JSON.stringify(entries);
|
|
20942
|
+
const nodes = [{ key: SECTION_ORDER_KEY, text: orderJson }];
|
|
20943
|
+
for (const { from, to } of keyRekeys) {
|
|
20944
|
+
const inherited = editContentRef.current[from];
|
|
20945
|
+
if (inherited !== void 0) nodes.push({ key: to, text: inherited });
|
|
20946
|
+
}
|
|
20947
|
+
editContentRef.current = {
|
|
20948
|
+
...editContentRef.current,
|
|
20949
|
+
...Object.fromEntries(nodes.map(({ key, text }) => [key, text]))
|
|
20950
|
+
};
|
|
20951
|
+
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20952
|
+
postToParentRef.current({ type: "ow:change", nodes });
|
|
20953
|
+
window.dispatchEvent(new Event("resize"));
|
|
20954
|
+
const duplicateHeight = document.body.scrollHeight;
|
|
20955
|
+
if (duplicateHeight > 50) postToParentRef.current({ type: "ow:height", height: duplicateHeight });
|
|
20956
|
+
const clone = document.querySelector(`[data-ohw-instance="${CSS.escape(newId)}"]`);
|
|
20957
|
+
if (clone) aiSectionApiRef.current?.selectFromElement(clone);
|
|
20958
|
+
};
|
|
20959
|
+
window.addEventListener("message", handleDuplicateSection);
|
|
20279
20960
|
const handleDeactivate = (e) => {
|
|
20280
20961
|
if (e.data?.type !== "ow:deactivate") return;
|
|
20281
20962
|
if (document.documentElement.hasAttribute("data-ohw-panel-dragging")) return;
|
|
@@ -20285,6 +20966,12 @@ function OhhwellsBridge() {
|
|
|
20285
20966
|
closeLinkPopoverRef.current();
|
|
20286
20967
|
return;
|
|
20287
20968
|
}
|
|
20969
|
+
if (floatingPanelOpenRef.current) {
|
|
20970
|
+
setFloatingPanelRef.current(null);
|
|
20971
|
+
deselectRef.current();
|
|
20972
|
+
deactivateRef.current();
|
|
20973
|
+
return;
|
|
20974
|
+
}
|
|
20288
20975
|
deselectRef.current();
|
|
20289
20976
|
deactivateRef.current();
|
|
20290
20977
|
clearMediaSelectionRef.current();
|
|
@@ -20530,6 +21217,10 @@ function OhhwellsBridge() {
|
|
|
20530
21217
|
};
|
|
20531
21218
|
const handleSave = (e) => {
|
|
20532
21219
|
if (e.data?.type !== "ow:save") return;
|
|
21220
|
+
const pendingUndo = pendingDeleteUndoRef.current;
|
|
21221
|
+
const reapExclude = /* @__PURE__ */ new Set();
|
|
21222
|
+
if (pendingUndo?.sectionInstanceId) reapExclude.add(pendingUndo.sectionInstanceId);
|
|
21223
|
+
const reapNodes = reapCommittedAiSections(reapExclude);
|
|
20533
21224
|
const nodes = collectEditableNodes(editContentRef.current);
|
|
20534
21225
|
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
20535
21226
|
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
@@ -20549,6 +21240,11 @@ function OhhwellsBridge() {
|
|
|
20549
21240
|
const text = specs.length ? JSON.stringify(specs) : editContentRef.current[fieldsKey(formKey)];
|
|
20550
21241
|
if (text) nodes.push({ key: fieldsKey(formKey), type: "text", text });
|
|
20551
21242
|
});
|
|
21243
|
+
for (const reapNode of reapNodes) {
|
|
21244
|
+
if (reapNode.key.startsWith(AI_SLOT_KEY_PREFIX) && !nodes.some((n) => n.key === reapNode.key)) {
|
|
21245
|
+
nodes.push({ key: reapNode.key, type: "text", text: reapNode.text });
|
|
21246
|
+
}
|
|
21247
|
+
}
|
|
20552
21248
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
20553
21249
|
};
|
|
20554
21250
|
const handleInsertSection = (e) => {
|
|
@@ -20559,8 +21255,12 @@ function OhhwellsBridge() {
|
|
|
20559
21255
|
if (inserted) {
|
|
20560
21256
|
const tracker = getSectionsTracker();
|
|
20561
21257
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
|
|
20562
|
-
const
|
|
20563
|
-
|
|
21258
|
+
const reportHeight = () => {
|
|
21259
|
+
const h = document.body.scrollHeight;
|
|
21260
|
+
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
21261
|
+
};
|
|
21262
|
+
reportHeight();
|
|
21263
|
+
setTimeout(reportHeight, 500);
|
|
20564
21264
|
}
|
|
20565
21265
|
};
|
|
20566
21266
|
const handleSwitchSchedule = (e) => {
|
|
@@ -20962,11 +21662,12 @@ function OhhwellsBridge() {
|
|
|
20962
21662
|
window.removeEventListener("message", handleMoveSection);
|
|
20963
21663
|
window.removeEventListener("message", handlePanelDragging);
|
|
20964
21664
|
window.removeEventListener("message", handleDeleteSection);
|
|
21665
|
+
window.removeEventListener("message", handleDuplicateSection);
|
|
20965
21666
|
window.removeEventListener("message", handleDeactivate);
|
|
20966
|
-
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
20967
21667
|
window.removeEventListener("message", handleToastAction);
|
|
20968
21668
|
window.removeEventListener("message", handleFormCount);
|
|
20969
21669
|
window.removeEventListener("message", handleUiEscape);
|
|
21670
|
+
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
20970
21671
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
20971
21672
|
autoSaveTimers.current.clear();
|
|
20972
21673
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
@@ -21169,7 +21870,7 @@ function OhhwellsBridge() {
|
|
|
21169
21870
|
postToParent2({
|
|
21170
21871
|
type: "ow:ready",
|
|
21171
21872
|
version: "1",
|
|
21172
|
-
bridgeVersion: "0.1.
|
|
21873
|
+
bridgeVersion: "0.1.86",
|
|
21173
21874
|
path: pathname,
|
|
21174
21875
|
nodes: collectEditableNodes(editContentRef.current),
|
|
21175
21876
|
sections
|
|
@@ -22088,6 +22789,59 @@ function OhhwellsBridge() {
|
|
|
22088
22789
|
) : null
|
|
22089
22790
|
] });
|
|
22090
22791
|
}
|
|
22792
|
+
|
|
22793
|
+
// src/ui/EmptySection.tsx
|
|
22794
|
+
import Link3 from "next/link";
|
|
22795
|
+
import { Fragment as Fragment9, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
22796
|
+
function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
|
|
22797
|
+
return /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
22798
|
+
/* @__PURE__ */ jsx34(
|
|
22799
|
+
"p",
|
|
22800
|
+
{
|
|
22801
|
+
style: {
|
|
22802
|
+
fontFamily: "var(--brand-font-body)",
|
|
22803
|
+
fontSize: "0.75rem",
|
|
22804
|
+
fontWeight: 500,
|
|
22805
|
+
letterSpacing: "0.15em",
|
|
22806
|
+
textTransform: "uppercase",
|
|
22807
|
+
color: "var(--brand-accent)",
|
|
22808
|
+
marginBottom: "1.5rem"
|
|
22809
|
+
},
|
|
22810
|
+
children: /* @__PURE__ */ jsx34(Link3, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ jsx34("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
|
|
22811
|
+
}
|
|
22812
|
+
),
|
|
22813
|
+
/* @__PURE__ */ jsx34(
|
|
22814
|
+
"h1",
|
|
22815
|
+
{
|
|
22816
|
+
style: {
|
|
22817
|
+
fontFamily: "var(--brand-font-heading)",
|
|
22818
|
+
fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
|
|
22819
|
+
lineHeight: 1.1,
|
|
22820
|
+
letterSpacing: "-0.025em",
|
|
22821
|
+
color: "var(--brand-text)",
|
|
22822
|
+
marginBottom: "1rem"
|
|
22823
|
+
},
|
|
22824
|
+
...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
|
|
22825
|
+
children: title
|
|
22826
|
+
}
|
|
22827
|
+
),
|
|
22828
|
+
/* @__PURE__ */ jsx34(
|
|
22829
|
+
"p",
|
|
22830
|
+
{
|
|
22831
|
+
style: {
|
|
22832
|
+
fontFamily: "var(--brand-font-body)",
|
|
22833
|
+
fontSize: "1rem",
|
|
22834
|
+
lineHeight: 1.7,
|
|
22835
|
+
fontWeight: 300,
|
|
22836
|
+
color: "var(--brand-text-muted)",
|
|
22837
|
+
maxWidth: "340px"
|
|
22838
|
+
},
|
|
22839
|
+
...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
|
|
22840
|
+
children: "This page doesn't have any content yet."
|
|
22841
|
+
}
|
|
22842
|
+
)
|
|
22843
|
+
] });
|
|
22844
|
+
}
|
|
22091
22845
|
export {
|
|
22092
22846
|
AI_DEFAULT_BRAND,
|
|
22093
22847
|
AI_TREE_SCHEMA_VERSIONS,
|
|
@@ -22104,6 +22858,7 @@ export {
|
|
|
22104
22858
|
DropdownMenuItem,
|
|
22105
22859
|
DropdownMenuSeparator,
|
|
22106
22860
|
DropdownMenuTrigger,
|
|
22861
|
+
EmptySection,
|
|
22107
22862
|
ItemActionToolbar,
|
|
22108
22863
|
ItemInteractionLayer,
|
|
22109
22864
|
LinkEditorPanel,
|