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