@ohhwells/bridge 0.1.85 → 0.1.86-next.255
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 +1057 -341
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +1056 -341
- package/dist/index.js.map +1 -1
- package/dist/pages.cjs +141 -0
- package/dist/pages.cjs.map +1 -0
- package/dist/pages.d.cts +45 -0
- package/dist/pages.d.ts +45 -0
- package/dist/pages.js +107 -0
- package/dist/pages.js.map +1 -0
- package/dist/styles.css +55 -0
- package/package.json +8 -3
package/dist/index.js
CHANGED
|
@@ -69,6 +69,10 @@ function isRenderableTree(value) {
|
|
|
69
69
|
|
|
70
70
|
// src/lib/ai-sections-store.ts
|
|
71
71
|
var AI_SECTIONS_KEY = "__ohw_ai_sections";
|
|
72
|
+
var AI_SLOT_KEY_PREFIX = "ai.";
|
|
73
|
+
function aiSlotKeyPrefixFor(sectionId) {
|
|
74
|
+
return `${AI_SLOT_KEY_PREFIX}${sectionId}.`;
|
|
75
|
+
}
|
|
72
76
|
var EMPTY_AI_SECTIONS = { v: 1, sections: [] };
|
|
73
77
|
function parseAiSectionsState(raw) {
|
|
74
78
|
if (!raw) return EMPTY_AI_SECTIONS;
|
|
@@ -112,6 +116,63 @@ function applyTreeToState(state, payload) {
|
|
|
112
116
|
const others = state.sections.filter((existing) => existing.id !== entry.id);
|
|
113
117
|
return { ...state, v: 1, sections: [...others, entry] };
|
|
114
118
|
}
|
|
119
|
+
function foldAlignIntoTrees(state, store) {
|
|
120
|
+
const byId = new Map(state.sections.map((entry) => [entry.id, entry]));
|
|
121
|
+
const nextTrees = /* @__PURE__ */ new Map();
|
|
122
|
+
const treeFor = (id) => {
|
|
123
|
+
const cloned = nextTrees.get(id);
|
|
124
|
+
if (cloned) return cloned;
|
|
125
|
+
const entry = byId.get(id);
|
|
126
|
+
if (!entry) return void 0;
|
|
127
|
+
const fresh = {
|
|
128
|
+
...entry.tree,
|
|
129
|
+
rows: entry.tree.rows.map((row) => ({ ...row, blocks: row.blocks.map((block) => ({ ...block })) }))
|
|
130
|
+
};
|
|
131
|
+
nextTrees.set(id, fresh);
|
|
132
|
+
return fresh;
|
|
133
|
+
};
|
|
134
|
+
const nodes = {};
|
|
135
|
+
for (const [key, override] of Object.entries(store.nodes)) {
|
|
136
|
+
const match = override.align !== void 0 && key.startsWith(AI_SLOT_KEY_PREFIX) ? key.match(/^ai\.(.+?)\.r(\d+)\.b(\d+)(?:\.|$)/) : null;
|
|
137
|
+
const tree = match ? treeFor(match[1]) : void 0;
|
|
138
|
+
const block = match && tree ? tree.rows[Number(match[2])]?.blocks[Number(match[3])] : void 0;
|
|
139
|
+
if (!block) {
|
|
140
|
+
nodes[key] = override;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
block.align = override.align;
|
|
144
|
+
const rest = { ...override };
|
|
145
|
+
delete rest.align;
|
|
146
|
+
if (Object.keys(rest).length > 0) nodes[key] = rest;
|
|
147
|
+
}
|
|
148
|
+
const sections = {};
|
|
149
|
+
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
150
|
+
const tree = override.align !== void 0 ? treeFor(sectionId) : void 0;
|
|
151
|
+
if (!tree) {
|
|
152
|
+
sections[sectionId] = override;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
for (const row of tree.rows) {
|
|
156
|
+
for (const block of row.blocks) block.align = override.align;
|
|
157
|
+
}
|
|
158
|
+
const rest = { ...override };
|
|
159
|
+
delete rest.align;
|
|
160
|
+
if (Object.keys(rest).length > 0) sections[sectionId] = rest;
|
|
161
|
+
}
|
|
162
|
+
if (nextTrees.size === 0) return { state, store, changed: false };
|
|
163
|
+
return {
|
|
164
|
+
state: {
|
|
165
|
+
...state,
|
|
166
|
+
v: 1,
|
|
167
|
+
sections: state.sections.map((entry) => {
|
|
168
|
+
const tree = nextTrees.get(entry.id);
|
|
169
|
+
return tree ? { ...entry, tree } : entry;
|
|
170
|
+
})
|
|
171
|
+
},
|
|
172
|
+
store: { v: 1, sections, nodes },
|
|
173
|
+
changed: true
|
|
174
|
+
};
|
|
175
|
+
}
|
|
115
176
|
function removeFromState(state, id) {
|
|
116
177
|
return { ...state, v: 1, sections: state.sections.filter((entry) => entry.id !== id) };
|
|
117
178
|
}
|
|
@@ -123,6 +184,33 @@ function deleteSectionFromState(state, sectionId) {
|
|
|
123
184
|
if (removed.includes(sectionId)) return state;
|
|
124
185
|
return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
|
|
125
186
|
}
|
|
187
|
+
function reapRemovedAiSections(state, store, removedIds, excludeIds = /* @__PURE__ */ new Set()) {
|
|
188
|
+
const generated = new Set(state.sections.map((entry) => entry.id));
|
|
189
|
+
const reapedIds = [...new Set(removedIds)].filter((id) => generated.has(id) && !excludeIds.has(id));
|
|
190
|
+
if (reapedIds.length === 0) {
|
|
191
|
+
return { state, store, reapedIds: [], slotPrefixes: [], changed: false };
|
|
192
|
+
}
|
|
193
|
+
const reaped = new Set(reapedIds);
|
|
194
|
+
const slotPrefixes = reapedIds.map(aiSlotKeyPrefixFor);
|
|
195
|
+
const nextState = {
|
|
196
|
+
...state,
|
|
197
|
+
v: 1,
|
|
198
|
+
sections: state.sections.filter((entry) => !reaped.has(entry.id))
|
|
199
|
+
};
|
|
200
|
+
let nextStore = store;
|
|
201
|
+
if (store) {
|
|
202
|
+
const sections = {};
|
|
203
|
+
for (const [key, override] of Object.entries(store.sections)) {
|
|
204
|
+
if (!reaped.has(key)) sections[key] = override;
|
|
205
|
+
}
|
|
206
|
+
const nodes = {};
|
|
207
|
+
for (const [key, override] of Object.entries(store.nodes)) {
|
|
208
|
+
if (!slotPrefixes.some((prefix) => key.startsWith(prefix))) nodes[key] = override;
|
|
209
|
+
}
|
|
210
|
+
nextStore = { v: 1, sections, nodes };
|
|
211
|
+
}
|
|
212
|
+
return { state: nextState, store: nextStore, reapedIds, slotPrefixes, changed: true };
|
|
213
|
+
}
|
|
126
214
|
|
|
127
215
|
// src/lib/brand-chrome.ts
|
|
128
216
|
var BRAND_NAME_KEY = "__ohw_brand_name";
|
|
@@ -330,6 +418,12 @@ function styleSheetCss() {
|
|
|
330
418
|
`[data-ohw-style-spacing="${spacing}"] { padding-top: ${px}px !important; padding-bottom: ${px}px !important; }`
|
|
331
419
|
);
|
|
332
420
|
}
|
|
421
|
+
rules.push(
|
|
422
|
+
`[data-ohw-style-corners="sharp"] :is(.card, [data-ohw-card]) { border-radius: 0 !important; }`
|
|
423
|
+
);
|
|
424
|
+
for (const align of ["left", "center", "right"]) {
|
|
425
|
+
rules.push(`[data-ohw-style-align="${align}"] { text-align: ${align} !important; }`);
|
|
426
|
+
}
|
|
333
427
|
return rules.join("\n");
|
|
334
428
|
}
|
|
335
429
|
var STYLE_FONT_LINK_ID = "ohw-style-fonts";
|
|
@@ -356,10 +450,25 @@ var SECTION_ATTRS = {
|
|
|
356
450
|
textDistribution: "data-ohw-style-distribution",
|
|
357
451
|
headlineScale: "data-ohw-style-headline",
|
|
358
452
|
imageAspect: "data-ohw-style-aspect",
|
|
359
|
-
spacing: "data-ohw-style-spacing"
|
|
453
|
+
spacing: "data-ohw-style-spacing",
|
|
454
|
+
cornerStyle: "data-ohw-style-corners",
|
|
455
|
+
align: "data-ohw-style-align"
|
|
360
456
|
};
|
|
361
457
|
var NODE_WROTE_ATTR = "data-ohw-style-node";
|
|
362
|
-
var NODE_PROPS = [
|
|
458
|
+
var NODE_PROPS = [
|
|
459
|
+
"color",
|
|
460
|
+
"font-family",
|
|
461
|
+
"font-size",
|
|
462
|
+
"background",
|
|
463
|
+
"text-align",
|
|
464
|
+
"justify-content",
|
|
465
|
+
"align-items"
|
|
466
|
+
];
|
|
467
|
+
var ALIGN_JUSTIFY = {
|
|
468
|
+
left: "flex-start",
|
|
469
|
+
center: "center",
|
|
470
|
+
right: "flex-end"
|
|
471
|
+
};
|
|
363
472
|
function saveInline(el, prop) {
|
|
364
473
|
const attr = `data-ohw-style-prev-${prop}`;
|
|
365
474
|
if (el.hasAttribute(attr)) return;
|
|
@@ -403,6 +512,10 @@ function clearNodeProps(root) {
|
|
|
403
512
|
function buttonSurfaceOf(el) {
|
|
404
513
|
return el.closest("a, button") ?? el;
|
|
405
514
|
}
|
|
515
|
+
function alignSubjectOf(el) {
|
|
516
|
+
const button = el.closest('[data-ohw-role="button"]');
|
|
517
|
+
return button?.parentElement ?? el;
|
|
518
|
+
}
|
|
406
519
|
function applyStylesToDom(store) {
|
|
407
520
|
ensureStyleSheet();
|
|
408
521
|
clearSectionAttrs(document);
|
|
@@ -448,6 +561,18 @@ function applyStylesToDom(store) {
|
|
|
448
561
|
el.style.setProperty("font-size", `${override.fontSize}px`, "important");
|
|
449
562
|
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
450
563
|
}
|
|
564
|
+
if (override.align !== void 0) {
|
|
565
|
+
const subject = alignSubjectOf(el);
|
|
566
|
+
saveInline(subject, "text-align");
|
|
567
|
+
saveInline(subject, "justify-content");
|
|
568
|
+
subject.style.setProperty("text-align", override.align, "important");
|
|
569
|
+
subject.style.setProperty(
|
|
570
|
+
"justify-content",
|
|
571
|
+
ALIGN_JUSTIFY[override.align] ?? "flex-start",
|
|
572
|
+
"important"
|
|
573
|
+
);
|
|
574
|
+
subject.setAttribute(NODE_WROTE_ATTR, "");
|
|
575
|
+
}
|
|
451
576
|
if (override.buttonBackground !== void 0 || override.buttonText !== void 0) {
|
|
452
577
|
const surface = buttonSurfaceOf(el);
|
|
453
578
|
if (override.buttonBackground !== void 0) {
|
|
@@ -468,9 +593,494 @@ function applyStylesToDom(store) {
|
|
|
468
593
|
import { flushSync } from "react-dom";
|
|
469
594
|
import { createRoot } from "react-dom/client";
|
|
470
595
|
|
|
596
|
+
// src/lib/sections.ts
|
|
597
|
+
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
598
|
+
function isChromeSection(el) {
|
|
599
|
+
return el.matches("header, nav, footer, aside");
|
|
600
|
+
}
|
|
601
|
+
function titleCaseSectionId(id) {
|
|
602
|
+
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
603
|
+
}
|
|
604
|
+
function parseSectionsFromRoot(root) {
|
|
605
|
+
const seen = /* @__PURE__ */ new Set();
|
|
606
|
+
const sections = [];
|
|
607
|
+
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
608
|
+
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
609
|
+
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
610
|
+
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
611
|
+
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
612
|
+
continue;
|
|
613
|
+
seen.add(id);
|
|
614
|
+
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
615
|
+
sections.push({ id, label });
|
|
616
|
+
}
|
|
617
|
+
return sections;
|
|
618
|
+
}
|
|
619
|
+
function collectSectionsFromDom() {
|
|
620
|
+
if (typeof document === "undefined") return [];
|
|
621
|
+
return parseSectionsFromRoot(document);
|
|
622
|
+
}
|
|
623
|
+
function parseSectionsFromHtml(html) {
|
|
624
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
625
|
+
return parseSectionsFromRoot(doc);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// src/lib/section-instances.ts
|
|
629
|
+
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
630
|
+
var REMOVED_ATTR = "data-ohw-section-removed";
|
|
631
|
+
function isRemovedSection(el) {
|
|
632
|
+
return el.hasAttribute(REMOVED_ATTR);
|
|
633
|
+
}
|
|
634
|
+
function topLevelSections() {
|
|
635
|
+
return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
636
|
+
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el) && !isRemovedSection(el)
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
function instanceIdOf(el) {
|
|
640
|
+
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
641
|
+
}
|
|
642
|
+
function findByInstanceId(instanceId) {
|
|
643
|
+
const escapedId = CSS.escape(instanceId);
|
|
644
|
+
return document.querySelector(`[data-ohw-instance="${escapedId}"]`) ?? document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
645
|
+
}
|
|
646
|
+
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
647
|
+
const sections = topLevelSections();
|
|
648
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
649
|
+
if (index === -1) return null;
|
|
650
|
+
const dragged = sections[index];
|
|
651
|
+
const others = sections.filter((_, i) => i !== index);
|
|
652
|
+
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
653
|
+
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
654
|
+
return reordered.map((el, order) => ({
|
|
655
|
+
instanceId: instanceIdOf(el),
|
|
656
|
+
type: el.getAttribute("data-ohw-section") ?? "",
|
|
657
|
+
order,
|
|
658
|
+
pagePath: currentPath
|
|
659
|
+
}));
|
|
660
|
+
}
|
|
661
|
+
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
662
|
+
const sections = topLevelSections();
|
|
663
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
664
|
+
if (index === -1) return null;
|
|
665
|
+
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
666
|
+
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
667
|
+
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
668
|
+
if (!entries) return null;
|
|
669
|
+
applyPersistedOrder(entries);
|
|
670
|
+
return entries;
|
|
671
|
+
}
|
|
672
|
+
function syncRemovedFlags(entries) {
|
|
673
|
+
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
674
|
+
document.querySelectorAll(`[${REMOVED_ATTR}]`).forEach((el) => {
|
|
675
|
+
if (!removedIds.has(instanceIdOf(el))) {
|
|
676
|
+
el.style.removeProperty("display");
|
|
677
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
678
|
+
}
|
|
679
|
+
});
|
|
680
|
+
for (const id of removedIds) {
|
|
681
|
+
const el = findByInstanceId(id);
|
|
682
|
+
if (el) {
|
|
683
|
+
el.style.display = "none";
|
|
684
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
function applyPersistedOrder(entries) {
|
|
689
|
+
syncRemovedFlags(entries);
|
|
690
|
+
if (entries.length === 0) return;
|
|
691
|
+
const sections = topLevelSections();
|
|
692
|
+
if (sections.length === 0) return;
|
|
693
|
+
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
694
|
+
const ordered = [...sections].sort((a, b) => {
|
|
695
|
+
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
696
|
+
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
697
|
+
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
698
|
+
if (aOrder === void 0) return 1;
|
|
699
|
+
if (bOrder === void 0) return -1;
|
|
700
|
+
return aOrder - bOrder;
|
|
701
|
+
});
|
|
702
|
+
let prev = null;
|
|
703
|
+
for (const el of ordered) {
|
|
704
|
+
if (prev) prev.after(el);
|
|
705
|
+
prev = el;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
709
|
+
if (!findByInstanceId(instanceId)) return null;
|
|
710
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
711
|
+
const allSections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
712
|
+
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
|
|
713
|
+
);
|
|
714
|
+
allSections.forEach((el, order) => {
|
|
715
|
+
const id = instanceIdOf(el);
|
|
716
|
+
if (!byId.has(id)) {
|
|
717
|
+
byId.set(id, { instanceId: id, type: el.getAttribute("data-ohw-section") ?? "", order, pagePath: currentPath });
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
const target = byId.get(instanceId);
|
|
721
|
+
if (!target) return null;
|
|
722
|
+
byId.set(instanceId, { ...target, removed });
|
|
723
|
+
const entries = Array.from(byId.values());
|
|
724
|
+
applyPersistedOrder(entries);
|
|
725
|
+
return entries;
|
|
726
|
+
}
|
|
727
|
+
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
728
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
729
|
+
}
|
|
730
|
+
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
731
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
732
|
+
}
|
|
733
|
+
function duplicateSectionInstance(instanceId, newId, currentPath, existingEntries) {
|
|
734
|
+
const original = findByInstanceId(instanceId);
|
|
735
|
+
if (!original) return null;
|
|
736
|
+
const clone = original.cloneNode(true);
|
|
737
|
+
clone.setAttribute("data-ohw-instance", newId);
|
|
738
|
+
const keyRekeys = rekeySectionSubtree(clone, newId);
|
|
739
|
+
original.insertAdjacentElement("afterend", clone);
|
|
740
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
741
|
+
const entries = topLevelSections().map((el, order) => {
|
|
742
|
+
const id = instanceIdOf(el);
|
|
743
|
+
return {
|
|
744
|
+
instanceId: id,
|
|
745
|
+
type: el.getAttribute("data-ohw-section") ?? "",
|
|
746
|
+
order,
|
|
747
|
+
pagePath: currentPath,
|
|
748
|
+
...byId.get(id)?.removed ? { removed: true } : {}
|
|
749
|
+
};
|
|
750
|
+
});
|
|
751
|
+
applyPersistedOrder(entries);
|
|
752
|
+
return { entries, keyRekeys };
|
|
753
|
+
}
|
|
754
|
+
function newInstanceId() {
|
|
755
|
+
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
756
|
+
}
|
|
757
|
+
function getPageSectionOrderEntries(raw, currentPath) {
|
|
758
|
+
if (!raw) return [];
|
|
759
|
+
try {
|
|
760
|
+
const entries = JSON.parse(raw);
|
|
761
|
+
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
762
|
+
} catch {
|
|
763
|
+
return [];
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
function rekeySectionSubtree(root, instanceId) {
|
|
767
|
+
const suffix = `::${instanceId}`;
|
|
768
|
+
const pairs = [];
|
|
769
|
+
const rekey = (el, attr) => {
|
|
770
|
+
const current = el.getAttribute(attr);
|
|
771
|
+
if (!current) return;
|
|
772
|
+
const base = current.includes("::") ? current.slice(0, current.indexOf("::")) : current;
|
|
773
|
+
const next = `${base}${suffix}`;
|
|
774
|
+
el.setAttribute(attr, next);
|
|
775
|
+
pairs.push({ from: current, to: next });
|
|
776
|
+
};
|
|
777
|
+
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
778
|
+
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
779
|
+
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
780
|
+
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
781
|
+
return pairs;
|
|
782
|
+
}
|
|
783
|
+
function initSectionInstancesFromContent(content, currentPath) {
|
|
784
|
+
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
785
|
+
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
786
|
+
});
|
|
787
|
+
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
788
|
+
for (const entry of entries) {
|
|
789
|
+
if (entry.instanceId === entry.type) continue;
|
|
790
|
+
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
791
|
+
const original = document.querySelector(
|
|
792
|
+
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
793
|
+
);
|
|
794
|
+
if (!original) continue;
|
|
795
|
+
const clone = original.cloneNode(true);
|
|
796
|
+
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
797
|
+
rekeySectionSubtree(clone, entry.instanceId);
|
|
798
|
+
original.insertAdjacentElement("afterend", clone);
|
|
799
|
+
}
|
|
800
|
+
applyPersistedOrder(entries);
|
|
801
|
+
}
|
|
802
|
+
|
|
471
803
|
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
472
804
|
import React from "react";
|
|
473
805
|
import { ArrowLeft, ArrowRight, ChevronDown, icons as lucideIcons } from "lucide-react";
|
|
806
|
+
|
|
807
|
+
// src/lib/placeholder-imagery.ts
|
|
808
|
+
var U = (id) => `https://images.unsplash.com/photo-${id}?auto=format&fit=crop&w=1600&q=80`;
|
|
809
|
+
var GENERIC = [
|
|
810
|
+
U("1441986300917-64674bd600d8"),
|
|
811
|
+
U("1486406146926-c627a92ad1ab"),
|
|
812
|
+
U("1497032628192-86f99bcd76bc"),
|
|
813
|
+
U("1521737604893-d14cc237f11d"),
|
|
814
|
+
U("1522071820081-009f0129c71c"),
|
|
815
|
+
U("1519389950473-47ba0277781c"),
|
|
816
|
+
U("1460925895917-afdab827c52f"),
|
|
817
|
+
U("1504384308090-c894fdcc538d")
|
|
818
|
+
];
|
|
819
|
+
var PEOPLE = [
|
|
820
|
+
U("1500648767791-00dcc994a43e"),
|
|
821
|
+
U("1494790108377-be9c29b29330"),
|
|
822
|
+
U("1507003211169-0a1dd7228f2d"),
|
|
823
|
+
U("1438761681033-6461ffad8d80"),
|
|
824
|
+
U("1544005313-94ddf0286df2"),
|
|
825
|
+
U("1472099645785-5658abf4ff4e"),
|
|
826
|
+
U("1519085360753-af0119f7cbe7"),
|
|
827
|
+
U("1534528741775-53994a69daeb")
|
|
828
|
+
];
|
|
829
|
+
var THEMED = [
|
|
830
|
+
{
|
|
831
|
+
keywords: ["portrait", "headshot", "person", "people", "team", "staff", "avatar", "founder", "face"],
|
|
832
|
+
pool: PEOPLE
|
|
833
|
+
},
|
|
834
|
+
{
|
|
835
|
+
keywords: ["pet", "dog", "cat", "puppy", "kitten", "vet", "animal"],
|
|
836
|
+
pool: [
|
|
837
|
+
U("1548199973-03cce0bbc87b"),
|
|
838
|
+
U("1450778869180-41d0601e046e"),
|
|
839
|
+
U("1583511655857-d19b40a7a54e"),
|
|
840
|
+
U("1587300003388-59208cc962cb"),
|
|
841
|
+
U("1517849845537-4d257902454a"),
|
|
842
|
+
U("1601758228041-f3b2795255f1")
|
|
843
|
+
]
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
keywords: [
|
|
847
|
+
"baker",
|
|
848
|
+
"bakery",
|
|
849
|
+
"cafe",
|
|
850
|
+
"coffee",
|
|
851
|
+
"latte",
|
|
852
|
+
"restaurant",
|
|
853
|
+
"pastr",
|
|
854
|
+
"bread",
|
|
855
|
+
"cake",
|
|
856
|
+
"cater",
|
|
857
|
+
"chef",
|
|
858
|
+
"kitchen",
|
|
859
|
+
"food",
|
|
860
|
+
"pizza",
|
|
861
|
+
"dessert",
|
|
862
|
+
"brunch",
|
|
863
|
+
"bistro",
|
|
864
|
+
"deli",
|
|
865
|
+
"dish",
|
|
866
|
+
"menu"
|
|
867
|
+
],
|
|
868
|
+
pool: [
|
|
869
|
+
U("1509440159596-0249088772ff"),
|
|
870
|
+
U("1555507036-ab1f4038808a"),
|
|
871
|
+
U("1517433670267-08bbd4be890f"),
|
|
872
|
+
U("1486427944299-d1955d23e34d"),
|
|
873
|
+
U("1504754524776-8f4f37790ca0"),
|
|
874
|
+
U("1495474472287-4d71bcdd2085"),
|
|
875
|
+
U("1521017432531-fbd92d768814"),
|
|
876
|
+
U("1556909114-f6e7ad7d3136")
|
|
877
|
+
]
|
|
878
|
+
},
|
|
879
|
+
{
|
|
880
|
+
keywords: [
|
|
881
|
+
"shop",
|
|
882
|
+
"store",
|
|
883
|
+
"boutique",
|
|
884
|
+
"retail",
|
|
885
|
+
"clothing",
|
|
886
|
+
"fashion",
|
|
887
|
+
"jewel",
|
|
888
|
+
"gift",
|
|
889
|
+
"florist",
|
|
890
|
+
"market",
|
|
891
|
+
"grocer",
|
|
892
|
+
"product",
|
|
893
|
+
"storefront"
|
|
894
|
+
],
|
|
895
|
+
pool: [
|
|
896
|
+
U("1441984904996-e0b6ba687e04"),
|
|
897
|
+
U("1472851294608-062f824d29cc"),
|
|
898
|
+
U("1523381210434-271e8be1f52b"),
|
|
899
|
+
U("1534452203293-494d7ddbf7e0"),
|
|
900
|
+
U("1445205170230-053b83016050"),
|
|
901
|
+
U("1560243563-062bfc001d68")
|
|
902
|
+
]
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
keywords: [
|
|
906
|
+
"yoga",
|
|
907
|
+
"pilates",
|
|
908
|
+
"fitness",
|
|
909
|
+
"gym",
|
|
910
|
+
"workout",
|
|
911
|
+
"trainer",
|
|
912
|
+
"wellness",
|
|
913
|
+
"meditat",
|
|
914
|
+
"massage",
|
|
915
|
+
"therap",
|
|
916
|
+
"physio",
|
|
917
|
+
"chiro",
|
|
918
|
+
"nutrition",
|
|
919
|
+
"spa",
|
|
920
|
+
"studio"
|
|
921
|
+
],
|
|
922
|
+
pool: [
|
|
923
|
+
U("1544367567-0f2fcb009e0b"),
|
|
924
|
+
U("1506126613408-eca07ce68773"),
|
|
925
|
+
U("1545205597-3d9d02c29597"),
|
|
926
|
+
U("1552196563-55cd4e45efb3"),
|
|
927
|
+
U("1518611012118-696072aa579a"),
|
|
928
|
+
U("1571019613454-1cb2f99b2d8b"),
|
|
929
|
+
U("1540555700478-4be289fbecef"),
|
|
930
|
+
U("1519824145371-296894a0daa9")
|
|
931
|
+
]
|
|
932
|
+
},
|
|
933
|
+
{
|
|
934
|
+
keywords: [
|
|
935
|
+
"salon",
|
|
936
|
+
"hairdress",
|
|
937
|
+
"haircut",
|
|
938
|
+
"barber",
|
|
939
|
+
"manicure",
|
|
940
|
+
"pedicure",
|
|
941
|
+
"nails",
|
|
942
|
+
"beauty",
|
|
943
|
+
"makeup",
|
|
944
|
+
"cosmetic",
|
|
945
|
+
"eyelash",
|
|
946
|
+
"eyebrow",
|
|
947
|
+
"skincare",
|
|
948
|
+
"esthetic",
|
|
949
|
+
"waxing",
|
|
950
|
+
"hair"
|
|
951
|
+
],
|
|
952
|
+
pool: [
|
|
953
|
+
U("1560066984-138dadb4c035"),
|
|
954
|
+
U("1522337660859-02fbefca4702"),
|
|
955
|
+
U("1562322140-8baeececf3df"),
|
|
956
|
+
U("1521590832167-7bcbfaa6381f"),
|
|
957
|
+
U("1487412947147-5cebf100ffc2"),
|
|
958
|
+
U("1526045478516-99145907023c")
|
|
959
|
+
]
|
|
960
|
+
},
|
|
961
|
+
{
|
|
962
|
+
keywords: [
|
|
963
|
+
"cleaning",
|
|
964
|
+
"plumb",
|
|
965
|
+
"electric",
|
|
966
|
+
"landscap",
|
|
967
|
+
"contractor",
|
|
968
|
+
"handyman",
|
|
969
|
+
"renov",
|
|
970
|
+
"hvac",
|
|
971
|
+
"roofing",
|
|
972
|
+
"painting",
|
|
973
|
+
"carpentry",
|
|
974
|
+
"flooring",
|
|
975
|
+
"movers",
|
|
976
|
+
"construction",
|
|
977
|
+
"tools"
|
|
978
|
+
],
|
|
979
|
+
pool: [
|
|
980
|
+
U("1581578731548-c64695cc6952"),
|
|
981
|
+
U("1504307651254-35680f356dfd"),
|
|
982
|
+
U("1581092160562-40aa08e78837"),
|
|
983
|
+
U("1621905251189-08b45d6a269e"),
|
|
984
|
+
U("1558618666-fcd25c85cd64"),
|
|
985
|
+
U("1585128792020-803d29415281")
|
|
986
|
+
]
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
keywords: [
|
|
990
|
+
"legal",
|
|
991
|
+
"attorney",
|
|
992
|
+
"lawyer",
|
|
993
|
+
"account",
|
|
994
|
+
"bookkeep",
|
|
995
|
+
"consult",
|
|
996
|
+
"coaching",
|
|
997
|
+
"financ",
|
|
998
|
+
"insurance",
|
|
999
|
+
"realtor",
|
|
1000
|
+
"estate",
|
|
1001
|
+
"marketing",
|
|
1002
|
+
"agency",
|
|
1003
|
+
"office",
|
|
1004
|
+
"business",
|
|
1005
|
+
"desk"
|
|
1006
|
+
],
|
|
1007
|
+
pool: [
|
|
1008
|
+
U("1497366216548-37526070297c"),
|
|
1009
|
+
U("1497366811353-6870744d04b2"),
|
|
1010
|
+
U("1454165804606-c3d57bc86b40"),
|
|
1011
|
+
U("1521791136064-7986c2920216"),
|
|
1012
|
+
U("1556761175-b413da4baf72"),
|
|
1013
|
+
U("1542744173-8e7e53415bb0")
|
|
1014
|
+
]
|
|
1015
|
+
},
|
|
1016
|
+
{
|
|
1017
|
+
keywords: [
|
|
1018
|
+
"wedding",
|
|
1019
|
+
"event",
|
|
1020
|
+
"party",
|
|
1021
|
+
"celebrat",
|
|
1022
|
+
"venue",
|
|
1023
|
+
"community",
|
|
1024
|
+
"nonprofit",
|
|
1025
|
+
"charity",
|
|
1026
|
+
"workshop",
|
|
1027
|
+
"photograph",
|
|
1028
|
+
"concert"
|
|
1029
|
+
],
|
|
1030
|
+
pool: [
|
|
1031
|
+
U("1511578314322-379afb476865"),
|
|
1032
|
+
U("1501281668745-f7f57925c3b4"),
|
|
1033
|
+
U("1523580494863-6f3031224c94"),
|
|
1034
|
+
U("1540575467063-178a50c2df87"),
|
|
1035
|
+
U("1505236858219-8359eb29e329"),
|
|
1036
|
+
U("1528605248644-14dd04022da1")
|
|
1037
|
+
]
|
|
1038
|
+
}
|
|
1039
|
+
];
|
|
1040
|
+
function poolForSubject(subject) {
|
|
1041
|
+
for (const theme of THEMED) {
|
|
1042
|
+
if (theme.keywords.some((k) => subject.includes(k))) {
|
|
1043
|
+
return theme.pool;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
return GENERIC;
|
|
1047
|
+
}
|
|
1048
|
+
function mixedHash(text) {
|
|
1049
|
+
let hash = 2166136261;
|
|
1050
|
+
for (let i = 0; i < text.length; i++) {
|
|
1051
|
+
hash ^= text.charCodeAt(i);
|
|
1052
|
+
hash = Math.imul(hash, 16777619);
|
|
1053
|
+
}
|
|
1054
|
+
return hash >>> 16 & 65535;
|
|
1055
|
+
}
|
|
1056
|
+
function resolvePlaceholderRef(ref) {
|
|
1057
|
+
const match = /^placeholder:([a-z0-9-]+)$/.exec(ref);
|
|
1058
|
+
if (!match) return null;
|
|
1059
|
+
const subject = match[1];
|
|
1060
|
+
const pool = poolForSubject(subject.replace(/-\d+$/, ""));
|
|
1061
|
+
return pool[mixedHash(ref) % pool.length];
|
|
1062
|
+
}
|
|
1063
|
+
function collectPlaceholderRefs(tree) {
|
|
1064
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1065
|
+
for (const match of JSON.stringify(tree ?? null).matchAll(/"(placeholder:[a-z0-9-]+)"/gu)) {
|
|
1066
|
+
seen.add(match[1]);
|
|
1067
|
+
}
|
|
1068
|
+
return [...seen];
|
|
1069
|
+
}
|
|
1070
|
+
function buildPlaceholderMap(tree) {
|
|
1071
|
+
const map = {};
|
|
1072
|
+
const cursor = /* @__PURE__ */ new Map();
|
|
1073
|
+
for (const ref of collectPlaceholderRefs(tree)) {
|
|
1074
|
+
const subject = ref.slice("placeholder:".length).replace(/-\d+$/, "");
|
|
1075
|
+
const pool = poolForSubject(subject);
|
|
1076
|
+
const start = cursor.get(pool) ?? mixedHash(ref) % pool.length;
|
|
1077
|
+
map[ref] = pool[start % pool.length];
|
|
1078
|
+
cursor.set(pool, start + 1);
|
|
1079
|
+
}
|
|
1080
|
+
return map;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
474
1084
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
475
1085
|
function lucideByName(name) {
|
|
476
1086
|
const pascal = name.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
@@ -484,6 +1094,7 @@ var typeStyle = (spec, font) => ({
|
|
|
484
1094
|
fontWeight: spec.weight
|
|
485
1095
|
});
|
|
486
1096
|
var str = (value) => typeof value === "string" ? value : "";
|
|
1097
|
+
var cardRadius = (slots) => slots.cornerStyle === "sharp" ? 0 : AI_TREE_TOKENS.radiusCard;
|
|
487
1098
|
var featureLines = (value) => value.split(/\n|<br\s*\/?>/i).map((line) => line.trim()).filter(Boolean);
|
|
488
1099
|
var CHECK_MASK = `data:image/svg+xml,${encodeURIComponent(
|
|
489
1100
|
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>'
|
|
@@ -543,6 +1154,22 @@ function accentBandContext(brand) {
|
|
|
543
1154
|
function textAttrs(ctx, path) {
|
|
544
1155
|
return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
|
|
545
1156
|
}
|
|
1157
|
+
var AI_RESPONSIVE_CSS = [
|
|
1158
|
+
"@media (max-width: 960px) {",
|
|
1159
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
|
|
1160
|
+
' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
|
|
1161
|
+
"}",
|
|
1162
|
+
"@media (max-width: 640px) {",
|
|
1163
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
|
|
1164
|
+
" [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
|
|
1165
|
+
// Group containers flatten to a column on phones; span placements come along for free.
|
|
1166
|
+
" [data-ai-responsive] [data-ai-group] { display: flex !important; flex-direction: column !important; }",
|
|
1167
|
+
" [data-ai-responsive] [data-ai-group] > * { grid-column: auto !important; }",
|
|
1168
|
+
" [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
|
|
1169
|
+
" [data-ai-responsive] { overflow-x: hidden; }",
|
|
1170
|
+
" [data-ai-responsive] img { max-width: 100%; }",
|
|
1171
|
+
"}"
|
|
1172
|
+
].join("\n");
|
|
546
1173
|
var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
547
1174
|
function MediaBox({
|
|
548
1175
|
refValue,
|
|
@@ -555,13 +1182,17 @@ function MediaBox({
|
|
|
555
1182
|
const url = refValue ? ctx.resolveMedia(refValue) : null;
|
|
556
1183
|
const isIcon = /^(lucide|simple):/.test(refValue);
|
|
557
1184
|
const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
|
|
558
|
-
const editAttrs = ctx.keyFor && editPath
|
|
1185
|
+
const editAttrs = ctx.keyFor && editPath ? {
|
|
1186
|
+
"data-ohw-key": ctx.keyFor(editPath),
|
|
1187
|
+
"data-ohw-editable": isIcon ? "icon" : "image"
|
|
1188
|
+
} : {};
|
|
559
1189
|
if (isIcon) {
|
|
560
1190
|
const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
|
|
561
1191
|
return /* @__PURE__ */ jsx(
|
|
562
1192
|
"span",
|
|
563
1193
|
{
|
|
564
1194
|
"data-ai-icon": refValue,
|
|
1195
|
+
...editAttrs,
|
|
565
1196
|
style: {
|
|
566
1197
|
display: "inline-flex",
|
|
567
1198
|
width: 48,
|
|
@@ -656,7 +1287,7 @@ function TextBlock({ slots, ctx, path }) {
|
|
|
656
1287
|
}
|
|
657
1288
|
function SectionHeaderBlock({ node, ctx, path }) {
|
|
658
1289
|
const slots = node.slots ?? {};
|
|
659
|
-
const align = slots.alignment === "center" ? "center" : "left";
|
|
1290
|
+
const align = node.align ?? (slots.alignment === "center" ? "center" : "left");
|
|
660
1291
|
const children = node.children ?? [];
|
|
661
1292
|
const buttonRowIdx = children.findIndex((c) => c.type === "button-row");
|
|
662
1293
|
const buttonRow = buttonRowIdx >= 0 ? children[buttonRowIdx] : void 0;
|
|
@@ -700,7 +1331,7 @@ function SectionHeaderBlock({ node, ctx, path }) {
|
|
|
700
1331
|
display: "flex",
|
|
701
1332
|
gap: AI_TREE_TOKENS.spacing6,
|
|
702
1333
|
marginTop: AI_TREE_TOKENS.spacing8,
|
|
703
|
-
justifyContent: align === "center" ? "center" : "flex-start"
|
|
1334
|
+
justifyContent: align === "center" ? "center" : align === "right" ? "flex-end" : "flex-start"
|
|
704
1335
|
},
|
|
705
1336
|
children: (buttonRow.children ?? []).map((button, i) => /* @__PURE__ */ jsx(
|
|
706
1337
|
ButtonEl,
|
|
@@ -806,10 +1437,11 @@ function PricingCard({ node, ctx, path }) {
|
|
|
806
1437
|
return /* @__PURE__ */ jsxs(
|
|
807
1438
|
"div",
|
|
808
1439
|
{
|
|
1440
|
+
"data-ohw-card": "",
|
|
809
1441
|
style: {
|
|
810
1442
|
background: hasBg ? ctx.brand.palette.light : "transparent",
|
|
811
1443
|
border: `1px solid ${dark}`,
|
|
812
|
-
borderRadius:
|
|
1444
|
+
borderRadius: cardRadius(slots),
|
|
813
1445
|
padding: AI_TREE_TOKENS.paddingBlock,
|
|
814
1446
|
display: "flex",
|
|
815
1447
|
flexDirection: "column",
|
|
@@ -914,10 +1546,11 @@ function TestimonialCard({ node, ctx, path }) {
|
|
|
914
1546
|
return /* @__PURE__ */ jsx(
|
|
915
1547
|
"div",
|
|
916
1548
|
{
|
|
1549
|
+
"data-ohw-card": "",
|
|
917
1550
|
"data-ai-avatar-pos": avatarPos ?? void 0,
|
|
918
1551
|
style: {
|
|
919
1552
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
920
|
-
borderRadius: hasBg ?
|
|
1553
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
921
1554
|
overflow: "hidden",
|
|
922
1555
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
923
1556
|
minWidth: 0
|
|
@@ -952,10 +1585,11 @@ function TeamCard({ node, ctx, path }) {
|
|
|
952
1585
|
return /* @__PURE__ */ jsxs(
|
|
953
1586
|
"div",
|
|
954
1587
|
{
|
|
1588
|
+
"data-ohw-card": "",
|
|
955
1589
|
"data-ai-avatar-pos": avatarPos ?? void 0,
|
|
956
1590
|
style: {
|
|
957
1591
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
958
|
-
borderRadius: hasBg ?
|
|
1592
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
959
1593
|
overflow: "hidden",
|
|
960
1594
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
961
1595
|
minWidth: 0,
|
|
@@ -1033,7 +1667,7 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1033
1667
|
editPath: `${path}.media`
|
|
1034
1668
|
}
|
|
1035
1669
|
) : null;
|
|
1036
|
-
const centered = slots.alignment === "center";
|
|
1670
|
+
const centered = (node.align ?? slots.alignment) === "center";
|
|
1037
1671
|
const content = /* @__PURE__ */ jsxs(
|
|
1038
1672
|
"div",
|
|
1039
1673
|
{
|
|
@@ -1126,9 +1760,10 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1126
1760
|
return /* @__PURE__ */ jsxs(
|
|
1127
1761
|
"div",
|
|
1128
1762
|
{
|
|
1763
|
+
"data-ohw-card": "",
|
|
1129
1764
|
style: {
|
|
1130
1765
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1131
|
-
borderRadius: hasBg ?
|
|
1766
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1132
1767
|
overflow: "hidden",
|
|
1133
1768
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1134
1769
|
display: horizontal ? "flex" : "block",
|
|
@@ -1156,7 +1791,7 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1156
1791
|
) : /* @__PURE__ */ jsx(
|
|
1157
1792
|
"div",
|
|
1158
1793
|
{
|
|
1159
|
-
style: /^(lucide|simple):/.test(mediaRef) ? { padding: `${AI_TREE_TOKENS.paddingBlock}px ${AI_TREE_TOKENS.paddingBlock}px 0` } : hasBg ? void 0 : { borderRadius:
|
|
1794
|
+
style: /^(lucide|simple):/.test(mediaRef) ? { padding: `${AI_TREE_TOKENS.paddingBlock}px ${AI_TREE_TOKENS.paddingBlock}px 0` } : hasBg ? void 0 : { borderRadius: cardRadius(slots), overflow: "hidden" },
|
|
1160
1795
|
children: media
|
|
1161
1796
|
}
|
|
1162
1797
|
)),
|
|
@@ -1447,7 +2082,7 @@ function CollectionBlock({ node, ctx, path }) {
|
|
|
1447
2082
|
return /* @__PURE__ */ jsx(
|
|
1448
2083
|
"div",
|
|
1449
2084
|
{
|
|
1450
|
-
"data-ai-grid":
|
|
2085
|
+
"data-ai-grid": String(itemsPerRow),
|
|
1451
2086
|
style: {
|
|
1452
2087
|
display: "grid",
|
|
1453
2088
|
gridTemplateColumns: `repeat(${itemsPerRow}, 1fr)`,
|
|
@@ -1567,6 +2202,32 @@ function renderNode(node, ctx, path) {
|
|
|
1567
2202
|
if (child) {
|
|
1568
2203
|
return renderNode(child, ctx, `${path}.c0`);
|
|
1569
2204
|
}
|
|
2205
|
+
if (str(slots.provider) === "map" && str(slots.query)) {
|
|
2206
|
+
const query = str(slots.query);
|
|
2207
|
+
const mapAttrs = ctx.keyFor ? {
|
|
2208
|
+
"data-ohw-key": ctx.keyFor(`${path}.query`),
|
|
2209
|
+
"data-ohw-editable": "map",
|
|
2210
|
+
"data-ohw-map-query": query
|
|
2211
|
+
} : {};
|
|
2212
|
+
return /* @__PURE__ */ jsx(
|
|
2213
|
+
"iframe",
|
|
2214
|
+
{
|
|
2215
|
+
...mapAttrs,
|
|
2216
|
+
"data-ai-embed": "map",
|
|
2217
|
+
title: str(slots.title) || "Map",
|
|
2218
|
+
src: `https://www.google.com/maps?q=${encodeURIComponent(query)}&output=embed`,
|
|
2219
|
+
loading: "lazy",
|
|
2220
|
+
referrerPolicy: "no-referrer-when-downgrade",
|
|
2221
|
+
style: {
|
|
2222
|
+
width: "100%",
|
|
2223
|
+
minHeight: 320,
|
|
2224
|
+
border: 0,
|
|
2225
|
+
borderRadius: AI_TREE_TOKENS.radiusCard,
|
|
2226
|
+
display: "block"
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
);
|
|
2230
|
+
}
|
|
1570
2231
|
return /* @__PURE__ */ jsx(
|
|
1571
2232
|
"div",
|
|
1572
2233
|
{
|
|
@@ -1723,9 +2384,14 @@ function AiTreeRenderer({
|
|
|
1723
2384
|
const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
|
|
1724
2385
|
const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
|
|
1725
2386
|
const blockBrand = band?.brand ?? resolvedBrand;
|
|
2387
|
+
const placeholderMap = buildPlaceholderMap(tree);
|
|
1726
2388
|
const ctx = {
|
|
1727
2389
|
brand: blockBrand,
|
|
1728
|
-
|
|
2390
|
+
// An owner/library ref resolves through the host resolver; a `placeholder:<subject>` ref the
|
|
2391
|
+
// host cannot resolve falls back to real stock photography (the per-section map first, then a
|
|
2392
|
+
// standalone resolve), so generated galleries, image rows, and overlay backgrounds arrive with
|
|
2393
|
+
// photos instead of grey boxes.
|
|
2394
|
+
resolveMedia: (ref) => resolveMedia?.(ref) ?? placeholderMap[ref] ?? resolvePlaceholderRef(ref),
|
|
1729
2395
|
cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
|
|
1730
2396
|
keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
|
|
1731
2397
|
sectionAlignment: (tree.settings ?? {}).alignment === "center" ? "center" : "left",
|
|
@@ -1752,11 +2418,25 @@ function AiTreeRenderer({
|
|
|
1752
2418
|
}
|
|
1753
2419
|
})();
|
|
1754
2420
|
const distributed = !isOverlay && settings.textDistribution;
|
|
2421
|
+
const rowAlignItems = (rowAlign) => {
|
|
2422
|
+
if (rowAlign === "top") return "start";
|
|
2423
|
+
if (rowAlign === "bottom") return "end";
|
|
2424
|
+
if (rowAlign === "center" || rowAlign === "stretch") return rowAlign;
|
|
2425
|
+
if (distributed === "space-between") return "stretch";
|
|
2426
|
+
return (distributed ?? settings.verticalPosition) === "top" ? "start" : "center";
|
|
2427
|
+
};
|
|
2428
|
+
const cellAlignStyle = (blockAlign) => blockAlign ? {
|
|
2429
|
+
display: "flex",
|
|
2430
|
+
flexDirection: "column",
|
|
2431
|
+
alignItems: blockAlign === "left" ? "flex-start" : blockAlign === "right" ? "flex-end" : "center",
|
|
2432
|
+
textAlign: blockAlign
|
|
2433
|
+
} : {};
|
|
1755
2434
|
return /* @__PURE__ */ jsxs(
|
|
1756
2435
|
"section",
|
|
1757
2436
|
{
|
|
1758
2437
|
"data-ai-section": tree.tag ?? "",
|
|
1759
2438
|
...bgAttrs,
|
|
2439
|
+
"data-ai-responsive": "",
|
|
1760
2440
|
style: {
|
|
1761
2441
|
position: "relative",
|
|
1762
2442
|
padding: `${pad}px 0`,
|
|
@@ -1767,12 +2447,13 @@ function AiTreeRenderer({
|
|
|
1767
2447
|
color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
|
|
1768
2448
|
},
|
|
1769
2449
|
children: [
|
|
1770
|
-
|
|
2450
|
+
/* @__PURE__ */ jsx("style", { children: AI_RESPONSIVE_CSS }),
|
|
1771
2451
|
/* @__PURE__ */ jsx("style", { children: AI_MOBILE_CSS }),
|
|
2452
|
+
isOverlay && backgroundUrl && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
|
|
1772
2453
|
/* @__PURE__ */ jsx(
|
|
1773
2454
|
"div",
|
|
1774
2455
|
{
|
|
1775
|
-
"data-ai-
|
|
2456
|
+
"data-ai-section-inner": "",
|
|
1776
2457
|
style: {
|
|
1777
2458
|
position: "relative",
|
|
1778
2459
|
maxWidth: AI_TREE_TOKENS.sectionMaxWidth,
|
|
@@ -1783,12 +2464,12 @@ function AiTreeRenderer({
|
|
|
1783
2464
|
children: tree.rows.map((row, r2) => /* @__PURE__ */ jsx(
|
|
1784
2465
|
"div",
|
|
1785
2466
|
{
|
|
1786
|
-
"data-ai-
|
|
2467
|
+
"data-ai-columns": "",
|
|
1787
2468
|
style: {
|
|
1788
2469
|
display: "grid",
|
|
1789
2470
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
1790
2471
|
gap: AI_TREE_TOKENS.spacing6,
|
|
1791
|
-
alignItems:
|
|
2472
|
+
alignItems: rowAlignItems(row.align),
|
|
1792
2473
|
marginTop: r2 > 0 ? AI_TREE_TOKENS.spacing8 : 0
|
|
1793
2474
|
},
|
|
1794
2475
|
children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ jsx(
|
|
@@ -1798,6 +2479,8 @@ function AiTreeRenderer({
|
|
|
1798
2479
|
style: {
|
|
1799
2480
|
gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`,
|
|
1800
2481
|
minWidth: 0,
|
|
2482
|
+
// Horizontal placement of the block's content within its column.
|
|
2483
|
+
...cellAlignStyle(block.align),
|
|
1801
2484
|
// space-between: each column becomes a flex column whose content spreads over
|
|
1802
2485
|
// the full row height instead of clumping at the top.
|
|
1803
2486
|
...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
|
|
@@ -1820,7 +2503,7 @@ function AiTreeRenderer({
|
|
|
1820
2503
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1821
2504
|
var CONTAINER_ATTR = "data-ohw-ai-generated";
|
|
1822
2505
|
var REPLACED_ATTR = "data-ohw-ai-replaced-by";
|
|
1823
|
-
var
|
|
2506
|
+
var REMOVED_ATTR2 = "data-ohw-ai-removed";
|
|
1824
2507
|
var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
|
|
1825
2508
|
var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
1826
2509
|
function readRootVar(name) {
|
|
@@ -1914,18 +2597,18 @@ function placeContainer(container, entry) {
|
|
|
1914
2597
|
}
|
|
1915
2598
|
function syncRemovedSections(state) {
|
|
1916
2599
|
const removed = new Set(state.removed ?? []);
|
|
1917
|
-
for (const el of document.querySelectorAll(`[${
|
|
2600
|
+
for (const el of document.querySelectorAll(`[${REMOVED_ATTR2}]`)) {
|
|
1918
2601
|
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
1919
2602
|
if (!removed.has(id)) {
|
|
1920
2603
|
el.style.removeProperty("display");
|
|
1921
|
-
el.removeAttribute(
|
|
2604
|
+
el.removeAttribute(REMOVED_ATTR2);
|
|
1922
2605
|
}
|
|
1923
2606
|
}
|
|
1924
2607
|
for (const id of removed) {
|
|
1925
2608
|
const section = findTemplateSection(id);
|
|
1926
2609
|
if (section && !section.hasAttribute(REPLACED_ATTR)) {
|
|
1927
2610
|
section.style.display = "none";
|
|
1928
|
-
section.setAttribute(
|
|
2611
|
+
section.setAttribute(REMOVED_ATTR2, "");
|
|
1929
2612
|
}
|
|
1930
2613
|
}
|
|
1931
2614
|
}
|
|
@@ -1942,7 +2625,7 @@ function syncTemplateHidden(state, pageHasSections) {
|
|
|
1942
2625
|
if (el.hasAttribute(CONTAINER_ATTR)) continue;
|
|
1943
2626
|
if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
|
|
1944
2627
|
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
1945
|
-
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(
|
|
2628
|
+
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR2)) continue;
|
|
1946
2629
|
el.style.display = "none";
|
|
1947
2630
|
el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
|
|
1948
2631
|
}
|
|
@@ -1966,18 +2649,23 @@ function syncReplacedOriginals(state) {
|
|
|
1966
2649
|
}
|
|
1967
2650
|
}
|
|
1968
2651
|
var sectionOrderIndex = /* @__PURE__ */ new Map();
|
|
2652
|
+
var removedSectionIds = /* @__PURE__ */ new Set();
|
|
1969
2653
|
function setAiSectionOrder(raw, currentPath) {
|
|
1970
2654
|
const next = /* @__PURE__ */ new Map();
|
|
2655
|
+
const removed = /* @__PURE__ */ new Set();
|
|
1971
2656
|
if (raw) {
|
|
1972
2657
|
try {
|
|
1973
2658
|
const entries = JSON.parse(raw);
|
|
1974
2659
|
for (const entry of entries) {
|
|
1975
|
-
if (
|
|
2660
|
+
if (entry.pagePath && entry.pagePath !== currentPath) continue;
|
|
2661
|
+
next.set(entry.instanceId, entry.order);
|
|
2662
|
+
if (entry.removed) removed.add(entry.instanceId);
|
|
1976
2663
|
}
|
|
1977
2664
|
} catch {
|
|
1978
2665
|
}
|
|
1979
2666
|
}
|
|
1980
2667
|
sectionOrderIndex = next;
|
|
2668
|
+
removedSectionIds = removed;
|
|
1981
2669
|
}
|
|
1982
2670
|
function applyExplicitOrder(entries) {
|
|
1983
2671
|
if (sectionOrderIndex.size === 0) return entries;
|
|
@@ -2013,6 +2701,18 @@ function orderByChain(sections) {
|
|
|
2013
2701
|
for (const root of roots) visit(root);
|
|
2014
2702
|
return out.length === sections.length ? out : sections;
|
|
2015
2703
|
}
|
|
2704
|
+
function syncSoftRemovedGenerated() {
|
|
2705
|
+
for (const [id, section] of mounted) {
|
|
2706
|
+
const el = section.container;
|
|
2707
|
+
if (removedSectionIds.has(id)) {
|
|
2708
|
+
el.style.display = "none";
|
|
2709
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
2710
|
+
} else if (el.hasAttribute(REMOVED_ATTR)) {
|
|
2711
|
+
el.style.removeProperty("display");
|
|
2712
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2016
2716
|
function applyAiSectionsToDom(state, options) {
|
|
2017
2717
|
if (typeof document === "undefined") return;
|
|
2018
2718
|
const brandOverride = deriveBrandOverride();
|
|
@@ -2080,6 +2780,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2080
2780
|
syncReplacedOriginals(state);
|
|
2081
2781
|
syncRemovedSections(state);
|
|
2082
2782
|
syncTemplateHidden(state, pageSections.length > 0);
|
|
2783
|
+
syncSoftRemovedGenerated();
|
|
2083
2784
|
}
|
|
2084
2785
|
|
|
2085
2786
|
// src/useLinkHrefGuardian.ts
|
|
@@ -7809,6 +8510,7 @@ function MediaOverlay({
|
|
|
7809
8510
|
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
7810
8511
|
);
|
|
7811
8512
|
}, [isVideo]);
|
|
8513
|
+
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
7812
8514
|
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
7813
8515
|
const box = {
|
|
7814
8516
|
position: "fixed",
|
|
@@ -7938,17 +8640,17 @@ function MediaOverlay({
|
|
|
7938
8640
|
},
|
|
7939
8641
|
children: [
|
|
7940
8642
|
isVideo ? /* @__PURE__ */ jsx15(Film, { size: 14 }) : /* @__PURE__ */ jsx15(ImageIcon, { size: 14 }),
|
|
7941
|
-
|
|
8643
|
+
replaceLabel
|
|
7942
8644
|
]
|
|
7943
8645
|
}
|
|
7944
8646
|
),
|
|
7945
|
-
replaceMode
|
|
8647
|
+
showChrome && replaceMode !== "none" && /* @__PURE__ */ jsxs7(
|
|
7946
8648
|
Button,
|
|
7947
8649
|
{
|
|
7948
8650
|
"data-ohw-media-overlay": "",
|
|
7949
8651
|
variant: "outline",
|
|
7950
8652
|
size: "sm",
|
|
7951
|
-
"aria-label":
|
|
8653
|
+
"aria-label": replaceLabel,
|
|
7952
8654
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
7953
8655
|
style: {
|
|
7954
8656
|
...OVERLAY_BUTTON_STYLE,
|
|
@@ -7971,7 +8673,7 @@ function MediaOverlay({
|
|
|
7971
8673
|
},
|
|
7972
8674
|
children: [
|
|
7973
8675
|
isVideo ? /* @__PURE__ */ jsx15(Film, { size: 14 }) : /* @__PURE__ */ jsx15(ImageIcon, { size: 14 }),
|
|
7974
|
-
replaceMode === "full" ?
|
|
8676
|
+
replaceMode === "full" ? replaceLabel : null
|
|
7975
8677
|
]
|
|
7976
8678
|
}
|
|
7977
8679
|
)
|
|
@@ -8008,219 +8710,37 @@ function CarouselOverlay({
|
|
|
8008
8710
|
width: rect.width,
|
|
8009
8711
|
height: rect.height,
|
|
8010
8712
|
zIndex: 2147483646,
|
|
8011
|
-
pointerEvents: "auto",
|
|
8012
|
-
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
8013
|
-
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
8014
|
-
},
|
|
8015
|
-
onClick: () => onEdit(hover.key),
|
|
8016
|
-
children: /* @__PURE__ */ jsxs8(
|
|
8017
|
-
Button,
|
|
8018
|
-
{
|
|
8019
|
-
"data-ohw-carousel-overlay": "",
|
|
8020
|
-
variant: "outline",
|
|
8021
|
-
size: "sm",
|
|
8022
|
-
className: "cursor-pointer gap-1.5 hover:bg-background",
|
|
8023
|
-
style: OVERLAY_BUTTON_STYLE2,
|
|
8024
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
8025
|
-
onClick: (e) => {
|
|
8026
|
-
e.stopPropagation();
|
|
8027
|
-
onEdit(hover.key);
|
|
8028
|
-
},
|
|
8029
|
-
children: [
|
|
8030
|
-
/* @__PURE__ */ jsx16(GalleryHorizontal, { size: 14 }),
|
|
8031
|
-
"Edit gallery"
|
|
8032
|
-
]
|
|
8033
|
-
}
|
|
8034
|
-
)
|
|
8035
|
-
}
|
|
8036
|
-
);
|
|
8037
|
-
}
|
|
8038
|
-
|
|
8039
|
-
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
8040
|
-
import { useCallback as useCallback2, useEffect as useEffect4, useRef as useRef4, useState as useState5 } from "react";
|
|
8041
|
-
import { Check, X } from "lucide-react";
|
|
8042
|
-
|
|
8043
|
-
// src/lib/sections.ts
|
|
8044
|
-
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
8045
|
-
function isChromeSection(el) {
|
|
8046
|
-
return el.matches("header, nav, footer, aside");
|
|
8047
|
-
}
|
|
8048
|
-
function titleCaseSectionId(id) {
|
|
8049
|
-
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
8050
|
-
}
|
|
8051
|
-
function parseSectionsFromRoot(root) {
|
|
8052
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8053
|
-
const sections = [];
|
|
8054
|
-
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
8055
|
-
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
8056
|
-
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
8057
|
-
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
8058
|
-
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
8059
|
-
continue;
|
|
8060
|
-
seen.add(id);
|
|
8061
|
-
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
8062
|
-
sections.push({ id, label });
|
|
8063
|
-
}
|
|
8064
|
-
return sections;
|
|
8065
|
-
}
|
|
8066
|
-
function collectSectionsFromDom() {
|
|
8067
|
-
if (typeof document === "undefined") return [];
|
|
8068
|
-
return parseSectionsFromRoot(document);
|
|
8069
|
-
}
|
|
8070
|
-
function parseSectionsFromHtml(html) {
|
|
8071
|
-
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
8072
|
-
return parseSectionsFromRoot(doc);
|
|
8073
|
-
}
|
|
8074
|
-
|
|
8075
|
-
// src/lib/section-instances.ts
|
|
8076
|
-
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
8077
|
-
var REMOVED_ATTR2 = "data-ohw-section-removed";
|
|
8078
|
-
function isRemovedSection(el) {
|
|
8079
|
-
return el.hasAttribute(REMOVED_ATTR2);
|
|
8080
|
-
}
|
|
8081
|
-
function topLevelSections() {
|
|
8082
|
-
return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
8083
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el) && !isRemovedSection(el)
|
|
8084
|
-
);
|
|
8085
|
-
}
|
|
8086
|
-
function instanceIdOf(el) {
|
|
8087
|
-
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
8088
|
-
}
|
|
8089
|
-
function findByInstanceId(instanceId) {
|
|
8090
|
-
const escapedId = CSS.escape(instanceId);
|
|
8091
|
-
return document.querySelector(`[data-ohw-instance="${escapedId}"]`) ?? document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
8092
|
-
}
|
|
8093
|
-
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
8094
|
-
const sections = topLevelSections();
|
|
8095
|
-
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8096
|
-
if (index === -1) return null;
|
|
8097
|
-
const dragged = sections[index];
|
|
8098
|
-
const others = sections.filter((_, i) => i !== index);
|
|
8099
|
-
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
8100
|
-
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
8101
|
-
return reordered.map((el, order) => ({
|
|
8102
|
-
instanceId: instanceIdOf(el),
|
|
8103
|
-
type: el.getAttribute("data-ohw-section") ?? "",
|
|
8104
|
-
order,
|
|
8105
|
-
pagePath: currentPath
|
|
8106
|
-
}));
|
|
8107
|
-
}
|
|
8108
|
-
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
8109
|
-
const sections = topLevelSections();
|
|
8110
|
-
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8111
|
-
if (index === -1) return null;
|
|
8112
|
-
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
8113
|
-
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
8114
|
-
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
8115
|
-
if (!entries) return null;
|
|
8116
|
-
applyPersistedOrder(entries);
|
|
8117
|
-
return entries;
|
|
8118
|
-
}
|
|
8119
|
-
function syncRemovedFlags(entries) {
|
|
8120
|
-
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
8121
|
-
document.querySelectorAll(`[${REMOVED_ATTR2}]`).forEach((el) => {
|
|
8122
|
-
if (!removedIds.has(instanceIdOf(el))) {
|
|
8123
|
-
el.style.removeProperty("display");
|
|
8124
|
-
el.removeAttribute(REMOVED_ATTR2);
|
|
8125
|
-
}
|
|
8126
|
-
});
|
|
8127
|
-
for (const id of removedIds) {
|
|
8128
|
-
const el = findByInstanceId(id);
|
|
8129
|
-
if (el) {
|
|
8130
|
-
el.style.display = "none";
|
|
8131
|
-
el.setAttribute(REMOVED_ATTR2, "");
|
|
8713
|
+
pointerEvents: "auto",
|
|
8714
|
+
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
8715
|
+
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
8716
|
+
},
|
|
8717
|
+
onClick: () => onEdit(hover.key),
|
|
8718
|
+
children: /* @__PURE__ */ jsxs8(
|
|
8719
|
+
Button,
|
|
8720
|
+
{
|
|
8721
|
+
"data-ohw-carousel-overlay": "",
|
|
8722
|
+
variant: "outline",
|
|
8723
|
+
size: "sm",
|
|
8724
|
+
className: "cursor-pointer gap-1.5 hover:bg-background",
|
|
8725
|
+
style: OVERLAY_BUTTON_STYLE2,
|
|
8726
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
8727
|
+
onClick: (e) => {
|
|
8728
|
+
e.stopPropagation();
|
|
8729
|
+
onEdit(hover.key);
|
|
8730
|
+
},
|
|
8731
|
+
children: [
|
|
8732
|
+
/* @__PURE__ */ jsx16(GalleryHorizontal, { size: 14 }),
|
|
8733
|
+
"Edit gallery"
|
|
8734
|
+
]
|
|
8735
|
+
}
|
|
8736
|
+
)
|
|
8132
8737
|
}
|
|
8133
|
-
}
|
|
8134
|
-
}
|
|
8135
|
-
function applyPersistedOrder(entries) {
|
|
8136
|
-
syncRemovedFlags(entries);
|
|
8137
|
-
if (entries.length === 0) return;
|
|
8138
|
-
const sections = topLevelSections();
|
|
8139
|
-
if (sections.length === 0) return;
|
|
8140
|
-
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
8141
|
-
const ordered = [...sections].sort((a, b) => {
|
|
8142
|
-
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
8143
|
-
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
8144
|
-
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
8145
|
-
if (aOrder === void 0) return 1;
|
|
8146
|
-
if (bOrder === void 0) return -1;
|
|
8147
|
-
return aOrder - bOrder;
|
|
8148
|
-
});
|
|
8149
|
-
let prev = null;
|
|
8150
|
-
for (const el of ordered) {
|
|
8151
|
-
if (prev) prev.after(el);
|
|
8152
|
-
prev = el;
|
|
8153
|
-
}
|
|
8154
|
-
}
|
|
8155
|
-
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
8156
|
-
if (!findByInstanceId(instanceId)) return null;
|
|
8157
|
-
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
8158
|
-
const allSections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
8159
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
|
|
8160
8738
|
);
|
|
8161
|
-
allSections.forEach((el, order) => {
|
|
8162
|
-
const id = instanceIdOf(el);
|
|
8163
|
-
if (!byId.has(id)) {
|
|
8164
|
-
byId.set(id, { instanceId: id, type: el.getAttribute("data-ohw-section") ?? "", order, pagePath: currentPath });
|
|
8165
|
-
}
|
|
8166
|
-
});
|
|
8167
|
-
const target = byId.get(instanceId);
|
|
8168
|
-
if (!target) return null;
|
|
8169
|
-
byId.set(instanceId, { ...target, removed });
|
|
8170
|
-
const entries = Array.from(byId.values());
|
|
8171
|
-
applyPersistedOrder(entries);
|
|
8172
|
-
return entries;
|
|
8173
|
-
}
|
|
8174
|
-
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
8175
|
-
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
8176
|
-
}
|
|
8177
|
-
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
8178
|
-
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
8179
|
-
}
|
|
8180
|
-
function newInstanceId() {
|
|
8181
|
-
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
8182
|
-
}
|
|
8183
|
-
function getPageSectionOrderEntries(raw, currentPath) {
|
|
8184
|
-
if (!raw) return [];
|
|
8185
|
-
try {
|
|
8186
|
-
const entries = JSON.parse(raw);
|
|
8187
|
-
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
8188
|
-
} catch {
|
|
8189
|
-
return [];
|
|
8190
|
-
}
|
|
8191
|
-
}
|
|
8192
|
-
function rekeySectionSubtree(root, instanceId) {
|
|
8193
|
-
const suffix = `::${instanceId}`;
|
|
8194
|
-
const rekey = (el, attr) => {
|
|
8195
|
-
const current = el.getAttribute(attr);
|
|
8196
|
-
if (current) el.setAttribute(attr, `${current}${suffix}`);
|
|
8197
|
-
};
|
|
8198
|
-
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
8199
|
-
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
8200
|
-
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
8201
|
-
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
8202
|
-
}
|
|
8203
|
-
function initSectionInstancesFromContent(content, currentPath) {
|
|
8204
|
-
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
8205
|
-
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
8206
|
-
});
|
|
8207
|
-
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
8208
|
-
for (const entry of entries) {
|
|
8209
|
-
if (entry.instanceId === entry.type) continue;
|
|
8210
|
-
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
8211
|
-
const original = document.querySelector(
|
|
8212
|
-
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
8213
|
-
);
|
|
8214
|
-
if (!original) continue;
|
|
8215
|
-
const clone = original.cloneNode(true);
|
|
8216
|
-
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
8217
|
-
rekeySectionSubtree(clone, entry.instanceId);
|
|
8218
|
-
original.insertAdjacentElement("afterend", clone);
|
|
8219
|
-
}
|
|
8220
|
-
applyPersistedOrder(entries);
|
|
8221
8739
|
}
|
|
8222
8740
|
|
|
8223
8741
|
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
8742
|
+
import { useCallback as useCallback2, useEffect as useEffect4, useRef as useRef4, useState as useState5 } from "react";
|
|
8743
|
+
import { Check, X } from "lucide-react";
|
|
8224
8744
|
import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
8225
8745
|
function findSectionElement(instanceId) {
|
|
8226
8746
|
const escaped = CSS.escape(instanceId);
|
|
@@ -12936,6 +13456,7 @@ function readLogoSizeState(content, placement) {
|
|
|
12936
13456
|
function getLogoElement(el) {
|
|
12937
13457
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
12938
13458
|
if (marked) return marked;
|
|
13459
|
+
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
12939
13460
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
12940
13461
|
if (!root) return null;
|
|
12941
13462
|
const anchor = el.closest("a");
|
|
@@ -14317,6 +14838,9 @@ function collectEditableNodes(extraContent, root = document) {
|
|
|
14317
14838
|
if (el.dataset.ohwEditable === "link") {
|
|
14318
14839
|
return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref3(el) };
|
|
14319
14840
|
}
|
|
14841
|
+
if (el.dataset.ohwEditable === "map") {
|
|
14842
|
+
return { key: el.dataset.ohwKey ?? "", type: "map", text: el.dataset.ohwMapQuery ?? "" };
|
|
14843
|
+
}
|
|
14320
14844
|
return {
|
|
14321
14845
|
key: el.dataset.ohwKey ?? "",
|
|
14322
14846
|
type: el.dataset.ohwEditable ?? "text",
|
|
@@ -14870,21 +15394,10 @@ function parseSchedulingInsertAfter(insertAfter) {
|
|
|
14870
15394
|
insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
|
|
14871
15395
|
};
|
|
14872
15396
|
}
|
|
14873
|
-
function
|
|
14874
|
-
|
|
14875
|
-
const
|
|
14876
|
-
|
|
14877
|
-
return { effectiveInsertAfter, insertBefore };
|
|
14878
|
-
}
|
|
14879
|
-
function getSchedulingMountPoint(insertAfter) {
|
|
14880
|
-
const { anchor } = parseSchedulingInsertAfter(insertAfter);
|
|
14881
|
-
let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
|
|
14882
|
-
if (!anchorEl && anchor === "scheduling") {
|
|
14883
|
-
const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
|
|
14884
|
-
anchorEl = widgets.at(-1) ?? null;
|
|
14885
|
-
}
|
|
14886
|
-
if (!anchorEl) return null;
|
|
14887
|
-
return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
15397
|
+
function resolveEntryAnchor(entry) {
|
|
15398
|
+
if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
|
|
15399
|
+
const parsed = parseSchedulingInsertAfter(entry.insertAfter);
|
|
15400
|
+
return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
|
|
14888
15401
|
}
|
|
14889
15402
|
function schedulingMountDepth(insertAfter) {
|
|
14890
15403
|
if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
|
|
@@ -14901,8 +15414,7 @@ function getPageSchedulingEntries(raw) {
|
|
|
14901
15414
|
}
|
|
14902
15415
|
}
|
|
14903
15416
|
function isSchedulingWidgetMissing(entry) {
|
|
14904
|
-
|
|
14905
|
-
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
|
|
15417
|
+
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
|
|
14906
15418
|
}
|
|
14907
15419
|
function hasMissingSchedulingWidgets(entries) {
|
|
14908
15420
|
return entries.some(isSchedulingWidgetMissing);
|
|
@@ -14932,16 +15444,17 @@ function initSectionsFromContent(content, removeExisting = false) {
|
|
|
14932
15444
|
} catch {
|
|
14933
15445
|
}
|
|
14934
15446
|
}
|
|
14935
|
-
function mountSchedulingWidget(
|
|
14936
|
-
const
|
|
14937
|
-
const sectionId = schedulingSectionId(
|
|
15447
|
+
function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
|
|
15448
|
+
const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
|
|
15449
|
+
const sectionId = schedulingSectionId(widgetId);
|
|
14938
15450
|
if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
|
|
14939
|
-
const
|
|
14940
|
-
if (!
|
|
15451
|
+
const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
|
|
15452
|
+
if (!anchorEl) return false;
|
|
15453
|
+
const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
14941
15454
|
const container = document.createElement("div");
|
|
14942
15455
|
container.dataset.ohwSectionContainer = "scheduling";
|
|
14943
|
-
if (
|
|
14944
|
-
const beforeAnchor = document.querySelector(`[data-ohw-section="${
|
|
15456
|
+
if (beforeId) {
|
|
15457
|
+
const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
|
|
14945
15458
|
const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
|
|
14946
15459
|
if (!beforePoint) return false;
|
|
14947
15460
|
beforePoint.insertAdjacentElement("beforebegin", container);
|
|
@@ -14952,19 +15465,25 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
14952
15465
|
}
|
|
14953
15466
|
tail.insertAdjacentElement("afterend", container);
|
|
14954
15467
|
}
|
|
14955
|
-
|
|
14956
|
-
|
|
14957
|
-
|
|
14958
|
-
|
|
14959
|
-
|
|
14960
|
-
|
|
14961
|
-
|
|
14962
|
-
|
|
14963
|
-
|
|
14964
|
-
|
|
14965
|
-
|
|
14966
|
-
|
|
14967
|
-
|
|
15468
|
+
try {
|
|
15469
|
+
const root = createRoot2(container);
|
|
15470
|
+
flushSync2(() => {
|
|
15471
|
+
root.render(
|
|
15472
|
+
/* @__PURE__ */ jsx33(
|
|
15473
|
+
SchedulingWidget,
|
|
15474
|
+
{
|
|
15475
|
+
notifyOnConnect,
|
|
15476
|
+
initialScheduleId: scheduleId,
|
|
15477
|
+
insertAfter: widgetId
|
|
15478
|
+
}
|
|
15479
|
+
)
|
|
15480
|
+
);
|
|
15481
|
+
});
|
|
15482
|
+
} catch (err) {
|
|
15483
|
+
console.error("[ow:scheduling] render threw", err);
|
|
15484
|
+
container.remove();
|
|
15485
|
+
return false;
|
|
15486
|
+
}
|
|
14968
15487
|
const tracker = getSectionsTracker();
|
|
14969
15488
|
let sections = [];
|
|
14970
15489
|
try {
|
|
@@ -14972,10 +15491,12 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
14972
15491
|
} catch {
|
|
14973
15492
|
}
|
|
14974
15493
|
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
14975
|
-
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter ===
|
|
15494
|
+
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
|
|
14976
15495
|
sections.push({
|
|
14977
15496
|
type: "scheduling",
|
|
14978
|
-
insertAfter:
|
|
15497
|
+
insertAfter: widgetId,
|
|
15498
|
+
anchorId,
|
|
15499
|
+
beforeId: beforeId ?? null,
|
|
14979
15500
|
pagePath: window.location.pathname,
|
|
14980
15501
|
...scheduleId ? { scheduleId } : {}
|
|
14981
15502
|
});
|
|
@@ -14989,7 +15510,8 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
|
14989
15510
|
for (let i = pending.length - 1; i >= 0; i--) {
|
|
14990
15511
|
const entry = pending[i];
|
|
14991
15512
|
const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
|
|
14992
|
-
|
|
15513
|
+
const { anchorId, beforeId } = resolveEntryAnchor(entry);
|
|
15514
|
+
if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
|
|
14993
15515
|
pending.splice(i, 1);
|
|
14994
15516
|
}
|
|
14995
15517
|
}
|
|
@@ -15081,7 +15603,7 @@ var EDITOR_CHROME_SELECTOR = '[data-ohw-toolbar], [data-ohw-form-toolbar], [data
|
|
|
15081
15603
|
function isOverEditorChrome(x, y) {
|
|
15082
15604
|
return document.elementsFromPoint(x, y).some((el) => el instanceof HTMLElement && el.matches(EDITOR_CHROME_SELECTOR));
|
|
15083
15605
|
}
|
|
15084
|
-
var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]):not([data-ohw-editable="icon"]):not([data-ohw-editable="form"])';
|
|
15606
|
+
var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]):not([data-ohw-editable="icon"]):not([data-ohw-editable="form"]):not([data-ohw-editable="map"])';
|
|
15085
15607
|
function getVideoEl2(el) {
|
|
15086
15608
|
return el instanceof HTMLVideoElement ? el : el.querySelector("video");
|
|
15087
15609
|
}
|
|
@@ -15137,6 +15659,12 @@ function applyVideoSettingNode(key, val) {
|
|
|
15137
15659
|
});
|
|
15138
15660
|
return true;
|
|
15139
15661
|
}
|
|
15662
|
+
function applyMapQuery(el, val) {
|
|
15663
|
+
if (!(el instanceof HTMLIFrameElement)) return;
|
|
15664
|
+
const nextSrc = `https://www.google.com/maps?q=${encodeURIComponent(val)}&output=embed`;
|
|
15665
|
+
if (el.src !== nextSrc) el.src = nextSrc;
|
|
15666
|
+
el.setAttribute("data-ohw-map-query", val);
|
|
15667
|
+
}
|
|
15140
15668
|
function applyLinkByKey(key, val) {
|
|
15141
15669
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
15142
15670
|
if (el.dataset.ohwEditable === "link") applyLinkHref(el, val);
|
|
@@ -15147,6 +15675,11 @@ function applyLinkByKey(key, val) {
|
|
|
15147
15675
|
hrefAnchors.forEach((el) => applyLinkHref(el, val));
|
|
15148
15676
|
}
|
|
15149
15677
|
}
|
|
15678
|
+
function isInsideLinkEditor(target) {
|
|
15679
|
+
return Boolean(
|
|
15680
|
+
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"]')
|
|
15681
|
+
);
|
|
15682
|
+
}
|
|
15150
15683
|
function isInsideFloatingPanel(target) {
|
|
15151
15684
|
return Boolean(target.closest("[data-ohw-floating-panel]"));
|
|
15152
15685
|
}
|
|
@@ -15154,11 +15687,6 @@ function isPointOverFloatingPanel(clientX, clientY) {
|
|
|
15154
15687
|
const el = document.elementFromPoint(clientX, clientY);
|
|
15155
15688
|
return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
|
|
15156
15689
|
}
|
|
15157
|
-
function isInsideLinkEditor(target) {
|
|
15158
|
-
return Boolean(
|
|
15159
|
-
target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest("[data-ohw-footer-container-chrome]") || target.closest("[data-ohw-footer-add-button]") || target.closest("[data-ohw-more-menu]") || target.closest('[data-slot="dropdown-menu-content"]') || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
|
|
15160
|
-
);
|
|
15161
|
-
}
|
|
15162
15690
|
function getHrefKeyFromElement(el) {
|
|
15163
15691
|
if (!el) return null;
|
|
15164
15692
|
const anchor = el.closest("[data-ohw-href-key]");
|
|
@@ -15417,7 +15945,7 @@ function getNavigationSelectionParent(el) {
|
|
|
15417
15945
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
15418
15946
|
return getFooterLinksContainer();
|
|
15419
15947
|
}
|
|
15420
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
15948
|
+
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isFooterLinksContainer(el) || isInferredFooterGroup2(el)) {
|
|
15421
15949
|
return getNavigationRoot(el);
|
|
15422
15950
|
}
|
|
15423
15951
|
return null;
|
|
@@ -15632,7 +16160,6 @@ var ICONS = {
|
|
|
15632
16160
|
insertUnorderedList: '<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>',
|
|
15633
16161
|
insertOrderedList: '<line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/>'
|
|
15634
16162
|
};
|
|
15635
|
-
var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
|
|
15636
16163
|
var SELECTION_CHROME_GAP2 = 4;
|
|
15637
16164
|
var TOOLBAR_STROKE_GAP2 = 4;
|
|
15638
16165
|
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
@@ -16012,6 +16539,7 @@ function StateToggle({
|
|
|
16012
16539
|
);
|
|
16013
16540
|
}
|
|
16014
16541
|
var contentCache = /* @__PURE__ */ new Map();
|
|
16542
|
+
var fetchedContentPaths = /* @__PURE__ */ new Set();
|
|
16015
16543
|
var brandingCache = /* @__PURE__ */ new Map();
|
|
16016
16544
|
var OHW_LOADER_STYLE = {
|
|
16017
16545
|
position: "fixed",
|
|
@@ -16541,13 +17069,6 @@ function OhhwellsBridge() {
|
|
|
16541
17069
|
const [isItemDragging, setIsItemDragging] = useState13(false);
|
|
16542
17070
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = useState13(false);
|
|
16543
17071
|
isFooterFrameSelectionRef.current = isFooterFrameSelection;
|
|
16544
|
-
const [floatingPanel, setFloatingPanel] = useState13(null);
|
|
16545
|
-
const floatingPanelOpenRef = useRef10(false);
|
|
16546
|
-
floatingPanelOpenRef.current = floatingPanel !== null;
|
|
16547
|
-
const [floatingPanelPos, setFloatingPanelPos] = useState13(null);
|
|
16548
|
-
const [logoSizeDraft, setLogoSizeDraft] = useState13(null);
|
|
16549
|
-
const [editorViewport, setEditorViewport] = useState13("desktop");
|
|
16550
|
-
const [parentScrollSnap, setParentScrollSnap] = useState13(null);
|
|
16551
17072
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState13(null);
|
|
16552
17073
|
const [footerHeadingVisible, setFooterHeadingVisible] = useState13(null);
|
|
16553
17074
|
const footerDragRef = useRef10(null);
|
|
@@ -16565,6 +17086,13 @@ function OhhwellsBridge() {
|
|
|
16565
17086
|
const brandKitRef = useRef10("");
|
|
16566
17087
|
const stylesRef = useRef10("");
|
|
16567
17088
|
const pendingDeleteUndoRef = useRef10(null);
|
|
17089
|
+
const [floatingPanel, setFloatingPanel] = useState13(null);
|
|
17090
|
+
const floatingPanelOpenRef = useRef10(false);
|
|
17091
|
+
const setFloatingPanelRef = useRef10(setFloatingPanel);
|
|
17092
|
+
const [floatingPanelPos, setFloatingPanelPos] = useState13(null);
|
|
17093
|
+
const [logoSizeDraft, setLogoSizeDraft] = useState13(null);
|
|
17094
|
+
const [editorViewport, setEditorViewport] = useState13("desktop");
|
|
17095
|
+
const [parentScrollSnap, setParentScrollSnap] = useState13(null);
|
|
16568
17096
|
const [sitePages, setSitePages] = useState13([]);
|
|
16569
17097
|
const [sectionsByPath, setSectionsByPath] = useState13({});
|
|
16570
17098
|
const sectionsPrefetchGenRef = useRef10(0);
|
|
@@ -16573,7 +17101,18 @@ function OhhwellsBridge() {
|
|
|
16573
17101
|
const linkPopoverOpenRef = useRef10(false);
|
|
16574
17102
|
const linkPopoverGraceUntilRef = useRef10(0);
|
|
16575
17103
|
setLinkPopoverRef.current = setLinkPopover;
|
|
17104
|
+
setFloatingPanelRef.current = setFloatingPanel;
|
|
16576
17105
|
linkPopoverSessionRef.current = linkPopover;
|
|
17106
|
+
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
17107
|
+
useEffect13(() => {
|
|
17108
|
+
const syncViewport = () => {
|
|
17109
|
+
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
17110
|
+
setEditorViewport((prev) => prev === next ? prev : next);
|
|
17111
|
+
};
|
|
17112
|
+
syncViewport();
|
|
17113
|
+
window.addEventListener("resize", syncViewport);
|
|
17114
|
+
return () => window.removeEventListener("resize", syncViewport);
|
|
17115
|
+
}, []);
|
|
16577
17116
|
const {
|
|
16578
17117
|
navDragRef,
|
|
16579
17118
|
navDropSlots,
|
|
@@ -17898,17 +18437,19 @@ function OhhwellsBridge() {
|
|
|
17898
18437
|
}
|
|
17899
18438
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
17900
18439
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
18440
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
17901
18441
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
17902
18442
|
}
|
|
17903
18443
|
applyBrandChrome(content);
|
|
18444
|
+
initSectionInstancesFromContent(content, window.location.pathname);
|
|
17904
18445
|
for (const [key, val] of Object.entries(content)) {
|
|
17905
18446
|
if (key === "__ohw_sections") continue;
|
|
17906
18447
|
if (key === AI_SECTIONS_KEY) continue;
|
|
18448
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18449
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
17907
18450
|
if (key === BRAND_KIT_KEY) continue;
|
|
17908
18451
|
if (key === STYLE_STORE_KEY) continue;
|
|
17909
18452
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
17910
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
17911
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
17912
18453
|
if (applyVideoSettingNode(key, val)) continue;
|
|
17913
18454
|
if (applyCarouselNode(key, val)) continue;
|
|
17914
18455
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -17936,6 +18477,8 @@ function OhhwellsBridge() {
|
|
|
17936
18477
|
}
|
|
17937
18478
|
} else if (el.dataset.ohwEditable === "link") {
|
|
17938
18479
|
applyLinkHref(el, val);
|
|
18480
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
18481
|
+
applyMapQuery(el, val);
|
|
17939
18482
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
17940
18483
|
applyIconMarkup(el, val);
|
|
17941
18484
|
} else if (el.dataset.ohwEditable === "form") {
|
|
@@ -17956,7 +18499,6 @@ function OhhwellsBridge() {
|
|
|
17956
18499
|
if (isEditModeRef.current) requestMissingSocialIconsRef.current();
|
|
17957
18500
|
enforceLinkHrefs();
|
|
17958
18501
|
initSectionsFromContent(content, true);
|
|
17959
|
-
initSectionInstancesFromContent(content, window.location.pathname);
|
|
17960
18502
|
sectionsLoadedRef.current = true;
|
|
17961
18503
|
pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
|
|
17962
18504
|
if (imageLoads.length === 0) return Promise.resolve();
|
|
@@ -17975,7 +18517,9 @@ function OhhwellsBridge() {
|
|
|
17975
18517
|
let cancelled = false;
|
|
17976
18518
|
setFetchState("loading");
|
|
17977
18519
|
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
17978
|
-
|
|
18520
|
+
const initialPath = pathname;
|
|
18521
|
+
fetchedContentPaths.add(`${subdomain}::${initialPath}`);
|
|
18522
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
17979
18523
|
if (cancelled) return;
|
|
17980
18524
|
const content = data?.content ?? {};
|
|
17981
18525
|
const branding = Boolean(data?.showBranding);
|
|
@@ -18109,16 +18653,17 @@ function OhhwellsBridge() {
|
|
|
18109
18653
|
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
18110
18654
|
}
|
|
18111
18655
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
18656
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
18112
18657
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
18113
18658
|
}
|
|
18114
18659
|
for (const [key, val] of Object.entries(content)) {
|
|
18115
18660
|
if (key === "__ohw_sections") continue;
|
|
18116
18661
|
if (key === AI_SECTIONS_KEY) continue;
|
|
18662
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18663
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18117
18664
|
if (key === BRAND_KIT_KEY) continue;
|
|
18118
18665
|
if (key === STYLE_STORE_KEY) continue;
|
|
18119
18666
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
18120
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18121
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18122
18667
|
if (applyVideoSettingNode(key, val)) continue;
|
|
18123
18668
|
if (applyCarouselNode(key, val)) continue;
|
|
18124
18669
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -18133,6 +18678,8 @@ function OhhwellsBridge() {
|
|
|
18133
18678
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
18134
18679
|
} else if (el.dataset.ohwEditable === "link") {
|
|
18135
18680
|
applyLinkHref(el, val);
|
|
18681
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
18682
|
+
applyMapQuery(el, val);
|
|
18136
18683
|
} else if (el.dataset.ohwEditable === "form") {
|
|
18137
18684
|
} else if (isIconMarkupValue(val)) {
|
|
18138
18685
|
} else if (el.innerHTML !== val) {
|
|
@@ -18164,6 +18711,17 @@ function OhhwellsBridge() {
|
|
|
18164
18711
|
debounceTimer = setTimeout(applyFromCache, 150);
|
|
18165
18712
|
};
|
|
18166
18713
|
applyFromCache();
|
|
18714
|
+
const pathCacheKey = `${subdomain}::${pathname}`;
|
|
18715
|
+
if (!fetchedContentPaths.has(pathCacheKey)) {
|
|
18716
|
+
fetchedContentPaths.add(pathCacheKey);
|
|
18717
|
+
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
18718
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
18719
|
+
if (!data?.content) return;
|
|
18720
|
+
contentCache.set(subdomain, data.content);
|
|
18721
|
+
applyFromCache();
|
|
18722
|
+
}).catch(() => {
|
|
18723
|
+
});
|
|
18724
|
+
}
|
|
18167
18725
|
observer = new MutationObserver(scheduleApply);
|
|
18168
18726
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
18169
18727
|
return () => {
|
|
@@ -18279,26 +18837,11 @@ function OhhwellsBridge() {
|
|
|
18279
18837
|
const t2 = setTimeout(measure, 500);
|
|
18280
18838
|
const ro = new ResizeObserver(schedule);
|
|
18281
18839
|
ro.observe(document.body);
|
|
18282
|
-
let lastWidth = window.innerWidth;
|
|
18283
|
-
let resizeTimers = [];
|
|
18284
|
-
const clearResizeTimers = () => {
|
|
18285
|
-
resizeTimers.forEach(clearTimeout);
|
|
18286
|
-
resizeTimers = [];
|
|
18287
|
-
};
|
|
18288
|
-
const handleResize = () => {
|
|
18289
|
-
if (window.innerWidth === lastWidth) return;
|
|
18290
|
-
lastWidth = window.innerWidth;
|
|
18291
|
-
clearResizeTimers();
|
|
18292
|
-
resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
|
|
18293
|
-
};
|
|
18294
|
-
window.addEventListener("resize", handleResize);
|
|
18295
18840
|
return () => {
|
|
18296
18841
|
clearTimeout(t1);
|
|
18297
18842
|
clearTimeout(t2);
|
|
18298
18843
|
if (raf != null) cancelAnimationFrame(raf);
|
|
18299
18844
|
ro.disconnect();
|
|
18300
|
-
clearResizeTimers();
|
|
18301
|
-
window.removeEventListener("resize", handleResize);
|
|
18302
18845
|
};
|
|
18303
18846
|
}, [pathname, isEditMode, postToParent2]);
|
|
18304
18847
|
useEffect13(() => {
|
|
@@ -18544,9 +19087,6 @@ function OhhwellsBridge() {
|
|
|
18544
19087
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
18545
19088
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
18546
19089
|
if (isInsideLinkEditor(target)) return;
|
|
18547
|
-
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
18548
|
-
clearMediaSelectionRef.current();
|
|
18549
|
-
}
|
|
18550
19090
|
if (isInsideFloatingPanel(target)) return;
|
|
18551
19091
|
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
18552
19092
|
if (target.closest(
|
|
@@ -18554,6 +19094,9 @@ function OhhwellsBridge() {
|
|
|
18554
19094
|
)) {
|
|
18555
19095
|
return;
|
|
18556
19096
|
}
|
|
19097
|
+
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
19098
|
+
clearMediaSelectionRef.current();
|
|
19099
|
+
}
|
|
18557
19100
|
{
|
|
18558
19101
|
const formEl = getFormElement(target);
|
|
18559
19102
|
const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
|
|
@@ -18705,14 +19248,6 @@ function OhhwellsBridge() {
|
|
|
18705
19248
|
}
|
|
18706
19249
|
const clickedButton = findClosestButtonLike(target);
|
|
18707
19250
|
const buttonOnMedia = Boolean(clickedButton && isMediaEditable(editable) && editable.contains(clickedButton));
|
|
18708
|
-
console.log("[click-debug]", {
|
|
18709
|
-
editableType: editable.dataset.ohwEditable,
|
|
18710
|
-
editableTag: editable.tagName,
|
|
18711
|
-
targetTag: target.tagName,
|
|
18712
|
-
clickedButtonTag: clickedButton?.tagName ?? null,
|
|
18713
|
-
buttonOnMedia,
|
|
18714
|
-
isMediaEditableEditable: isMediaEditable(editable)
|
|
18715
|
-
});
|
|
18716
19251
|
if (isMediaEditable(editable) && !buttonOnMedia) {
|
|
18717
19252
|
e.preventDefault();
|
|
18718
19253
|
e.stopPropagation();
|
|
@@ -18739,11 +19274,6 @@ function OhhwellsBridge() {
|
|
|
18739
19274
|
const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
|
|
18740
19275
|
const hrefCtx = getHrefKeyFromElement(hrefLookupTarget);
|
|
18741
19276
|
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
18742
|
-
console.log("[click-debug 2]", {
|
|
18743
|
-
hrefLookupTargetTag: hrefLookupTarget.tagName,
|
|
18744
|
-
hrefCtx: hrefCtx ? { key: hrefCtx.key } : null,
|
|
18745
|
-
navAnchorTag: navAnchor?.tagName ?? null
|
|
18746
|
-
});
|
|
18747
19277
|
if (navAnchor) {
|
|
18748
19278
|
e.preventDefault();
|
|
18749
19279
|
e.stopPropagation();
|
|
@@ -18913,6 +19443,9 @@ function OhhwellsBridge() {
|
|
|
18913
19443
|
setHoveredItemRect(null);
|
|
18914
19444
|
hoveredNavContainerRef.current = null;
|
|
18915
19445
|
setHoveredNavContainerRect(null);
|
|
19446
|
+
siblingHintElRef.current = null;
|
|
19447
|
+
setSiblingHintRect(null);
|
|
19448
|
+
setSiblingHintRects([]);
|
|
18916
19449
|
return;
|
|
18917
19450
|
}
|
|
18918
19451
|
{
|
|
@@ -19031,7 +19564,6 @@ function OhhwellsBridge() {
|
|
|
19031
19564
|
hoveredNavContainerRef.current = null;
|
|
19032
19565
|
setHoveredNavContainerRect(null);
|
|
19033
19566
|
hoveredItemElRef.current = editable;
|
|
19034
|
-
setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
|
|
19035
19567
|
}
|
|
19036
19568
|
}
|
|
19037
19569
|
}
|
|
@@ -19328,7 +19860,7 @@ function OhhwellsBridge() {
|
|
|
19328
19860
|
}
|
|
19329
19861
|
};
|
|
19330
19862
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
19331
|
-
if (linkPopoverOpenRef.current) {
|
|
19863
|
+
if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
19332
19864
|
if (hoveredImageRef.current) {
|
|
19333
19865
|
hoveredImageRef.current = null;
|
|
19334
19866
|
hoveredImageHasTextOverlapRef.current = false;
|
|
@@ -19693,8 +20225,7 @@ function OhhwellsBridge() {
|
|
|
19693
20225
|
};
|
|
19694
20226
|
const handleMouseMove = (e) => {
|
|
19695
20227
|
const { clientX, clientY } = e;
|
|
19696
|
-
if (
|
|
19697
|
-
if (isOverEditorChrome(clientX, clientY)) {
|
|
20228
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
|
|
19698
20229
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
19699
20230
|
formHoverElRef.current = null;
|
|
19700
20231
|
setFormHoverRect(null);
|
|
@@ -19702,6 +20233,12 @@ function OhhwellsBridge() {
|
|
|
19702
20233
|
setHoveredItemRect(null);
|
|
19703
20234
|
hoveredNavContainerRef.current = null;
|
|
19704
20235
|
setHoveredNavContainerRect(null);
|
|
20236
|
+
siblingHintElRef.current = null;
|
|
20237
|
+
setSiblingHintRect(null);
|
|
20238
|
+
setSiblingHintRects([]);
|
|
20239
|
+
dismissImageHover();
|
|
20240
|
+
clearImageHover();
|
|
20241
|
+
setSectionGap(null);
|
|
19705
20242
|
return;
|
|
19706
20243
|
}
|
|
19707
20244
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
@@ -19713,7 +20250,11 @@ function OhhwellsBridge() {
|
|
|
19713
20250
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
19714
20251
|
const { clientX, clientY } = e.data;
|
|
19715
20252
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
19716
|
-
if (
|
|
20253
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
20254
|
+
dismissImageHover();
|
|
20255
|
+
clearImageHover();
|
|
20256
|
+
return;
|
|
20257
|
+
}
|
|
19717
20258
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
19718
20259
|
probeSectionGapAt(clientX, clientY);
|
|
19719
20260
|
probeImageAt(clientX, clientY);
|
|
@@ -19992,6 +20533,44 @@ function OhhwellsBridge() {
|
|
|
19992
20533
|
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
19993
20534
|
}, 400));
|
|
19994
20535
|
};
|
|
20536
|
+
const reapCommittedAiSections = (excludeIds) => {
|
|
20537
|
+
const aiState = parseAiSectionsState(aiSectionsRef.current);
|
|
20538
|
+
if (aiState.sections.length === 0) return [];
|
|
20539
|
+
let orderEntries = [];
|
|
20540
|
+
try {
|
|
20541
|
+
const parsed = JSON.parse(editContentRef.current[SECTION_ORDER_KEY] ?? "[]");
|
|
20542
|
+
if (Array.isArray(parsed)) orderEntries = parsed;
|
|
20543
|
+
} catch {
|
|
20544
|
+
return [];
|
|
20545
|
+
}
|
|
20546
|
+
const removedIds = orderEntries.filter((entry) => entry && typeof entry.instanceId === "string" && entry.removed).map((entry) => entry.instanceId);
|
|
20547
|
+
if (removedIds.length === 0) return [];
|
|
20548
|
+
const result = reapRemovedAiSections(aiState, parseStyleStore(stylesRef.current), removedIds, excludeIds);
|
|
20549
|
+
if (!result.changed) return [];
|
|
20550
|
+
const nodes = [];
|
|
20551
|
+
aiSectionsRef.current = serializeAiSectionsState(result.state);
|
|
20552
|
+
nodes.push({ key: AI_SECTIONS_KEY, text: aiSectionsRef.current });
|
|
20553
|
+
const reaped = new Set(result.reapedIds);
|
|
20554
|
+
const nextOrderJson = JSON.stringify(orderEntries.filter((entry) => !reaped.has(entry.instanceId)));
|
|
20555
|
+
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: nextOrderJson };
|
|
20556
|
+
setAiSectionOrder(nextOrderJson, window.location.pathname);
|
|
20557
|
+
nodes.push({ key: SECTION_ORDER_KEY, text: nextOrderJson });
|
|
20558
|
+
if (result.store) {
|
|
20559
|
+
stylesRef.current = JSON.stringify(result.store);
|
|
20560
|
+
nodes.push({ key: STYLE_STORE_KEY, text: stylesRef.current });
|
|
20561
|
+
}
|
|
20562
|
+
const nextContent = { ...editContentRef.current };
|
|
20563
|
+
for (const key of Object.keys(nextContent)) {
|
|
20564
|
+
if (key.startsWith(AI_SLOT_KEY_PREFIX) && result.slotPrefixes.some((prefix) => key.startsWith(prefix)) && nextContent[key] !== "") {
|
|
20565
|
+
nextContent[key] = "";
|
|
20566
|
+
nodes.push({ key, text: "" });
|
|
20567
|
+
}
|
|
20568
|
+
}
|
|
20569
|
+
editContentRef.current = nextContent;
|
|
20570
|
+
applyAiSectionsToDom(result.state);
|
|
20571
|
+
applyStylesToDom(parseStyleStore(stylesRef.current));
|
|
20572
|
+
return nodes;
|
|
20573
|
+
};
|
|
19995
20574
|
const handleHydrate = (e) => {
|
|
19996
20575
|
if (e.data?.type !== "ow:hydrate") return;
|
|
19997
20576
|
const content = e.data.content;
|
|
@@ -20010,9 +20589,11 @@ function OhhwellsBridge() {
|
|
|
20010
20589
|
}
|
|
20011
20590
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
20012
20591
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
20592
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
20013
20593
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
20014
20594
|
}
|
|
20015
20595
|
applyBrandChrome(content);
|
|
20596
|
+
initSectionInstancesFromContent(content, window.location.pathname);
|
|
20016
20597
|
let sectionsJson = null;
|
|
20017
20598
|
for (const [key, val] of Object.entries(content)) {
|
|
20018
20599
|
if (key === "__ohw_sections") {
|
|
@@ -20020,11 +20601,11 @@ function OhhwellsBridge() {
|
|
|
20020
20601
|
continue;
|
|
20021
20602
|
}
|
|
20022
20603
|
if (key === AI_SECTIONS_KEY) continue;
|
|
20604
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
20605
|
+
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
20023
20606
|
if (key === BRAND_KIT_KEY) continue;
|
|
20024
20607
|
if (key === STYLE_STORE_KEY) continue;
|
|
20025
20608
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
20026
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
20027
|
-
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
20028
20609
|
if (applyVideoSettingNode(key, val)) continue;
|
|
20029
20610
|
if (applyCarouselNode(key, val)) continue;
|
|
20030
20611
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -20038,6 +20619,8 @@ function OhhwellsBridge() {
|
|
|
20038
20619
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
20039
20620
|
} else if (el.dataset.ohwEditable === "link") {
|
|
20040
20621
|
applyLinkHref(el, val);
|
|
20622
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
20623
|
+
applyMapQuery(el, val);
|
|
20041
20624
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
20042
20625
|
applyIconMarkup(el, val);
|
|
20043
20626
|
} else if (isIconMarkupValue(val)) {
|
|
@@ -20054,12 +20637,16 @@ function OhhwellsBridge() {
|
|
|
20054
20637
|
sectionsLoadedRef.current = true;
|
|
20055
20638
|
pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
|
|
20056
20639
|
}
|
|
20057
|
-
initSectionInstancesFromContent(content, window.location.pathname);
|
|
20058
20640
|
editContentRef.current = { ...editContentRef.current, ...content };
|
|
20059
20641
|
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
20060
20642
|
reconcileFooterOrderFromContent(editContentRef.current);
|
|
20061
20643
|
syncNavigationDragCursorAttrs();
|
|
20062
20644
|
enforceLinkHrefs();
|
|
20645
|
+
const hydrateReapExclude = /* @__PURE__ */ new Set();
|
|
20646
|
+
const hydratePendingUndo = pendingDeleteUndoRef.current;
|
|
20647
|
+
if (hydratePendingUndo?.sectionInstanceId) hydrateReapExclude.add(hydratePendingUndo.sectionInstanceId);
|
|
20648
|
+
const reapNodes = reapCommittedAiSections(hydrateReapExclude);
|
|
20649
|
+
if (reapNodes.length > 0) postToParentRef.current({ type: "ow:change", nodes: reapNodes });
|
|
20063
20650
|
const hydratedHeight = document.body.scrollHeight;
|
|
20064
20651
|
if (hydratedHeight > 50) postToParentRef.current({ type: "ow:height", height: hydratedHeight });
|
|
20065
20652
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
@@ -20199,12 +20786,35 @@ function OhhwellsBridge() {
|
|
|
20199
20786
|
window.addEventListener("message", handleAiSetBrand);
|
|
20200
20787
|
const handleAiSetStyles = (e) => {
|
|
20201
20788
|
if (e.data?.type !== "ow:ai-set-styles") return;
|
|
20202
|
-
|
|
20789
|
+
let value = typeof e.data.value === "string" ? e.data.value : "";
|
|
20203
20790
|
const previous = stylesRef.current;
|
|
20791
|
+
let previousSections;
|
|
20792
|
+
const store = parseStyleStore(value);
|
|
20793
|
+
if (store) {
|
|
20794
|
+
const folded = foldAlignIntoTrees(parseAiSectionsState(aiSectionsRef.current), store);
|
|
20795
|
+
if (folded.changed) {
|
|
20796
|
+
const nextSections = serializeAiSectionsState(folded.state);
|
|
20797
|
+
if (nextSections !== aiSectionsRef.current) {
|
|
20798
|
+
previousSections = aiSectionsRef.current;
|
|
20799
|
+
aiSectionsRef.current = nextSections;
|
|
20800
|
+
applyAiSectionsToDom(folded.state);
|
|
20801
|
+
postToParentRef.current({
|
|
20802
|
+
type: "ow:change",
|
|
20803
|
+
nodes: [{ key: AI_SECTIONS_KEY, text: nextSections }]
|
|
20804
|
+
});
|
|
20805
|
+
}
|
|
20806
|
+
value = JSON.stringify(folded.store);
|
|
20807
|
+
}
|
|
20808
|
+
}
|
|
20204
20809
|
stylesRef.current = value;
|
|
20205
20810
|
applyStylesToDom(parseStyleStore(value));
|
|
20206
20811
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: STYLE_STORE_KEY, text: value }] });
|
|
20207
|
-
postToParentRef.current({
|
|
20812
|
+
postToParentRef.current({
|
|
20813
|
+
type: "ow:ai-styles-applied",
|
|
20814
|
+
previous,
|
|
20815
|
+
value,
|
|
20816
|
+
...previousSections !== void 0 ? { previousSections } : {}
|
|
20817
|
+
});
|
|
20208
20818
|
};
|
|
20209
20819
|
window.addEventListener("message", handleAiSetStyles);
|
|
20210
20820
|
const handleGetBrand = (e) => {
|
|
@@ -20243,6 +20853,7 @@ function OhhwellsBridge() {
|
|
|
20243
20853
|
if (!entries) return;
|
|
20244
20854
|
const orderJson = JSON.stringify(entries);
|
|
20245
20855
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
20856
|
+
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20246
20857
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
20247
20858
|
aiSectionApiRef.current?.clear();
|
|
20248
20859
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20251,6 +20862,7 @@ function OhhwellsBridge() {
|
|
|
20251
20862
|
const actionId = newInstanceId();
|
|
20252
20863
|
pendingDeleteUndoRef.current = {
|
|
20253
20864
|
actionId,
|
|
20865
|
+
sectionInstanceId: instanceId,
|
|
20254
20866
|
restore: () => {
|
|
20255
20867
|
const restoredEntries = getPageSectionOrderEntries(
|
|
20256
20868
|
editContentRef.current[SECTION_ORDER_KEY],
|
|
@@ -20260,6 +20872,7 @@ function OhhwellsBridge() {
|
|
|
20260
20872
|
if (!restored) return;
|
|
20261
20873
|
const restoredJson = JSON.stringify(restored);
|
|
20262
20874
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: restoredJson };
|
|
20875
|
+
setAiSectionOrder(restoredJson, window.location.pathname);
|
|
20263
20876
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: restoredJson }] });
|
|
20264
20877
|
window.dispatchEvent(new Event("resize"));
|
|
20265
20878
|
const restoreHeight = document.body.scrollHeight;
|
|
@@ -20276,6 +20889,34 @@ function OhhwellsBridge() {
|
|
|
20276
20889
|
});
|
|
20277
20890
|
};
|
|
20278
20891
|
window.addEventListener("message", handleDeleteSection);
|
|
20892
|
+
const handleDuplicateSection = (e) => {
|
|
20893
|
+
if (e.data?.type !== "ow:duplicate-section") return;
|
|
20894
|
+
const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
|
|
20895
|
+
if (!instanceId) return;
|
|
20896
|
+
const newId = newInstanceId();
|
|
20897
|
+
const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname);
|
|
20898
|
+
const result = duplicateSectionInstance(instanceId, newId, window.location.pathname, currentEntries);
|
|
20899
|
+
if (!result) return;
|
|
20900
|
+
const { entries, keyRekeys } = result;
|
|
20901
|
+
const orderJson = JSON.stringify(entries);
|
|
20902
|
+
const nodes = [{ key: SECTION_ORDER_KEY, text: orderJson }];
|
|
20903
|
+
for (const { from, to } of keyRekeys) {
|
|
20904
|
+
const inherited = editContentRef.current[from];
|
|
20905
|
+
if (inherited !== void 0) nodes.push({ key: to, text: inherited });
|
|
20906
|
+
}
|
|
20907
|
+
editContentRef.current = {
|
|
20908
|
+
...editContentRef.current,
|
|
20909
|
+
...Object.fromEntries(nodes.map(({ key, text }) => [key, text]))
|
|
20910
|
+
};
|
|
20911
|
+
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20912
|
+
postToParentRef.current({ type: "ow:change", nodes });
|
|
20913
|
+
window.dispatchEvent(new Event("resize"));
|
|
20914
|
+
const duplicateHeight = document.body.scrollHeight;
|
|
20915
|
+
if (duplicateHeight > 50) postToParentRef.current({ type: "ow:height", height: duplicateHeight });
|
|
20916
|
+
const clone = document.querySelector(`[data-ohw-instance="${CSS.escape(newId)}"]`);
|
|
20917
|
+
if (clone) aiSectionApiRef.current?.selectFromElement(clone);
|
|
20918
|
+
};
|
|
20919
|
+
window.addEventListener("message", handleDuplicateSection);
|
|
20279
20920
|
const handleDeactivate = (e) => {
|
|
20280
20921
|
if (e.data?.type !== "ow:deactivate") return;
|
|
20281
20922
|
if (document.documentElement.hasAttribute("data-ohw-panel-dragging")) return;
|
|
@@ -20285,6 +20926,12 @@ function OhhwellsBridge() {
|
|
|
20285
20926
|
closeLinkPopoverRef.current();
|
|
20286
20927
|
return;
|
|
20287
20928
|
}
|
|
20929
|
+
if (floatingPanelOpenRef.current) {
|
|
20930
|
+
setFloatingPanelRef.current(null);
|
|
20931
|
+
deselectRef.current();
|
|
20932
|
+
deactivateRef.current();
|
|
20933
|
+
return;
|
|
20934
|
+
}
|
|
20288
20935
|
deselectRef.current();
|
|
20289
20936
|
deactivateRef.current();
|
|
20290
20937
|
clearMediaSelectionRef.current();
|
|
@@ -20530,6 +21177,10 @@ function OhhwellsBridge() {
|
|
|
20530
21177
|
};
|
|
20531
21178
|
const handleSave = (e) => {
|
|
20532
21179
|
if (e.data?.type !== "ow:save") return;
|
|
21180
|
+
const pendingUndo = pendingDeleteUndoRef.current;
|
|
21181
|
+
const reapExclude = /* @__PURE__ */ new Set();
|
|
21182
|
+
if (pendingUndo?.sectionInstanceId) reapExclude.add(pendingUndo.sectionInstanceId);
|
|
21183
|
+
const reapNodes = reapCommittedAiSections(reapExclude);
|
|
20533
21184
|
const nodes = collectEditableNodes(editContentRef.current);
|
|
20534
21185
|
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
20535
21186
|
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
@@ -20549,6 +21200,11 @@ function OhhwellsBridge() {
|
|
|
20549
21200
|
const text = specs.length ? JSON.stringify(specs) : editContentRef.current[fieldsKey(formKey)];
|
|
20550
21201
|
if (text) nodes.push({ key: fieldsKey(formKey), type: "text", text });
|
|
20551
21202
|
});
|
|
21203
|
+
for (const reapNode of reapNodes) {
|
|
21204
|
+
if (reapNode.key.startsWith(AI_SLOT_KEY_PREFIX) && !nodes.some((n) => n.key === reapNode.key)) {
|
|
21205
|
+
nodes.push({ key: reapNode.key, type: "text", text: reapNode.text });
|
|
21206
|
+
}
|
|
21207
|
+
}
|
|
20552
21208
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
20553
21209
|
};
|
|
20554
21210
|
const handleInsertSection = (e) => {
|
|
@@ -20559,8 +21215,12 @@ function OhhwellsBridge() {
|
|
|
20559
21215
|
if (inserted) {
|
|
20560
21216
|
const tracker = getSectionsTracker();
|
|
20561
21217
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
|
|
20562
|
-
const
|
|
20563
|
-
|
|
21218
|
+
const reportHeight = () => {
|
|
21219
|
+
const h = document.body.scrollHeight;
|
|
21220
|
+
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
21221
|
+
};
|
|
21222
|
+
reportHeight();
|
|
21223
|
+
setTimeout(reportHeight, 500);
|
|
20564
21224
|
}
|
|
20565
21225
|
};
|
|
20566
21226
|
const handleSwitchSchedule = (e) => {
|
|
@@ -20962,11 +21622,12 @@ function OhhwellsBridge() {
|
|
|
20962
21622
|
window.removeEventListener("message", handleMoveSection);
|
|
20963
21623
|
window.removeEventListener("message", handlePanelDragging);
|
|
20964
21624
|
window.removeEventListener("message", handleDeleteSection);
|
|
21625
|
+
window.removeEventListener("message", handleDuplicateSection);
|
|
20965
21626
|
window.removeEventListener("message", handleDeactivate);
|
|
20966
|
-
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
20967
21627
|
window.removeEventListener("message", handleToastAction);
|
|
20968
21628
|
window.removeEventListener("message", handleFormCount);
|
|
20969
21629
|
window.removeEventListener("message", handleUiEscape);
|
|
21630
|
+
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
20970
21631
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
20971
21632
|
autoSaveTimers.current.clear();
|
|
20972
21633
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
@@ -21169,7 +21830,7 @@ function OhhwellsBridge() {
|
|
|
21169
21830
|
postToParent2({
|
|
21170
21831
|
type: "ow:ready",
|
|
21171
21832
|
version: "1",
|
|
21172
|
-
bridgeVersion: "0.1.
|
|
21833
|
+
bridgeVersion: "0.1.86",
|
|
21173
21834
|
path: pathname,
|
|
21174
21835
|
nodes: collectEditableNodes(editContentRef.current),
|
|
21175
21836
|
sections
|
|
@@ -22088,6 +22749,59 @@ function OhhwellsBridge() {
|
|
|
22088
22749
|
) : null
|
|
22089
22750
|
] });
|
|
22090
22751
|
}
|
|
22752
|
+
|
|
22753
|
+
// src/ui/EmptySection.tsx
|
|
22754
|
+
import Link3 from "next/link";
|
|
22755
|
+
import { Fragment as Fragment9, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
22756
|
+
function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
|
|
22757
|
+
return /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
22758
|
+
/* @__PURE__ */ jsx34(
|
|
22759
|
+
"p",
|
|
22760
|
+
{
|
|
22761
|
+
style: {
|
|
22762
|
+
fontFamily: "var(--brand-font-body)",
|
|
22763
|
+
fontSize: "0.75rem",
|
|
22764
|
+
fontWeight: 500,
|
|
22765
|
+
letterSpacing: "0.15em",
|
|
22766
|
+
textTransform: "uppercase",
|
|
22767
|
+
color: "var(--brand-accent)",
|
|
22768
|
+
marginBottom: "1.5rem"
|
|
22769
|
+
},
|
|
22770
|
+
children: /* @__PURE__ */ jsx34(Link3, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ jsx34("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
|
|
22771
|
+
}
|
|
22772
|
+
),
|
|
22773
|
+
/* @__PURE__ */ jsx34(
|
|
22774
|
+
"h1",
|
|
22775
|
+
{
|
|
22776
|
+
style: {
|
|
22777
|
+
fontFamily: "var(--brand-font-heading)",
|
|
22778
|
+
fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
|
|
22779
|
+
lineHeight: 1.1,
|
|
22780
|
+
letterSpacing: "-0.025em",
|
|
22781
|
+
color: "var(--brand-text)",
|
|
22782
|
+
marginBottom: "1rem"
|
|
22783
|
+
},
|
|
22784
|
+
...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
|
|
22785
|
+
children: title
|
|
22786
|
+
}
|
|
22787
|
+
),
|
|
22788
|
+
/* @__PURE__ */ jsx34(
|
|
22789
|
+
"p",
|
|
22790
|
+
{
|
|
22791
|
+
style: {
|
|
22792
|
+
fontFamily: "var(--brand-font-body)",
|
|
22793
|
+
fontSize: "1rem",
|
|
22794
|
+
lineHeight: 1.7,
|
|
22795
|
+
fontWeight: 300,
|
|
22796
|
+
color: "var(--brand-text-muted)",
|
|
22797
|
+
maxWidth: "340px"
|
|
22798
|
+
},
|
|
22799
|
+
...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
|
|
22800
|
+
children: "This page doesn't have any content yet."
|
|
22801
|
+
}
|
|
22802
|
+
)
|
|
22803
|
+
] });
|
|
22804
|
+
}
|
|
22091
22805
|
export {
|
|
22092
22806
|
AI_DEFAULT_BRAND,
|
|
22093
22807
|
AI_TREE_SCHEMA_VERSIONS,
|
|
@@ -22104,6 +22818,7 @@ export {
|
|
|
22104
22818
|
DropdownMenuItem,
|
|
22105
22819
|
DropdownMenuSeparator,
|
|
22106
22820
|
DropdownMenuTrigger,
|
|
22821
|
+
EmptySection,
|
|
22107
22822
|
ItemActionToolbar,
|
|
22108
22823
|
ItemInteractionLayer,
|
|
22109
22824
|
LinkEditorPanel,
|