@ohhwells/bridge 0.1.87 → 0.1.88-next.262
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 +1152 -377
- 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 +1151 -377
- 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.cjs
CHANGED
|
@@ -46,6 +46,7 @@ __export(index_exports, {
|
|
|
46
46
|
DropdownMenuItem: () => DropdownMenuItem,
|
|
47
47
|
DropdownMenuSeparator: () => DropdownMenuSeparator,
|
|
48
48
|
DropdownMenuTrigger: () => DropdownMenuTrigger,
|
|
49
|
+
EmptySection: () => EmptySection,
|
|
49
50
|
ItemActionToolbar: () => ItemActionToolbar,
|
|
50
51
|
ItemInteractionLayer: () => ItemInteractionLayer,
|
|
51
52
|
LinkEditorPanel: () => LinkEditorPanel,
|
|
@@ -142,6 +143,10 @@ function isRenderableTree(value) {
|
|
|
142
143
|
|
|
143
144
|
// src/lib/ai-sections-store.ts
|
|
144
145
|
var AI_SECTIONS_KEY = "__ohw_ai_sections";
|
|
146
|
+
var AI_SLOT_KEY_PREFIX = "ai.";
|
|
147
|
+
function aiSlotKeyPrefixFor(sectionId) {
|
|
148
|
+
return `${AI_SLOT_KEY_PREFIX}${sectionId}.`;
|
|
149
|
+
}
|
|
145
150
|
var EMPTY_AI_SECTIONS = { v: 1, sections: [] };
|
|
146
151
|
function parseAiSectionsState(raw) {
|
|
147
152
|
if (!raw) return EMPTY_AI_SECTIONS;
|
|
@@ -185,6 +190,63 @@ function applyTreeToState(state, payload) {
|
|
|
185
190
|
const others = state.sections.filter((existing) => existing.id !== entry.id);
|
|
186
191
|
return { ...state, v: 1, sections: [...others, entry] };
|
|
187
192
|
}
|
|
193
|
+
function foldAlignIntoTrees(state, store) {
|
|
194
|
+
const byId = new Map(state.sections.map((entry) => [entry.id, entry]));
|
|
195
|
+
const nextTrees = /* @__PURE__ */ new Map();
|
|
196
|
+
const treeFor = (id) => {
|
|
197
|
+
const cloned = nextTrees.get(id);
|
|
198
|
+
if (cloned) return cloned;
|
|
199
|
+
const entry = byId.get(id);
|
|
200
|
+
if (!entry) return void 0;
|
|
201
|
+
const fresh = {
|
|
202
|
+
...entry.tree,
|
|
203
|
+
rows: entry.tree.rows.map((row) => ({ ...row, blocks: row.blocks.map((block) => ({ ...block })) }))
|
|
204
|
+
};
|
|
205
|
+
nextTrees.set(id, fresh);
|
|
206
|
+
return fresh;
|
|
207
|
+
};
|
|
208
|
+
const nodes = {};
|
|
209
|
+
for (const [key, override] of Object.entries(store.nodes)) {
|
|
210
|
+
const match = override.align !== void 0 && key.startsWith(AI_SLOT_KEY_PREFIX) ? key.match(/^ai\.(.+?)\.r(\d+)\.b(\d+)(?:\.|$)/) : null;
|
|
211
|
+
const tree = match ? treeFor(match[1]) : void 0;
|
|
212
|
+
const block = match && tree ? tree.rows[Number(match[2])]?.blocks[Number(match[3])] : void 0;
|
|
213
|
+
if (!block) {
|
|
214
|
+
nodes[key] = override;
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
block.align = override.align;
|
|
218
|
+
const rest = { ...override };
|
|
219
|
+
delete rest.align;
|
|
220
|
+
if (Object.keys(rest).length > 0) nodes[key] = rest;
|
|
221
|
+
}
|
|
222
|
+
const sections = {};
|
|
223
|
+
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
224
|
+
const tree = override.align !== void 0 ? treeFor(sectionId) : void 0;
|
|
225
|
+
if (!tree) {
|
|
226
|
+
sections[sectionId] = override;
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
for (const row of tree.rows) {
|
|
230
|
+
for (const block of row.blocks) block.align = override.align;
|
|
231
|
+
}
|
|
232
|
+
const rest = { ...override };
|
|
233
|
+
delete rest.align;
|
|
234
|
+
if (Object.keys(rest).length > 0) sections[sectionId] = rest;
|
|
235
|
+
}
|
|
236
|
+
if (nextTrees.size === 0) return { state, store, changed: false };
|
|
237
|
+
return {
|
|
238
|
+
state: {
|
|
239
|
+
...state,
|
|
240
|
+
v: 1,
|
|
241
|
+
sections: state.sections.map((entry) => {
|
|
242
|
+
const tree = nextTrees.get(entry.id);
|
|
243
|
+
return tree ? { ...entry, tree } : entry;
|
|
244
|
+
})
|
|
245
|
+
},
|
|
246
|
+
store: { v: 1, sections, nodes },
|
|
247
|
+
changed: true
|
|
248
|
+
};
|
|
249
|
+
}
|
|
188
250
|
function removeFromState(state, id) {
|
|
189
251
|
return { ...state, v: 1, sections: state.sections.filter((entry) => entry.id !== id) };
|
|
190
252
|
}
|
|
@@ -196,6 +258,33 @@ function deleteSectionFromState(state, sectionId) {
|
|
|
196
258
|
if (removed.includes(sectionId)) return state;
|
|
197
259
|
return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
|
|
198
260
|
}
|
|
261
|
+
function reapRemovedAiSections(state, store, removedIds, excludeIds = /* @__PURE__ */ new Set()) {
|
|
262
|
+
const generated = new Set(state.sections.map((entry) => entry.id));
|
|
263
|
+
const reapedIds = [...new Set(removedIds)].filter((id) => generated.has(id) && !excludeIds.has(id));
|
|
264
|
+
if (reapedIds.length === 0) {
|
|
265
|
+
return { state, store, reapedIds: [], slotPrefixes: [], changed: false };
|
|
266
|
+
}
|
|
267
|
+
const reaped = new Set(reapedIds);
|
|
268
|
+
const slotPrefixes = reapedIds.map(aiSlotKeyPrefixFor);
|
|
269
|
+
const nextState = {
|
|
270
|
+
...state,
|
|
271
|
+
v: 1,
|
|
272
|
+
sections: state.sections.filter((entry) => !reaped.has(entry.id))
|
|
273
|
+
};
|
|
274
|
+
let nextStore = store;
|
|
275
|
+
if (store) {
|
|
276
|
+
const sections = {};
|
|
277
|
+
for (const [key, override] of Object.entries(store.sections)) {
|
|
278
|
+
if (!reaped.has(key)) sections[key] = override;
|
|
279
|
+
}
|
|
280
|
+
const nodes = {};
|
|
281
|
+
for (const [key, override] of Object.entries(store.nodes)) {
|
|
282
|
+
if (!slotPrefixes.some((prefix) => key.startsWith(prefix))) nodes[key] = override;
|
|
283
|
+
}
|
|
284
|
+
nextStore = { v: 1, sections, nodes };
|
|
285
|
+
}
|
|
286
|
+
return { state: nextState, store: nextStore, reapedIds, slotPrefixes, changed: true };
|
|
287
|
+
}
|
|
199
288
|
|
|
200
289
|
// src/lib/brand-chrome.ts
|
|
201
290
|
var BRAND_NAME_KEY = "__ohw_brand_name";
|
|
@@ -403,6 +492,13 @@ function styleSheetCss() {
|
|
|
403
492
|
`[data-ohw-style-spacing="${spacing}"] { padding-top: ${px}px !important; padding-bottom: ${px}px !important; }`
|
|
404
493
|
);
|
|
405
494
|
}
|
|
495
|
+
rules.push(
|
|
496
|
+
`[data-ohw-style-corners="sharp"] :is(.card, [data-ohw-card], img, picture, figure, [data-ohw-editable="bg-image"]) { border-radius: 0 !important; }`,
|
|
497
|
+
`[data-ohw-style-corners="sharp"] :has(> img) { border-radius: 0 !important; }`
|
|
498
|
+
);
|
|
499
|
+
for (const align of ["left", "center", "right"]) {
|
|
500
|
+
rules.push(`[data-ohw-style-align="${align}"] { text-align: ${align} !important; }`);
|
|
501
|
+
}
|
|
406
502
|
return rules.join("\n");
|
|
407
503
|
}
|
|
408
504
|
var STYLE_FONT_LINK_ID = "ohw-style-fonts";
|
|
@@ -429,10 +525,25 @@ var SECTION_ATTRS = {
|
|
|
429
525
|
textDistribution: "data-ohw-style-distribution",
|
|
430
526
|
headlineScale: "data-ohw-style-headline",
|
|
431
527
|
imageAspect: "data-ohw-style-aspect",
|
|
432
|
-
spacing: "data-ohw-style-spacing"
|
|
528
|
+
spacing: "data-ohw-style-spacing",
|
|
529
|
+
cornerStyle: "data-ohw-style-corners",
|
|
530
|
+
align: "data-ohw-style-align"
|
|
433
531
|
};
|
|
434
532
|
var NODE_WROTE_ATTR = "data-ohw-style-node";
|
|
435
|
-
var NODE_PROPS = [
|
|
533
|
+
var NODE_PROPS = [
|
|
534
|
+
"color",
|
|
535
|
+
"font-family",
|
|
536
|
+
"font-size",
|
|
537
|
+
"background",
|
|
538
|
+
"text-align",
|
|
539
|
+
"justify-content",
|
|
540
|
+
"align-items"
|
|
541
|
+
];
|
|
542
|
+
var ALIGN_JUSTIFY = {
|
|
543
|
+
left: "flex-start",
|
|
544
|
+
center: "center",
|
|
545
|
+
right: "flex-end"
|
|
546
|
+
};
|
|
436
547
|
function saveInline(el, prop) {
|
|
437
548
|
const attr = `data-ohw-style-prev-${prop}`;
|
|
438
549
|
if (el.hasAttribute(attr)) return;
|
|
@@ -476,6 +587,10 @@ function clearNodeProps(root) {
|
|
|
476
587
|
function buttonSurfaceOf(el) {
|
|
477
588
|
return el.closest("a, button") ?? el;
|
|
478
589
|
}
|
|
590
|
+
function alignSubjectOf(el) {
|
|
591
|
+
const button = el.closest('[data-ohw-role="button"]');
|
|
592
|
+
return button?.parentElement ?? el;
|
|
593
|
+
}
|
|
479
594
|
function applyStylesToDom(store) {
|
|
480
595
|
ensureStyleSheet();
|
|
481
596
|
clearSectionAttrs(document);
|
|
@@ -521,6 +636,18 @@ function applyStylesToDom(store) {
|
|
|
521
636
|
el.style.setProperty("font-size", `${override.fontSize}px`, "important");
|
|
522
637
|
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
523
638
|
}
|
|
639
|
+
if (override.align !== void 0) {
|
|
640
|
+
const subject = alignSubjectOf(el);
|
|
641
|
+
saveInline(subject, "text-align");
|
|
642
|
+
saveInline(subject, "justify-content");
|
|
643
|
+
subject.style.setProperty("text-align", override.align, "important");
|
|
644
|
+
subject.style.setProperty(
|
|
645
|
+
"justify-content",
|
|
646
|
+
ALIGN_JUSTIFY[override.align] ?? "flex-start",
|
|
647
|
+
"important"
|
|
648
|
+
);
|
|
649
|
+
subject.setAttribute(NODE_WROTE_ATTR, "");
|
|
650
|
+
}
|
|
524
651
|
if (override.buttonBackground !== void 0 || override.buttonText !== void 0) {
|
|
525
652
|
const surface = buttonSurfaceOf(el);
|
|
526
653
|
if (override.buttonBackground !== void 0) {
|
|
@@ -541,9 +668,510 @@ function applyStylesToDom(store) {
|
|
|
541
668
|
var import_react_dom = require("react-dom");
|
|
542
669
|
var import_client = require("react-dom/client");
|
|
543
670
|
|
|
671
|
+
// src/lib/sections.ts
|
|
672
|
+
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
673
|
+
function isChromeSection(el) {
|
|
674
|
+
return el.matches("header, nav, footer, aside");
|
|
675
|
+
}
|
|
676
|
+
function titleCaseSectionId(id) {
|
|
677
|
+
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
678
|
+
}
|
|
679
|
+
function parseSectionsFromRoot(root) {
|
|
680
|
+
const seen = /* @__PURE__ */ new Set();
|
|
681
|
+
const sections = [];
|
|
682
|
+
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
683
|
+
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
684
|
+
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
685
|
+
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
686
|
+
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
687
|
+
continue;
|
|
688
|
+
seen.add(id);
|
|
689
|
+
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
690
|
+
sections.push({ id, label });
|
|
691
|
+
}
|
|
692
|
+
return sections;
|
|
693
|
+
}
|
|
694
|
+
function collectSectionsFromDom() {
|
|
695
|
+
if (typeof document === "undefined") return [];
|
|
696
|
+
return parseSectionsFromRoot(document);
|
|
697
|
+
}
|
|
698
|
+
function parseSectionsFromHtml(html) {
|
|
699
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
700
|
+
return parseSectionsFromRoot(doc);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// src/lib/section-instances.ts
|
|
704
|
+
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
705
|
+
var REMOVED_ATTR = "data-ohw-section-removed";
|
|
706
|
+
function isRemovedSection(el) {
|
|
707
|
+
return el.hasAttribute(REMOVED_ATTR);
|
|
708
|
+
}
|
|
709
|
+
function topLevelSections() {
|
|
710
|
+
return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
711
|
+
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el) && !isRemovedSection(el)
|
|
712
|
+
);
|
|
713
|
+
}
|
|
714
|
+
function instanceIdOf(el) {
|
|
715
|
+
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
716
|
+
}
|
|
717
|
+
function findByInstanceId(instanceId) {
|
|
718
|
+
const escapedId = CSS.escape(instanceId);
|
|
719
|
+
return document.querySelector(`[data-ohw-instance="${escapedId}"]`) ?? document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
720
|
+
}
|
|
721
|
+
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
722
|
+
const sections = topLevelSections();
|
|
723
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
724
|
+
if (index === -1) return null;
|
|
725
|
+
const dragged = sections[index];
|
|
726
|
+
const others = sections.filter((_, i) => i !== index);
|
|
727
|
+
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
728
|
+
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
729
|
+
return reordered.map((el, order) => ({
|
|
730
|
+
instanceId: instanceIdOf(el),
|
|
731
|
+
type: el.getAttribute("data-ohw-section") ?? "",
|
|
732
|
+
order,
|
|
733
|
+
pagePath: currentPath
|
|
734
|
+
}));
|
|
735
|
+
}
|
|
736
|
+
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
737
|
+
const sections = topLevelSections();
|
|
738
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
739
|
+
if (index === -1) return null;
|
|
740
|
+
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
741
|
+
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
742
|
+
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
743
|
+
if (!entries) return null;
|
|
744
|
+
applyPersistedOrder(entries);
|
|
745
|
+
return entries;
|
|
746
|
+
}
|
|
747
|
+
function syncRemovedFlags(entries) {
|
|
748
|
+
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
749
|
+
document.querySelectorAll(`[${REMOVED_ATTR}]`).forEach((el) => {
|
|
750
|
+
if (!removedIds.has(instanceIdOf(el))) {
|
|
751
|
+
el.style.removeProperty("display");
|
|
752
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
753
|
+
}
|
|
754
|
+
});
|
|
755
|
+
for (const id of removedIds) {
|
|
756
|
+
const el = findByInstanceId(id);
|
|
757
|
+
if (el) {
|
|
758
|
+
el.style.display = "none";
|
|
759
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
function applyPersistedOrder(entries) {
|
|
764
|
+
syncRemovedFlags(entries);
|
|
765
|
+
if (entries.length === 0) return;
|
|
766
|
+
const sections = topLevelSections();
|
|
767
|
+
if (sections.length === 0) return;
|
|
768
|
+
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
769
|
+
const ordered = [...sections].sort((a, b) => {
|
|
770
|
+
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
771
|
+
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
772
|
+
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
773
|
+
if (aOrder === void 0) return 1;
|
|
774
|
+
if (bOrder === void 0) return -1;
|
|
775
|
+
return aOrder - bOrder;
|
|
776
|
+
});
|
|
777
|
+
let prev = null;
|
|
778
|
+
for (const el of ordered) {
|
|
779
|
+
if (prev) prev.after(el);
|
|
780
|
+
prev = el;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
784
|
+
if (!findByInstanceId(instanceId)) return null;
|
|
785
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
786
|
+
const allSections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
787
|
+
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
|
|
788
|
+
);
|
|
789
|
+
allSections.forEach((el, order) => {
|
|
790
|
+
const id = instanceIdOf(el);
|
|
791
|
+
if (!byId.has(id)) {
|
|
792
|
+
byId.set(id, { instanceId: id, type: el.getAttribute("data-ohw-section") ?? "", order, pagePath: currentPath });
|
|
793
|
+
}
|
|
794
|
+
});
|
|
795
|
+
const target = byId.get(instanceId);
|
|
796
|
+
if (!target) return null;
|
|
797
|
+
byId.set(instanceId, { ...target, removed });
|
|
798
|
+
const entries = Array.from(byId.values());
|
|
799
|
+
applyPersistedOrder(entries);
|
|
800
|
+
return entries;
|
|
801
|
+
}
|
|
802
|
+
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
803
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
804
|
+
}
|
|
805
|
+
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
806
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
807
|
+
}
|
|
808
|
+
function duplicateSectionInstance(instanceId, newId, currentPath, existingEntries) {
|
|
809
|
+
const original = findByInstanceId(instanceId);
|
|
810
|
+
if (!original) return null;
|
|
811
|
+
const clone = original.cloneNode(true);
|
|
812
|
+
clone.setAttribute("data-ohw-instance", newId);
|
|
813
|
+
const keyRekeys = rekeySectionSubtree(clone, newId);
|
|
814
|
+
original.insertAdjacentElement("afterend", clone);
|
|
815
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
816
|
+
const entries = topLevelSections().map((el, order) => {
|
|
817
|
+
const id = instanceIdOf(el);
|
|
818
|
+
return {
|
|
819
|
+
instanceId: id,
|
|
820
|
+
type: el.getAttribute("data-ohw-section") ?? "",
|
|
821
|
+
order,
|
|
822
|
+
pagePath: currentPath,
|
|
823
|
+
...byId.get(id)?.removed ? { removed: true } : {}
|
|
824
|
+
};
|
|
825
|
+
});
|
|
826
|
+
applyPersistedOrder(entries);
|
|
827
|
+
return { entries, keyRekeys };
|
|
828
|
+
}
|
|
829
|
+
function newInstanceId() {
|
|
830
|
+
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
831
|
+
}
|
|
832
|
+
function getPageSectionOrderEntries(raw, currentPath) {
|
|
833
|
+
if (!raw) return [];
|
|
834
|
+
try {
|
|
835
|
+
const entries = JSON.parse(raw);
|
|
836
|
+
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
837
|
+
} catch {
|
|
838
|
+
return [];
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
function mergePageSectionOrder(raw, currentPath, pageEntries) {
|
|
842
|
+
let all = [];
|
|
843
|
+
if (raw) {
|
|
844
|
+
try {
|
|
845
|
+
const parsed = JSON.parse(raw);
|
|
846
|
+
if (Array.isArray(parsed)) all = parsed;
|
|
847
|
+
} catch {
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
const otherPages = all.filter((e) => e && e.pagePath && e.pagePath !== currentPath);
|
|
851
|
+
const pageIds = new Set(pageEntries.map((e) => e.instanceId));
|
|
852
|
+
const removedHere = all.filter(
|
|
853
|
+
(e) => e && (!e.pagePath || e.pagePath === currentPath) && e.removed && !pageIds.has(e.instanceId)
|
|
854
|
+
);
|
|
855
|
+
return [...otherPages, ...removedHere, ...pageEntries];
|
|
856
|
+
}
|
|
857
|
+
function rekeySectionSubtree(root, instanceId) {
|
|
858
|
+
const suffix = `::${instanceId}`;
|
|
859
|
+
const pairs = [];
|
|
860
|
+
const rekey = (el, attr) => {
|
|
861
|
+
const current = el.getAttribute(attr);
|
|
862
|
+
if (!current) return;
|
|
863
|
+
const base = current.includes("::") ? current.slice(0, current.indexOf("::")) : current;
|
|
864
|
+
const next = `${base}${suffix}`;
|
|
865
|
+
el.setAttribute(attr, next);
|
|
866
|
+
pairs.push({ from: current, to: next });
|
|
867
|
+
};
|
|
868
|
+
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
869
|
+
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
870
|
+
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
871
|
+
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
872
|
+
return pairs;
|
|
873
|
+
}
|
|
874
|
+
function initSectionInstancesFromContent(content, currentPath) {
|
|
875
|
+
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
876
|
+
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
877
|
+
});
|
|
878
|
+
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
879
|
+
for (const entry of entries) {
|
|
880
|
+
if (entry.instanceId === entry.type) continue;
|
|
881
|
+
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
882
|
+
const original = document.querySelector(
|
|
883
|
+
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
884
|
+
);
|
|
885
|
+
if (!original) continue;
|
|
886
|
+
const clone = original.cloneNode(true);
|
|
887
|
+
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
888
|
+
rekeySectionSubtree(clone, entry.instanceId);
|
|
889
|
+
original.insertAdjacentElement("afterend", clone);
|
|
890
|
+
}
|
|
891
|
+
applyPersistedOrder(entries);
|
|
892
|
+
}
|
|
893
|
+
|
|
544
894
|
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
545
895
|
var import_react = __toESM(require("react"), 1);
|
|
546
896
|
var import_lucide_react = require("lucide-react");
|
|
897
|
+
|
|
898
|
+
// src/lib/placeholder-imagery.ts
|
|
899
|
+
var U = (id) => `https://images.unsplash.com/photo-${id}?auto=format&fit=crop&w=1600&q=80`;
|
|
900
|
+
var GENERIC = [
|
|
901
|
+
U("1441986300917-64674bd600d8"),
|
|
902
|
+
U("1486406146926-c627a92ad1ab"),
|
|
903
|
+
U("1497032628192-86f99bcd76bc"),
|
|
904
|
+
U("1521737604893-d14cc237f11d"),
|
|
905
|
+
U("1522071820081-009f0129c71c"),
|
|
906
|
+
U("1519389950473-47ba0277781c"),
|
|
907
|
+
U("1460925895917-afdab827c52f"),
|
|
908
|
+
U("1504384308090-c894fdcc538d")
|
|
909
|
+
];
|
|
910
|
+
var PEOPLE = [
|
|
911
|
+
U("1500648767791-00dcc994a43e"),
|
|
912
|
+
U("1494790108377-be9c29b29330"),
|
|
913
|
+
U("1507003211169-0a1dd7228f2d"),
|
|
914
|
+
U("1438761681033-6461ffad8d80"),
|
|
915
|
+
U("1544005313-94ddf0286df2"),
|
|
916
|
+
U("1472099645785-5658abf4ff4e"),
|
|
917
|
+
U("1519085360753-af0119f7cbe7"),
|
|
918
|
+
U("1534528741775-53994a69daeb")
|
|
919
|
+
];
|
|
920
|
+
var THEMED = [
|
|
921
|
+
{
|
|
922
|
+
keywords: ["portrait", "headshot", "person", "people", "team", "staff", "avatar", "founder", "face"],
|
|
923
|
+
pool: PEOPLE
|
|
924
|
+
},
|
|
925
|
+
{
|
|
926
|
+
keywords: ["pet", "dog", "cat", "puppy", "kitten", "vet", "animal"],
|
|
927
|
+
pool: [
|
|
928
|
+
U("1548199973-03cce0bbc87b"),
|
|
929
|
+
U("1450778869180-41d0601e046e"),
|
|
930
|
+
U("1583511655857-d19b40a7a54e"),
|
|
931
|
+
U("1587300003388-59208cc962cb"),
|
|
932
|
+
U("1517849845537-4d257902454a"),
|
|
933
|
+
U("1601758228041-f3b2795255f1")
|
|
934
|
+
]
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
keywords: [
|
|
938
|
+
"baker",
|
|
939
|
+
"bakery",
|
|
940
|
+
"cafe",
|
|
941
|
+
"coffee",
|
|
942
|
+
"latte",
|
|
943
|
+
"restaurant",
|
|
944
|
+
"pastr",
|
|
945
|
+
"bread",
|
|
946
|
+
"cake",
|
|
947
|
+
"cater",
|
|
948
|
+
"chef",
|
|
949
|
+
"kitchen",
|
|
950
|
+
"food",
|
|
951
|
+
"pizza",
|
|
952
|
+
"dessert",
|
|
953
|
+
"brunch",
|
|
954
|
+
"bistro",
|
|
955
|
+
"deli",
|
|
956
|
+
"dish",
|
|
957
|
+
"menu"
|
|
958
|
+
],
|
|
959
|
+
pool: [
|
|
960
|
+
U("1509440159596-0249088772ff"),
|
|
961
|
+
U("1555507036-ab1f4038808a"),
|
|
962
|
+
U("1517433670267-08bbd4be890f"),
|
|
963
|
+
U("1486427944299-d1955d23e34d"),
|
|
964
|
+
U("1504754524776-8f4f37790ca0"),
|
|
965
|
+
U("1495474472287-4d71bcdd2085"),
|
|
966
|
+
U("1521017432531-fbd92d768814"),
|
|
967
|
+
U("1556909114-f6e7ad7d3136")
|
|
968
|
+
]
|
|
969
|
+
},
|
|
970
|
+
{
|
|
971
|
+
keywords: [
|
|
972
|
+
"shop",
|
|
973
|
+
"store",
|
|
974
|
+
"boutique",
|
|
975
|
+
"retail",
|
|
976
|
+
"clothing",
|
|
977
|
+
"fashion",
|
|
978
|
+
"jewel",
|
|
979
|
+
"gift",
|
|
980
|
+
"florist",
|
|
981
|
+
"market",
|
|
982
|
+
"grocer",
|
|
983
|
+
"product",
|
|
984
|
+
"storefront"
|
|
985
|
+
],
|
|
986
|
+
pool: [
|
|
987
|
+
U("1441984904996-e0b6ba687e04"),
|
|
988
|
+
U("1472851294608-062f824d29cc"),
|
|
989
|
+
U("1523381210434-271e8be1f52b"),
|
|
990
|
+
U("1534452203293-494d7ddbf7e0"),
|
|
991
|
+
U("1445205170230-053b83016050"),
|
|
992
|
+
U("1560243563-062bfc001d68")
|
|
993
|
+
]
|
|
994
|
+
},
|
|
995
|
+
{
|
|
996
|
+
keywords: [
|
|
997
|
+
"yoga",
|
|
998
|
+
"pilates",
|
|
999
|
+
"fitness",
|
|
1000
|
+
"gym",
|
|
1001
|
+
"workout",
|
|
1002
|
+
"trainer",
|
|
1003
|
+
"wellness",
|
|
1004
|
+
"meditat",
|
|
1005
|
+
"massage",
|
|
1006
|
+
"therap",
|
|
1007
|
+
"physio",
|
|
1008
|
+
"chiro",
|
|
1009
|
+
"nutrition",
|
|
1010
|
+
"spa",
|
|
1011
|
+
"studio"
|
|
1012
|
+
],
|
|
1013
|
+
pool: [
|
|
1014
|
+
U("1544367567-0f2fcb009e0b"),
|
|
1015
|
+
U("1506126613408-eca07ce68773"),
|
|
1016
|
+
U("1545205597-3d9d02c29597"),
|
|
1017
|
+
U("1552196563-55cd4e45efb3"),
|
|
1018
|
+
U("1518611012118-696072aa579a"),
|
|
1019
|
+
U("1571019613454-1cb2f99b2d8b"),
|
|
1020
|
+
U("1540555700478-4be289fbecef"),
|
|
1021
|
+
U("1519824145371-296894a0daa9")
|
|
1022
|
+
]
|
|
1023
|
+
},
|
|
1024
|
+
{
|
|
1025
|
+
keywords: [
|
|
1026
|
+
"salon",
|
|
1027
|
+
"hairdress",
|
|
1028
|
+
"haircut",
|
|
1029
|
+
"barber",
|
|
1030
|
+
"manicure",
|
|
1031
|
+
"pedicure",
|
|
1032
|
+
"nails",
|
|
1033
|
+
"beauty",
|
|
1034
|
+
"makeup",
|
|
1035
|
+
"cosmetic",
|
|
1036
|
+
"eyelash",
|
|
1037
|
+
"eyebrow",
|
|
1038
|
+
"skincare",
|
|
1039
|
+
"esthetic",
|
|
1040
|
+
"waxing",
|
|
1041
|
+
"hair"
|
|
1042
|
+
],
|
|
1043
|
+
pool: [
|
|
1044
|
+
U("1560066984-138dadb4c035"),
|
|
1045
|
+
U("1522337660859-02fbefca4702"),
|
|
1046
|
+
U("1562322140-8baeececf3df"),
|
|
1047
|
+
U("1521590832167-7bcbfaa6381f"),
|
|
1048
|
+
U("1487412947147-5cebf100ffc2"),
|
|
1049
|
+
U("1526045478516-99145907023c")
|
|
1050
|
+
]
|
|
1051
|
+
},
|
|
1052
|
+
{
|
|
1053
|
+
keywords: [
|
|
1054
|
+
"cleaning",
|
|
1055
|
+
"plumb",
|
|
1056
|
+
"electric",
|
|
1057
|
+
"landscap",
|
|
1058
|
+
"contractor",
|
|
1059
|
+
"handyman",
|
|
1060
|
+
"renov",
|
|
1061
|
+
"hvac",
|
|
1062
|
+
"roofing",
|
|
1063
|
+
"painting",
|
|
1064
|
+
"carpentry",
|
|
1065
|
+
"flooring",
|
|
1066
|
+
"movers",
|
|
1067
|
+
"construction",
|
|
1068
|
+
"tools"
|
|
1069
|
+
],
|
|
1070
|
+
pool: [
|
|
1071
|
+
U("1581578731548-c64695cc6952"),
|
|
1072
|
+
U("1504307651254-35680f356dfd"),
|
|
1073
|
+
U("1581092160562-40aa08e78837"),
|
|
1074
|
+
U("1621905251189-08b45d6a269e"),
|
|
1075
|
+
U("1558618666-fcd25c85cd64"),
|
|
1076
|
+
U("1585128792020-803d29415281")
|
|
1077
|
+
]
|
|
1078
|
+
},
|
|
1079
|
+
{
|
|
1080
|
+
keywords: [
|
|
1081
|
+
"legal",
|
|
1082
|
+
"attorney",
|
|
1083
|
+
"lawyer",
|
|
1084
|
+
"account",
|
|
1085
|
+
"bookkeep",
|
|
1086
|
+
"consult",
|
|
1087
|
+
"coaching",
|
|
1088
|
+
"financ",
|
|
1089
|
+
"insurance",
|
|
1090
|
+
"realtor",
|
|
1091
|
+
"estate",
|
|
1092
|
+
"marketing",
|
|
1093
|
+
"agency",
|
|
1094
|
+
"office",
|
|
1095
|
+
"business",
|
|
1096
|
+
"desk"
|
|
1097
|
+
],
|
|
1098
|
+
pool: [
|
|
1099
|
+
U("1497366216548-37526070297c"),
|
|
1100
|
+
U("1497366811353-6870744d04b2"),
|
|
1101
|
+
U("1454165804606-c3d57bc86b40"),
|
|
1102
|
+
U("1521791136064-7986c2920216"),
|
|
1103
|
+
U("1556761175-b413da4baf72"),
|
|
1104
|
+
U("1542744173-8e7e53415bb0")
|
|
1105
|
+
]
|
|
1106
|
+
},
|
|
1107
|
+
{
|
|
1108
|
+
keywords: [
|
|
1109
|
+
"wedding",
|
|
1110
|
+
"event",
|
|
1111
|
+
"party",
|
|
1112
|
+
"celebrat",
|
|
1113
|
+
"venue",
|
|
1114
|
+
"community",
|
|
1115
|
+
"nonprofit",
|
|
1116
|
+
"charity",
|
|
1117
|
+
"workshop",
|
|
1118
|
+
"photograph",
|
|
1119
|
+
"concert"
|
|
1120
|
+
],
|
|
1121
|
+
pool: [
|
|
1122
|
+
U("1511578314322-379afb476865"),
|
|
1123
|
+
U("1501281668745-f7f57925c3b4"),
|
|
1124
|
+
U("1523580494863-6f3031224c94"),
|
|
1125
|
+
U("1540575467063-178a50c2df87"),
|
|
1126
|
+
U("1505236858219-8359eb29e329"),
|
|
1127
|
+
U("1528605248644-14dd04022da1")
|
|
1128
|
+
]
|
|
1129
|
+
}
|
|
1130
|
+
];
|
|
1131
|
+
function poolForSubject(subject) {
|
|
1132
|
+
for (const theme of THEMED) {
|
|
1133
|
+
if (theme.keywords.some((k) => subject.includes(k))) {
|
|
1134
|
+
return theme.pool;
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
return GENERIC;
|
|
1138
|
+
}
|
|
1139
|
+
function mixedHash(text) {
|
|
1140
|
+
let hash = 2166136261;
|
|
1141
|
+
for (let i = 0; i < text.length; i++) {
|
|
1142
|
+
hash ^= text.charCodeAt(i);
|
|
1143
|
+
hash = Math.imul(hash, 16777619);
|
|
1144
|
+
}
|
|
1145
|
+
return hash >>> 16 & 65535;
|
|
1146
|
+
}
|
|
1147
|
+
function resolvePlaceholderRef(ref) {
|
|
1148
|
+
const match = /^placeholder:([a-z0-9-]+)$/.exec(ref);
|
|
1149
|
+
if (!match) return null;
|
|
1150
|
+
const subject = match[1];
|
|
1151
|
+
const pool = poolForSubject(subject.replace(/-\d+$/, ""));
|
|
1152
|
+
return pool[mixedHash(ref) % pool.length];
|
|
1153
|
+
}
|
|
1154
|
+
function collectPlaceholderRefs(tree) {
|
|
1155
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1156
|
+
for (const match of JSON.stringify(tree ?? null).matchAll(/"(placeholder:[a-z0-9-]+)"/gu)) {
|
|
1157
|
+
seen.add(match[1]);
|
|
1158
|
+
}
|
|
1159
|
+
return [...seen];
|
|
1160
|
+
}
|
|
1161
|
+
function buildPlaceholderMap(tree) {
|
|
1162
|
+
const map = {};
|
|
1163
|
+
const cursor = /* @__PURE__ */ new Map();
|
|
1164
|
+
for (const ref of collectPlaceholderRefs(tree)) {
|
|
1165
|
+
const subject = ref.slice("placeholder:".length).replace(/-\d+$/, "");
|
|
1166
|
+
const pool = poolForSubject(subject);
|
|
1167
|
+
const start = cursor.get(pool) ?? mixedHash(ref) % pool.length;
|
|
1168
|
+
map[ref] = pool[start % pool.length];
|
|
1169
|
+
cursor.set(pool, start + 1);
|
|
1170
|
+
}
|
|
1171
|
+
return map;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
547
1175
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
548
1176
|
function lucideByName(name) {
|
|
549
1177
|
const pascal = name.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
@@ -557,6 +1185,7 @@ var typeStyle = (spec, font) => ({
|
|
|
557
1185
|
fontWeight: spec.weight
|
|
558
1186
|
});
|
|
559
1187
|
var str = (value) => typeof value === "string" ? value : "";
|
|
1188
|
+
var cardRadius = (slots) => slots.cornerStyle === "sharp" ? 0 : AI_TREE_TOKENS.radiusCard;
|
|
560
1189
|
var featureLines = (value) => value.split(/\n|<br\s*\/?>/i).map((line) => line.trim()).filter(Boolean);
|
|
561
1190
|
var CHECK_MASK = `data:image/svg+xml,${encodeURIComponent(
|
|
562
1191
|
'<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>'
|
|
@@ -583,6 +1212,25 @@ var FEATURE_LINE_CSS = [
|
|
|
583
1212
|
`background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
|
|
584
1213
|
`mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
|
|
585
1214
|
].join("");
|
|
1215
|
+
function buttonShellStyle(ctx, fullWidth) {
|
|
1216
|
+
const bs = ctx.buttonStyle;
|
|
1217
|
+
if (bs) {
|
|
1218
|
+
return {
|
|
1219
|
+
borderRadius: bs.radius,
|
|
1220
|
+
...bs.padding ? { padding: bs.padding } : {},
|
|
1221
|
+
...bs.fontFamily ? { fontFamily: bs.fontFamily } : { fontFamily: ctx.brand.fonts.body },
|
|
1222
|
+
...bs.fontSize ? { fontSize: bs.fontSize } : {},
|
|
1223
|
+
...bs.fontWeight ? { fontWeight: bs.fontWeight } : {},
|
|
1224
|
+
...bs.letterSpacing && bs.letterSpacing !== "normal" ? { letterSpacing: bs.letterSpacing } : {},
|
|
1225
|
+
...bs.textTransform && bs.textTransform !== "none" ? { textTransform: bs.textTransform } : {}
|
|
1226
|
+
};
|
|
1227
|
+
}
|
|
1228
|
+
return {
|
|
1229
|
+
borderRadius: AI_TREE_TOKENS.radiusButton,
|
|
1230
|
+
padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
|
|
1231
|
+
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
586
1234
|
function hexLuminance(color) {
|
|
587
1235
|
const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
|
|
588
1236
|
if (!m) return null;
|
|
@@ -599,6 +1247,12 @@ function hexContrast(a, b) {
|
|
|
599
1247
|
const [hi, lo] = la > lb ? [la, lb] : [lb, la];
|
|
600
1248
|
return (hi + 0.05) / (lo + 0.05);
|
|
601
1249
|
}
|
|
1250
|
+
function primaryButtonLabel(brand) {
|
|
1251
|
+
const darkC = hexContrast(brand.palette.primary, brand.palette.dark);
|
|
1252
|
+
const lightC = hexContrast(brand.palette.primary, AI_TREE_TOKENS.textPrimaryForeground);
|
|
1253
|
+
if (darkC === null || lightC === null) return AI_TREE_TOKENS.textPrimaryForeground;
|
|
1254
|
+
return darkC > lightC ? brand.palette.dark : AI_TREE_TOKENS.textPrimaryForeground;
|
|
1255
|
+
}
|
|
602
1256
|
function accentBandContext(brand) {
|
|
603
1257
|
const p = brand.palette;
|
|
604
1258
|
const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
|
|
@@ -616,6 +1270,22 @@ function accentBandContext(brand) {
|
|
|
616
1270
|
function textAttrs(ctx, path) {
|
|
617
1271
|
return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
|
|
618
1272
|
}
|
|
1273
|
+
var AI_RESPONSIVE_CSS = [
|
|
1274
|
+
"@media (max-width: 960px) {",
|
|
1275
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
|
|
1276
|
+
' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
|
|
1277
|
+
"}",
|
|
1278
|
+
"@media (max-width: 640px) {",
|
|
1279
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
|
|
1280
|
+
" [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
|
|
1281
|
+
// Group containers flatten to a column on phones; span placements come along for free.
|
|
1282
|
+
" [data-ai-responsive] [data-ai-group] { display: flex !important; flex-direction: column !important; }",
|
|
1283
|
+
" [data-ai-responsive] [data-ai-group] > * { grid-column: auto !important; }",
|
|
1284
|
+
" [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
|
|
1285
|
+
" [data-ai-responsive] { overflow-x: hidden; }",
|
|
1286
|
+
" [data-ai-responsive] img { max-width: 100%; }",
|
|
1287
|
+
"}"
|
|
1288
|
+
].join("\n");
|
|
619
1289
|
var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
620
1290
|
function MediaBox({
|
|
621
1291
|
refValue,
|
|
@@ -628,13 +1298,17 @@ function MediaBox({
|
|
|
628
1298
|
const url = refValue ? ctx.resolveMedia(refValue) : null;
|
|
629
1299
|
const isIcon = /^(lucide|simple):/.test(refValue);
|
|
630
1300
|
const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
|
|
631
|
-
const editAttrs = ctx.keyFor && editPath
|
|
1301
|
+
const editAttrs = ctx.keyFor && editPath ? {
|
|
1302
|
+
"data-ohw-key": ctx.keyFor(editPath),
|
|
1303
|
+
"data-ohw-editable": isIcon ? "icon" : "image"
|
|
1304
|
+
} : {};
|
|
632
1305
|
if (isIcon) {
|
|
633
1306
|
const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
|
|
634
1307
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
635
1308
|
"span",
|
|
636
1309
|
{
|
|
637
1310
|
"data-ai-icon": refValue,
|
|
1311
|
+
...editAttrs,
|
|
638
1312
|
style: {
|
|
639
1313
|
display: "inline-flex",
|
|
640
1314
|
width: 48,
|
|
@@ -698,12 +1372,10 @@ function ButtonEl({
|
|
|
698
1372
|
width: fullWidth ? "100%" : void 0,
|
|
699
1373
|
alignItems: "center",
|
|
700
1374
|
justifyContent: "center",
|
|
701
|
-
padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
|
|
702
|
-
borderRadius: AI_TREE_TOKENS.radiusButton,
|
|
703
1375
|
textDecoration: "none",
|
|
704
1376
|
cursor: "pointer",
|
|
705
|
-
...
|
|
706
|
-
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ??
|
|
1377
|
+
...buttonShellStyle(ctx, fullWidth),
|
|
1378
|
+
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand) }
|
|
707
1379
|
},
|
|
708
1380
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
|
|
709
1381
|
}
|
|
@@ -729,7 +1401,7 @@ function TextBlock({ slots, ctx, path }) {
|
|
|
729
1401
|
}
|
|
730
1402
|
function SectionHeaderBlock({ node, ctx, path }) {
|
|
731
1403
|
const slots = node.slots ?? {};
|
|
732
|
-
const align = slots.alignment === "center" ? "center" : "left";
|
|
1404
|
+
const align = node.align ?? (slots.alignment === "center" ? "center" : "left");
|
|
733
1405
|
const children = node.children ?? [];
|
|
734
1406
|
const buttonRowIdx = children.findIndex((c) => c.type === "button-row");
|
|
735
1407
|
const buttonRow = buttonRowIdx >= 0 ? children[buttonRowIdx] : void 0;
|
|
@@ -773,7 +1445,7 @@ function SectionHeaderBlock({ node, ctx, path }) {
|
|
|
773
1445
|
display: "flex",
|
|
774
1446
|
gap: AI_TREE_TOKENS.spacing6,
|
|
775
1447
|
marginTop: AI_TREE_TOKENS.spacing8,
|
|
776
|
-
justifyContent: align === "center" ? "center" : "flex-start"
|
|
1448
|
+
justifyContent: align === "center" ? "center" : align === "right" ? "flex-end" : "flex-start"
|
|
777
1449
|
},
|
|
778
1450
|
children: (buttonRow.children ?? []).map((button, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
779
1451
|
ButtonEl,
|
|
@@ -879,10 +1551,11 @@ function PricingCard({ node, ctx, path }) {
|
|
|
879
1551
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
880
1552
|
"div",
|
|
881
1553
|
{
|
|
1554
|
+
"data-ohw-card": "",
|
|
882
1555
|
style: {
|
|
883
1556
|
background: hasBg ? ctx.brand.palette.light : "transparent",
|
|
884
1557
|
border: `1px solid ${dark}`,
|
|
885
|
-
borderRadius:
|
|
1558
|
+
borderRadius: cardRadius(slots),
|
|
886
1559
|
padding: AI_TREE_TOKENS.paddingBlock,
|
|
887
1560
|
display: "flex",
|
|
888
1561
|
flexDirection: "column",
|
|
@@ -987,10 +1660,11 @@ function TestimonialCard({ node, ctx, path }) {
|
|
|
987
1660
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
988
1661
|
"div",
|
|
989
1662
|
{
|
|
1663
|
+
"data-ohw-card": "",
|
|
990
1664
|
"data-ai-avatar-pos": avatarPos ?? void 0,
|
|
991
1665
|
style: {
|
|
992
1666
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
993
|
-
borderRadius: hasBg ?
|
|
1667
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
994
1668
|
overflow: "hidden",
|
|
995
1669
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
996
1670
|
minWidth: 0
|
|
@@ -1025,10 +1699,11 @@ function TeamCard({ node, ctx, path }) {
|
|
|
1025
1699
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1026
1700
|
"div",
|
|
1027
1701
|
{
|
|
1702
|
+
"data-ohw-card": "",
|
|
1028
1703
|
"data-ai-avatar-pos": avatarPos ?? void 0,
|
|
1029
1704
|
style: {
|
|
1030
1705
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1031
|
-
borderRadius: hasBg ?
|
|
1706
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1032
1707
|
overflow: "hidden",
|
|
1033
1708
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1034
1709
|
minWidth: 0,
|
|
@@ -1106,7 +1781,7 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1106
1781
|
editPath: `${path}.media`
|
|
1107
1782
|
}
|
|
1108
1783
|
) : null;
|
|
1109
|
-
const centered = slots.alignment === "center";
|
|
1784
|
+
const centered = (node.align ?? slots.alignment) === "center";
|
|
1110
1785
|
const content = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1111
1786
|
"div",
|
|
1112
1787
|
{
|
|
@@ -1199,9 +1874,10 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1199
1874
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1200
1875
|
"div",
|
|
1201
1876
|
{
|
|
1877
|
+
"data-ohw-card": "",
|
|
1202
1878
|
style: {
|
|
1203
1879
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1204
|
-
borderRadius: hasBg ?
|
|
1880
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1205
1881
|
overflow: "hidden",
|
|
1206
1882
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1207
1883
|
display: horizontal ? "flex" : "block",
|
|
@@ -1229,7 +1905,7 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1229
1905
|
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1230
1906
|
"div",
|
|
1231
1907
|
{
|
|
1232
|
-
style: /^(lucide|simple):/.test(mediaRef) ? { padding: `${AI_TREE_TOKENS.paddingBlock}px ${AI_TREE_TOKENS.paddingBlock}px 0` } : hasBg ? void 0 : { borderRadius:
|
|
1908
|
+
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" },
|
|
1233
1909
|
children: media
|
|
1234
1910
|
}
|
|
1235
1911
|
)),
|
|
@@ -1520,7 +2196,7 @@ function CollectionBlock({ node, ctx, path }) {
|
|
|
1520
2196
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1521
2197
|
"div",
|
|
1522
2198
|
{
|
|
1523
|
-
"data-ai-grid":
|
|
2199
|
+
"data-ai-grid": String(itemsPerRow),
|
|
1524
2200
|
style: {
|
|
1525
2201
|
display: "grid",
|
|
1526
2202
|
gridTemplateColumns: `repeat(${itemsPerRow}, 1fr)`,
|
|
@@ -1640,6 +2316,32 @@ function renderNode(node, ctx, path) {
|
|
|
1640
2316
|
if (child) {
|
|
1641
2317
|
return renderNode(child, ctx, `${path}.c0`);
|
|
1642
2318
|
}
|
|
2319
|
+
if (str(slots.provider) === "map" && str(slots.query)) {
|
|
2320
|
+
const query = str(slots.query);
|
|
2321
|
+
const mapAttrs = ctx.keyFor ? {
|
|
2322
|
+
"data-ohw-key": ctx.keyFor(`${path}.query`),
|
|
2323
|
+
"data-ohw-editable": "map",
|
|
2324
|
+
"data-ohw-map-query": query
|
|
2325
|
+
} : {};
|
|
2326
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2327
|
+
"iframe",
|
|
2328
|
+
{
|
|
2329
|
+
...mapAttrs,
|
|
2330
|
+
"data-ai-embed": "map",
|
|
2331
|
+
title: str(slots.title) || "Map",
|
|
2332
|
+
src: `https://www.google.com/maps?q=${encodeURIComponent(query)}&output=embed`,
|
|
2333
|
+
loading: "lazy",
|
|
2334
|
+
referrerPolicy: "no-referrer-when-downgrade",
|
|
2335
|
+
style: {
|
|
2336
|
+
width: "100%",
|
|
2337
|
+
minHeight: 320,
|
|
2338
|
+
border: 0,
|
|
2339
|
+
borderRadius: AI_TREE_TOKENS.radiusCard,
|
|
2340
|
+
display: "block"
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
);
|
|
2344
|
+
}
|
|
1643
2345
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1644
2346
|
"div",
|
|
1645
2347
|
{
|
|
@@ -1743,15 +2445,12 @@ function renderNode(node, ctx, path) {
|
|
|
1743
2445
|
alignSelf: submitAlign,
|
|
1744
2446
|
border: "none",
|
|
1745
2447
|
cursor: "pointer",
|
|
1746
|
-
padding
|
|
1747
|
-
|
|
1748
|
-
// CTA); 8px only when the page has no template button to match.
|
|
1749
|
-
borderRadius: ctx.buttonRadius ?? 8,
|
|
2448
|
+
// Shape/padding/typography follow the host template's own buttons.
|
|
2449
|
+
...buttonShellStyle(ctx),
|
|
1750
2450
|
// Brand-styled: primary fill, brand-derived label colour (not a fixed token) so it
|
|
1751
2451
|
// reads correctly on custom palettes.
|
|
1752
2452
|
background: ctx.brand.palette.primary,
|
|
1753
|
-
color: ctx.buttonLabel ?? ctx.brand
|
|
1754
|
-
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
2453
|
+
color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand)
|
|
1755
2454
|
},
|
|
1756
2455
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
|
|
1757
2456
|
},
|
|
@@ -1786,7 +2485,7 @@ function renderNode(node, ctx, path) {
|
|
|
1786
2485
|
function AiTreeRenderer({
|
|
1787
2486
|
tree,
|
|
1788
2487
|
brand,
|
|
1789
|
-
|
|
2488
|
+
buttonStyle,
|
|
1790
2489
|
resolveMedia,
|
|
1791
2490
|
editKeyPrefix
|
|
1792
2491
|
}) {
|
|
@@ -1796,13 +2495,18 @@ function AiTreeRenderer({
|
|
|
1796
2495
|
const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
|
|
1797
2496
|
const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
|
|
1798
2497
|
const blockBrand = band?.brand ?? resolvedBrand;
|
|
2498
|
+
const placeholderMap = buildPlaceholderMap(tree);
|
|
1799
2499
|
const ctx = {
|
|
1800
2500
|
brand: blockBrand,
|
|
1801
|
-
|
|
2501
|
+
// An owner/library ref resolves through the host resolver; a `placeholder:<subject>` ref the
|
|
2502
|
+
// host cannot resolve falls back to real stock photography (the per-section map first, then a
|
|
2503
|
+
// standalone resolve), so generated galleries, image rows, and overlay backgrounds arrive with
|
|
2504
|
+
// photos instead of grey boxes.
|
|
2505
|
+
resolveMedia: (ref) => resolveMedia?.(ref) ?? placeholderMap[ref] ?? resolvePlaceholderRef(ref),
|
|
1802
2506
|
cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
|
|
1803
2507
|
keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
|
|
1804
2508
|
sectionAlignment: (tree.settings ?? {}).alignment === "center" ? "center" : "left",
|
|
1805
|
-
|
|
2509
|
+
buttonStyle,
|
|
1806
2510
|
...band ? { buttonLabel: band.buttonLabel } : {}
|
|
1807
2511
|
};
|
|
1808
2512
|
const settings = tree.settings ?? {};
|
|
@@ -1825,11 +2529,25 @@ function AiTreeRenderer({
|
|
|
1825
2529
|
}
|
|
1826
2530
|
})();
|
|
1827
2531
|
const distributed = !isOverlay && settings.textDistribution;
|
|
2532
|
+
const rowAlignItems = (rowAlign) => {
|
|
2533
|
+
if (rowAlign === "top") return "start";
|
|
2534
|
+
if (rowAlign === "bottom") return "end";
|
|
2535
|
+
if (rowAlign === "center" || rowAlign === "stretch") return rowAlign;
|
|
2536
|
+
if (distributed === "space-between") return "stretch";
|
|
2537
|
+
return (distributed ?? settings.verticalPosition) === "top" ? "start" : "center";
|
|
2538
|
+
};
|
|
2539
|
+
const cellAlignStyle = (blockAlign) => blockAlign ? {
|
|
2540
|
+
display: "flex",
|
|
2541
|
+
flexDirection: "column",
|
|
2542
|
+
alignItems: blockAlign === "left" ? "flex-start" : blockAlign === "right" ? "flex-end" : "center",
|
|
2543
|
+
textAlign: blockAlign
|
|
2544
|
+
} : {};
|
|
1828
2545
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1829
2546
|
"section",
|
|
1830
2547
|
{
|
|
1831
2548
|
"data-ai-section": tree.tag ?? "",
|
|
1832
2549
|
...bgAttrs,
|
|
2550
|
+
"data-ai-responsive": "",
|
|
1833
2551
|
style: {
|
|
1834
2552
|
position: "relative",
|
|
1835
2553
|
padding: `${pad}px 0`,
|
|
@@ -1840,12 +2558,13 @@ function AiTreeRenderer({
|
|
|
1840
2558
|
color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
|
|
1841
2559
|
},
|
|
1842
2560
|
children: [
|
|
1843
|
-
|
|
2561
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
|
|
1844
2562
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
|
|
2563
|
+
isOverlay && backgroundUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
|
|
1845
2564
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1846
2565
|
"div",
|
|
1847
2566
|
{
|
|
1848
|
-
"data-ai-
|
|
2567
|
+
"data-ai-section-inner": "",
|
|
1849
2568
|
style: {
|
|
1850
2569
|
position: "relative",
|
|
1851
2570
|
maxWidth: AI_TREE_TOKENS.sectionMaxWidth,
|
|
@@ -1856,12 +2575,12 @@ function AiTreeRenderer({
|
|
|
1856
2575
|
children: tree.rows.map((row, r2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1857
2576
|
"div",
|
|
1858
2577
|
{
|
|
1859
|
-
"data-ai-
|
|
2578
|
+
"data-ai-columns": "",
|
|
1860
2579
|
style: {
|
|
1861
2580
|
display: "grid",
|
|
1862
2581
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
1863
2582
|
gap: AI_TREE_TOKENS.spacing6,
|
|
1864
|
-
alignItems:
|
|
2583
|
+
alignItems: rowAlignItems(row.align),
|
|
1865
2584
|
marginTop: r2 > 0 ? AI_TREE_TOKENS.spacing8 : 0
|
|
1866
2585
|
},
|
|
1867
2586
|
children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -1871,6 +2590,8 @@ function AiTreeRenderer({
|
|
|
1871
2590
|
style: {
|
|
1872
2591
|
gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`,
|
|
1873
2592
|
minWidth: 0,
|
|
2593
|
+
// Horizontal placement of the block's content within its column.
|
|
2594
|
+
...cellAlignStyle(block.align),
|
|
1874
2595
|
// space-between: each column becomes a flex column whose content spreads over
|
|
1875
2596
|
// the full row height instead of clumping at the top.
|
|
1876
2597
|
...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
|
|
@@ -1893,7 +2614,7 @@ function AiTreeRenderer({
|
|
|
1893
2614
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1894
2615
|
var CONTAINER_ATTR = "data-ohw-ai-generated";
|
|
1895
2616
|
var REPLACED_ATTR = "data-ohw-ai-replaced-by";
|
|
1896
|
-
var
|
|
2617
|
+
var REMOVED_ATTR2 = "data-ohw-ai-removed";
|
|
1897
2618
|
var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
|
|
1898
2619
|
var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
1899
2620
|
function readRootVar(name) {
|
|
@@ -1917,13 +2638,13 @@ function deriveBrandOverride() {
|
|
|
1917
2638
|
};
|
|
1918
2639
|
}
|
|
1919
2640
|
function deriveTemplateBrand() {
|
|
1920
|
-
const
|
|
1921
|
-
const
|
|
1922
|
-
const light = readRootVar("--color-light");
|
|
2641
|
+
const primary = readRootVar("--brand-primary") || readRootVar("--color-primary");
|
|
2642
|
+
const dark = readRootVar("--brand-text") || readRootVar("--color-dark");
|
|
2643
|
+
const light = readRootVar("--brand-background") || readRootVar("--color-light");
|
|
1923
2644
|
if (!dark || !primary || !light) return null;
|
|
1924
|
-
const accent = readRootVar("--color-accent");
|
|
1925
|
-
const heading = readRootVar("--font-heading") || readRootVar("--font-display");
|
|
1926
|
-
const body = readRootVar("--font-body");
|
|
2645
|
+
const accent = readRootVar("--brand-accent") || readRootVar("--color-accent");
|
|
2646
|
+
const heading = readRootVar("--brand-font-heading") || readRootVar("--font-heading") || readRootVar("--font-display");
|
|
2647
|
+
const body = readRootVar("--brand-font-body") || readRootVar("--font-body");
|
|
1927
2648
|
return {
|
|
1928
2649
|
palette: { dark, primary, accent: accent || dark, light },
|
|
1929
2650
|
fonts: {
|
|
@@ -1932,12 +2653,32 @@ function deriveTemplateBrand() {
|
|
|
1932
2653
|
}
|
|
1933
2654
|
};
|
|
1934
2655
|
}
|
|
1935
|
-
function
|
|
2656
|
+
function deriveTemplateButtonStyle() {
|
|
1936
2657
|
if (typeof document === "undefined") return null;
|
|
1937
|
-
const btn = document.
|
|
2658
|
+
const btn = Array.from(document.querySelectorAll('[data-ohw-role="button"]')).find(
|
|
2659
|
+
(el) => !el.closest(`[${CONTAINER_ATTR}]`)
|
|
2660
|
+
);
|
|
1938
2661
|
if (!btn) return null;
|
|
1939
|
-
const
|
|
1940
|
-
|
|
2662
|
+
const cs = getComputedStyle(btn);
|
|
2663
|
+
const corners = [
|
|
2664
|
+
cs.borderTopLeftRadius,
|
|
2665
|
+
cs.borderTopRightRadius,
|
|
2666
|
+
cs.borderBottomRightRadius,
|
|
2667
|
+
cs.borderBottomLeftRadius
|
|
2668
|
+
].map((v) => v || "0px");
|
|
2669
|
+
const radius = corners.every((v) => v === corners[0]) ? corners[0] : corners.join(" ");
|
|
2670
|
+
const px = (v) => parseFloat(v) || 0;
|
|
2671
|
+
const padY = Math.max(px(cs.paddingTop), px(cs.paddingBottom));
|
|
2672
|
+
const padX = Math.max(px(cs.paddingLeft), px(cs.paddingRight));
|
|
2673
|
+
return {
|
|
2674
|
+
radius: radius || "10px",
|
|
2675
|
+
padding: `${padY}px ${padX}px`,
|
|
2676
|
+
fontFamily: cs.fontFamily || "",
|
|
2677
|
+
fontSize: cs.fontSize || "",
|
|
2678
|
+
fontWeight: cs.fontWeight || "",
|
|
2679
|
+
letterSpacing: cs.letterSpacing || "",
|
|
2680
|
+
textTransform: cs.textTransform || ""
|
|
2681
|
+
};
|
|
1941
2682
|
}
|
|
1942
2683
|
var mounted = /* @__PURE__ */ new Map();
|
|
1943
2684
|
function findTemplateSection(id) {
|
|
@@ -1987,18 +2728,18 @@ function placeContainer(container, entry) {
|
|
|
1987
2728
|
}
|
|
1988
2729
|
function syncRemovedSections(state) {
|
|
1989
2730
|
const removed = new Set(state.removed ?? []);
|
|
1990
|
-
for (const el of document.querySelectorAll(`[${
|
|
2731
|
+
for (const el of document.querySelectorAll(`[${REMOVED_ATTR2}]`)) {
|
|
1991
2732
|
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
1992
2733
|
if (!removed.has(id)) {
|
|
1993
2734
|
el.style.removeProperty("display");
|
|
1994
|
-
el.removeAttribute(
|
|
2735
|
+
el.removeAttribute(REMOVED_ATTR2);
|
|
1995
2736
|
}
|
|
1996
2737
|
}
|
|
1997
2738
|
for (const id of removed) {
|
|
1998
2739
|
const section = findTemplateSection(id);
|
|
1999
2740
|
if (section && !section.hasAttribute(REPLACED_ATTR)) {
|
|
2000
2741
|
section.style.display = "none";
|
|
2001
|
-
section.setAttribute(
|
|
2742
|
+
section.setAttribute(REMOVED_ATTR2, "");
|
|
2002
2743
|
}
|
|
2003
2744
|
}
|
|
2004
2745
|
}
|
|
@@ -2015,7 +2756,7 @@ function syncTemplateHidden(state, pageHasSections) {
|
|
|
2015
2756
|
if (el.hasAttribute(CONTAINER_ATTR)) continue;
|
|
2016
2757
|
if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
|
|
2017
2758
|
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
2018
|
-
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(
|
|
2759
|
+
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR2)) continue;
|
|
2019
2760
|
el.style.display = "none";
|
|
2020
2761
|
el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
|
|
2021
2762
|
}
|
|
@@ -2039,18 +2780,23 @@ function syncReplacedOriginals(state) {
|
|
|
2039
2780
|
}
|
|
2040
2781
|
}
|
|
2041
2782
|
var sectionOrderIndex = /* @__PURE__ */ new Map();
|
|
2783
|
+
var removedSectionIds = /* @__PURE__ */ new Set();
|
|
2042
2784
|
function setAiSectionOrder(raw, currentPath) {
|
|
2043
2785
|
const next = /* @__PURE__ */ new Map();
|
|
2786
|
+
const removed = /* @__PURE__ */ new Set();
|
|
2044
2787
|
if (raw) {
|
|
2045
2788
|
try {
|
|
2046
2789
|
const entries = JSON.parse(raw);
|
|
2047
2790
|
for (const entry of entries) {
|
|
2048
|
-
if (
|
|
2791
|
+
if (entry.pagePath && entry.pagePath !== currentPath) continue;
|
|
2792
|
+
next.set(entry.instanceId, entry.order);
|
|
2793
|
+
if (entry.removed) removed.add(entry.instanceId);
|
|
2049
2794
|
}
|
|
2050
2795
|
} catch {
|
|
2051
2796
|
}
|
|
2052
2797
|
}
|
|
2053
2798
|
sectionOrderIndex = next;
|
|
2799
|
+
removedSectionIds = removed;
|
|
2054
2800
|
}
|
|
2055
2801
|
function applyExplicitOrder(entries) {
|
|
2056
2802
|
if (sectionOrderIndex.size === 0) return entries;
|
|
@@ -2086,11 +2832,23 @@ function orderByChain(sections) {
|
|
|
2086
2832
|
for (const root of roots) visit(root);
|
|
2087
2833
|
return out.length === sections.length ? out : sections;
|
|
2088
2834
|
}
|
|
2835
|
+
function syncSoftRemovedGenerated() {
|
|
2836
|
+
for (const [id, section] of mounted) {
|
|
2837
|
+
const el = section.container;
|
|
2838
|
+
if (removedSectionIds.has(id)) {
|
|
2839
|
+
el.style.display = "none";
|
|
2840
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
2841
|
+
} else if (el.hasAttribute(REMOVED_ATTR)) {
|
|
2842
|
+
el.style.removeProperty("display");
|
|
2843
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2089
2847
|
function applyAiSectionsToDom(state, options) {
|
|
2090
2848
|
if (typeof document === "undefined") return;
|
|
2091
2849
|
const brandOverride = deriveBrandOverride();
|
|
2092
2850
|
const templateBrand = deriveTemplateBrand();
|
|
2093
|
-
const
|
|
2851
|
+
const templateButtonStyle = deriveTemplateButtonStyle();
|
|
2094
2852
|
const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
|
|
2095
2853
|
const pagePath = window.location.pathname;
|
|
2096
2854
|
const pageSections = state.sections.filter((entry) => (entry.path ?? "/") === pagePath);
|
|
@@ -2130,7 +2888,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2130
2888
|
{
|
|
2131
2889
|
tree: entry.tree,
|
|
2132
2890
|
brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
|
|
2133
|
-
|
|
2891
|
+
buttonStyle: templateButtonStyle,
|
|
2134
2892
|
resolveMedia,
|
|
2135
2893
|
editKeyPrefix: `ai.${entry.id}`
|
|
2136
2894
|
}
|
|
@@ -2153,6 +2911,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2153
2911
|
syncReplacedOriginals(state);
|
|
2154
2912
|
syncRemovedSections(state);
|
|
2155
2913
|
syncTemplateHidden(state, pageSections.length > 0);
|
|
2914
|
+
syncSoftRemovedGenerated();
|
|
2156
2915
|
}
|
|
2157
2916
|
|
|
2158
2917
|
// src/useLinkHrefGuardian.ts
|
|
@@ -7882,6 +8641,7 @@ function MediaOverlay({
|
|
|
7882
8641
|
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
7883
8642
|
);
|
|
7884
8643
|
}, [isVideo]);
|
|
8644
|
+
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
7885
8645
|
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
7886
8646
|
const box = {
|
|
7887
8647
|
position: "fixed",
|
|
@@ -8011,17 +8771,17 @@ function MediaOverlay({
|
|
|
8011
8771
|
},
|
|
8012
8772
|
children: [
|
|
8013
8773
|
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
8014
|
-
|
|
8774
|
+
replaceLabel
|
|
8015
8775
|
]
|
|
8016
8776
|
}
|
|
8017
8777
|
),
|
|
8018
|
-
replaceMode
|
|
8778
|
+
showChrome && replaceMode !== "none" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
8019
8779
|
Button,
|
|
8020
8780
|
{
|
|
8021
8781
|
"data-ohw-media-overlay": "",
|
|
8022
8782
|
variant: "outline",
|
|
8023
8783
|
size: "sm",
|
|
8024
|
-
"aria-label":
|
|
8784
|
+
"aria-label": replaceLabel,
|
|
8025
8785
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
8026
8786
|
style: {
|
|
8027
8787
|
...OVERLAY_BUTTON_STYLE,
|
|
@@ -8044,7 +8804,7 @@ function MediaOverlay({
|
|
|
8044
8804
|
},
|
|
8045
8805
|
children: [
|
|
8046
8806
|
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
8047
|
-
replaceMode === "full" ?
|
|
8807
|
+
replaceMode === "full" ? replaceLabel : null
|
|
8048
8808
|
]
|
|
8049
8809
|
}
|
|
8050
8810
|
)
|
|
@@ -8085,215 +8845,33 @@ function CarouselOverlay({
|
|
|
8085
8845
|
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
8086
8846
|
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
8087
8847
|
},
|
|
8088
|
-
onClick: () => onEdit(hover.key),
|
|
8089
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
8090
|
-
Button,
|
|
8091
|
-
{
|
|
8092
|
-
"data-ohw-carousel-overlay": "",
|
|
8093
|
-
variant: "outline",
|
|
8094
|
-
size: "sm",
|
|
8095
|
-
className: "cursor-pointer gap-1.5 hover:bg-background",
|
|
8096
|
-
style: OVERLAY_BUTTON_STYLE2,
|
|
8097
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
8098
|
-
onClick: (e) => {
|
|
8099
|
-
e.stopPropagation();
|
|
8100
|
-
onEdit(hover.key);
|
|
8101
|
-
},
|
|
8102
|
-
children: [
|
|
8103
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react6.GalleryHorizontal, { size: 14 }),
|
|
8104
|
-
"Edit gallery"
|
|
8105
|
-
]
|
|
8106
|
-
}
|
|
8107
|
-
)
|
|
8108
|
-
}
|
|
8109
|
-
);
|
|
8110
|
-
}
|
|
8111
|
-
|
|
8112
|
-
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
8113
|
-
var import_react8 = require("react");
|
|
8114
|
-
var import_lucide_react7 = require("lucide-react");
|
|
8115
|
-
|
|
8116
|
-
// src/lib/sections.ts
|
|
8117
|
-
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
8118
|
-
function isChromeSection(el) {
|
|
8119
|
-
return el.matches("header, nav, footer, aside");
|
|
8120
|
-
}
|
|
8121
|
-
function titleCaseSectionId(id) {
|
|
8122
|
-
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
8123
|
-
}
|
|
8124
|
-
function parseSectionsFromRoot(root) {
|
|
8125
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8126
|
-
const sections = [];
|
|
8127
|
-
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
8128
|
-
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
8129
|
-
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
8130
|
-
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
8131
|
-
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
8132
|
-
continue;
|
|
8133
|
-
seen.add(id);
|
|
8134
|
-
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
8135
|
-
sections.push({ id, label });
|
|
8136
|
-
}
|
|
8137
|
-
return sections;
|
|
8138
|
-
}
|
|
8139
|
-
function collectSectionsFromDom() {
|
|
8140
|
-
if (typeof document === "undefined") return [];
|
|
8141
|
-
return parseSectionsFromRoot(document);
|
|
8142
|
-
}
|
|
8143
|
-
function parseSectionsFromHtml(html) {
|
|
8144
|
-
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
8145
|
-
return parseSectionsFromRoot(doc);
|
|
8146
|
-
}
|
|
8147
|
-
|
|
8148
|
-
// src/lib/section-instances.ts
|
|
8149
|
-
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
8150
|
-
var REMOVED_ATTR2 = "data-ohw-section-removed";
|
|
8151
|
-
function isRemovedSection(el) {
|
|
8152
|
-
return el.hasAttribute(REMOVED_ATTR2);
|
|
8153
|
-
}
|
|
8154
|
-
function topLevelSections() {
|
|
8155
|
-
return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
8156
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el) && !isRemovedSection(el)
|
|
8157
|
-
);
|
|
8158
|
-
}
|
|
8159
|
-
function instanceIdOf(el) {
|
|
8160
|
-
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
8161
|
-
}
|
|
8162
|
-
function findByInstanceId(instanceId) {
|
|
8163
|
-
const escapedId = CSS.escape(instanceId);
|
|
8164
|
-
return document.querySelector(`[data-ohw-instance="${escapedId}"]`) ?? document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
8165
|
-
}
|
|
8166
|
-
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
8167
|
-
const sections = topLevelSections();
|
|
8168
|
-
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8169
|
-
if (index === -1) return null;
|
|
8170
|
-
const dragged = sections[index];
|
|
8171
|
-
const others = sections.filter((_, i) => i !== index);
|
|
8172
|
-
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
8173
|
-
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
8174
|
-
return reordered.map((el, order) => ({
|
|
8175
|
-
instanceId: instanceIdOf(el),
|
|
8176
|
-
type: el.getAttribute("data-ohw-section") ?? "",
|
|
8177
|
-
order,
|
|
8178
|
-
pagePath: currentPath
|
|
8179
|
-
}));
|
|
8180
|
-
}
|
|
8181
|
-
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
8182
|
-
const sections = topLevelSections();
|
|
8183
|
-
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8184
|
-
if (index === -1) return null;
|
|
8185
|
-
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
8186
|
-
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
8187
|
-
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
8188
|
-
if (!entries) return null;
|
|
8189
|
-
applyPersistedOrder(entries);
|
|
8190
|
-
return entries;
|
|
8191
|
-
}
|
|
8192
|
-
function syncRemovedFlags(entries) {
|
|
8193
|
-
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
8194
|
-
document.querySelectorAll(`[${REMOVED_ATTR2}]`).forEach((el) => {
|
|
8195
|
-
if (!removedIds.has(instanceIdOf(el))) {
|
|
8196
|
-
el.style.removeProperty("display");
|
|
8197
|
-
el.removeAttribute(REMOVED_ATTR2);
|
|
8198
|
-
}
|
|
8199
|
-
});
|
|
8200
|
-
for (const id of removedIds) {
|
|
8201
|
-
const el = findByInstanceId(id);
|
|
8202
|
-
if (el) {
|
|
8203
|
-
el.style.display = "none";
|
|
8204
|
-
el.setAttribute(REMOVED_ATTR2, "");
|
|
8848
|
+
onClick: () => onEdit(hover.key),
|
|
8849
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
8850
|
+
Button,
|
|
8851
|
+
{
|
|
8852
|
+
"data-ohw-carousel-overlay": "",
|
|
8853
|
+
variant: "outline",
|
|
8854
|
+
size: "sm",
|
|
8855
|
+
className: "cursor-pointer gap-1.5 hover:bg-background",
|
|
8856
|
+
style: OVERLAY_BUTTON_STYLE2,
|
|
8857
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
8858
|
+
onClick: (e) => {
|
|
8859
|
+
e.stopPropagation();
|
|
8860
|
+
onEdit(hover.key);
|
|
8861
|
+
},
|
|
8862
|
+
children: [
|
|
8863
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react6.GalleryHorizontal, { size: 14 }),
|
|
8864
|
+
"Edit gallery"
|
|
8865
|
+
]
|
|
8866
|
+
}
|
|
8867
|
+
)
|
|
8205
8868
|
}
|
|
8206
|
-
}
|
|
8207
|
-
}
|
|
8208
|
-
function applyPersistedOrder(entries) {
|
|
8209
|
-
syncRemovedFlags(entries);
|
|
8210
|
-
if (entries.length === 0) return;
|
|
8211
|
-
const sections = topLevelSections();
|
|
8212
|
-
if (sections.length === 0) return;
|
|
8213
|
-
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
8214
|
-
const ordered = [...sections].sort((a, b) => {
|
|
8215
|
-
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
8216
|
-
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
8217
|
-
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
8218
|
-
if (aOrder === void 0) return 1;
|
|
8219
|
-
if (bOrder === void 0) return -1;
|
|
8220
|
-
return aOrder - bOrder;
|
|
8221
|
-
});
|
|
8222
|
-
let prev = null;
|
|
8223
|
-
for (const el of ordered) {
|
|
8224
|
-
if (prev) prev.after(el);
|
|
8225
|
-
prev = el;
|
|
8226
|
-
}
|
|
8227
|
-
}
|
|
8228
|
-
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
8229
|
-
if (!findByInstanceId(instanceId)) return null;
|
|
8230
|
-
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
8231
|
-
const allSections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
8232
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
|
|
8233
8869
|
);
|
|
8234
|
-
allSections.forEach((el, order) => {
|
|
8235
|
-
const id = instanceIdOf(el);
|
|
8236
|
-
if (!byId.has(id)) {
|
|
8237
|
-
byId.set(id, { instanceId: id, type: el.getAttribute("data-ohw-section") ?? "", order, pagePath: currentPath });
|
|
8238
|
-
}
|
|
8239
|
-
});
|
|
8240
|
-
const target = byId.get(instanceId);
|
|
8241
|
-
if (!target) return null;
|
|
8242
|
-
byId.set(instanceId, { ...target, removed });
|
|
8243
|
-
const entries = Array.from(byId.values());
|
|
8244
|
-
applyPersistedOrder(entries);
|
|
8245
|
-
return entries;
|
|
8246
|
-
}
|
|
8247
|
-
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
8248
|
-
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
8249
|
-
}
|
|
8250
|
-
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
8251
|
-
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
8252
|
-
}
|
|
8253
|
-
function newInstanceId() {
|
|
8254
|
-
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
8255
|
-
}
|
|
8256
|
-
function getPageSectionOrderEntries(raw, currentPath) {
|
|
8257
|
-
if (!raw) return [];
|
|
8258
|
-
try {
|
|
8259
|
-
const entries = JSON.parse(raw);
|
|
8260
|
-
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
8261
|
-
} catch {
|
|
8262
|
-
return [];
|
|
8263
|
-
}
|
|
8264
|
-
}
|
|
8265
|
-
function rekeySectionSubtree(root, instanceId) {
|
|
8266
|
-
const suffix = `::${instanceId}`;
|
|
8267
|
-
const rekey = (el, attr) => {
|
|
8268
|
-
const current = el.getAttribute(attr);
|
|
8269
|
-
if (current) el.setAttribute(attr, `${current}${suffix}`);
|
|
8270
|
-
};
|
|
8271
|
-
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
8272
|
-
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
8273
|
-
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
8274
|
-
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
8275
|
-
}
|
|
8276
|
-
function initSectionInstancesFromContent(content, currentPath) {
|
|
8277
|
-
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
8278
|
-
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
8279
|
-
});
|
|
8280
|
-
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
8281
|
-
for (const entry of entries) {
|
|
8282
|
-
if (entry.instanceId === entry.type) continue;
|
|
8283
|
-
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
8284
|
-
const original = document.querySelector(
|
|
8285
|
-
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
8286
|
-
);
|
|
8287
|
-
if (!original) continue;
|
|
8288
|
-
const clone = original.cloneNode(true);
|
|
8289
|
-
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
8290
|
-
rekeySectionSubtree(clone, entry.instanceId);
|
|
8291
|
-
original.insertAdjacentElement("afterend", clone);
|
|
8292
|
-
}
|
|
8293
|
-
applyPersistedOrder(entries);
|
|
8294
8870
|
}
|
|
8295
8871
|
|
|
8296
8872
|
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
8873
|
+
var import_react8 = require("react");
|
|
8874
|
+
var import_lucide_react7 = require("lucide-react");
|
|
8297
8875
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
8298
8876
|
function findSectionElement(instanceId) {
|
|
8299
8877
|
const escaped = CSS.escape(instanceId);
|
|
@@ -11196,7 +11774,6 @@ function iconMarkupSizedFor(slot, markup) {
|
|
|
11196
11774
|
holder.innerHTML = markup;
|
|
11197
11775
|
const glyph = holder.querySelector(GLYPH_SELECTOR);
|
|
11198
11776
|
if (!glyph) return markup;
|
|
11199
|
-
glyph.style.display = "block";
|
|
11200
11777
|
if (!box) {
|
|
11201
11778
|
glyph.style.width = "1.5em";
|
|
11202
11779
|
glyph.style.height = "1.5em";
|
|
@@ -13010,6 +13587,7 @@ function readLogoSizeState(content, placement) {
|
|
|
13010
13587
|
function getLogoElement(el) {
|
|
13011
13588
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
13012
13589
|
if (marked) return marked;
|
|
13590
|
+
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
13013
13591
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
13014
13592
|
if (!root) return null;
|
|
13015
13593
|
const anchor = el.closest("a");
|
|
@@ -14076,15 +14654,17 @@ function useSectionDrag({
|
|
|
14076
14654
|
clearSectionDragVisuals();
|
|
14077
14655
|
return;
|
|
14078
14656
|
}
|
|
14079
|
-
const orderJson = JSON.stringify(
|
|
14657
|
+
const orderJson = JSON.stringify(
|
|
14658
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
14659
|
+
);
|
|
14080
14660
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
14081
14661
|
setAiSectionOrder(orderJson, window.location.pathname);
|
|
14082
14662
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
14083
|
-
applyPersistedOrder(
|
|
14663
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
14084
14664
|
clearSectionDragVisuals();
|
|
14085
14665
|
requestAnimationFrame(() => {
|
|
14086
14666
|
if (editContentRef.current[SECTION_ORDER_KEY] === orderJson) {
|
|
14087
|
-
applyPersistedOrder(
|
|
14667
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
14088
14668
|
}
|
|
14089
14669
|
requestAnimationFrame(() => {
|
|
14090
14670
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -14385,6 +14965,9 @@ function collectEditableNodes(extraContent, root = document) {
|
|
|
14385
14965
|
if (el.dataset.ohwEditable === "link") {
|
|
14386
14966
|
return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref3(el) };
|
|
14387
14967
|
}
|
|
14968
|
+
if (el.dataset.ohwEditable === "map") {
|
|
14969
|
+
return { key: el.dataset.ohwKey ?? "", type: "map", text: el.dataset.ohwMapQuery ?? "" };
|
|
14970
|
+
}
|
|
14388
14971
|
return {
|
|
14389
14972
|
key: el.dataset.ohwKey ?? "",
|
|
14390
14973
|
type: el.dataset.ohwEditable ?? "text",
|
|
@@ -14938,21 +15521,10 @@ function parseSchedulingInsertAfter(insertAfter) {
|
|
|
14938
15521
|
insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
|
|
14939
15522
|
};
|
|
14940
15523
|
}
|
|
14941
|
-
function
|
|
14942
|
-
|
|
14943
|
-
const
|
|
14944
|
-
|
|
14945
|
-
return { effectiveInsertAfter, insertBefore };
|
|
14946
|
-
}
|
|
14947
|
-
function getSchedulingMountPoint(insertAfter) {
|
|
14948
|
-
const { anchor } = parseSchedulingInsertAfter(insertAfter);
|
|
14949
|
-
let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
|
|
14950
|
-
if (!anchorEl && anchor === "scheduling") {
|
|
14951
|
-
const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
|
|
14952
|
-
anchorEl = widgets.at(-1) ?? null;
|
|
14953
|
-
}
|
|
14954
|
-
if (!anchorEl) return null;
|
|
14955
|
-
return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
15524
|
+
function resolveEntryAnchor(entry) {
|
|
15525
|
+
if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
|
|
15526
|
+
const parsed = parseSchedulingInsertAfter(entry.insertAfter);
|
|
15527
|
+
return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
|
|
14956
15528
|
}
|
|
14957
15529
|
function schedulingMountDepth(insertAfter) {
|
|
14958
15530
|
if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
|
|
@@ -14969,8 +15541,7 @@ function getPageSchedulingEntries(raw) {
|
|
|
14969
15541
|
}
|
|
14970
15542
|
}
|
|
14971
15543
|
function isSchedulingWidgetMissing(entry) {
|
|
14972
|
-
|
|
14973
|
-
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
|
|
15544
|
+
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
|
|
14974
15545
|
}
|
|
14975
15546
|
function hasMissingSchedulingWidgets(entries) {
|
|
14976
15547
|
return entries.some(isSchedulingWidgetMissing);
|
|
@@ -15000,16 +15571,17 @@ function initSectionsFromContent(content, removeExisting = false) {
|
|
|
15000
15571
|
} catch {
|
|
15001
15572
|
}
|
|
15002
15573
|
}
|
|
15003
|
-
function mountSchedulingWidget(
|
|
15004
|
-
const
|
|
15005
|
-
const sectionId = schedulingSectionId(
|
|
15574
|
+
function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
|
|
15575
|
+
const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
|
|
15576
|
+
const sectionId = schedulingSectionId(widgetId);
|
|
15006
15577
|
if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
|
|
15007
|
-
const
|
|
15008
|
-
if (!
|
|
15578
|
+
const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
|
|
15579
|
+
if (!anchorEl) return false;
|
|
15580
|
+
const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
15009
15581
|
const container = document.createElement("div");
|
|
15010
15582
|
container.dataset.ohwSectionContainer = "scheduling";
|
|
15011
|
-
if (
|
|
15012
|
-
const beforeAnchor = document.querySelector(`[data-ohw-section="${
|
|
15583
|
+
if (beforeId) {
|
|
15584
|
+
const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
|
|
15013
15585
|
const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
|
|
15014
15586
|
if (!beforePoint) return false;
|
|
15015
15587
|
beforePoint.insertAdjacentElement("beforebegin", container);
|
|
@@ -15020,19 +15592,25 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
15020
15592
|
}
|
|
15021
15593
|
tail.insertAdjacentElement("afterend", container);
|
|
15022
15594
|
}
|
|
15023
|
-
|
|
15024
|
-
|
|
15025
|
-
|
|
15026
|
-
|
|
15027
|
-
|
|
15028
|
-
|
|
15029
|
-
|
|
15030
|
-
|
|
15031
|
-
|
|
15032
|
-
|
|
15033
|
-
|
|
15034
|
-
|
|
15035
|
-
|
|
15595
|
+
try {
|
|
15596
|
+
const root = (0, import_client2.createRoot)(container);
|
|
15597
|
+
(0, import_react_dom3.flushSync)(() => {
|
|
15598
|
+
root.render(
|
|
15599
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
15600
|
+
SchedulingWidget,
|
|
15601
|
+
{
|
|
15602
|
+
notifyOnConnect,
|
|
15603
|
+
initialScheduleId: scheduleId,
|
|
15604
|
+
insertAfter: widgetId
|
|
15605
|
+
}
|
|
15606
|
+
)
|
|
15607
|
+
);
|
|
15608
|
+
});
|
|
15609
|
+
} catch (err) {
|
|
15610
|
+
console.error("[ow:scheduling] render threw", err);
|
|
15611
|
+
container.remove();
|
|
15612
|
+
return false;
|
|
15613
|
+
}
|
|
15036
15614
|
const tracker = getSectionsTracker();
|
|
15037
15615
|
let sections = [];
|
|
15038
15616
|
try {
|
|
@@ -15040,10 +15618,12 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
15040
15618
|
} catch {
|
|
15041
15619
|
}
|
|
15042
15620
|
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
15043
|
-
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter ===
|
|
15621
|
+
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
|
|
15044
15622
|
sections.push({
|
|
15045
15623
|
type: "scheduling",
|
|
15046
|
-
insertAfter:
|
|
15624
|
+
insertAfter: widgetId,
|
|
15625
|
+
anchorId,
|
|
15626
|
+
beforeId: beforeId ?? null,
|
|
15047
15627
|
pagePath: window.location.pathname,
|
|
15048
15628
|
...scheduleId ? { scheduleId } : {}
|
|
15049
15629
|
});
|
|
@@ -15057,7 +15637,8 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
|
15057
15637
|
for (let i = pending.length - 1; i >= 0; i--) {
|
|
15058
15638
|
const entry = pending[i];
|
|
15059
15639
|
const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
|
|
15060
|
-
|
|
15640
|
+
const { anchorId, beforeId } = resolveEntryAnchor(entry);
|
|
15641
|
+
if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
|
|
15061
15642
|
pending.splice(i, 1);
|
|
15062
15643
|
}
|
|
15063
15644
|
}
|
|
@@ -15149,7 +15730,7 @@ var EDITOR_CHROME_SELECTOR = '[data-ohw-toolbar], [data-ohw-form-toolbar], [data
|
|
|
15149
15730
|
function isOverEditorChrome(x, y) {
|
|
15150
15731
|
return document.elementsFromPoint(x, y).some((el) => el instanceof HTMLElement && el.matches(EDITOR_CHROME_SELECTOR));
|
|
15151
15732
|
}
|
|
15152
|
-
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"])';
|
|
15733
|
+
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"])';
|
|
15153
15734
|
function getVideoEl2(el) {
|
|
15154
15735
|
return el instanceof HTMLVideoElement ? el : el.querySelector("video");
|
|
15155
15736
|
}
|
|
@@ -15205,6 +15786,12 @@ function applyVideoSettingNode(key, val) {
|
|
|
15205
15786
|
});
|
|
15206
15787
|
return true;
|
|
15207
15788
|
}
|
|
15789
|
+
function applyMapQuery(el, val) {
|
|
15790
|
+
if (!(el instanceof HTMLIFrameElement)) return;
|
|
15791
|
+
const nextSrc = `https://www.google.com/maps?q=${encodeURIComponent(val)}&output=embed`;
|
|
15792
|
+
if (el.src !== nextSrc) el.src = nextSrc;
|
|
15793
|
+
el.setAttribute("data-ohw-map-query", val);
|
|
15794
|
+
}
|
|
15208
15795
|
function applyLinkByKey(key, val) {
|
|
15209
15796
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
15210
15797
|
if (el.dataset.ohwEditable === "link") applyLinkHref(el, val);
|
|
@@ -15215,6 +15802,11 @@ function applyLinkByKey(key, val) {
|
|
|
15215
15802
|
hrefAnchors.forEach((el) => applyLinkHref(el, val));
|
|
15216
15803
|
}
|
|
15217
15804
|
}
|
|
15805
|
+
function isInsideLinkEditor(target) {
|
|
15806
|
+
return Boolean(
|
|
15807
|
+
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"]')
|
|
15808
|
+
);
|
|
15809
|
+
}
|
|
15218
15810
|
function isInsideFloatingPanel(target) {
|
|
15219
15811
|
return Boolean(target.closest("[data-ohw-floating-panel]"));
|
|
15220
15812
|
}
|
|
@@ -15222,11 +15814,6 @@ function isPointOverFloatingPanel(clientX, clientY) {
|
|
|
15222
15814
|
const el = document.elementFromPoint(clientX, clientY);
|
|
15223
15815
|
return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
|
|
15224
15816
|
}
|
|
15225
|
-
function isInsideLinkEditor(target) {
|
|
15226
|
-
return Boolean(
|
|
15227
|
-
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"]')
|
|
15228
|
-
);
|
|
15229
|
-
}
|
|
15230
15817
|
function getHrefKeyFromElement(el) {
|
|
15231
15818
|
if (!el) return null;
|
|
15232
15819
|
const anchor = el.closest("[data-ohw-href-key]");
|
|
@@ -15485,7 +16072,7 @@ function getNavigationSelectionParent(el) {
|
|
|
15485
16072
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
15486
16073
|
return getFooterLinksContainer();
|
|
15487
16074
|
}
|
|
15488
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
16075
|
+
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)) {
|
|
15489
16076
|
return getNavigationRoot(el);
|
|
15490
16077
|
}
|
|
15491
16078
|
return null;
|
|
@@ -15700,7 +16287,6 @@ var ICONS = {
|
|
|
15700
16287
|
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"/>',
|
|
15701
16288
|
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"/>'
|
|
15702
16289
|
};
|
|
15703
|
-
var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
|
|
15704
16290
|
var SELECTION_CHROME_GAP2 = 4;
|
|
15705
16291
|
var TOOLBAR_STROKE_GAP2 = 4;
|
|
15706
16292
|
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
@@ -16080,6 +16666,7 @@ function StateToggle({
|
|
|
16080
16666
|
);
|
|
16081
16667
|
}
|
|
16082
16668
|
var contentCache = /* @__PURE__ */ new Map();
|
|
16669
|
+
var fetchedContentPaths = /* @__PURE__ */ new Set();
|
|
16083
16670
|
var brandingCache = /* @__PURE__ */ new Map();
|
|
16084
16671
|
var OHW_LOADER_STYLE = {
|
|
16085
16672
|
position: "fixed",
|
|
@@ -16609,13 +17196,6 @@ function OhhwellsBridge() {
|
|
|
16609
17196
|
const [isItemDragging, setIsItemDragging] = (0, import_react17.useState)(false);
|
|
16610
17197
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react17.useState)(false);
|
|
16611
17198
|
isFooterFrameSelectionRef.current = isFooterFrameSelection;
|
|
16612
|
-
const [floatingPanel, setFloatingPanel] = (0, import_react17.useState)(null);
|
|
16613
|
-
const floatingPanelOpenRef = (0, import_react17.useRef)(false);
|
|
16614
|
-
floatingPanelOpenRef.current = floatingPanel !== null;
|
|
16615
|
-
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react17.useState)(null);
|
|
16616
|
-
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react17.useState)(null);
|
|
16617
|
-
const [editorViewport, setEditorViewport] = (0, import_react17.useState)("desktop");
|
|
16618
|
-
const [parentScrollSnap, setParentScrollSnap] = (0, import_react17.useState)(null);
|
|
16619
17199
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react17.useState)(null);
|
|
16620
17200
|
const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react17.useState)(null);
|
|
16621
17201
|
const footerDragRef = (0, import_react17.useRef)(null);
|
|
@@ -16633,6 +17213,13 @@ function OhhwellsBridge() {
|
|
|
16633
17213
|
const brandKitRef = (0, import_react17.useRef)("");
|
|
16634
17214
|
const stylesRef = (0, import_react17.useRef)("");
|
|
16635
17215
|
const pendingDeleteUndoRef = (0, import_react17.useRef)(null);
|
|
17216
|
+
const [floatingPanel, setFloatingPanel] = (0, import_react17.useState)(null);
|
|
17217
|
+
const floatingPanelOpenRef = (0, import_react17.useRef)(false);
|
|
17218
|
+
const setFloatingPanelRef = (0, import_react17.useRef)(setFloatingPanel);
|
|
17219
|
+
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react17.useState)(null);
|
|
17220
|
+
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react17.useState)(null);
|
|
17221
|
+
const [editorViewport, setEditorViewport] = (0, import_react17.useState)("desktop");
|
|
17222
|
+
const [parentScrollSnap, setParentScrollSnap] = (0, import_react17.useState)(null);
|
|
16636
17223
|
const [sitePages, setSitePages] = (0, import_react17.useState)([]);
|
|
16637
17224
|
const [sectionsByPath, setSectionsByPath] = (0, import_react17.useState)({});
|
|
16638
17225
|
const sectionsPrefetchGenRef = (0, import_react17.useRef)(0);
|
|
@@ -16641,7 +17228,18 @@ function OhhwellsBridge() {
|
|
|
16641
17228
|
const linkPopoverOpenRef = (0, import_react17.useRef)(false);
|
|
16642
17229
|
const linkPopoverGraceUntilRef = (0, import_react17.useRef)(0);
|
|
16643
17230
|
setLinkPopoverRef.current = setLinkPopover;
|
|
17231
|
+
setFloatingPanelRef.current = setFloatingPanel;
|
|
16644
17232
|
linkPopoverSessionRef.current = linkPopover;
|
|
17233
|
+
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
17234
|
+
(0, import_react17.useEffect)(() => {
|
|
17235
|
+
const syncViewport = () => {
|
|
17236
|
+
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
17237
|
+
setEditorViewport((prev) => prev === next ? prev : next);
|
|
17238
|
+
};
|
|
17239
|
+
syncViewport();
|
|
17240
|
+
window.addEventListener("resize", syncViewport);
|
|
17241
|
+
return () => window.removeEventListener("resize", syncViewport);
|
|
17242
|
+
}, []);
|
|
16645
17243
|
const {
|
|
16646
17244
|
navDragRef,
|
|
16647
17245
|
navDropSlots,
|
|
@@ -17966,17 +18564,19 @@ function OhhwellsBridge() {
|
|
|
17966
18564
|
}
|
|
17967
18565
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
17968
18566
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
18567
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
17969
18568
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
17970
18569
|
}
|
|
17971
18570
|
applyBrandChrome(content);
|
|
18571
|
+
initSectionInstancesFromContent(content, window.location.pathname);
|
|
17972
18572
|
for (const [key, val] of Object.entries(content)) {
|
|
17973
18573
|
if (key === "__ohw_sections") continue;
|
|
17974
18574
|
if (key === AI_SECTIONS_KEY) continue;
|
|
18575
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18576
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
17975
18577
|
if (key === BRAND_KIT_KEY) continue;
|
|
17976
18578
|
if (key === STYLE_STORE_KEY) continue;
|
|
17977
18579
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
17978
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
17979
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
17980
18580
|
if (applyVideoSettingNode(key, val)) continue;
|
|
17981
18581
|
if (applyCarouselNode(key, val)) continue;
|
|
17982
18582
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -18004,6 +18604,8 @@ function OhhwellsBridge() {
|
|
|
18004
18604
|
}
|
|
18005
18605
|
} else if (el.dataset.ohwEditable === "link") {
|
|
18006
18606
|
applyLinkHref(el, val);
|
|
18607
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
18608
|
+
applyMapQuery(el, val);
|
|
18007
18609
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
18008
18610
|
applyIconMarkup(el, val);
|
|
18009
18611
|
} else if (el.dataset.ohwEditable === "form") {
|
|
@@ -18024,7 +18626,6 @@ function OhhwellsBridge() {
|
|
|
18024
18626
|
if (isEditModeRef.current) requestMissingSocialIconsRef.current();
|
|
18025
18627
|
enforceLinkHrefs();
|
|
18026
18628
|
initSectionsFromContent(content, true);
|
|
18027
|
-
initSectionInstancesFromContent(content, window.location.pathname);
|
|
18028
18629
|
sectionsLoadedRef.current = true;
|
|
18029
18630
|
pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
|
|
18030
18631
|
if (imageLoads.length === 0) return Promise.resolve();
|
|
@@ -18043,7 +18644,9 @@ function OhhwellsBridge() {
|
|
|
18043
18644
|
let cancelled = false;
|
|
18044
18645
|
setFetchState("loading");
|
|
18045
18646
|
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
18046
|
-
|
|
18647
|
+
const initialPath = pathname;
|
|
18648
|
+
fetchedContentPaths.add(`${subdomain}::${initialPath}`);
|
|
18649
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
18047
18650
|
if (cancelled) return;
|
|
18048
18651
|
const content = data?.content ?? {};
|
|
18049
18652
|
const branding = Boolean(data?.showBranding);
|
|
@@ -18177,16 +18780,17 @@ function OhhwellsBridge() {
|
|
|
18177
18780
|
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
18178
18781
|
}
|
|
18179
18782
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
18783
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
18180
18784
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
18181
18785
|
}
|
|
18182
18786
|
for (const [key, val] of Object.entries(content)) {
|
|
18183
18787
|
if (key === "__ohw_sections") continue;
|
|
18184
18788
|
if (key === AI_SECTIONS_KEY) continue;
|
|
18789
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18790
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18185
18791
|
if (key === BRAND_KIT_KEY) continue;
|
|
18186
18792
|
if (key === STYLE_STORE_KEY) continue;
|
|
18187
18793
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
18188
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18189
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18190
18794
|
if (applyVideoSettingNode(key, val)) continue;
|
|
18191
18795
|
if (applyCarouselNode(key, val)) continue;
|
|
18192
18796
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -18201,6 +18805,8 @@ function OhhwellsBridge() {
|
|
|
18201
18805
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
18202
18806
|
} else if (el.dataset.ohwEditable === "link") {
|
|
18203
18807
|
applyLinkHref(el, val);
|
|
18808
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
18809
|
+
applyMapQuery(el, val);
|
|
18204
18810
|
} else if (el.dataset.ohwEditable === "form") {
|
|
18205
18811
|
} else if (isIconMarkupValue(val)) {
|
|
18206
18812
|
} else if (el.innerHTML !== val) {
|
|
@@ -18232,6 +18838,17 @@ function OhhwellsBridge() {
|
|
|
18232
18838
|
debounceTimer = setTimeout(applyFromCache, 150);
|
|
18233
18839
|
};
|
|
18234
18840
|
applyFromCache();
|
|
18841
|
+
const pathCacheKey = `${subdomain}::${pathname}`;
|
|
18842
|
+
if (!fetchedContentPaths.has(pathCacheKey)) {
|
|
18843
|
+
fetchedContentPaths.add(pathCacheKey);
|
|
18844
|
+
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
18845
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
18846
|
+
if (!data?.content) return;
|
|
18847
|
+
contentCache.set(subdomain, data.content);
|
|
18848
|
+
applyFromCache();
|
|
18849
|
+
}).catch(() => {
|
|
18850
|
+
});
|
|
18851
|
+
}
|
|
18235
18852
|
observer = new MutationObserver(scheduleApply);
|
|
18236
18853
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
18237
18854
|
return () => {
|
|
@@ -18347,26 +18964,11 @@ function OhhwellsBridge() {
|
|
|
18347
18964
|
const t2 = setTimeout(measure, 500);
|
|
18348
18965
|
const ro = new ResizeObserver(schedule);
|
|
18349
18966
|
ro.observe(document.body);
|
|
18350
|
-
let lastWidth = window.innerWidth;
|
|
18351
|
-
let resizeTimers = [];
|
|
18352
|
-
const clearResizeTimers = () => {
|
|
18353
|
-
resizeTimers.forEach(clearTimeout);
|
|
18354
|
-
resizeTimers = [];
|
|
18355
|
-
};
|
|
18356
|
-
const handleResize = () => {
|
|
18357
|
-
if (window.innerWidth === lastWidth) return;
|
|
18358
|
-
lastWidth = window.innerWidth;
|
|
18359
|
-
clearResizeTimers();
|
|
18360
|
-
resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
|
|
18361
|
-
};
|
|
18362
|
-
window.addEventListener("resize", handleResize);
|
|
18363
18967
|
return () => {
|
|
18364
18968
|
clearTimeout(t1);
|
|
18365
18969
|
clearTimeout(t2);
|
|
18366
18970
|
if (raf != null) cancelAnimationFrame(raf);
|
|
18367
18971
|
ro.disconnect();
|
|
18368
|
-
clearResizeTimers();
|
|
18369
|
-
window.removeEventListener("resize", handleResize);
|
|
18370
18972
|
};
|
|
18371
18973
|
}, [pathname, isEditMode, postToParent2]);
|
|
18372
18974
|
(0, import_react17.useEffect)(() => {
|
|
@@ -18410,15 +19012,6 @@ function OhhwellsBridge() {
|
|
|
18410
19012
|
[style*="100vh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
|
|
18411
19013
|
[style*="100svh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
|
|
18412
19014
|
[style*="100dvh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
|
|
18413
|
-
/* A section written as min-height: var(--ohw-canvas-h, 100svh) \u2014 the documented way to
|
|
18414
|
-
build a full-viewport section that still grows for its own content \u2014 matches the three
|
|
18415
|
-
rules above on substring alone, since the fallback text contains "100svh" too. Forcing
|
|
18416
|
-
a literal height on top of that turns "at least one screen" into "exactly one screen",
|
|
18417
|
-
so content taller than one screen (a long mobile hero, say) overflows a centered flex
|
|
18418
|
-
column upward, under whatever sits above it. Only the min-height half belongs to it. */
|
|
18419
|
-
[style*="min-height"][style*="100vh"],
|
|
18420
|
-
[style*="min-height"][style*="100svh"],
|
|
18421
|
-
[style*="min-height"][style*="100dvh"] { height: auto !important; }
|
|
18422
19015
|
/* Emptied text keeps somewhere to click. A label typed down to nothing collapses to a
|
|
18423
19016
|
couple of pixels, and getting back into it meant hunting for the caret with the mouse.
|
|
18424
19017
|
Edit mode only \u2014 the published page shows nothing where there is nothing (OHH-736). */
|
|
@@ -18621,9 +19214,6 @@ function OhhwellsBridge() {
|
|
|
18621
19214
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
18622
19215
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
18623
19216
|
if (isInsideLinkEditor(target)) return;
|
|
18624
|
-
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
18625
|
-
clearMediaSelectionRef.current();
|
|
18626
|
-
}
|
|
18627
19217
|
if (isInsideFloatingPanel(target)) return;
|
|
18628
19218
|
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
18629
19219
|
if (target.closest(
|
|
@@ -18631,6 +19221,9 @@ function OhhwellsBridge() {
|
|
|
18631
19221
|
)) {
|
|
18632
19222
|
return;
|
|
18633
19223
|
}
|
|
19224
|
+
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
19225
|
+
clearMediaSelectionRef.current();
|
|
19226
|
+
}
|
|
18634
19227
|
{
|
|
18635
19228
|
const formEl = getFormElement(target);
|
|
18636
19229
|
const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
|
|
@@ -18782,14 +19375,6 @@ function OhhwellsBridge() {
|
|
|
18782
19375
|
}
|
|
18783
19376
|
const clickedButton = findClosestButtonLike(target);
|
|
18784
19377
|
const buttonOnMedia = Boolean(clickedButton && isMediaEditable(editable) && editable.contains(clickedButton));
|
|
18785
|
-
console.log("[click-debug]", {
|
|
18786
|
-
editableType: editable.dataset.ohwEditable,
|
|
18787
|
-
editableTag: editable.tagName,
|
|
18788
|
-
targetTag: target.tagName,
|
|
18789
|
-
clickedButtonTag: clickedButton?.tagName ?? null,
|
|
18790
|
-
buttonOnMedia,
|
|
18791
|
-
isMediaEditableEditable: isMediaEditable(editable)
|
|
18792
|
-
});
|
|
18793
19378
|
if (isMediaEditable(editable) && !buttonOnMedia) {
|
|
18794
19379
|
e.preventDefault();
|
|
18795
19380
|
e.stopPropagation();
|
|
@@ -18816,11 +19401,6 @@ function OhhwellsBridge() {
|
|
|
18816
19401
|
const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
|
|
18817
19402
|
const hrefCtx = getHrefKeyFromElement(hrefLookupTarget);
|
|
18818
19403
|
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
18819
|
-
console.log("[click-debug 2]", {
|
|
18820
|
-
hrefLookupTargetTag: hrefLookupTarget.tagName,
|
|
18821
|
-
hrefCtx: hrefCtx ? { key: hrefCtx.key } : null,
|
|
18822
|
-
navAnchorTag: navAnchor?.tagName ?? null
|
|
18823
|
-
});
|
|
18824
19404
|
if (navAnchor) {
|
|
18825
19405
|
e.preventDefault();
|
|
18826
19406
|
e.stopPropagation();
|
|
@@ -18990,6 +19570,9 @@ function OhhwellsBridge() {
|
|
|
18990
19570
|
setHoveredItemRect(null);
|
|
18991
19571
|
hoveredNavContainerRef.current = null;
|
|
18992
19572
|
setHoveredNavContainerRect(null);
|
|
19573
|
+
siblingHintElRef.current = null;
|
|
19574
|
+
setSiblingHintRect(null);
|
|
19575
|
+
setSiblingHintRects([]);
|
|
18993
19576
|
return;
|
|
18994
19577
|
}
|
|
18995
19578
|
{
|
|
@@ -19108,7 +19691,6 @@ function OhhwellsBridge() {
|
|
|
19108
19691
|
hoveredNavContainerRef.current = null;
|
|
19109
19692
|
setHoveredNavContainerRect(null);
|
|
19110
19693
|
hoveredItemElRef.current = editable;
|
|
19111
|
-
setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
|
|
19112
19694
|
}
|
|
19113
19695
|
}
|
|
19114
19696
|
}
|
|
@@ -19405,7 +19987,7 @@ function OhhwellsBridge() {
|
|
|
19405
19987
|
}
|
|
19406
19988
|
};
|
|
19407
19989
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
19408
|
-
if (linkPopoverOpenRef.current) {
|
|
19990
|
+
if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
19409
19991
|
if (hoveredImageRef.current) {
|
|
19410
19992
|
hoveredImageRef.current = null;
|
|
19411
19993
|
hoveredImageHasTextOverlapRef.current = false;
|
|
@@ -19770,8 +20352,7 @@ function OhhwellsBridge() {
|
|
|
19770
20352
|
};
|
|
19771
20353
|
const handleMouseMove = (e) => {
|
|
19772
20354
|
const { clientX, clientY } = e;
|
|
19773
|
-
if (
|
|
19774
|
-
if (isOverEditorChrome(clientX, clientY)) {
|
|
20355
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
|
|
19775
20356
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
19776
20357
|
formHoverElRef.current = null;
|
|
19777
20358
|
setFormHoverRect(null);
|
|
@@ -19779,6 +20360,12 @@ function OhhwellsBridge() {
|
|
|
19779
20360
|
setHoveredItemRect(null);
|
|
19780
20361
|
hoveredNavContainerRef.current = null;
|
|
19781
20362
|
setHoveredNavContainerRect(null);
|
|
20363
|
+
siblingHintElRef.current = null;
|
|
20364
|
+
setSiblingHintRect(null);
|
|
20365
|
+
setSiblingHintRects([]);
|
|
20366
|
+
dismissImageHover();
|
|
20367
|
+
clearImageHover();
|
|
20368
|
+
setSectionGap(null);
|
|
19782
20369
|
return;
|
|
19783
20370
|
}
|
|
19784
20371
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
@@ -19790,7 +20377,11 @@ function OhhwellsBridge() {
|
|
|
19790
20377
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
19791
20378
|
const { clientX, clientY } = e.data;
|
|
19792
20379
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
19793
|
-
if (
|
|
20380
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
20381
|
+
dismissImageHover();
|
|
20382
|
+
clearImageHover();
|
|
20383
|
+
return;
|
|
20384
|
+
}
|
|
19794
20385
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
19795
20386
|
probeSectionGapAt(clientX, clientY);
|
|
19796
20387
|
probeImageAt(clientX, clientY);
|
|
@@ -20069,6 +20660,44 @@ function OhhwellsBridge() {
|
|
|
20069
20660
|
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
20070
20661
|
}, 400));
|
|
20071
20662
|
};
|
|
20663
|
+
const reapCommittedAiSections = (excludeIds) => {
|
|
20664
|
+
const aiState = parseAiSectionsState(aiSectionsRef.current);
|
|
20665
|
+
if (aiState.sections.length === 0) return [];
|
|
20666
|
+
let orderEntries = [];
|
|
20667
|
+
try {
|
|
20668
|
+
const parsed = JSON.parse(editContentRef.current[SECTION_ORDER_KEY] ?? "[]");
|
|
20669
|
+
if (Array.isArray(parsed)) orderEntries = parsed;
|
|
20670
|
+
} catch {
|
|
20671
|
+
return [];
|
|
20672
|
+
}
|
|
20673
|
+
const removedIds = orderEntries.filter((entry) => entry && typeof entry.instanceId === "string" && entry.removed).map((entry) => entry.instanceId);
|
|
20674
|
+
if (removedIds.length === 0) return [];
|
|
20675
|
+
const result = reapRemovedAiSections(aiState, parseStyleStore(stylesRef.current), removedIds, excludeIds);
|
|
20676
|
+
if (!result.changed) return [];
|
|
20677
|
+
const nodes = [];
|
|
20678
|
+
aiSectionsRef.current = serializeAiSectionsState(result.state);
|
|
20679
|
+
nodes.push({ key: AI_SECTIONS_KEY, text: aiSectionsRef.current });
|
|
20680
|
+
const reaped = new Set(result.reapedIds);
|
|
20681
|
+
const nextOrderJson = JSON.stringify(orderEntries.filter((entry) => !reaped.has(entry.instanceId)));
|
|
20682
|
+
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: nextOrderJson };
|
|
20683
|
+
setAiSectionOrder(nextOrderJson, window.location.pathname);
|
|
20684
|
+
nodes.push({ key: SECTION_ORDER_KEY, text: nextOrderJson });
|
|
20685
|
+
if (result.store) {
|
|
20686
|
+
stylesRef.current = JSON.stringify(result.store);
|
|
20687
|
+
nodes.push({ key: STYLE_STORE_KEY, text: stylesRef.current });
|
|
20688
|
+
}
|
|
20689
|
+
const nextContent = { ...editContentRef.current };
|
|
20690
|
+
for (const key of Object.keys(nextContent)) {
|
|
20691
|
+
if (key.startsWith(AI_SLOT_KEY_PREFIX) && result.slotPrefixes.some((prefix) => key.startsWith(prefix)) && nextContent[key] !== "") {
|
|
20692
|
+
nextContent[key] = "";
|
|
20693
|
+
nodes.push({ key, text: "" });
|
|
20694
|
+
}
|
|
20695
|
+
}
|
|
20696
|
+
editContentRef.current = nextContent;
|
|
20697
|
+
applyAiSectionsToDom(result.state);
|
|
20698
|
+
applyStylesToDom(parseStyleStore(stylesRef.current));
|
|
20699
|
+
return nodes;
|
|
20700
|
+
};
|
|
20072
20701
|
const handleHydrate = (e) => {
|
|
20073
20702
|
if (e.data?.type !== "ow:hydrate") return;
|
|
20074
20703
|
const content = e.data.content;
|
|
@@ -20087,9 +20716,11 @@ function OhhwellsBridge() {
|
|
|
20087
20716
|
}
|
|
20088
20717
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
20089
20718
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
20719
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
20090
20720
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
20091
20721
|
}
|
|
20092
20722
|
applyBrandChrome(content);
|
|
20723
|
+
initSectionInstancesFromContent(content, window.location.pathname);
|
|
20093
20724
|
let sectionsJson = null;
|
|
20094
20725
|
for (const [key, val] of Object.entries(content)) {
|
|
20095
20726
|
if (key === "__ohw_sections") {
|
|
@@ -20097,11 +20728,11 @@ function OhhwellsBridge() {
|
|
|
20097
20728
|
continue;
|
|
20098
20729
|
}
|
|
20099
20730
|
if (key === AI_SECTIONS_KEY) continue;
|
|
20731
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
20732
|
+
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
20100
20733
|
if (key === BRAND_KIT_KEY) continue;
|
|
20101
20734
|
if (key === STYLE_STORE_KEY) continue;
|
|
20102
20735
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
20103
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
20104
|
-
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
20105
20736
|
if (applyVideoSettingNode(key, val)) continue;
|
|
20106
20737
|
if (applyCarouselNode(key, val)) continue;
|
|
20107
20738
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -20115,6 +20746,8 @@ function OhhwellsBridge() {
|
|
|
20115
20746
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
20116
20747
|
} else if (el.dataset.ohwEditable === "link") {
|
|
20117
20748
|
applyLinkHref(el, val);
|
|
20749
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
20750
|
+
applyMapQuery(el, val);
|
|
20118
20751
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
20119
20752
|
applyIconMarkup(el, val);
|
|
20120
20753
|
} else if (isIconMarkupValue(val)) {
|
|
@@ -20131,12 +20764,16 @@ function OhhwellsBridge() {
|
|
|
20131
20764
|
sectionsLoadedRef.current = true;
|
|
20132
20765
|
pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
|
|
20133
20766
|
}
|
|
20134
|
-
initSectionInstancesFromContent(content, window.location.pathname);
|
|
20135
20767
|
editContentRef.current = { ...editContentRef.current, ...content };
|
|
20136
20768
|
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
20137
20769
|
reconcileFooterOrderFromContent(editContentRef.current);
|
|
20138
20770
|
syncNavigationDragCursorAttrs();
|
|
20139
20771
|
enforceLinkHrefs();
|
|
20772
|
+
const hydrateReapExclude = /* @__PURE__ */ new Set();
|
|
20773
|
+
const hydratePendingUndo = pendingDeleteUndoRef.current;
|
|
20774
|
+
if (hydratePendingUndo?.sectionInstanceId) hydrateReapExclude.add(hydratePendingUndo.sectionInstanceId);
|
|
20775
|
+
const reapNodes = reapCommittedAiSections(hydrateReapExclude);
|
|
20776
|
+
if (reapNodes.length > 0) postToParentRef.current({ type: "ow:change", nodes: reapNodes });
|
|
20140
20777
|
const hydratedHeight = document.body.scrollHeight;
|
|
20141
20778
|
if (hydratedHeight > 50) postToParentRef.current({ type: "ow:height", height: hydratedHeight });
|
|
20142
20779
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
@@ -20276,12 +20913,35 @@ function OhhwellsBridge() {
|
|
|
20276
20913
|
window.addEventListener("message", handleAiSetBrand);
|
|
20277
20914
|
const handleAiSetStyles = (e) => {
|
|
20278
20915
|
if (e.data?.type !== "ow:ai-set-styles") return;
|
|
20279
|
-
|
|
20916
|
+
let value = typeof e.data.value === "string" ? e.data.value : "";
|
|
20280
20917
|
const previous = stylesRef.current;
|
|
20918
|
+
let previousSections;
|
|
20919
|
+
const store = parseStyleStore(value);
|
|
20920
|
+
if (store) {
|
|
20921
|
+
const folded = foldAlignIntoTrees(parseAiSectionsState(aiSectionsRef.current), store);
|
|
20922
|
+
if (folded.changed) {
|
|
20923
|
+
const nextSections = serializeAiSectionsState(folded.state);
|
|
20924
|
+
if (nextSections !== aiSectionsRef.current) {
|
|
20925
|
+
previousSections = aiSectionsRef.current;
|
|
20926
|
+
aiSectionsRef.current = nextSections;
|
|
20927
|
+
applyAiSectionsToDom(folded.state);
|
|
20928
|
+
postToParentRef.current({
|
|
20929
|
+
type: "ow:change",
|
|
20930
|
+
nodes: [{ key: AI_SECTIONS_KEY, text: nextSections }]
|
|
20931
|
+
});
|
|
20932
|
+
}
|
|
20933
|
+
value = JSON.stringify(folded.store);
|
|
20934
|
+
}
|
|
20935
|
+
}
|
|
20281
20936
|
stylesRef.current = value;
|
|
20282
20937
|
applyStylesToDom(parseStyleStore(value));
|
|
20283
20938
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: STYLE_STORE_KEY, text: value }] });
|
|
20284
|
-
postToParentRef.current({
|
|
20939
|
+
postToParentRef.current({
|
|
20940
|
+
type: "ow:ai-styles-applied",
|
|
20941
|
+
previous,
|
|
20942
|
+
value,
|
|
20943
|
+
...previousSections !== void 0 ? { previousSections } : {}
|
|
20944
|
+
});
|
|
20285
20945
|
};
|
|
20286
20946
|
window.addEventListener("message", handleAiSetStyles);
|
|
20287
20947
|
const handleGetBrand = (e) => {
|
|
@@ -20298,8 +20958,11 @@ function OhhwellsBridge() {
|
|
|
20298
20958
|
if (!instanceId || !direction) return;
|
|
20299
20959
|
const entries = moveSectionInstance(instanceId, direction, window.location.pathname);
|
|
20300
20960
|
if (!entries) return;
|
|
20301
|
-
const orderJson = JSON.stringify(
|
|
20961
|
+
const orderJson = JSON.stringify(
|
|
20962
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
20963
|
+
);
|
|
20302
20964
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
20965
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
20303
20966
|
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20304
20967
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
20305
20968
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20318,8 +20981,11 @@ function OhhwellsBridge() {
|
|
|
20318
20981
|
const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname);
|
|
20319
20982
|
const entries = deleteSectionInstance(instanceId, window.location.pathname, currentEntries);
|
|
20320
20983
|
if (!entries) return;
|
|
20321
|
-
const orderJson = JSON.stringify(
|
|
20984
|
+
const orderJson = JSON.stringify(
|
|
20985
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
20986
|
+
);
|
|
20322
20987
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
20988
|
+
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20323
20989
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
20324
20990
|
aiSectionApiRef.current?.clear();
|
|
20325
20991
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20328,6 +20994,7 @@ function OhhwellsBridge() {
|
|
|
20328
20994
|
const actionId = newInstanceId();
|
|
20329
20995
|
pendingDeleteUndoRef.current = {
|
|
20330
20996
|
actionId,
|
|
20997
|
+
sectionInstanceId: instanceId,
|
|
20331
20998
|
restore: () => {
|
|
20332
20999
|
const restoredEntries = getPageSectionOrderEntries(
|
|
20333
21000
|
editContentRef.current[SECTION_ORDER_KEY],
|
|
@@ -20335,8 +21002,11 @@ function OhhwellsBridge() {
|
|
|
20335
21002
|
);
|
|
20336
21003
|
const restored = restoreSectionInstance(instanceId, window.location.pathname, restoredEntries);
|
|
20337
21004
|
if (!restored) return;
|
|
20338
|
-
const restoredJson = JSON.stringify(
|
|
21005
|
+
const restoredJson = JSON.stringify(
|
|
21006
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, restored)
|
|
21007
|
+
);
|
|
20339
21008
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: restoredJson };
|
|
21009
|
+
setAiSectionOrder(restoredJson, window.location.pathname);
|
|
20340
21010
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: restoredJson }] });
|
|
20341
21011
|
window.dispatchEvent(new Event("resize"));
|
|
20342
21012
|
const restoreHeight = document.body.scrollHeight;
|
|
@@ -20353,6 +21023,37 @@ function OhhwellsBridge() {
|
|
|
20353
21023
|
});
|
|
20354
21024
|
};
|
|
20355
21025
|
window.addEventListener("message", handleDeleteSection);
|
|
21026
|
+
const handleDuplicateSection = (e) => {
|
|
21027
|
+
if (e.data?.type !== "ow:duplicate-section") return;
|
|
21028
|
+
const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
|
|
21029
|
+
if (!instanceId) return;
|
|
21030
|
+
const newId = newInstanceId();
|
|
21031
|
+
const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname);
|
|
21032
|
+
const result = duplicateSectionInstance(instanceId, newId, window.location.pathname, currentEntries);
|
|
21033
|
+
if (!result) return;
|
|
21034
|
+
const { entries, keyRekeys } = result;
|
|
21035
|
+
const orderJson = JSON.stringify(
|
|
21036
|
+
mergePageSectionOrder(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname, entries)
|
|
21037
|
+
);
|
|
21038
|
+
const nodes = [{ key: SECTION_ORDER_KEY, text: orderJson }];
|
|
21039
|
+
for (const { from, to } of keyRekeys) {
|
|
21040
|
+
const inherited = editContentRef.current[from];
|
|
21041
|
+
if (inherited !== void 0) nodes.push({ key: to, text: inherited });
|
|
21042
|
+
}
|
|
21043
|
+
editContentRef.current = {
|
|
21044
|
+
...editContentRef.current,
|
|
21045
|
+
...Object.fromEntries(nodes.map(({ key, text }) => [key, text]))
|
|
21046
|
+
};
|
|
21047
|
+
applyPersistedOrder(getPageSectionOrderEntries(orderJson, window.location.pathname));
|
|
21048
|
+
setAiSectionOrder(orderJson, window.location.pathname);
|
|
21049
|
+
postToParentRef.current({ type: "ow:change", nodes });
|
|
21050
|
+
window.dispatchEvent(new Event("resize"));
|
|
21051
|
+
const duplicateHeight = document.body.scrollHeight;
|
|
21052
|
+
if (duplicateHeight > 50) postToParentRef.current({ type: "ow:height", height: duplicateHeight });
|
|
21053
|
+
const clone = document.querySelector(`[data-ohw-instance="${CSS.escape(newId)}"]`);
|
|
21054
|
+
if (clone) aiSectionApiRef.current?.selectFromElement(clone);
|
|
21055
|
+
};
|
|
21056
|
+
window.addEventListener("message", handleDuplicateSection);
|
|
20356
21057
|
const handleDeactivate = (e) => {
|
|
20357
21058
|
if (e.data?.type !== "ow:deactivate") return;
|
|
20358
21059
|
if (document.documentElement.hasAttribute("data-ohw-panel-dragging")) return;
|
|
@@ -20362,6 +21063,12 @@ function OhhwellsBridge() {
|
|
|
20362
21063
|
closeLinkPopoverRef.current();
|
|
20363
21064
|
return;
|
|
20364
21065
|
}
|
|
21066
|
+
if (floatingPanelOpenRef.current) {
|
|
21067
|
+
setFloatingPanelRef.current(null);
|
|
21068
|
+
deselectRef.current();
|
|
21069
|
+
deactivateRef.current();
|
|
21070
|
+
return;
|
|
21071
|
+
}
|
|
20365
21072
|
deselectRef.current();
|
|
20366
21073
|
deactivateRef.current();
|
|
20367
21074
|
clearMediaSelectionRef.current();
|
|
@@ -20607,6 +21314,10 @@ function OhhwellsBridge() {
|
|
|
20607
21314
|
};
|
|
20608
21315
|
const handleSave = (e) => {
|
|
20609
21316
|
if (e.data?.type !== "ow:save") return;
|
|
21317
|
+
const pendingUndo = pendingDeleteUndoRef.current;
|
|
21318
|
+
const reapExclude = /* @__PURE__ */ new Set();
|
|
21319
|
+
if (pendingUndo?.sectionInstanceId) reapExclude.add(pendingUndo.sectionInstanceId);
|
|
21320
|
+
const reapNodes = reapCommittedAiSections(reapExclude);
|
|
20610
21321
|
const nodes = collectEditableNodes(editContentRef.current);
|
|
20611
21322
|
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
20612
21323
|
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
@@ -20626,6 +21337,11 @@ function OhhwellsBridge() {
|
|
|
20626
21337
|
const text = specs.length ? JSON.stringify(specs) : editContentRef.current[fieldsKey(formKey)];
|
|
20627
21338
|
if (text) nodes.push({ key: fieldsKey(formKey), type: "text", text });
|
|
20628
21339
|
});
|
|
21340
|
+
for (const reapNode of reapNodes) {
|
|
21341
|
+
if (reapNode.key.startsWith(AI_SLOT_KEY_PREFIX) && !nodes.some((n) => n.key === reapNode.key)) {
|
|
21342
|
+
nodes.push({ key: reapNode.key, type: "text", text: reapNode.text });
|
|
21343
|
+
}
|
|
21344
|
+
}
|
|
20629
21345
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
20630
21346
|
};
|
|
20631
21347
|
const handleInsertSection = (e) => {
|
|
@@ -20636,8 +21352,12 @@ function OhhwellsBridge() {
|
|
|
20636
21352
|
if (inserted) {
|
|
20637
21353
|
const tracker = getSectionsTracker();
|
|
20638
21354
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
|
|
20639
|
-
const
|
|
20640
|
-
|
|
21355
|
+
const reportHeight = () => {
|
|
21356
|
+
const h = document.body.scrollHeight;
|
|
21357
|
+
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
21358
|
+
};
|
|
21359
|
+
reportHeight();
|
|
21360
|
+
setTimeout(reportHeight, 500);
|
|
20641
21361
|
}
|
|
20642
21362
|
};
|
|
20643
21363
|
const handleSwitchSchedule = (e) => {
|
|
@@ -21039,11 +21759,12 @@ function OhhwellsBridge() {
|
|
|
21039
21759
|
window.removeEventListener("message", handleMoveSection);
|
|
21040
21760
|
window.removeEventListener("message", handlePanelDragging);
|
|
21041
21761
|
window.removeEventListener("message", handleDeleteSection);
|
|
21762
|
+
window.removeEventListener("message", handleDuplicateSection);
|
|
21042
21763
|
window.removeEventListener("message", handleDeactivate);
|
|
21043
|
-
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
21044
21764
|
window.removeEventListener("message", handleToastAction);
|
|
21045
21765
|
window.removeEventListener("message", handleFormCount);
|
|
21046
21766
|
window.removeEventListener("message", handleUiEscape);
|
|
21767
|
+
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
21047
21768
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
21048
21769
|
autoSaveTimers.current.clear();
|
|
21049
21770
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
@@ -21246,7 +21967,7 @@ function OhhwellsBridge() {
|
|
|
21246
21967
|
postToParent2({
|
|
21247
21968
|
type: "ow:ready",
|
|
21248
21969
|
version: "1",
|
|
21249
|
-
bridgeVersion: "0.1.
|
|
21970
|
+
bridgeVersion: "0.1.88",
|
|
21250
21971
|
path: pathname,
|
|
21251
21972
|
nodes: collectEditableNodes(editContentRef.current),
|
|
21252
21973
|
sections
|
|
@@ -22165,6 +22886,59 @@ function OhhwellsBridge() {
|
|
|
22165
22886
|
) : null
|
|
22166
22887
|
] });
|
|
22167
22888
|
}
|
|
22889
|
+
|
|
22890
|
+
// src/ui/EmptySection.tsx
|
|
22891
|
+
var import_link = __toESM(require("next/link"), 1);
|
|
22892
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
22893
|
+
function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
|
|
22894
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
22895
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
22896
|
+
"p",
|
|
22897
|
+
{
|
|
22898
|
+
style: {
|
|
22899
|
+
fontFamily: "var(--brand-font-body)",
|
|
22900
|
+
fontSize: "0.75rem",
|
|
22901
|
+
fontWeight: 500,
|
|
22902
|
+
letterSpacing: "0.15em",
|
|
22903
|
+
textTransform: "uppercase",
|
|
22904
|
+
color: "var(--brand-accent)",
|
|
22905
|
+
marginBottom: "1.5rem"
|
|
22906
|
+
},
|
|
22907
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_link.default, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
|
|
22908
|
+
}
|
|
22909
|
+
),
|
|
22910
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
22911
|
+
"h1",
|
|
22912
|
+
{
|
|
22913
|
+
style: {
|
|
22914
|
+
fontFamily: "var(--brand-font-heading)",
|
|
22915
|
+
fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
|
|
22916
|
+
lineHeight: 1.1,
|
|
22917
|
+
letterSpacing: "-0.025em",
|
|
22918
|
+
color: "var(--brand-text)",
|
|
22919
|
+
marginBottom: "1rem"
|
|
22920
|
+
},
|
|
22921
|
+
...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
|
|
22922
|
+
children: title
|
|
22923
|
+
}
|
|
22924
|
+
),
|
|
22925
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
22926
|
+
"p",
|
|
22927
|
+
{
|
|
22928
|
+
style: {
|
|
22929
|
+
fontFamily: "var(--brand-font-body)",
|
|
22930
|
+
fontSize: "1rem",
|
|
22931
|
+
lineHeight: 1.7,
|
|
22932
|
+
fontWeight: 300,
|
|
22933
|
+
color: "var(--brand-text-muted)",
|
|
22934
|
+
maxWidth: "340px"
|
|
22935
|
+
},
|
|
22936
|
+
...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
|
|
22937
|
+
children: "This page doesn't have any content yet."
|
|
22938
|
+
}
|
|
22939
|
+
)
|
|
22940
|
+
] });
|
|
22941
|
+
}
|
|
22168
22942
|
// Annotate the CommonJS export names for ESM import in node:
|
|
22169
22943
|
0 && (module.exports = {
|
|
22170
22944
|
AI_DEFAULT_BRAND,
|
|
@@ -22182,6 +22956,7 @@ function OhhwellsBridge() {
|
|
|
22182
22956
|
DropdownMenuItem,
|
|
22183
22957
|
DropdownMenuSeparator,
|
|
22184
22958
|
DropdownMenuTrigger,
|
|
22959
|
+
EmptySection,
|
|
22185
22960
|
ItemActionToolbar,
|
|
22186
22961
|
ItemInteractionLayer,
|
|
22187
22962
|
LinkEditorPanel,
|