@ohhwells/bridge 0.1.85 → 0.1.86-next.256
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1121 -365
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -4
- package/dist/index.d.ts +32 -4
- package/dist/index.js +1120 -365
- package/dist/index.js.map +1 -1
- package/dist/pages.cjs +141 -0
- package/dist/pages.cjs.map +1 -0
- package/dist/pages.d.cts +45 -0
- package/dist/pages.d.ts +45 -0
- package/dist/pages.js +107 -0
- package/dist/pages.js.map +1 -0
- package/dist/styles.css +55 -0
- package/package.json +8 -3
package/dist/index.cjs
CHANGED
|
@@ -46,6 +46,7 @@ __export(index_exports, {
|
|
|
46
46
|
DropdownMenuItem: () => DropdownMenuItem,
|
|
47
47
|
DropdownMenuSeparator: () => DropdownMenuSeparator,
|
|
48
48
|
DropdownMenuTrigger: () => DropdownMenuTrigger,
|
|
49
|
+
EmptySection: () => EmptySection,
|
|
49
50
|
ItemActionToolbar: () => ItemActionToolbar,
|
|
50
51
|
ItemInteractionLayer: () => ItemInteractionLayer,
|
|
51
52
|
LinkEditorPanel: () => LinkEditorPanel,
|
|
@@ -142,6 +143,10 @@ function isRenderableTree(value) {
|
|
|
142
143
|
|
|
143
144
|
// src/lib/ai-sections-store.ts
|
|
144
145
|
var AI_SECTIONS_KEY = "__ohw_ai_sections";
|
|
146
|
+
var AI_SLOT_KEY_PREFIX = "ai.";
|
|
147
|
+
function aiSlotKeyPrefixFor(sectionId) {
|
|
148
|
+
return `${AI_SLOT_KEY_PREFIX}${sectionId}.`;
|
|
149
|
+
}
|
|
145
150
|
var EMPTY_AI_SECTIONS = { v: 1, sections: [] };
|
|
146
151
|
function parseAiSectionsState(raw) {
|
|
147
152
|
if (!raw) return EMPTY_AI_SECTIONS;
|
|
@@ -185,6 +190,63 @@ function applyTreeToState(state, payload) {
|
|
|
185
190
|
const others = state.sections.filter((existing) => existing.id !== entry.id);
|
|
186
191
|
return { ...state, v: 1, sections: [...others, entry] };
|
|
187
192
|
}
|
|
193
|
+
function foldAlignIntoTrees(state, store) {
|
|
194
|
+
const byId = new Map(state.sections.map((entry) => [entry.id, entry]));
|
|
195
|
+
const nextTrees = /* @__PURE__ */ new Map();
|
|
196
|
+
const treeFor = (id) => {
|
|
197
|
+
const cloned = nextTrees.get(id);
|
|
198
|
+
if (cloned) return cloned;
|
|
199
|
+
const entry = byId.get(id);
|
|
200
|
+
if (!entry) return void 0;
|
|
201
|
+
const fresh = {
|
|
202
|
+
...entry.tree,
|
|
203
|
+
rows: entry.tree.rows.map((row) => ({ ...row, blocks: row.blocks.map((block) => ({ ...block })) }))
|
|
204
|
+
};
|
|
205
|
+
nextTrees.set(id, fresh);
|
|
206
|
+
return fresh;
|
|
207
|
+
};
|
|
208
|
+
const nodes = {};
|
|
209
|
+
for (const [key, override] of Object.entries(store.nodes)) {
|
|
210
|
+
const match = override.align !== void 0 && key.startsWith(AI_SLOT_KEY_PREFIX) ? key.match(/^ai\.(.+?)\.r(\d+)\.b(\d+)(?:\.|$)/) : null;
|
|
211
|
+
const tree = match ? treeFor(match[1]) : void 0;
|
|
212
|
+
const block = match && tree ? tree.rows[Number(match[2])]?.blocks[Number(match[3])] : void 0;
|
|
213
|
+
if (!block) {
|
|
214
|
+
nodes[key] = override;
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
block.align = override.align;
|
|
218
|
+
const rest = { ...override };
|
|
219
|
+
delete rest.align;
|
|
220
|
+
if (Object.keys(rest).length > 0) nodes[key] = rest;
|
|
221
|
+
}
|
|
222
|
+
const sections = {};
|
|
223
|
+
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
224
|
+
const tree = override.align !== void 0 ? treeFor(sectionId) : void 0;
|
|
225
|
+
if (!tree) {
|
|
226
|
+
sections[sectionId] = override;
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
for (const row of tree.rows) {
|
|
230
|
+
for (const block of row.blocks) block.align = override.align;
|
|
231
|
+
}
|
|
232
|
+
const rest = { ...override };
|
|
233
|
+
delete rest.align;
|
|
234
|
+
if (Object.keys(rest).length > 0) sections[sectionId] = rest;
|
|
235
|
+
}
|
|
236
|
+
if (nextTrees.size === 0) return { state, store, changed: false };
|
|
237
|
+
return {
|
|
238
|
+
state: {
|
|
239
|
+
...state,
|
|
240
|
+
v: 1,
|
|
241
|
+
sections: state.sections.map((entry) => {
|
|
242
|
+
const tree = nextTrees.get(entry.id);
|
|
243
|
+
return tree ? { ...entry, tree } : entry;
|
|
244
|
+
})
|
|
245
|
+
},
|
|
246
|
+
store: { v: 1, sections, nodes },
|
|
247
|
+
changed: true
|
|
248
|
+
};
|
|
249
|
+
}
|
|
188
250
|
function removeFromState(state, id) {
|
|
189
251
|
return { ...state, v: 1, sections: state.sections.filter((entry) => entry.id !== id) };
|
|
190
252
|
}
|
|
@@ -196,6 +258,33 @@ function deleteSectionFromState(state, sectionId) {
|
|
|
196
258
|
if (removed.includes(sectionId)) return state;
|
|
197
259
|
return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
|
|
198
260
|
}
|
|
261
|
+
function reapRemovedAiSections(state, store, removedIds, excludeIds = /* @__PURE__ */ new Set()) {
|
|
262
|
+
const generated = new Set(state.sections.map((entry) => entry.id));
|
|
263
|
+
const reapedIds = [...new Set(removedIds)].filter((id) => generated.has(id) && !excludeIds.has(id));
|
|
264
|
+
if (reapedIds.length === 0) {
|
|
265
|
+
return { state, store, reapedIds: [], slotPrefixes: [], changed: false };
|
|
266
|
+
}
|
|
267
|
+
const reaped = new Set(reapedIds);
|
|
268
|
+
const slotPrefixes = reapedIds.map(aiSlotKeyPrefixFor);
|
|
269
|
+
const nextState = {
|
|
270
|
+
...state,
|
|
271
|
+
v: 1,
|
|
272
|
+
sections: state.sections.filter((entry) => !reaped.has(entry.id))
|
|
273
|
+
};
|
|
274
|
+
let nextStore = store;
|
|
275
|
+
if (store) {
|
|
276
|
+
const sections = {};
|
|
277
|
+
for (const [key, override] of Object.entries(store.sections)) {
|
|
278
|
+
if (!reaped.has(key)) sections[key] = override;
|
|
279
|
+
}
|
|
280
|
+
const nodes = {};
|
|
281
|
+
for (const [key, override] of Object.entries(store.nodes)) {
|
|
282
|
+
if (!slotPrefixes.some((prefix) => key.startsWith(prefix))) nodes[key] = override;
|
|
283
|
+
}
|
|
284
|
+
nextStore = { v: 1, sections, nodes };
|
|
285
|
+
}
|
|
286
|
+
return { state: nextState, store: nextStore, reapedIds, slotPrefixes, changed: true };
|
|
287
|
+
}
|
|
199
288
|
|
|
200
289
|
// src/lib/brand-chrome.ts
|
|
201
290
|
var BRAND_NAME_KEY = "__ohw_brand_name";
|
|
@@ -403,6 +492,12 @@ function styleSheetCss() {
|
|
|
403
492
|
`[data-ohw-style-spacing="${spacing}"] { padding-top: ${px}px !important; padding-bottom: ${px}px !important; }`
|
|
404
493
|
);
|
|
405
494
|
}
|
|
495
|
+
rules.push(
|
|
496
|
+
`[data-ohw-style-corners="sharp"] :is(.card, [data-ohw-card]) { border-radius: 0 !important; }`
|
|
497
|
+
);
|
|
498
|
+
for (const align of ["left", "center", "right"]) {
|
|
499
|
+
rules.push(`[data-ohw-style-align="${align}"] { text-align: ${align} !important; }`);
|
|
500
|
+
}
|
|
406
501
|
return rules.join("\n");
|
|
407
502
|
}
|
|
408
503
|
var STYLE_FONT_LINK_ID = "ohw-style-fonts";
|
|
@@ -429,10 +524,25 @@ var SECTION_ATTRS = {
|
|
|
429
524
|
textDistribution: "data-ohw-style-distribution",
|
|
430
525
|
headlineScale: "data-ohw-style-headline",
|
|
431
526
|
imageAspect: "data-ohw-style-aspect",
|
|
432
|
-
spacing: "data-ohw-style-spacing"
|
|
527
|
+
spacing: "data-ohw-style-spacing",
|
|
528
|
+
cornerStyle: "data-ohw-style-corners",
|
|
529
|
+
align: "data-ohw-style-align"
|
|
433
530
|
};
|
|
434
531
|
var NODE_WROTE_ATTR = "data-ohw-style-node";
|
|
435
|
-
var NODE_PROPS = [
|
|
532
|
+
var NODE_PROPS = [
|
|
533
|
+
"color",
|
|
534
|
+
"font-family",
|
|
535
|
+
"font-size",
|
|
536
|
+
"background",
|
|
537
|
+
"text-align",
|
|
538
|
+
"justify-content",
|
|
539
|
+
"align-items"
|
|
540
|
+
];
|
|
541
|
+
var ALIGN_JUSTIFY = {
|
|
542
|
+
left: "flex-start",
|
|
543
|
+
center: "center",
|
|
544
|
+
right: "flex-end"
|
|
545
|
+
};
|
|
436
546
|
function saveInline(el, prop) {
|
|
437
547
|
const attr = `data-ohw-style-prev-${prop}`;
|
|
438
548
|
if (el.hasAttribute(attr)) return;
|
|
@@ -476,6 +586,10 @@ function clearNodeProps(root) {
|
|
|
476
586
|
function buttonSurfaceOf(el) {
|
|
477
587
|
return el.closest("a, button") ?? el;
|
|
478
588
|
}
|
|
589
|
+
function alignSubjectOf(el) {
|
|
590
|
+
const button = el.closest('[data-ohw-role="button"]');
|
|
591
|
+
return button?.parentElement ?? el;
|
|
592
|
+
}
|
|
479
593
|
function applyStylesToDom(store) {
|
|
480
594
|
ensureStyleSheet();
|
|
481
595
|
clearSectionAttrs(document);
|
|
@@ -521,6 +635,18 @@ function applyStylesToDom(store) {
|
|
|
521
635
|
el.style.setProperty("font-size", `${override.fontSize}px`, "important");
|
|
522
636
|
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
523
637
|
}
|
|
638
|
+
if (override.align !== void 0) {
|
|
639
|
+
const subject = alignSubjectOf(el);
|
|
640
|
+
saveInline(subject, "text-align");
|
|
641
|
+
saveInline(subject, "justify-content");
|
|
642
|
+
subject.style.setProperty("text-align", override.align, "important");
|
|
643
|
+
subject.style.setProperty(
|
|
644
|
+
"justify-content",
|
|
645
|
+
ALIGN_JUSTIFY[override.align] ?? "flex-start",
|
|
646
|
+
"important"
|
|
647
|
+
);
|
|
648
|
+
subject.setAttribute(NODE_WROTE_ATTR, "");
|
|
649
|
+
}
|
|
524
650
|
if (override.buttonBackground !== void 0 || override.buttonText !== void 0) {
|
|
525
651
|
const surface = buttonSurfaceOf(el);
|
|
526
652
|
if (override.buttonBackground !== void 0) {
|
|
@@ -541,9 +667,494 @@ function applyStylesToDom(store) {
|
|
|
541
667
|
var import_react_dom = require("react-dom");
|
|
542
668
|
var import_client = require("react-dom/client");
|
|
543
669
|
|
|
670
|
+
// src/lib/sections.ts
|
|
671
|
+
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
672
|
+
function isChromeSection(el) {
|
|
673
|
+
return el.matches("header, nav, footer, aside");
|
|
674
|
+
}
|
|
675
|
+
function titleCaseSectionId(id) {
|
|
676
|
+
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
677
|
+
}
|
|
678
|
+
function parseSectionsFromRoot(root) {
|
|
679
|
+
const seen = /* @__PURE__ */ new Set();
|
|
680
|
+
const sections = [];
|
|
681
|
+
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
682
|
+
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
683
|
+
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
684
|
+
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
685
|
+
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
686
|
+
continue;
|
|
687
|
+
seen.add(id);
|
|
688
|
+
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
689
|
+
sections.push({ id, label });
|
|
690
|
+
}
|
|
691
|
+
return sections;
|
|
692
|
+
}
|
|
693
|
+
function collectSectionsFromDom() {
|
|
694
|
+
if (typeof document === "undefined") return [];
|
|
695
|
+
return parseSectionsFromRoot(document);
|
|
696
|
+
}
|
|
697
|
+
function parseSectionsFromHtml(html) {
|
|
698
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
699
|
+
return parseSectionsFromRoot(doc);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// src/lib/section-instances.ts
|
|
703
|
+
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
704
|
+
var REMOVED_ATTR = "data-ohw-section-removed";
|
|
705
|
+
function isRemovedSection(el) {
|
|
706
|
+
return el.hasAttribute(REMOVED_ATTR);
|
|
707
|
+
}
|
|
708
|
+
function topLevelSections() {
|
|
709
|
+
return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
710
|
+
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el) && !isRemovedSection(el)
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
function instanceIdOf(el) {
|
|
714
|
+
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
715
|
+
}
|
|
716
|
+
function findByInstanceId(instanceId) {
|
|
717
|
+
const escapedId = CSS.escape(instanceId);
|
|
718
|
+
return document.querySelector(`[data-ohw-instance="${escapedId}"]`) ?? document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
719
|
+
}
|
|
720
|
+
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
721
|
+
const sections = topLevelSections();
|
|
722
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
723
|
+
if (index === -1) return null;
|
|
724
|
+
const dragged = sections[index];
|
|
725
|
+
const others = sections.filter((_, i) => i !== index);
|
|
726
|
+
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
727
|
+
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
728
|
+
return reordered.map((el, order) => ({
|
|
729
|
+
instanceId: instanceIdOf(el),
|
|
730
|
+
type: el.getAttribute("data-ohw-section") ?? "",
|
|
731
|
+
order,
|
|
732
|
+
pagePath: currentPath
|
|
733
|
+
}));
|
|
734
|
+
}
|
|
735
|
+
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
736
|
+
const sections = topLevelSections();
|
|
737
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
738
|
+
if (index === -1) return null;
|
|
739
|
+
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
740
|
+
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
741
|
+
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
742
|
+
if (!entries) return null;
|
|
743
|
+
applyPersistedOrder(entries);
|
|
744
|
+
return entries;
|
|
745
|
+
}
|
|
746
|
+
function syncRemovedFlags(entries) {
|
|
747
|
+
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
748
|
+
document.querySelectorAll(`[${REMOVED_ATTR}]`).forEach((el) => {
|
|
749
|
+
if (!removedIds.has(instanceIdOf(el))) {
|
|
750
|
+
el.style.removeProperty("display");
|
|
751
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
for (const id of removedIds) {
|
|
755
|
+
const el = findByInstanceId(id);
|
|
756
|
+
if (el) {
|
|
757
|
+
el.style.display = "none";
|
|
758
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
function applyPersistedOrder(entries) {
|
|
763
|
+
syncRemovedFlags(entries);
|
|
764
|
+
if (entries.length === 0) return;
|
|
765
|
+
const sections = topLevelSections();
|
|
766
|
+
if (sections.length === 0) return;
|
|
767
|
+
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
768
|
+
const ordered = [...sections].sort((a, b) => {
|
|
769
|
+
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
770
|
+
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
771
|
+
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
772
|
+
if (aOrder === void 0) return 1;
|
|
773
|
+
if (bOrder === void 0) return -1;
|
|
774
|
+
return aOrder - bOrder;
|
|
775
|
+
});
|
|
776
|
+
let prev = null;
|
|
777
|
+
for (const el of ordered) {
|
|
778
|
+
if (prev) prev.after(el);
|
|
779
|
+
prev = el;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
783
|
+
if (!findByInstanceId(instanceId)) return null;
|
|
784
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
785
|
+
const allSections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
786
|
+
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
|
|
787
|
+
);
|
|
788
|
+
allSections.forEach((el, order) => {
|
|
789
|
+
const id = instanceIdOf(el);
|
|
790
|
+
if (!byId.has(id)) {
|
|
791
|
+
byId.set(id, { instanceId: id, type: el.getAttribute("data-ohw-section") ?? "", order, pagePath: currentPath });
|
|
792
|
+
}
|
|
793
|
+
});
|
|
794
|
+
const target = byId.get(instanceId);
|
|
795
|
+
if (!target) return null;
|
|
796
|
+
byId.set(instanceId, { ...target, removed });
|
|
797
|
+
const entries = Array.from(byId.values());
|
|
798
|
+
applyPersistedOrder(entries);
|
|
799
|
+
return entries;
|
|
800
|
+
}
|
|
801
|
+
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
802
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
803
|
+
}
|
|
804
|
+
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
805
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
806
|
+
}
|
|
807
|
+
function duplicateSectionInstance(instanceId, newId, currentPath, existingEntries) {
|
|
808
|
+
const original = findByInstanceId(instanceId);
|
|
809
|
+
if (!original) return null;
|
|
810
|
+
const clone = original.cloneNode(true);
|
|
811
|
+
clone.setAttribute("data-ohw-instance", newId);
|
|
812
|
+
const keyRekeys = rekeySectionSubtree(clone, newId);
|
|
813
|
+
original.insertAdjacentElement("afterend", clone);
|
|
814
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
815
|
+
const entries = topLevelSections().map((el, order) => {
|
|
816
|
+
const id = instanceIdOf(el);
|
|
817
|
+
return {
|
|
818
|
+
instanceId: id,
|
|
819
|
+
type: el.getAttribute("data-ohw-section") ?? "",
|
|
820
|
+
order,
|
|
821
|
+
pagePath: currentPath,
|
|
822
|
+
...byId.get(id)?.removed ? { removed: true } : {}
|
|
823
|
+
};
|
|
824
|
+
});
|
|
825
|
+
applyPersistedOrder(entries);
|
|
826
|
+
return { entries, keyRekeys };
|
|
827
|
+
}
|
|
828
|
+
function newInstanceId() {
|
|
829
|
+
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
830
|
+
}
|
|
831
|
+
function getPageSectionOrderEntries(raw, currentPath) {
|
|
832
|
+
if (!raw) return [];
|
|
833
|
+
try {
|
|
834
|
+
const entries = JSON.parse(raw);
|
|
835
|
+
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
836
|
+
} catch {
|
|
837
|
+
return [];
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
function rekeySectionSubtree(root, instanceId) {
|
|
841
|
+
const suffix = `::${instanceId}`;
|
|
842
|
+
const pairs = [];
|
|
843
|
+
const rekey = (el, attr) => {
|
|
844
|
+
const current = el.getAttribute(attr);
|
|
845
|
+
if (!current) return;
|
|
846
|
+
const base = current.includes("::") ? current.slice(0, current.indexOf("::")) : current;
|
|
847
|
+
const next = `${base}${suffix}`;
|
|
848
|
+
el.setAttribute(attr, next);
|
|
849
|
+
pairs.push({ from: current, to: next });
|
|
850
|
+
};
|
|
851
|
+
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
852
|
+
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
853
|
+
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
854
|
+
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
855
|
+
return pairs;
|
|
856
|
+
}
|
|
857
|
+
function initSectionInstancesFromContent(content, currentPath) {
|
|
858
|
+
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
859
|
+
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
860
|
+
});
|
|
861
|
+
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
862
|
+
for (const entry of entries) {
|
|
863
|
+
if (entry.instanceId === entry.type) continue;
|
|
864
|
+
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
865
|
+
const original = document.querySelector(
|
|
866
|
+
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
867
|
+
);
|
|
868
|
+
if (!original) continue;
|
|
869
|
+
const clone = original.cloneNode(true);
|
|
870
|
+
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
871
|
+
rekeySectionSubtree(clone, entry.instanceId);
|
|
872
|
+
original.insertAdjacentElement("afterend", clone);
|
|
873
|
+
}
|
|
874
|
+
applyPersistedOrder(entries);
|
|
875
|
+
}
|
|
876
|
+
|
|
544
877
|
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
545
878
|
var import_react = __toESM(require("react"), 1);
|
|
546
879
|
var import_lucide_react = require("lucide-react");
|
|
880
|
+
|
|
881
|
+
// src/lib/placeholder-imagery.ts
|
|
882
|
+
var U = (id) => `https://images.unsplash.com/photo-${id}?auto=format&fit=crop&w=1600&q=80`;
|
|
883
|
+
var GENERIC = [
|
|
884
|
+
U("1441986300917-64674bd600d8"),
|
|
885
|
+
U("1486406146926-c627a92ad1ab"),
|
|
886
|
+
U("1497032628192-86f99bcd76bc"),
|
|
887
|
+
U("1521737604893-d14cc237f11d"),
|
|
888
|
+
U("1522071820081-009f0129c71c"),
|
|
889
|
+
U("1519389950473-47ba0277781c"),
|
|
890
|
+
U("1460925895917-afdab827c52f"),
|
|
891
|
+
U("1504384308090-c894fdcc538d")
|
|
892
|
+
];
|
|
893
|
+
var PEOPLE = [
|
|
894
|
+
U("1500648767791-00dcc994a43e"),
|
|
895
|
+
U("1494790108377-be9c29b29330"),
|
|
896
|
+
U("1507003211169-0a1dd7228f2d"),
|
|
897
|
+
U("1438761681033-6461ffad8d80"),
|
|
898
|
+
U("1544005313-94ddf0286df2"),
|
|
899
|
+
U("1472099645785-5658abf4ff4e"),
|
|
900
|
+
U("1519085360753-af0119f7cbe7"),
|
|
901
|
+
U("1534528741775-53994a69daeb")
|
|
902
|
+
];
|
|
903
|
+
var THEMED = [
|
|
904
|
+
{
|
|
905
|
+
keywords: ["portrait", "headshot", "person", "people", "team", "staff", "avatar", "founder", "face"],
|
|
906
|
+
pool: PEOPLE
|
|
907
|
+
},
|
|
908
|
+
{
|
|
909
|
+
keywords: ["pet", "dog", "cat", "puppy", "kitten", "vet", "animal"],
|
|
910
|
+
pool: [
|
|
911
|
+
U("1548199973-03cce0bbc87b"),
|
|
912
|
+
U("1450778869180-41d0601e046e"),
|
|
913
|
+
U("1583511655857-d19b40a7a54e"),
|
|
914
|
+
U("1587300003388-59208cc962cb"),
|
|
915
|
+
U("1517849845537-4d257902454a"),
|
|
916
|
+
U("1601758228041-f3b2795255f1")
|
|
917
|
+
]
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
keywords: [
|
|
921
|
+
"baker",
|
|
922
|
+
"bakery",
|
|
923
|
+
"cafe",
|
|
924
|
+
"coffee",
|
|
925
|
+
"latte",
|
|
926
|
+
"restaurant",
|
|
927
|
+
"pastr",
|
|
928
|
+
"bread",
|
|
929
|
+
"cake",
|
|
930
|
+
"cater",
|
|
931
|
+
"chef",
|
|
932
|
+
"kitchen",
|
|
933
|
+
"food",
|
|
934
|
+
"pizza",
|
|
935
|
+
"dessert",
|
|
936
|
+
"brunch",
|
|
937
|
+
"bistro",
|
|
938
|
+
"deli",
|
|
939
|
+
"dish",
|
|
940
|
+
"menu"
|
|
941
|
+
],
|
|
942
|
+
pool: [
|
|
943
|
+
U("1509440159596-0249088772ff"),
|
|
944
|
+
U("1555507036-ab1f4038808a"),
|
|
945
|
+
U("1517433670267-08bbd4be890f"),
|
|
946
|
+
U("1486427944299-d1955d23e34d"),
|
|
947
|
+
U("1504754524776-8f4f37790ca0"),
|
|
948
|
+
U("1495474472287-4d71bcdd2085"),
|
|
949
|
+
U("1521017432531-fbd92d768814"),
|
|
950
|
+
U("1556909114-f6e7ad7d3136")
|
|
951
|
+
]
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
keywords: [
|
|
955
|
+
"shop",
|
|
956
|
+
"store",
|
|
957
|
+
"boutique",
|
|
958
|
+
"retail",
|
|
959
|
+
"clothing",
|
|
960
|
+
"fashion",
|
|
961
|
+
"jewel",
|
|
962
|
+
"gift",
|
|
963
|
+
"florist",
|
|
964
|
+
"market",
|
|
965
|
+
"grocer",
|
|
966
|
+
"product",
|
|
967
|
+
"storefront"
|
|
968
|
+
],
|
|
969
|
+
pool: [
|
|
970
|
+
U("1441984904996-e0b6ba687e04"),
|
|
971
|
+
U("1472851294608-062f824d29cc"),
|
|
972
|
+
U("1523381210434-271e8be1f52b"),
|
|
973
|
+
U("1534452203293-494d7ddbf7e0"),
|
|
974
|
+
U("1445205170230-053b83016050"),
|
|
975
|
+
U("1560243563-062bfc001d68")
|
|
976
|
+
]
|
|
977
|
+
},
|
|
978
|
+
{
|
|
979
|
+
keywords: [
|
|
980
|
+
"yoga",
|
|
981
|
+
"pilates",
|
|
982
|
+
"fitness",
|
|
983
|
+
"gym",
|
|
984
|
+
"workout",
|
|
985
|
+
"trainer",
|
|
986
|
+
"wellness",
|
|
987
|
+
"meditat",
|
|
988
|
+
"massage",
|
|
989
|
+
"therap",
|
|
990
|
+
"physio",
|
|
991
|
+
"chiro",
|
|
992
|
+
"nutrition",
|
|
993
|
+
"spa",
|
|
994
|
+
"studio"
|
|
995
|
+
],
|
|
996
|
+
pool: [
|
|
997
|
+
U("1544367567-0f2fcb009e0b"),
|
|
998
|
+
U("1506126613408-eca07ce68773"),
|
|
999
|
+
U("1545205597-3d9d02c29597"),
|
|
1000
|
+
U("1552196563-55cd4e45efb3"),
|
|
1001
|
+
U("1518611012118-696072aa579a"),
|
|
1002
|
+
U("1571019613454-1cb2f99b2d8b"),
|
|
1003
|
+
U("1540555700478-4be289fbecef"),
|
|
1004
|
+
U("1519824145371-296894a0daa9")
|
|
1005
|
+
]
|
|
1006
|
+
},
|
|
1007
|
+
{
|
|
1008
|
+
keywords: [
|
|
1009
|
+
"salon",
|
|
1010
|
+
"hairdress",
|
|
1011
|
+
"haircut",
|
|
1012
|
+
"barber",
|
|
1013
|
+
"manicure",
|
|
1014
|
+
"pedicure",
|
|
1015
|
+
"nails",
|
|
1016
|
+
"beauty",
|
|
1017
|
+
"makeup",
|
|
1018
|
+
"cosmetic",
|
|
1019
|
+
"eyelash",
|
|
1020
|
+
"eyebrow",
|
|
1021
|
+
"skincare",
|
|
1022
|
+
"esthetic",
|
|
1023
|
+
"waxing",
|
|
1024
|
+
"hair"
|
|
1025
|
+
],
|
|
1026
|
+
pool: [
|
|
1027
|
+
U("1560066984-138dadb4c035"),
|
|
1028
|
+
U("1522337660859-02fbefca4702"),
|
|
1029
|
+
U("1562322140-8baeececf3df"),
|
|
1030
|
+
U("1521590832167-7bcbfaa6381f"),
|
|
1031
|
+
U("1487412947147-5cebf100ffc2"),
|
|
1032
|
+
U("1526045478516-99145907023c")
|
|
1033
|
+
]
|
|
1034
|
+
},
|
|
1035
|
+
{
|
|
1036
|
+
keywords: [
|
|
1037
|
+
"cleaning",
|
|
1038
|
+
"plumb",
|
|
1039
|
+
"electric",
|
|
1040
|
+
"landscap",
|
|
1041
|
+
"contractor",
|
|
1042
|
+
"handyman",
|
|
1043
|
+
"renov",
|
|
1044
|
+
"hvac",
|
|
1045
|
+
"roofing",
|
|
1046
|
+
"painting",
|
|
1047
|
+
"carpentry",
|
|
1048
|
+
"flooring",
|
|
1049
|
+
"movers",
|
|
1050
|
+
"construction",
|
|
1051
|
+
"tools"
|
|
1052
|
+
],
|
|
1053
|
+
pool: [
|
|
1054
|
+
U("1581578731548-c64695cc6952"),
|
|
1055
|
+
U("1504307651254-35680f356dfd"),
|
|
1056
|
+
U("1581092160562-40aa08e78837"),
|
|
1057
|
+
U("1621905251189-08b45d6a269e"),
|
|
1058
|
+
U("1558618666-fcd25c85cd64"),
|
|
1059
|
+
U("1585128792020-803d29415281")
|
|
1060
|
+
]
|
|
1061
|
+
},
|
|
1062
|
+
{
|
|
1063
|
+
keywords: [
|
|
1064
|
+
"legal",
|
|
1065
|
+
"attorney",
|
|
1066
|
+
"lawyer",
|
|
1067
|
+
"account",
|
|
1068
|
+
"bookkeep",
|
|
1069
|
+
"consult",
|
|
1070
|
+
"coaching",
|
|
1071
|
+
"financ",
|
|
1072
|
+
"insurance",
|
|
1073
|
+
"realtor",
|
|
1074
|
+
"estate",
|
|
1075
|
+
"marketing",
|
|
1076
|
+
"agency",
|
|
1077
|
+
"office",
|
|
1078
|
+
"business",
|
|
1079
|
+
"desk"
|
|
1080
|
+
],
|
|
1081
|
+
pool: [
|
|
1082
|
+
U("1497366216548-37526070297c"),
|
|
1083
|
+
U("1497366811353-6870744d04b2"),
|
|
1084
|
+
U("1454165804606-c3d57bc86b40"),
|
|
1085
|
+
U("1521791136064-7986c2920216"),
|
|
1086
|
+
U("1556761175-b413da4baf72"),
|
|
1087
|
+
U("1542744173-8e7e53415bb0")
|
|
1088
|
+
]
|
|
1089
|
+
},
|
|
1090
|
+
{
|
|
1091
|
+
keywords: [
|
|
1092
|
+
"wedding",
|
|
1093
|
+
"event",
|
|
1094
|
+
"party",
|
|
1095
|
+
"celebrat",
|
|
1096
|
+
"venue",
|
|
1097
|
+
"community",
|
|
1098
|
+
"nonprofit",
|
|
1099
|
+
"charity",
|
|
1100
|
+
"workshop",
|
|
1101
|
+
"photograph",
|
|
1102
|
+
"concert"
|
|
1103
|
+
],
|
|
1104
|
+
pool: [
|
|
1105
|
+
U("1511578314322-379afb476865"),
|
|
1106
|
+
U("1501281668745-f7f57925c3b4"),
|
|
1107
|
+
U("1523580494863-6f3031224c94"),
|
|
1108
|
+
U("1540575467063-178a50c2df87"),
|
|
1109
|
+
U("1505236858219-8359eb29e329"),
|
|
1110
|
+
U("1528605248644-14dd04022da1")
|
|
1111
|
+
]
|
|
1112
|
+
}
|
|
1113
|
+
];
|
|
1114
|
+
function poolForSubject(subject) {
|
|
1115
|
+
for (const theme of THEMED) {
|
|
1116
|
+
if (theme.keywords.some((k) => subject.includes(k))) {
|
|
1117
|
+
return theme.pool;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
return GENERIC;
|
|
1121
|
+
}
|
|
1122
|
+
function mixedHash(text) {
|
|
1123
|
+
let hash = 2166136261;
|
|
1124
|
+
for (let i = 0; i < text.length; i++) {
|
|
1125
|
+
hash ^= text.charCodeAt(i);
|
|
1126
|
+
hash = Math.imul(hash, 16777619);
|
|
1127
|
+
}
|
|
1128
|
+
return hash >>> 16 & 65535;
|
|
1129
|
+
}
|
|
1130
|
+
function resolvePlaceholderRef(ref) {
|
|
1131
|
+
const match = /^placeholder:([a-z0-9-]+)$/.exec(ref);
|
|
1132
|
+
if (!match) return null;
|
|
1133
|
+
const subject = match[1];
|
|
1134
|
+
const pool = poolForSubject(subject.replace(/-\d+$/, ""));
|
|
1135
|
+
return pool[mixedHash(ref) % pool.length];
|
|
1136
|
+
}
|
|
1137
|
+
function collectPlaceholderRefs(tree) {
|
|
1138
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1139
|
+
for (const match of JSON.stringify(tree ?? null).matchAll(/"(placeholder:[a-z0-9-]+)"/gu)) {
|
|
1140
|
+
seen.add(match[1]);
|
|
1141
|
+
}
|
|
1142
|
+
return [...seen];
|
|
1143
|
+
}
|
|
1144
|
+
function buildPlaceholderMap(tree) {
|
|
1145
|
+
const map = {};
|
|
1146
|
+
const cursor = /* @__PURE__ */ new Map();
|
|
1147
|
+
for (const ref of collectPlaceholderRefs(tree)) {
|
|
1148
|
+
const subject = ref.slice("placeholder:".length).replace(/-\d+$/, "");
|
|
1149
|
+
const pool = poolForSubject(subject);
|
|
1150
|
+
const start = cursor.get(pool) ?? mixedHash(ref) % pool.length;
|
|
1151
|
+
map[ref] = pool[start % pool.length];
|
|
1152
|
+
cursor.set(pool, start + 1);
|
|
1153
|
+
}
|
|
1154
|
+
return map;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
547
1158
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
548
1159
|
function lucideByName(name) {
|
|
549
1160
|
const pascal = name.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
@@ -557,6 +1168,7 @@ var typeStyle = (spec, font) => ({
|
|
|
557
1168
|
fontWeight: spec.weight
|
|
558
1169
|
});
|
|
559
1170
|
var str = (value) => typeof value === "string" ? value : "";
|
|
1171
|
+
var cardRadius = (slots) => slots.cornerStyle === "sharp" ? 0 : AI_TREE_TOKENS.radiusCard;
|
|
560
1172
|
var featureLines = (value) => value.split(/\n|<br\s*\/?>/i).map((line) => line.trim()).filter(Boolean);
|
|
561
1173
|
var CHECK_MASK = `data:image/svg+xml,${encodeURIComponent(
|
|
562
1174
|
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>'
|
|
@@ -583,6 +1195,25 @@ var FEATURE_LINE_CSS = [
|
|
|
583
1195
|
`background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
|
|
584
1196
|
`mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
|
|
585
1197
|
].join("");
|
|
1198
|
+
function buttonShellStyle(ctx, fullWidth) {
|
|
1199
|
+
const bs = ctx.buttonStyle;
|
|
1200
|
+
if (bs) {
|
|
1201
|
+
return {
|
|
1202
|
+
borderRadius: bs.radius,
|
|
1203
|
+
...bs.padding ? { padding: bs.padding } : {},
|
|
1204
|
+
...bs.fontFamily ? { fontFamily: bs.fontFamily } : { fontFamily: ctx.brand.fonts.body },
|
|
1205
|
+
...bs.fontSize ? { fontSize: bs.fontSize } : {},
|
|
1206
|
+
...bs.fontWeight ? { fontWeight: bs.fontWeight } : {},
|
|
1207
|
+
...bs.letterSpacing && bs.letterSpacing !== "normal" ? { letterSpacing: bs.letterSpacing } : {},
|
|
1208
|
+
...bs.textTransform && bs.textTransform !== "none" ? { textTransform: bs.textTransform } : {}
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
return {
|
|
1212
|
+
borderRadius: AI_TREE_TOKENS.radiusButton,
|
|
1213
|
+
padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
|
|
1214
|
+
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
586
1217
|
function hexLuminance(color) {
|
|
587
1218
|
const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
|
|
588
1219
|
if (!m) return null;
|
|
@@ -599,6 +1230,12 @@ function hexContrast(a, b) {
|
|
|
599
1230
|
const [hi, lo] = la > lb ? [la, lb] : [lb, la];
|
|
600
1231
|
return (hi + 0.05) / (lo + 0.05);
|
|
601
1232
|
}
|
|
1233
|
+
function primaryButtonLabel(brand) {
|
|
1234
|
+
const darkC = hexContrast(brand.palette.primary, brand.palette.dark);
|
|
1235
|
+
const lightC = hexContrast(brand.palette.primary, AI_TREE_TOKENS.textPrimaryForeground);
|
|
1236
|
+
if (darkC === null || lightC === null) return AI_TREE_TOKENS.textPrimaryForeground;
|
|
1237
|
+
return darkC > lightC ? brand.palette.dark : AI_TREE_TOKENS.textPrimaryForeground;
|
|
1238
|
+
}
|
|
602
1239
|
function accentBandContext(brand) {
|
|
603
1240
|
const p = brand.palette;
|
|
604
1241
|
const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
|
|
@@ -616,6 +1253,22 @@ function accentBandContext(brand) {
|
|
|
616
1253
|
function textAttrs(ctx, path) {
|
|
617
1254
|
return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
|
|
618
1255
|
}
|
|
1256
|
+
var AI_RESPONSIVE_CSS = [
|
|
1257
|
+
"@media (max-width: 960px) {",
|
|
1258
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
|
|
1259
|
+
' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
|
|
1260
|
+
"}",
|
|
1261
|
+
"@media (max-width: 640px) {",
|
|
1262
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
|
|
1263
|
+
" [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
|
|
1264
|
+
// Group containers flatten to a column on phones; span placements come along for free.
|
|
1265
|
+
" [data-ai-responsive] [data-ai-group] { display: flex !important; flex-direction: column !important; }",
|
|
1266
|
+
" [data-ai-responsive] [data-ai-group] > * { grid-column: auto !important; }",
|
|
1267
|
+
" [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
|
|
1268
|
+
" [data-ai-responsive] { overflow-x: hidden; }",
|
|
1269
|
+
" [data-ai-responsive] img { max-width: 100%; }",
|
|
1270
|
+
"}"
|
|
1271
|
+
].join("\n");
|
|
619
1272
|
var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
620
1273
|
function MediaBox({
|
|
621
1274
|
refValue,
|
|
@@ -628,13 +1281,17 @@ function MediaBox({
|
|
|
628
1281
|
const url = refValue ? ctx.resolveMedia(refValue) : null;
|
|
629
1282
|
const isIcon = /^(lucide|simple):/.test(refValue);
|
|
630
1283
|
const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
|
|
631
|
-
const editAttrs = ctx.keyFor && editPath
|
|
1284
|
+
const editAttrs = ctx.keyFor && editPath ? {
|
|
1285
|
+
"data-ohw-key": ctx.keyFor(editPath),
|
|
1286
|
+
"data-ohw-editable": isIcon ? "icon" : "image"
|
|
1287
|
+
} : {};
|
|
632
1288
|
if (isIcon) {
|
|
633
1289
|
const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
|
|
634
1290
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
635
1291
|
"span",
|
|
636
1292
|
{
|
|
637
1293
|
"data-ai-icon": refValue,
|
|
1294
|
+
...editAttrs,
|
|
638
1295
|
style: {
|
|
639
1296
|
display: "inline-flex",
|
|
640
1297
|
width: 48,
|
|
@@ -698,12 +1355,10 @@ function ButtonEl({
|
|
|
698
1355
|
width: fullWidth ? "100%" : void 0,
|
|
699
1356
|
alignItems: "center",
|
|
700
1357
|
justifyContent: "center",
|
|
701
|
-
padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
|
|
702
|
-
borderRadius: AI_TREE_TOKENS.radiusButton,
|
|
703
1358
|
textDecoration: "none",
|
|
704
1359
|
cursor: "pointer",
|
|
705
|
-
...
|
|
706
|
-
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ??
|
|
1360
|
+
...buttonShellStyle(ctx, fullWidth),
|
|
1361
|
+
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand) }
|
|
707
1362
|
},
|
|
708
1363
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
|
|
709
1364
|
}
|
|
@@ -729,7 +1384,7 @@ function TextBlock({ slots, ctx, path }) {
|
|
|
729
1384
|
}
|
|
730
1385
|
function SectionHeaderBlock({ node, ctx, path }) {
|
|
731
1386
|
const slots = node.slots ?? {};
|
|
732
|
-
const align = slots.alignment === "center" ? "center" : "left";
|
|
1387
|
+
const align = node.align ?? (slots.alignment === "center" ? "center" : "left");
|
|
733
1388
|
const children = node.children ?? [];
|
|
734
1389
|
const buttonRowIdx = children.findIndex((c) => c.type === "button-row");
|
|
735
1390
|
const buttonRow = buttonRowIdx >= 0 ? children[buttonRowIdx] : void 0;
|
|
@@ -773,7 +1428,7 @@ function SectionHeaderBlock({ node, ctx, path }) {
|
|
|
773
1428
|
display: "flex",
|
|
774
1429
|
gap: AI_TREE_TOKENS.spacing6,
|
|
775
1430
|
marginTop: AI_TREE_TOKENS.spacing8,
|
|
776
|
-
justifyContent: align === "center" ? "center" : "flex-start"
|
|
1431
|
+
justifyContent: align === "center" ? "center" : align === "right" ? "flex-end" : "flex-start"
|
|
777
1432
|
},
|
|
778
1433
|
children: (buttonRow.children ?? []).map((button, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
779
1434
|
ButtonEl,
|
|
@@ -879,10 +1534,11 @@ function PricingCard({ node, ctx, path }) {
|
|
|
879
1534
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
880
1535
|
"div",
|
|
881
1536
|
{
|
|
1537
|
+
"data-ohw-card": "",
|
|
882
1538
|
style: {
|
|
883
1539
|
background: hasBg ? ctx.brand.palette.light : "transparent",
|
|
884
1540
|
border: `1px solid ${dark}`,
|
|
885
|
-
borderRadius:
|
|
1541
|
+
borderRadius: cardRadius(slots),
|
|
886
1542
|
padding: AI_TREE_TOKENS.paddingBlock,
|
|
887
1543
|
display: "flex",
|
|
888
1544
|
flexDirection: "column",
|
|
@@ -987,10 +1643,11 @@ function TestimonialCard({ node, ctx, path }) {
|
|
|
987
1643
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
988
1644
|
"div",
|
|
989
1645
|
{
|
|
1646
|
+
"data-ohw-card": "",
|
|
990
1647
|
"data-ai-avatar-pos": avatarPos ?? void 0,
|
|
991
1648
|
style: {
|
|
992
1649
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
993
|
-
borderRadius: hasBg ?
|
|
1650
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
994
1651
|
overflow: "hidden",
|
|
995
1652
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
996
1653
|
minWidth: 0
|
|
@@ -1025,10 +1682,11 @@ function TeamCard({ node, ctx, path }) {
|
|
|
1025
1682
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1026
1683
|
"div",
|
|
1027
1684
|
{
|
|
1685
|
+
"data-ohw-card": "",
|
|
1028
1686
|
"data-ai-avatar-pos": avatarPos ?? void 0,
|
|
1029
1687
|
style: {
|
|
1030
1688
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1031
|
-
borderRadius: hasBg ?
|
|
1689
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1032
1690
|
overflow: "hidden",
|
|
1033
1691
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1034
1692
|
minWidth: 0,
|
|
@@ -1106,7 +1764,7 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1106
1764
|
editPath: `${path}.media`
|
|
1107
1765
|
}
|
|
1108
1766
|
) : null;
|
|
1109
|
-
const centered = slots.alignment === "center";
|
|
1767
|
+
const centered = (node.align ?? slots.alignment) === "center";
|
|
1110
1768
|
const content = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1111
1769
|
"div",
|
|
1112
1770
|
{
|
|
@@ -1199,9 +1857,10 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1199
1857
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1200
1858
|
"div",
|
|
1201
1859
|
{
|
|
1860
|
+
"data-ohw-card": "",
|
|
1202
1861
|
style: {
|
|
1203
1862
|
background: hasBg ? ctx.cardSurface : "transparent",
|
|
1204
|
-
borderRadius: hasBg ?
|
|
1863
|
+
borderRadius: hasBg ? cardRadius(slots) : 0,
|
|
1205
1864
|
overflow: "hidden",
|
|
1206
1865
|
outline: slots.featured === true ? `2px solid ${ctx.brand.palette.primary}` : void 0,
|
|
1207
1866
|
display: horizontal ? "flex" : "block",
|
|
@@ -1229,7 +1888,7 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1229
1888
|
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1230
1889
|
"div",
|
|
1231
1890
|
{
|
|
1232
|
-
style: /^(lucide|simple):/.test(mediaRef) ? { padding: `${AI_TREE_TOKENS.paddingBlock}px ${AI_TREE_TOKENS.paddingBlock}px 0` } : hasBg ? void 0 : { borderRadius:
|
|
1891
|
+
style: /^(lucide|simple):/.test(mediaRef) ? { padding: `${AI_TREE_TOKENS.paddingBlock}px ${AI_TREE_TOKENS.paddingBlock}px 0` } : hasBg ? void 0 : { borderRadius: cardRadius(slots), overflow: "hidden" },
|
|
1233
1892
|
children: media
|
|
1234
1893
|
}
|
|
1235
1894
|
)),
|
|
@@ -1520,7 +2179,7 @@ function CollectionBlock({ node, ctx, path }) {
|
|
|
1520
2179
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1521
2180
|
"div",
|
|
1522
2181
|
{
|
|
1523
|
-
"data-ai-grid":
|
|
2182
|
+
"data-ai-grid": String(itemsPerRow),
|
|
1524
2183
|
style: {
|
|
1525
2184
|
display: "grid",
|
|
1526
2185
|
gridTemplateColumns: `repeat(${itemsPerRow}, 1fr)`,
|
|
@@ -1640,6 +2299,32 @@ function renderNode(node, ctx, path) {
|
|
|
1640
2299
|
if (child) {
|
|
1641
2300
|
return renderNode(child, ctx, `${path}.c0`);
|
|
1642
2301
|
}
|
|
2302
|
+
if (str(slots.provider) === "map" && str(slots.query)) {
|
|
2303
|
+
const query = str(slots.query);
|
|
2304
|
+
const mapAttrs = ctx.keyFor ? {
|
|
2305
|
+
"data-ohw-key": ctx.keyFor(`${path}.query`),
|
|
2306
|
+
"data-ohw-editable": "map",
|
|
2307
|
+
"data-ohw-map-query": query
|
|
2308
|
+
} : {};
|
|
2309
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2310
|
+
"iframe",
|
|
2311
|
+
{
|
|
2312
|
+
...mapAttrs,
|
|
2313
|
+
"data-ai-embed": "map",
|
|
2314
|
+
title: str(slots.title) || "Map",
|
|
2315
|
+
src: `https://www.google.com/maps?q=${encodeURIComponent(query)}&output=embed`,
|
|
2316
|
+
loading: "lazy",
|
|
2317
|
+
referrerPolicy: "no-referrer-when-downgrade",
|
|
2318
|
+
style: {
|
|
2319
|
+
width: "100%",
|
|
2320
|
+
minHeight: 320,
|
|
2321
|
+
border: 0,
|
|
2322
|
+
borderRadius: AI_TREE_TOKENS.radiusCard,
|
|
2323
|
+
display: "block"
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
);
|
|
2327
|
+
}
|
|
1643
2328
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1644
2329
|
"div",
|
|
1645
2330
|
{
|
|
@@ -1743,15 +2428,12 @@ function renderNode(node, ctx, path) {
|
|
|
1743
2428
|
alignSelf: submitAlign,
|
|
1744
2429
|
border: "none",
|
|
1745
2430
|
cursor: "pointer",
|
|
1746
|
-
padding
|
|
1747
|
-
|
|
1748
|
-
// CTA); 8px only when the page has no template button to match.
|
|
1749
|
-
borderRadius: ctx.buttonRadius ?? 8,
|
|
2431
|
+
// Shape/padding/typography follow the host template's own buttons.
|
|
2432
|
+
...buttonShellStyle(ctx),
|
|
1750
2433
|
// Brand-styled: primary fill, brand-derived label colour (not a fixed token) so it
|
|
1751
2434
|
// reads correctly on custom palettes.
|
|
1752
2435
|
background: ctx.brand.palette.primary,
|
|
1753
|
-
color: ctx.buttonLabel ?? ctx.brand
|
|
1754
|
-
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
2436
|
+
color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand)
|
|
1755
2437
|
},
|
|
1756
2438
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
|
|
1757
2439
|
},
|
|
@@ -1786,7 +2468,7 @@ function renderNode(node, ctx, path) {
|
|
|
1786
2468
|
function AiTreeRenderer({
|
|
1787
2469
|
tree,
|
|
1788
2470
|
brand,
|
|
1789
|
-
|
|
2471
|
+
buttonStyle,
|
|
1790
2472
|
resolveMedia,
|
|
1791
2473
|
editKeyPrefix
|
|
1792
2474
|
}) {
|
|
@@ -1796,13 +2478,18 @@ function AiTreeRenderer({
|
|
|
1796
2478
|
const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
|
|
1797
2479
|
const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
|
|
1798
2480
|
const blockBrand = band?.brand ?? resolvedBrand;
|
|
2481
|
+
const placeholderMap = buildPlaceholderMap(tree);
|
|
1799
2482
|
const ctx = {
|
|
1800
2483
|
brand: blockBrand,
|
|
1801
|
-
|
|
2484
|
+
// An owner/library ref resolves through the host resolver; a `placeholder:<subject>` ref the
|
|
2485
|
+
// host cannot resolve falls back to real stock photography (the per-section map first, then a
|
|
2486
|
+
// standalone resolve), so generated galleries, image rows, and overlay backgrounds arrive with
|
|
2487
|
+
// photos instead of grey boxes.
|
|
2488
|
+
resolveMedia: (ref) => resolveMedia?.(ref) ?? placeholderMap[ref] ?? resolvePlaceholderRef(ref),
|
|
1802
2489
|
cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
|
|
1803
2490
|
keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
|
|
1804
2491
|
sectionAlignment: (tree.settings ?? {}).alignment === "center" ? "center" : "left",
|
|
1805
|
-
|
|
2492
|
+
buttonStyle,
|
|
1806
2493
|
...band ? { buttonLabel: band.buttonLabel } : {}
|
|
1807
2494
|
};
|
|
1808
2495
|
const settings = tree.settings ?? {};
|
|
@@ -1825,11 +2512,25 @@ function AiTreeRenderer({
|
|
|
1825
2512
|
}
|
|
1826
2513
|
})();
|
|
1827
2514
|
const distributed = !isOverlay && settings.textDistribution;
|
|
2515
|
+
const rowAlignItems = (rowAlign) => {
|
|
2516
|
+
if (rowAlign === "top") return "start";
|
|
2517
|
+
if (rowAlign === "bottom") return "end";
|
|
2518
|
+
if (rowAlign === "center" || rowAlign === "stretch") return rowAlign;
|
|
2519
|
+
if (distributed === "space-between") return "stretch";
|
|
2520
|
+
return (distributed ?? settings.verticalPosition) === "top" ? "start" : "center";
|
|
2521
|
+
};
|
|
2522
|
+
const cellAlignStyle = (blockAlign) => blockAlign ? {
|
|
2523
|
+
display: "flex",
|
|
2524
|
+
flexDirection: "column",
|
|
2525
|
+
alignItems: blockAlign === "left" ? "flex-start" : blockAlign === "right" ? "flex-end" : "center",
|
|
2526
|
+
textAlign: blockAlign
|
|
2527
|
+
} : {};
|
|
1828
2528
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1829
2529
|
"section",
|
|
1830
2530
|
{
|
|
1831
2531
|
"data-ai-section": tree.tag ?? "",
|
|
1832
2532
|
...bgAttrs,
|
|
2533
|
+
"data-ai-responsive": "",
|
|
1833
2534
|
style: {
|
|
1834
2535
|
position: "relative",
|
|
1835
2536
|
padding: `${pad}px 0`,
|
|
@@ -1840,12 +2541,13 @@ function AiTreeRenderer({
|
|
|
1840
2541
|
color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
|
|
1841
2542
|
},
|
|
1842
2543
|
children: [
|
|
1843
|
-
|
|
2544
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
|
|
1844
2545
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
|
|
2546
|
+
isOverlay && backgroundUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
|
|
1845
2547
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1846
2548
|
"div",
|
|
1847
2549
|
{
|
|
1848
|
-
"data-ai-
|
|
2550
|
+
"data-ai-section-inner": "",
|
|
1849
2551
|
style: {
|
|
1850
2552
|
position: "relative",
|
|
1851
2553
|
maxWidth: AI_TREE_TOKENS.sectionMaxWidth,
|
|
@@ -1856,12 +2558,12 @@ function AiTreeRenderer({
|
|
|
1856
2558
|
children: tree.rows.map((row, r2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1857
2559
|
"div",
|
|
1858
2560
|
{
|
|
1859
|
-
"data-ai-
|
|
2561
|
+
"data-ai-columns": "",
|
|
1860
2562
|
style: {
|
|
1861
2563
|
display: "grid",
|
|
1862
2564
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
1863
2565
|
gap: AI_TREE_TOKENS.spacing6,
|
|
1864
|
-
alignItems:
|
|
2566
|
+
alignItems: rowAlignItems(row.align),
|
|
1865
2567
|
marginTop: r2 > 0 ? AI_TREE_TOKENS.spacing8 : 0
|
|
1866
2568
|
},
|
|
1867
2569
|
children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -1871,6 +2573,8 @@ function AiTreeRenderer({
|
|
|
1871
2573
|
style: {
|
|
1872
2574
|
gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`,
|
|
1873
2575
|
minWidth: 0,
|
|
2576
|
+
// Horizontal placement of the block's content within its column.
|
|
2577
|
+
...cellAlignStyle(block.align),
|
|
1874
2578
|
// space-between: each column becomes a flex column whose content spreads over
|
|
1875
2579
|
// the full row height instead of clumping at the top.
|
|
1876
2580
|
...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
|
|
@@ -1893,7 +2597,7 @@ function AiTreeRenderer({
|
|
|
1893
2597
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1894
2598
|
var CONTAINER_ATTR = "data-ohw-ai-generated";
|
|
1895
2599
|
var REPLACED_ATTR = "data-ohw-ai-replaced-by";
|
|
1896
|
-
var
|
|
2600
|
+
var REMOVED_ATTR2 = "data-ohw-ai-removed";
|
|
1897
2601
|
var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
|
|
1898
2602
|
var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
1899
2603
|
function readRootVar(name) {
|
|
@@ -1917,13 +2621,13 @@ function deriveBrandOverride() {
|
|
|
1917
2621
|
};
|
|
1918
2622
|
}
|
|
1919
2623
|
function deriveTemplateBrand() {
|
|
1920
|
-
const
|
|
1921
|
-
const
|
|
1922
|
-
const light = readRootVar("--color-light");
|
|
2624
|
+
const primary = readRootVar("--brand-primary") || readRootVar("--color-primary");
|
|
2625
|
+
const dark = readRootVar("--brand-text") || readRootVar("--color-dark");
|
|
2626
|
+
const light = readRootVar("--brand-background") || readRootVar("--color-light");
|
|
1923
2627
|
if (!dark || !primary || !light) return null;
|
|
1924
|
-
const accent = readRootVar("--color-accent");
|
|
1925
|
-
const heading = readRootVar("--font-heading") || readRootVar("--font-display");
|
|
1926
|
-
const body = readRootVar("--font-body");
|
|
2628
|
+
const accent = readRootVar("--brand-accent") || readRootVar("--color-accent");
|
|
2629
|
+
const heading = readRootVar("--brand-font-heading") || readRootVar("--font-heading") || readRootVar("--font-display");
|
|
2630
|
+
const body = readRootVar("--brand-font-body") || readRootVar("--font-body");
|
|
1927
2631
|
return {
|
|
1928
2632
|
palette: { dark, primary, accent: accent || dark, light },
|
|
1929
2633
|
fonts: {
|
|
@@ -1932,12 +2636,32 @@ function deriveTemplateBrand() {
|
|
|
1932
2636
|
}
|
|
1933
2637
|
};
|
|
1934
2638
|
}
|
|
1935
|
-
function
|
|
2639
|
+
function deriveTemplateButtonStyle() {
|
|
1936
2640
|
if (typeof document === "undefined") return null;
|
|
1937
|
-
const btn = document.
|
|
2641
|
+
const btn = Array.from(document.querySelectorAll('[data-ohw-role="button"]')).find(
|
|
2642
|
+
(el) => !el.closest(`[${CONTAINER_ATTR}]`)
|
|
2643
|
+
);
|
|
1938
2644
|
if (!btn) return null;
|
|
1939
|
-
const
|
|
1940
|
-
|
|
2645
|
+
const cs = getComputedStyle(btn);
|
|
2646
|
+
const corners = [
|
|
2647
|
+
cs.borderTopLeftRadius,
|
|
2648
|
+
cs.borderTopRightRadius,
|
|
2649
|
+
cs.borderBottomRightRadius,
|
|
2650
|
+
cs.borderBottomLeftRadius
|
|
2651
|
+
].map((v) => v || "0px");
|
|
2652
|
+
const radius = corners.every((v) => v === corners[0]) ? corners[0] : corners.join(" ");
|
|
2653
|
+
const px = (v) => parseFloat(v) || 0;
|
|
2654
|
+
const padY = Math.max(px(cs.paddingTop), px(cs.paddingBottom));
|
|
2655
|
+
const padX = Math.max(px(cs.paddingLeft), px(cs.paddingRight));
|
|
2656
|
+
return {
|
|
2657
|
+
radius: radius || "10px",
|
|
2658
|
+
padding: `${padY}px ${padX}px`,
|
|
2659
|
+
fontFamily: cs.fontFamily || "",
|
|
2660
|
+
fontSize: cs.fontSize || "",
|
|
2661
|
+
fontWeight: cs.fontWeight || "",
|
|
2662
|
+
letterSpacing: cs.letterSpacing || "",
|
|
2663
|
+
textTransform: cs.textTransform || ""
|
|
2664
|
+
};
|
|
1941
2665
|
}
|
|
1942
2666
|
var mounted = /* @__PURE__ */ new Map();
|
|
1943
2667
|
function findTemplateSection(id) {
|
|
@@ -1987,18 +2711,18 @@ function placeContainer(container, entry) {
|
|
|
1987
2711
|
}
|
|
1988
2712
|
function syncRemovedSections(state) {
|
|
1989
2713
|
const removed = new Set(state.removed ?? []);
|
|
1990
|
-
for (const el of document.querySelectorAll(`[${
|
|
2714
|
+
for (const el of document.querySelectorAll(`[${REMOVED_ATTR2}]`)) {
|
|
1991
2715
|
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
1992
2716
|
if (!removed.has(id)) {
|
|
1993
2717
|
el.style.removeProperty("display");
|
|
1994
|
-
el.removeAttribute(
|
|
2718
|
+
el.removeAttribute(REMOVED_ATTR2);
|
|
1995
2719
|
}
|
|
1996
2720
|
}
|
|
1997
2721
|
for (const id of removed) {
|
|
1998
2722
|
const section = findTemplateSection(id);
|
|
1999
2723
|
if (section && !section.hasAttribute(REPLACED_ATTR)) {
|
|
2000
2724
|
section.style.display = "none";
|
|
2001
|
-
section.setAttribute(
|
|
2725
|
+
section.setAttribute(REMOVED_ATTR2, "");
|
|
2002
2726
|
}
|
|
2003
2727
|
}
|
|
2004
2728
|
}
|
|
@@ -2015,7 +2739,7 @@ function syncTemplateHidden(state, pageHasSections) {
|
|
|
2015
2739
|
if (el.hasAttribute(CONTAINER_ATTR)) continue;
|
|
2016
2740
|
if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
|
|
2017
2741
|
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
2018
|
-
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(
|
|
2742
|
+
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR2)) continue;
|
|
2019
2743
|
el.style.display = "none";
|
|
2020
2744
|
el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
|
|
2021
2745
|
}
|
|
@@ -2039,18 +2763,23 @@ function syncReplacedOriginals(state) {
|
|
|
2039
2763
|
}
|
|
2040
2764
|
}
|
|
2041
2765
|
var sectionOrderIndex = /* @__PURE__ */ new Map();
|
|
2766
|
+
var removedSectionIds = /* @__PURE__ */ new Set();
|
|
2042
2767
|
function setAiSectionOrder(raw, currentPath) {
|
|
2043
2768
|
const next = /* @__PURE__ */ new Map();
|
|
2769
|
+
const removed = /* @__PURE__ */ new Set();
|
|
2044
2770
|
if (raw) {
|
|
2045
2771
|
try {
|
|
2046
2772
|
const entries = JSON.parse(raw);
|
|
2047
2773
|
for (const entry of entries) {
|
|
2048
|
-
if (
|
|
2774
|
+
if (entry.pagePath && entry.pagePath !== currentPath) continue;
|
|
2775
|
+
next.set(entry.instanceId, entry.order);
|
|
2776
|
+
if (entry.removed) removed.add(entry.instanceId);
|
|
2049
2777
|
}
|
|
2050
2778
|
} catch {
|
|
2051
2779
|
}
|
|
2052
2780
|
}
|
|
2053
2781
|
sectionOrderIndex = next;
|
|
2782
|
+
removedSectionIds = removed;
|
|
2054
2783
|
}
|
|
2055
2784
|
function applyExplicitOrder(entries) {
|
|
2056
2785
|
if (sectionOrderIndex.size === 0) return entries;
|
|
@@ -2086,11 +2815,23 @@ function orderByChain(sections) {
|
|
|
2086
2815
|
for (const root of roots) visit(root);
|
|
2087
2816
|
return out.length === sections.length ? out : sections;
|
|
2088
2817
|
}
|
|
2818
|
+
function syncSoftRemovedGenerated() {
|
|
2819
|
+
for (const [id, section] of mounted) {
|
|
2820
|
+
const el = section.container;
|
|
2821
|
+
if (removedSectionIds.has(id)) {
|
|
2822
|
+
el.style.display = "none";
|
|
2823
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
2824
|
+
} else if (el.hasAttribute(REMOVED_ATTR)) {
|
|
2825
|
+
el.style.removeProperty("display");
|
|
2826
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2089
2830
|
function applyAiSectionsToDom(state, options) {
|
|
2090
2831
|
if (typeof document === "undefined") return;
|
|
2091
2832
|
const brandOverride = deriveBrandOverride();
|
|
2092
2833
|
const templateBrand = deriveTemplateBrand();
|
|
2093
|
-
const
|
|
2834
|
+
const templateButtonStyle = deriveTemplateButtonStyle();
|
|
2094
2835
|
const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
|
|
2095
2836
|
const pagePath = window.location.pathname;
|
|
2096
2837
|
const pageSections = state.sections.filter((entry) => (entry.path ?? "/") === pagePath);
|
|
@@ -2130,7 +2871,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2130
2871
|
{
|
|
2131
2872
|
tree: entry.tree,
|
|
2132
2873
|
brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
|
|
2133
|
-
|
|
2874
|
+
buttonStyle: templateButtonStyle,
|
|
2134
2875
|
resolveMedia,
|
|
2135
2876
|
editKeyPrefix: `ai.${entry.id}`
|
|
2136
2877
|
}
|
|
@@ -2153,6 +2894,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2153
2894
|
syncReplacedOriginals(state);
|
|
2154
2895
|
syncRemovedSections(state);
|
|
2155
2896
|
syncTemplateHidden(state, pageSections.length > 0);
|
|
2897
|
+
syncSoftRemovedGenerated();
|
|
2156
2898
|
}
|
|
2157
2899
|
|
|
2158
2900
|
// src/useLinkHrefGuardian.ts
|
|
@@ -7882,6 +8624,7 @@ function MediaOverlay({
|
|
|
7882
8624
|
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
7883
8625
|
);
|
|
7884
8626
|
}, [isVideo]);
|
|
8627
|
+
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
7885
8628
|
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
7886
8629
|
const box = {
|
|
7887
8630
|
position: "fixed",
|
|
@@ -8011,17 +8754,17 @@ function MediaOverlay({
|
|
|
8011
8754
|
},
|
|
8012
8755
|
children: [
|
|
8013
8756
|
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
8014
|
-
|
|
8757
|
+
replaceLabel
|
|
8015
8758
|
]
|
|
8016
8759
|
}
|
|
8017
8760
|
),
|
|
8018
|
-
replaceMode
|
|
8761
|
+
showChrome && replaceMode !== "none" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
8019
8762
|
Button,
|
|
8020
8763
|
{
|
|
8021
8764
|
"data-ohw-media-overlay": "",
|
|
8022
8765
|
variant: "outline",
|
|
8023
8766
|
size: "sm",
|
|
8024
|
-
"aria-label":
|
|
8767
|
+
"aria-label": replaceLabel,
|
|
8025
8768
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
8026
8769
|
style: {
|
|
8027
8770
|
...OVERLAY_BUTTON_STYLE,
|
|
@@ -8044,7 +8787,7 @@ function MediaOverlay({
|
|
|
8044
8787
|
},
|
|
8045
8788
|
children: [
|
|
8046
8789
|
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
8047
|
-
replaceMode === "full" ?
|
|
8790
|
+
replaceMode === "full" ? replaceLabel : null
|
|
8048
8791
|
]
|
|
8049
8792
|
}
|
|
8050
8793
|
)
|
|
@@ -8081,219 +8824,37 @@ function CarouselOverlay({
|
|
|
8081
8824
|
width: rect.width,
|
|
8082
8825
|
height: rect.height,
|
|
8083
8826
|
zIndex: 2147483646,
|
|
8084
|
-
pointerEvents: "auto",
|
|
8085
|
-
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
8086
|
-
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
8087
|
-
},
|
|
8088
|
-
onClick: () => onEdit(hover.key),
|
|
8089
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
8090
|
-
Button,
|
|
8091
|
-
{
|
|
8092
|
-
"data-ohw-carousel-overlay": "",
|
|
8093
|
-
variant: "outline",
|
|
8094
|
-
size: "sm",
|
|
8095
|
-
className: "cursor-pointer gap-1.5 hover:bg-background",
|
|
8096
|
-
style: OVERLAY_BUTTON_STYLE2,
|
|
8097
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
8098
|
-
onClick: (e) => {
|
|
8099
|
-
e.stopPropagation();
|
|
8100
|
-
onEdit(hover.key);
|
|
8101
|
-
},
|
|
8102
|
-
children: [
|
|
8103
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react6.GalleryHorizontal, { size: 14 }),
|
|
8104
|
-
"Edit gallery"
|
|
8105
|
-
]
|
|
8106
|
-
}
|
|
8107
|
-
)
|
|
8108
|
-
}
|
|
8109
|
-
);
|
|
8110
|
-
}
|
|
8111
|
-
|
|
8112
|
-
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
8113
|
-
var import_react8 = require("react");
|
|
8114
|
-
var import_lucide_react7 = require("lucide-react");
|
|
8115
|
-
|
|
8116
|
-
// src/lib/sections.ts
|
|
8117
|
-
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
8118
|
-
function isChromeSection(el) {
|
|
8119
|
-
return el.matches("header, nav, footer, aside");
|
|
8120
|
-
}
|
|
8121
|
-
function titleCaseSectionId(id) {
|
|
8122
|
-
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
8123
|
-
}
|
|
8124
|
-
function parseSectionsFromRoot(root) {
|
|
8125
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8126
|
-
const sections = [];
|
|
8127
|
-
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
8128
|
-
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
8129
|
-
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
8130
|
-
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
8131
|
-
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
8132
|
-
continue;
|
|
8133
|
-
seen.add(id);
|
|
8134
|
-
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
8135
|
-
sections.push({ id, label });
|
|
8136
|
-
}
|
|
8137
|
-
return sections;
|
|
8138
|
-
}
|
|
8139
|
-
function collectSectionsFromDom() {
|
|
8140
|
-
if (typeof document === "undefined") return [];
|
|
8141
|
-
return parseSectionsFromRoot(document);
|
|
8142
|
-
}
|
|
8143
|
-
function parseSectionsFromHtml(html) {
|
|
8144
|
-
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
8145
|
-
return parseSectionsFromRoot(doc);
|
|
8146
|
-
}
|
|
8147
|
-
|
|
8148
|
-
// src/lib/section-instances.ts
|
|
8149
|
-
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
8150
|
-
var REMOVED_ATTR2 = "data-ohw-section-removed";
|
|
8151
|
-
function isRemovedSection(el) {
|
|
8152
|
-
return el.hasAttribute(REMOVED_ATTR2);
|
|
8153
|
-
}
|
|
8154
|
-
function topLevelSections() {
|
|
8155
|
-
return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
8156
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el) && !isRemovedSection(el)
|
|
8157
|
-
);
|
|
8158
|
-
}
|
|
8159
|
-
function instanceIdOf(el) {
|
|
8160
|
-
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
8161
|
-
}
|
|
8162
|
-
function findByInstanceId(instanceId) {
|
|
8163
|
-
const escapedId = CSS.escape(instanceId);
|
|
8164
|
-
return document.querySelector(`[data-ohw-instance="${escapedId}"]`) ?? document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
8165
|
-
}
|
|
8166
|
-
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
8167
|
-
const sections = topLevelSections();
|
|
8168
|
-
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8169
|
-
if (index === -1) return null;
|
|
8170
|
-
const dragged = sections[index];
|
|
8171
|
-
const others = sections.filter((_, i) => i !== index);
|
|
8172
|
-
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
8173
|
-
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
8174
|
-
return reordered.map((el, order) => ({
|
|
8175
|
-
instanceId: instanceIdOf(el),
|
|
8176
|
-
type: el.getAttribute("data-ohw-section") ?? "",
|
|
8177
|
-
order,
|
|
8178
|
-
pagePath: currentPath
|
|
8179
|
-
}));
|
|
8180
|
-
}
|
|
8181
|
-
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
8182
|
-
const sections = topLevelSections();
|
|
8183
|
-
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8184
|
-
if (index === -1) return null;
|
|
8185
|
-
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
8186
|
-
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
8187
|
-
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
8188
|
-
if (!entries) return null;
|
|
8189
|
-
applyPersistedOrder(entries);
|
|
8190
|
-
return entries;
|
|
8191
|
-
}
|
|
8192
|
-
function syncRemovedFlags(entries) {
|
|
8193
|
-
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
8194
|
-
document.querySelectorAll(`[${REMOVED_ATTR2}]`).forEach((el) => {
|
|
8195
|
-
if (!removedIds.has(instanceIdOf(el))) {
|
|
8196
|
-
el.style.removeProperty("display");
|
|
8197
|
-
el.removeAttribute(REMOVED_ATTR2);
|
|
8198
|
-
}
|
|
8199
|
-
});
|
|
8200
|
-
for (const id of removedIds) {
|
|
8201
|
-
const el = findByInstanceId(id);
|
|
8202
|
-
if (el) {
|
|
8203
|
-
el.style.display = "none";
|
|
8204
|
-
el.setAttribute(REMOVED_ATTR2, "");
|
|
8827
|
+
pointerEvents: "auto",
|
|
8828
|
+
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
8829
|
+
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
8830
|
+
},
|
|
8831
|
+
onClick: () => onEdit(hover.key),
|
|
8832
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
8833
|
+
Button,
|
|
8834
|
+
{
|
|
8835
|
+
"data-ohw-carousel-overlay": "",
|
|
8836
|
+
variant: "outline",
|
|
8837
|
+
size: "sm",
|
|
8838
|
+
className: "cursor-pointer gap-1.5 hover:bg-background",
|
|
8839
|
+
style: OVERLAY_BUTTON_STYLE2,
|
|
8840
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
8841
|
+
onClick: (e) => {
|
|
8842
|
+
e.stopPropagation();
|
|
8843
|
+
onEdit(hover.key);
|
|
8844
|
+
},
|
|
8845
|
+
children: [
|
|
8846
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react6.GalleryHorizontal, { size: 14 }),
|
|
8847
|
+
"Edit gallery"
|
|
8848
|
+
]
|
|
8849
|
+
}
|
|
8850
|
+
)
|
|
8205
8851
|
}
|
|
8206
|
-
}
|
|
8207
|
-
}
|
|
8208
|
-
function applyPersistedOrder(entries) {
|
|
8209
|
-
syncRemovedFlags(entries);
|
|
8210
|
-
if (entries.length === 0) return;
|
|
8211
|
-
const sections = topLevelSections();
|
|
8212
|
-
if (sections.length === 0) return;
|
|
8213
|
-
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
8214
|
-
const ordered = [...sections].sort((a, b) => {
|
|
8215
|
-
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
8216
|
-
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
8217
|
-
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
8218
|
-
if (aOrder === void 0) return 1;
|
|
8219
|
-
if (bOrder === void 0) return -1;
|
|
8220
|
-
return aOrder - bOrder;
|
|
8221
|
-
});
|
|
8222
|
-
let prev = null;
|
|
8223
|
-
for (const el of ordered) {
|
|
8224
|
-
if (prev) prev.after(el);
|
|
8225
|
-
prev = el;
|
|
8226
|
-
}
|
|
8227
|
-
}
|
|
8228
|
-
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
8229
|
-
if (!findByInstanceId(instanceId)) return null;
|
|
8230
|
-
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
8231
|
-
const allSections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
8232
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
|
|
8233
8852
|
);
|
|
8234
|
-
allSections.forEach((el, order) => {
|
|
8235
|
-
const id = instanceIdOf(el);
|
|
8236
|
-
if (!byId.has(id)) {
|
|
8237
|
-
byId.set(id, { instanceId: id, type: el.getAttribute("data-ohw-section") ?? "", order, pagePath: currentPath });
|
|
8238
|
-
}
|
|
8239
|
-
});
|
|
8240
|
-
const target = byId.get(instanceId);
|
|
8241
|
-
if (!target) return null;
|
|
8242
|
-
byId.set(instanceId, { ...target, removed });
|
|
8243
|
-
const entries = Array.from(byId.values());
|
|
8244
|
-
applyPersistedOrder(entries);
|
|
8245
|
-
return entries;
|
|
8246
|
-
}
|
|
8247
|
-
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
8248
|
-
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
8249
|
-
}
|
|
8250
|
-
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
8251
|
-
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
8252
|
-
}
|
|
8253
|
-
function newInstanceId() {
|
|
8254
|
-
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
8255
|
-
}
|
|
8256
|
-
function getPageSectionOrderEntries(raw, currentPath) {
|
|
8257
|
-
if (!raw) return [];
|
|
8258
|
-
try {
|
|
8259
|
-
const entries = JSON.parse(raw);
|
|
8260
|
-
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
8261
|
-
} catch {
|
|
8262
|
-
return [];
|
|
8263
|
-
}
|
|
8264
|
-
}
|
|
8265
|
-
function rekeySectionSubtree(root, instanceId) {
|
|
8266
|
-
const suffix = `::${instanceId}`;
|
|
8267
|
-
const rekey = (el, attr) => {
|
|
8268
|
-
const current = el.getAttribute(attr);
|
|
8269
|
-
if (current) el.setAttribute(attr, `${current}${suffix}`);
|
|
8270
|
-
};
|
|
8271
|
-
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
8272
|
-
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
8273
|
-
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
8274
|
-
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
8275
|
-
}
|
|
8276
|
-
function initSectionInstancesFromContent(content, currentPath) {
|
|
8277
|
-
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
8278
|
-
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
8279
|
-
});
|
|
8280
|
-
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
8281
|
-
for (const entry of entries) {
|
|
8282
|
-
if (entry.instanceId === entry.type) continue;
|
|
8283
|
-
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
8284
|
-
const original = document.querySelector(
|
|
8285
|
-
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
8286
|
-
);
|
|
8287
|
-
if (!original) continue;
|
|
8288
|
-
const clone = original.cloneNode(true);
|
|
8289
|
-
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
8290
|
-
rekeySectionSubtree(clone, entry.instanceId);
|
|
8291
|
-
original.insertAdjacentElement("afterend", clone);
|
|
8292
|
-
}
|
|
8293
|
-
applyPersistedOrder(entries);
|
|
8294
8853
|
}
|
|
8295
8854
|
|
|
8296
8855
|
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
8856
|
+
var import_react8 = require("react");
|
|
8857
|
+
var import_lucide_react7 = require("lucide-react");
|
|
8297
8858
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
8298
8859
|
function findSectionElement(instanceId) {
|
|
8299
8860
|
const escaped = CSS.escape(instanceId);
|
|
@@ -13009,6 +13570,7 @@ function readLogoSizeState(content, placement) {
|
|
|
13009
13570
|
function getLogoElement(el) {
|
|
13010
13571
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
13011
13572
|
if (marked) return marked;
|
|
13573
|
+
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
13012
13574
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
13013
13575
|
if (!root) return null;
|
|
13014
13576
|
const anchor = el.closest("a");
|
|
@@ -14384,6 +14946,9 @@ function collectEditableNodes(extraContent, root = document) {
|
|
|
14384
14946
|
if (el.dataset.ohwEditable === "link") {
|
|
14385
14947
|
return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref3(el) };
|
|
14386
14948
|
}
|
|
14949
|
+
if (el.dataset.ohwEditable === "map") {
|
|
14950
|
+
return { key: el.dataset.ohwKey ?? "", type: "map", text: el.dataset.ohwMapQuery ?? "" };
|
|
14951
|
+
}
|
|
14387
14952
|
return {
|
|
14388
14953
|
key: el.dataset.ohwKey ?? "",
|
|
14389
14954
|
type: el.dataset.ohwEditable ?? "text",
|
|
@@ -14937,21 +15502,10 @@ function parseSchedulingInsertAfter(insertAfter) {
|
|
|
14937
15502
|
insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
|
|
14938
15503
|
};
|
|
14939
15504
|
}
|
|
14940
|
-
function
|
|
14941
|
-
|
|
14942
|
-
const
|
|
14943
|
-
|
|
14944
|
-
return { effectiveInsertAfter, insertBefore };
|
|
14945
|
-
}
|
|
14946
|
-
function getSchedulingMountPoint(insertAfter) {
|
|
14947
|
-
const { anchor } = parseSchedulingInsertAfter(insertAfter);
|
|
14948
|
-
let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
|
|
14949
|
-
if (!anchorEl && anchor === "scheduling") {
|
|
14950
|
-
const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
|
|
14951
|
-
anchorEl = widgets.at(-1) ?? null;
|
|
14952
|
-
}
|
|
14953
|
-
if (!anchorEl) return null;
|
|
14954
|
-
return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
15505
|
+
function resolveEntryAnchor(entry) {
|
|
15506
|
+
if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
|
|
15507
|
+
const parsed = parseSchedulingInsertAfter(entry.insertAfter);
|
|
15508
|
+
return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
|
|
14955
15509
|
}
|
|
14956
15510
|
function schedulingMountDepth(insertAfter) {
|
|
14957
15511
|
if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
|
|
@@ -14968,8 +15522,7 @@ function getPageSchedulingEntries(raw) {
|
|
|
14968
15522
|
}
|
|
14969
15523
|
}
|
|
14970
15524
|
function isSchedulingWidgetMissing(entry) {
|
|
14971
|
-
|
|
14972
|
-
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
|
|
15525
|
+
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
|
|
14973
15526
|
}
|
|
14974
15527
|
function hasMissingSchedulingWidgets(entries) {
|
|
14975
15528
|
return entries.some(isSchedulingWidgetMissing);
|
|
@@ -14999,16 +15552,17 @@ function initSectionsFromContent(content, removeExisting = false) {
|
|
|
14999
15552
|
} catch {
|
|
15000
15553
|
}
|
|
15001
15554
|
}
|
|
15002
|
-
function mountSchedulingWidget(
|
|
15003
|
-
const
|
|
15004
|
-
const sectionId = schedulingSectionId(
|
|
15555
|
+
function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
|
|
15556
|
+
const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
|
|
15557
|
+
const sectionId = schedulingSectionId(widgetId);
|
|
15005
15558
|
if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
|
|
15006
|
-
const
|
|
15007
|
-
if (!
|
|
15559
|
+
const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
|
|
15560
|
+
if (!anchorEl) return false;
|
|
15561
|
+
const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
15008
15562
|
const container = document.createElement("div");
|
|
15009
15563
|
container.dataset.ohwSectionContainer = "scheduling";
|
|
15010
|
-
if (
|
|
15011
|
-
const beforeAnchor = document.querySelector(`[data-ohw-section="${
|
|
15564
|
+
if (beforeId) {
|
|
15565
|
+
const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
|
|
15012
15566
|
const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
|
|
15013
15567
|
if (!beforePoint) return false;
|
|
15014
15568
|
beforePoint.insertAdjacentElement("beforebegin", container);
|
|
@@ -15019,19 +15573,25 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
15019
15573
|
}
|
|
15020
15574
|
tail.insertAdjacentElement("afterend", container);
|
|
15021
15575
|
}
|
|
15022
|
-
|
|
15023
|
-
|
|
15024
|
-
|
|
15025
|
-
|
|
15026
|
-
|
|
15027
|
-
|
|
15028
|
-
|
|
15029
|
-
|
|
15030
|
-
|
|
15031
|
-
|
|
15032
|
-
|
|
15033
|
-
|
|
15034
|
-
|
|
15576
|
+
try {
|
|
15577
|
+
const root = (0, import_client2.createRoot)(container);
|
|
15578
|
+
(0, import_react_dom3.flushSync)(() => {
|
|
15579
|
+
root.render(
|
|
15580
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
15581
|
+
SchedulingWidget,
|
|
15582
|
+
{
|
|
15583
|
+
notifyOnConnect,
|
|
15584
|
+
initialScheduleId: scheduleId,
|
|
15585
|
+
insertAfter: widgetId
|
|
15586
|
+
}
|
|
15587
|
+
)
|
|
15588
|
+
);
|
|
15589
|
+
});
|
|
15590
|
+
} catch (err) {
|
|
15591
|
+
console.error("[ow:scheduling] render threw", err);
|
|
15592
|
+
container.remove();
|
|
15593
|
+
return false;
|
|
15594
|
+
}
|
|
15035
15595
|
const tracker = getSectionsTracker();
|
|
15036
15596
|
let sections = [];
|
|
15037
15597
|
try {
|
|
@@ -15039,10 +15599,12 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
15039
15599
|
} catch {
|
|
15040
15600
|
}
|
|
15041
15601
|
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
15042
|
-
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter ===
|
|
15602
|
+
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
|
|
15043
15603
|
sections.push({
|
|
15044
15604
|
type: "scheduling",
|
|
15045
|
-
insertAfter:
|
|
15605
|
+
insertAfter: widgetId,
|
|
15606
|
+
anchorId,
|
|
15607
|
+
beforeId: beforeId ?? null,
|
|
15046
15608
|
pagePath: window.location.pathname,
|
|
15047
15609
|
...scheduleId ? { scheduleId } : {}
|
|
15048
15610
|
});
|
|
@@ -15056,7 +15618,8 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
|
15056
15618
|
for (let i = pending.length - 1; i >= 0; i--) {
|
|
15057
15619
|
const entry = pending[i];
|
|
15058
15620
|
const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
|
|
15059
|
-
|
|
15621
|
+
const { anchorId, beforeId } = resolveEntryAnchor(entry);
|
|
15622
|
+
if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
|
|
15060
15623
|
pending.splice(i, 1);
|
|
15061
15624
|
}
|
|
15062
15625
|
}
|
|
@@ -15148,7 +15711,7 @@ var EDITOR_CHROME_SELECTOR = '[data-ohw-toolbar], [data-ohw-form-toolbar], [data
|
|
|
15148
15711
|
function isOverEditorChrome(x, y) {
|
|
15149
15712
|
return document.elementsFromPoint(x, y).some((el) => el instanceof HTMLElement && el.matches(EDITOR_CHROME_SELECTOR));
|
|
15150
15713
|
}
|
|
15151
|
-
var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]):not([data-ohw-editable="icon"]):not([data-ohw-editable="form"])';
|
|
15714
|
+
var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]):not([data-ohw-editable="icon"]):not([data-ohw-editable="form"]):not([data-ohw-editable="map"])';
|
|
15152
15715
|
function getVideoEl2(el) {
|
|
15153
15716
|
return el instanceof HTMLVideoElement ? el : el.querySelector("video");
|
|
15154
15717
|
}
|
|
@@ -15204,6 +15767,12 @@ function applyVideoSettingNode(key, val) {
|
|
|
15204
15767
|
});
|
|
15205
15768
|
return true;
|
|
15206
15769
|
}
|
|
15770
|
+
function applyMapQuery(el, val) {
|
|
15771
|
+
if (!(el instanceof HTMLIFrameElement)) return;
|
|
15772
|
+
const nextSrc = `https://www.google.com/maps?q=${encodeURIComponent(val)}&output=embed`;
|
|
15773
|
+
if (el.src !== nextSrc) el.src = nextSrc;
|
|
15774
|
+
el.setAttribute("data-ohw-map-query", val);
|
|
15775
|
+
}
|
|
15207
15776
|
function applyLinkByKey(key, val) {
|
|
15208
15777
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
15209
15778
|
if (el.dataset.ohwEditable === "link") applyLinkHref(el, val);
|
|
@@ -15214,6 +15783,11 @@ function applyLinkByKey(key, val) {
|
|
|
15214
15783
|
hrefAnchors.forEach((el) => applyLinkHref(el, val));
|
|
15215
15784
|
}
|
|
15216
15785
|
}
|
|
15786
|
+
function isInsideLinkEditor(target) {
|
|
15787
|
+
return Boolean(
|
|
15788
|
+
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"]')
|
|
15789
|
+
);
|
|
15790
|
+
}
|
|
15217
15791
|
function isInsideFloatingPanel(target) {
|
|
15218
15792
|
return Boolean(target.closest("[data-ohw-floating-panel]"));
|
|
15219
15793
|
}
|
|
@@ -15221,11 +15795,6 @@ function isPointOverFloatingPanel(clientX, clientY) {
|
|
|
15221
15795
|
const el = document.elementFromPoint(clientX, clientY);
|
|
15222
15796
|
return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
|
|
15223
15797
|
}
|
|
15224
|
-
function isInsideLinkEditor(target) {
|
|
15225
|
-
return Boolean(
|
|
15226
|
-
target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest("[data-ohw-footer-container-chrome]") || target.closest("[data-ohw-footer-add-button]") || target.closest("[data-ohw-more-menu]") || target.closest('[data-slot="dropdown-menu-content"]') || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
|
|
15227
|
-
);
|
|
15228
|
-
}
|
|
15229
15798
|
function getHrefKeyFromElement(el) {
|
|
15230
15799
|
if (!el) return null;
|
|
15231
15800
|
const anchor = el.closest("[data-ohw-href-key]");
|
|
@@ -15484,7 +16053,7 @@ function getNavigationSelectionParent(el) {
|
|
|
15484
16053
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
15485
16054
|
return getFooterLinksContainer();
|
|
15486
16055
|
}
|
|
15487
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
16056
|
+
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isFooterLinksContainer(el) || isInferredFooterGroup2(el)) {
|
|
15488
16057
|
return getNavigationRoot(el);
|
|
15489
16058
|
}
|
|
15490
16059
|
return null;
|
|
@@ -15699,7 +16268,6 @@ var ICONS = {
|
|
|
15699
16268
|
insertUnorderedList: '<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>',
|
|
15700
16269
|
insertOrderedList: '<line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/>'
|
|
15701
16270
|
};
|
|
15702
|
-
var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
|
|
15703
16271
|
var SELECTION_CHROME_GAP2 = 4;
|
|
15704
16272
|
var TOOLBAR_STROKE_GAP2 = 4;
|
|
15705
16273
|
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
@@ -16079,6 +16647,7 @@ function StateToggle({
|
|
|
16079
16647
|
);
|
|
16080
16648
|
}
|
|
16081
16649
|
var contentCache = /* @__PURE__ */ new Map();
|
|
16650
|
+
var fetchedContentPaths = /* @__PURE__ */ new Set();
|
|
16082
16651
|
var brandingCache = /* @__PURE__ */ new Map();
|
|
16083
16652
|
var OHW_LOADER_STYLE = {
|
|
16084
16653
|
position: "fixed",
|
|
@@ -16608,13 +17177,6 @@ function OhhwellsBridge() {
|
|
|
16608
17177
|
const [isItemDragging, setIsItemDragging] = (0, import_react17.useState)(false);
|
|
16609
17178
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react17.useState)(false);
|
|
16610
17179
|
isFooterFrameSelectionRef.current = isFooterFrameSelection;
|
|
16611
|
-
const [floatingPanel, setFloatingPanel] = (0, import_react17.useState)(null);
|
|
16612
|
-
const floatingPanelOpenRef = (0, import_react17.useRef)(false);
|
|
16613
|
-
floatingPanelOpenRef.current = floatingPanel !== null;
|
|
16614
|
-
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react17.useState)(null);
|
|
16615
|
-
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react17.useState)(null);
|
|
16616
|
-
const [editorViewport, setEditorViewport] = (0, import_react17.useState)("desktop");
|
|
16617
|
-
const [parentScrollSnap, setParentScrollSnap] = (0, import_react17.useState)(null);
|
|
16618
17180
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react17.useState)(null);
|
|
16619
17181
|
const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react17.useState)(null);
|
|
16620
17182
|
const footerDragRef = (0, import_react17.useRef)(null);
|
|
@@ -16632,6 +17194,13 @@ function OhhwellsBridge() {
|
|
|
16632
17194
|
const brandKitRef = (0, import_react17.useRef)("");
|
|
16633
17195
|
const stylesRef = (0, import_react17.useRef)("");
|
|
16634
17196
|
const pendingDeleteUndoRef = (0, import_react17.useRef)(null);
|
|
17197
|
+
const [floatingPanel, setFloatingPanel] = (0, import_react17.useState)(null);
|
|
17198
|
+
const floatingPanelOpenRef = (0, import_react17.useRef)(false);
|
|
17199
|
+
const setFloatingPanelRef = (0, import_react17.useRef)(setFloatingPanel);
|
|
17200
|
+
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react17.useState)(null);
|
|
17201
|
+
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react17.useState)(null);
|
|
17202
|
+
const [editorViewport, setEditorViewport] = (0, import_react17.useState)("desktop");
|
|
17203
|
+
const [parentScrollSnap, setParentScrollSnap] = (0, import_react17.useState)(null);
|
|
16635
17204
|
const [sitePages, setSitePages] = (0, import_react17.useState)([]);
|
|
16636
17205
|
const [sectionsByPath, setSectionsByPath] = (0, import_react17.useState)({});
|
|
16637
17206
|
const sectionsPrefetchGenRef = (0, import_react17.useRef)(0);
|
|
@@ -16640,7 +17209,18 @@ function OhhwellsBridge() {
|
|
|
16640
17209
|
const linkPopoverOpenRef = (0, import_react17.useRef)(false);
|
|
16641
17210
|
const linkPopoverGraceUntilRef = (0, import_react17.useRef)(0);
|
|
16642
17211
|
setLinkPopoverRef.current = setLinkPopover;
|
|
17212
|
+
setFloatingPanelRef.current = setFloatingPanel;
|
|
16643
17213
|
linkPopoverSessionRef.current = linkPopover;
|
|
17214
|
+
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
17215
|
+
(0, import_react17.useEffect)(() => {
|
|
17216
|
+
const syncViewport = () => {
|
|
17217
|
+
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
17218
|
+
setEditorViewport((prev) => prev === next ? prev : next);
|
|
17219
|
+
};
|
|
17220
|
+
syncViewport();
|
|
17221
|
+
window.addEventListener("resize", syncViewport);
|
|
17222
|
+
return () => window.removeEventListener("resize", syncViewport);
|
|
17223
|
+
}, []);
|
|
16644
17224
|
const {
|
|
16645
17225
|
navDragRef,
|
|
16646
17226
|
navDropSlots,
|
|
@@ -17965,17 +18545,19 @@ function OhhwellsBridge() {
|
|
|
17965
18545
|
}
|
|
17966
18546
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
17967
18547
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
18548
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
17968
18549
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
17969
18550
|
}
|
|
17970
18551
|
applyBrandChrome(content);
|
|
18552
|
+
initSectionInstancesFromContent(content, window.location.pathname);
|
|
17971
18553
|
for (const [key, val] of Object.entries(content)) {
|
|
17972
18554
|
if (key === "__ohw_sections") continue;
|
|
17973
18555
|
if (key === AI_SECTIONS_KEY) continue;
|
|
18556
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18557
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
17974
18558
|
if (key === BRAND_KIT_KEY) continue;
|
|
17975
18559
|
if (key === STYLE_STORE_KEY) continue;
|
|
17976
18560
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
17977
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
17978
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
17979
18561
|
if (applyVideoSettingNode(key, val)) continue;
|
|
17980
18562
|
if (applyCarouselNode(key, val)) continue;
|
|
17981
18563
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -18003,6 +18585,8 @@ function OhhwellsBridge() {
|
|
|
18003
18585
|
}
|
|
18004
18586
|
} else if (el.dataset.ohwEditable === "link") {
|
|
18005
18587
|
applyLinkHref(el, val);
|
|
18588
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
18589
|
+
applyMapQuery(el, val);
|
|
18006
18590
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
18007
18591
|
applyIconMarkup(el, val);
|
|
18008
18592
|
} else if (el.dataset.ohwEditable === "form") {
|
|
@@ -18023,7 +18607,6 @@ function OhhwellsBridge() {
|
|
|
18023
18607
|
if (isEditModeRef.current) requestMissingSocialIconsRef.current();
|
|
18024
18608
|
enforceLinkHrefs();
|
|
18025
18609
|
initSectionsFromContent(content, true);
|
|
18026
|
-
initSectionInstancesFromContent(content, window.location.pathname);
|
|
18027
18610
|
sectionsLoadedRef.current = true;
|
|
18028
18611
|
pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
|
|
18029
18612
|
if (imageLoads.length === 0) return Promise.resolve();
|
|
@@ -18042,7 +18625,9 @@ function OhhwellsBridge() {
|
|
|
18042
18625
|
let cancelled = false;
|
|
18043
18626
|
setFetchState("loading");
|
|
18044
18627
|
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
18045
|
-
|
|
18628
|
+
const initialPath = pathname;
|
|
18629
|
+
fetchedContentPaths.add(`${subdomain}::${initialPath}`);
|
|
18630
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
18046
18631
|
if (cancelled) return;
|
|
18047
18632
|
const content = data?.content ?? {};
|
|
18048
18633
|
const branding = Boolean(data?.showBranding);
|
|
@@ -18176,16 +18761,17 @@ function OhhwellsBridge() {
|
|
|
18176
18761
|
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
18177
18762
|
}
|
|
18178
18763
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
18764
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
18179
18765
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
18180
18766
|
}
|
|
18181
18767
|
for (const [key, val] of Object.entries(content)) {
|
|
18182
18768
|
if (key === "__ohw_sections") continue;
|
|
18183
18769
|
if (key === AI_SECTIONS_KEY) continue;
|
|
18770
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18771
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18184
18772
|
if (key === BRAND_KIT_KEY) continue;
|
|
18185
18773
|
if (key === STYLE_STORE_KEY) continue;
|
|
18186
18774
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
18187
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
18188
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
18189
18775
|
if (applyVideoSettingNode(key, val)) continue;
|
|
18190
18776
|
if (applyCarouselNode(key, val)) continue;
|
|
18191
18777
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -18200,6 +18786,8 @@ function OhhwellsBridge() {
|
|
|
18200
18786
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
18201
18787
|
} else if (el.dataset.ohwEditable === "link") {
|
|
18202
18788
|
applyLinkHref(el, val);
|
|
18789
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
18790
|
+
applyMapQuery(el, val);
|
|
18203
18791
|
} else if (el.dataset.ohwEditable === "form") {
|
|
18204
18792
|
} else if (isIconMarkupValue(val)) {
|
|
18205
18793
|
} else if (el.innerHTML !== val) {
|
|
@@ -18231,6 +18819,17 @@ function OhhwellsBridge() {
|
|
|
18231
18819
|
debounceTimer = setTimeout(applyFromCache, 150);
|
|
18232
18820
|
};
|
|
18233
18821
|
applyFromCache();
|
|
18822
|
+
const pathCacheKey = `${subdomain}::${pathname}`;
|
|
18823
|
+
if (!fetchedContentPaths.has(pathCacheKey)) {
|
|
18824
|
+
fetchedContentPaths.add(pathCacheKey);
|
|
18825
|
+
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
18826
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
18827
|
+
if (!data?.content) return;
|
|
18828
|
+
contentCache.set(subdomain, data.content);
|
|
18829
|
+
applyFromCache();
|
|
18830
|
+
}).catch(() => {
|
|
18831
|
+
});
|
|
18832
|
+
}
|
|
18234
18833
|
observer = new MutationObserver(scheduleApply);
|
|
18235
18834
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
18236
18835
|
return () => {
|
|
@@ -18346,26 +18945,11 @@ function OhhwellsBridge() {
|
|
|
18346
18945
|
const t2 = setTimeout(measure, 500);
|
|
18347
18946
|
const ro = new ResizeObserver(schedule);
|
|
18348
18947
|
ro.observe(document.body);
|
|
18349
|
-
let lastWidth = window.innerWidth;
|
|
18350
|
-
let resizeTimers = [];
|
|
18351
|
-
const clearResizeTimers = () => {
|
|
18352
|
-
resizeTimers.forEach(clearTimeout);
|
|
18353
|
-
resizeTimers = [];
|
|
18354
|
-
};
|
|
18355
|
-
const handleResize = () => {
|
|
18356
|
-
if (window.innerWidth === lastWidth) return;
|
|
18357
|
-
lastWidth = window.innerWidth;
|
|
18358
|
-
clearResizeTimers();
|
|
18359
|
-
resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
|
|
18360
|
-
};
|
|
18361
|
-
window.addEventListener("resize", handleResize);
|
|
18362
18948
|
return () => {
|
|
18363
18949
|
clearTimeout(t1);
|
|
18364
18950
|
clearTimeout(t2);
|
|
18365
18951
|
if (raf != null) cancelAnimationFrame(raf);
|
|
18366
18952
|
ro.disconnect();
|
|
18367
|
-
clearResizeTimers();
|
|
18368
|
-
window.removeEventListener("resize", handleResize);
|
|
18369
18953
|
};
|
|
18370
18954
|
}, [pathname, isEditMode, postToParent2]);
|
|
18371
18955
|
(0, import_react17.useEffect)(() => {
|
|
@@ -18611,9 +19195,6 @@ function OhhwellsBridge() {
|
|
|
18611
19195
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
18612
19196
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
18613
19197
|
if (isInsideLinkEditor(target)) return;
|
|
18614
|
-
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
18615
|
-
clearMediaSelectionRef.current();
|
|
18616
|
-
}
|
|
18617
19198
|
if (isInsideFloatingPanel(target)) return;
|
|
18618
19199
|
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
18619
19200
|
if (target.closest(
|
|
@@ -18621,6 +19202,9 @@ function OhhwellsBridge() {
|
|
|
18621
19202
|
)) {
|
|
18622
19203
|
return;
|
|
18623
19204
|
}
|
|
19205
|
+
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
19206
|
+
clearMediaSelectionRef.current();
|
|
19207
|
+
}
|
|
18624
19208
|
{
|
|
18625
19209
|
const formEl = getFormElement(target);
|
|
18626
19210
|
const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
|
|
@@ -18772,14 +19356,6 @@ function OhhwellsBridge() {
|
|
|
18772
19356
|
}
|
|
18773
19357
|
const clickedButton = findClosestButtonLike(target);
|
|
18774
19358
|
const buttonOnMedia = Boolean(clickedButton && isMediaEditable(editable) && editable.contains(clickedButton));
|
|
18775
|
-
console.log("[click-debug]", {
|
|
18776
|
-
editableType: editable.dataset.ohwEditable,
|
|
18777
|
-
editableTag: editable.tagName,
|
|
18778
|
-
targetTag: target.tagName,
|
|
18779
|
-
clickedButtonTag: clickedButton?.tagName ?? null,
|
|
18780
|
-
buttonOnMedia,
|
|
18781
|
-
isMediaEditableEditable: isMediaEditable(editable)
|
|
18782
|
-
});
|
|
18783
19359
|
if (isMediaEditable(editable) && !buttonOnMedia) {
|
|
18784
19360
|
e.preventDefault();
|
|
18785
19361
|
e.stopPropagation();
|
|
@@ -18806,11 +19382,6 @@ function OhhwellsBridge() {
|
|
|
18806
19382
|
const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
|
|
18807
19383
|
const hrefCtx = getHrefKeyFromElement(hrefLookupTarget);
|
|
18808
19384
|
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
18809
|
-
console.log("[click-debug 2]", {
|
|
18810
|
-
hrefLookupTargetTag: hrefLookupTarget.tagName,
|
|
18811
|
-
hrefCtx: hrefCtx ? { key: hrefCtx.key } : null,
|
|
18812
|
-
navAnchorTag: navAnchor?.tagName ?? null
|
|
18813
|
-
});
|
|
18814
19385
|
if (navAnchor) {
|
|
18815
19386
|
e.preventDefault();
|
|
18816
19387
|
e.stopPropagation();
|
|
@@ -18980,6 +19551,9 @@ function OhhwellsBridge() {
|
|
|
18980
19551
|
setHoveredItemRect(null);
|
|
18981
19552
|
hoveredNavContainerRef.current = null;
|
|
18982
19553
|
setHoveredNavContainerRect(null);
|
|
19554
|
+
siblingHintElRef.current = null;
|
|
19555
|
+
setSiblingHintRect(null);
|
|
19556
|
+
setSiblingHintRects([]);
|
|
18983
19557
|
return;
|
|
18984
19558
|
}
|
|
18985
19559
|
{
|
|
@@ -19098,7 +19672,6 @@ function OhhwellsBridge() {
|
|
|
19098
19672
|
hoveredNavContainerRef.current = null;
|
|
19099
19673
|
setHoveredNavContainerRect(null);
|
|
19100
19674
|
hoveredItemElRef.current = editable;
|
|
19101
|
-
setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
|
|
19102
19675
|
}
|
|
19103
19676
|
}
|
|
19104
19677
|
}
|
|
@@ -19395,7 +19968,7 @@ function OhhwellsBridge() {
|
|
|
19395
19968
|
}
|
|
19396
19969
|
};
|
|
19397
19970
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
19398
|
-
if (linkPopoverOpenRef.current) {
|
|
19971
|
+
if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
19399
19972
|
if (hoveredImageRef.current) {
|
|
19400
19973
|
hoveredImageRef.current = null;
|
|
19401
19974
|
hoveredImageHasTextOverlapRef.current = false;
|
|
@@ -19760,8 +20333,7 @@ function OhhwellsBridge() {
|
|
|
19760
20333
|
};
|
|
19761
20334
|
const handleMouseMove = (e) => {
|
|
19762
20335
|
const { clientX, clientY } = e;
|
|
19763
|
-
if (
|
|
19764
|
-
if (isOverEditorChrome(clientX, clientY)) {
|
|
20336
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
|
|
19765
20337
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
19766
20338
|
formHoverElRef.current = null;
|
|
19767
20339
|
setFormHoverRect(null);
|
|
@@ -19769,6 +20341,12 @@ function OhhwellsBridge() {
|
|
|
19769
20341
|
setHoveredItemRect(null);
|
|
19770
20342
|
hoveredNavContainerRef.current = null;
|
|
19771
20343
|
setHoveredNavContainerRect(null);
|
|
20344
|
+
siblingHintElRef.current = null;
|
|
20345
|
+
setSiblingHintRect(null);
|
|
20346
|
+
setSiblingHintRects([]);
|
|
20347
|
+
dismissImageHover();
|
|
20348
|
+
clearImageHover();
|
|
20349
|
+
setSectionGap(null);
|
|
19772
20350
|
return;
|
|
19773
20351
|
}
|
|
19774
20352
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
@@ -19780,7 +20358,11 @@ function OhhwellsBridge() {
|
|
|
19780
20358
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
19781
20359
|
const { clientX, clientY } = e.data;
|
|
19782
20360
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
19783
|
-
if (
|
|
20361
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
20362
|
+
dismissImageHover();
|
|
20363
|
+
clearImageHover();
|
|
20364
|
+
return;
|
|
20365
|
+
}
|
|
19784
20366
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
19785
20367
|
probeSectionGapAt(clientX, clientY);
|
|
19786
20368
|
probeImageAt(clientX, clientY);
|
|
@@ -20059,6 +20641,44 @@ function OhhwellsBridge() {
|
|
|
20059
20641
|
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
20060
20642
|
}, 400));
|
|
20061
20643
|
};
|
|
20644
|
+
const reapCommittedAiSections = (excludeIds) => {
|
|
20645
|
+
const aiState = parseAiSectionsState(aiSectionsRef.current);
|
|
20646
|
+
if (aiState.sections.length === 0) return [];
|
|
20647
|
+
let orderEntries = [];
|
|
20648
|
+
try {
|
|
20649
|
+
const parsed = JSON.parse(editContentRef.current[SECTION_ORDER_KEY] ?? "[]");
|
|
20650
|
+
if (Array.isArray(parsed)) orderEntries = parsed;
|
|
20651
|
+
} catch {
|
|
20652
|
+
return [];
|
|
20653
|
+
}
|
|
20654
|
+
const removedIds = orderEntries.filter((entry) => entry && typeof entry.instanceId === "string" && entry.removed).map((entry) => entry.instanceId);
|
|
20655
|
+
if (removedIds.length === 0) return [];
|
|
20656
|
+
const result = reapRemovedAiSections(aiState, parseStyleStore(stylesRef.current), removedIds, excludeIds);
|
|
20657
|
+
if (!result.changed) return [];
|
|
20658
|
+
const nodes = [];
|
|
20659
|
+
aiSectionsRef.current = serializeAiSectionsState(result.state);
|
|
20660
|
+
nodes.push({ key: AI_SECTIONS_KEY, text: aiSectionsRef.current });
|
|
20661
|
+
const reaped = new Set(result.reapedIds);
|
|
20662
|
+
const nextOrderJson = JSON.stringify(orderEntries.filter((entry) => !reaped.has(entry.instanceId)));
|
|
20663
|
+
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: nextOrderJson };
|
|
20664
|
+
setAiSectionOrder(nextOrderJson, window.location.pathname);
|
|
20665
|
+
nodes.push({ key: SECTION_ORDER_KEY, text: nextOrderJson });
|
|
20666
|
+
if (result.store) {
|
|
20667
|
+
stylesRef.current = JSON.stringify(result.store);
|
|
20668
|
+
nodes.push({ key: STYLE_STORE_KEY, text: stylesRef.current });
|
|
20669
|
+
}
|
|
20670
|
+
const nextContent = { ...editContentRef.current };
|
|
20671
|
+
for (const key of Object.keys(nextContent)) {
|
|
20672
|
+
if (key.startsWith(AI_SLOT_KEY_PREFIX) && result.slotPrefixes.some((prefix) => key.startsWith(prefix)) && nextContent[key] !== "") {
|
|
20673
|
+
nextContent[key] = "";
|
|
20674
|
+
nodes.push({ key, text: "" });
|
|
20675
|
+
}
|
|
20676
|
+
}
|
|
20677
|
+
editContentRef.current = nextContent;
|
|
20678
|
+
applyAiSectionsToDom(result.state);
|
|
20679
|
+
applyStylesToDom(parseStyleStore(stylesRef.current));
|
|
20680
|
+
return nodes;
|
|
20681
|
+
};
|
|
20062
20682
|
const handleHydrate = (e) => {
|
|
20063
20683
|
if (e.data?.type !== "ow:hydrate") return;
|
|
20064
20684
|
const content = e.data.content;
|
|
@@ -20077,9 +20697,11 @@ function OhhwellsBridge() {
|
|
|
20077
20697
|
}
|
|
20078
20698
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
20079
20699
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
20700
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
20080
20701
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
20081
20702
|
}
|
|
20082
20703
|
applyBrandChrome(content);
|
|
20704
|
+
initSectionInstancesFromContent(content, window.location.pathname);
|
|
20083
20705
|
let sectionsJson = null;
|
|
20084
20706
|
for (const [key, val] of Object.entries(content)) {
|
|
20085
20707
|
if (key === "__ohw_sections") {
|
|
@@ -20087,11 +20709,11 @@ function OhhwellsBridge() {
|
|
|
20087
20709
|
continue;
|
|
20088
20710
|
}
|
|
20089
20711
|
if (key === AI_SECTIONS_KEY) continue;
|
|
20712
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
20713
|
+
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
20090
20714
|
if (key === BRAND_KIT_KEY) continue;
|
|
20091
20715
|
if (key === STYLE_STORE_KEY) continue;
|
|
20092
20716
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
20093
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
20094
|
-
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
20095
20717
|
if (applyVideoSettingNode(key, val)) continue;
|
|
20096
20718
|
if (applyCarouselNode(key, val)) continue;
|
|
20097
20719
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -20105,6 +20727,8 @@ function OhhwellsBridge() {
|
|
|
20105
20727
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
20106
20728
|
} else if (el.dataset.ohwEditable === "link") {
|
|
20107
20729
|
applyLinkHref(el, val);
|
|
20730
|
+
} else if (el.dataset.ohwEditable === "map") {
|
|
20731
|
+
applyMapQuery(el, val);
|
|
20108
20732
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
20109
20733
|
applyIconMarkup(el, val);
|
|
20110
20734
|
} else if (isIconMarkupValue(val)) {
|
|
@@ -20121,12 +20745,16 @@ function OhhwellsBridge() {
|
|
|
20121
20745
|
sectionsLoadedRef.current = true;
|
|
20122
20746
|
pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
|
|
20123
20747
|
}
|
|
20124
|
-
initSectionInstancesFromContent(content, window.location.pathname);
|
|
20125
20748
|
editContentRef.current = { ...editContentRef.current, ...content };
|
|
20126
20749
|
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
20127
20750
|
reconcileFooterOrderFromContent(editContentRef.current);
|
|
20128
20751
|
syncNavigationDragCursorAttrs();
|
|
20129
20752
|
enforceLinkHrefs();
|
|
20753
|
+
const hydrateReapExclude = /* @__PURE__ */ new Set();
|
|
20754
|
+
const hydratePendingUndo = pendingDeleteUndoRef.current;
|
|
20755
|
+
if (hydratePendingUndo?.sectionInstanceId) hydrateReapExclude.add(hydratePendingUndo.sectionInstanceId);
|
|
20756
|
+
const reapNodes = reapCommittedAiSections(hydrateReapExclude);
|
|
20757
|
+
if (reapNodes.length > 0) postToParentRef.current({ type: "ow:change", nodes: reapNodes });
|
|
20130
20758
|
const hydratedHeight = document.body.scrollHeight;
|
|
20131
20759
|
if (hydratedHeight > 50) postToParentRef.current({ type: "ow:height", height: hydratedHeight });
|
|
20132
20760
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
@@ -20266,12 +20894,35 @@ function OhhwellsBridge() {
|
|
|
20266
20894
|
window.addEventListener("message", handleAiSetBrand);
|
|
20267
20895
|
const handleAiSetStyles = (e) => {
|
|
20268
20896
|
if (e.data?.type !== "ow:ai-set-styles") return;
|
|
20269
|
-
|
|
20897
|
+
let value = typeof e.data.value === "string" ? e.data.value : "";
|
|
20270
20898
|
const previous = stylesRef.current;
|
|
20899
|
+
let previousSections;
|
|
20900
|
+
const store = parseStyleStore(value);
|
|
20901
|
+
if (store) {
|
|
20902
|
+
const folded = foldAlignIntoTrees(parseAiSectionsState(aiSectionsRef.current), store);
|
|
20903
|
+
if (folded.changed) {
|
|
20904
|
+
const nextSections = serializeAiSectionsState(folded.state);
|
|
20905
|
+
if (nextSections !== aiSectionsRef.current) {
|
|
20906
|
+
previousSections = aiSectionsRef.current;
|
|
20907
|
+
aiSectionsRef.current = nextSections;
|
|
20908
|
+
applyAiSectionsToDom(folded.state);
|
|
20909
|
+
postToParentRef.current({
|
|
20910
|
+
type: "ow:change",
|
|
20911
|
+
nodes: [{ key: AI_SECTIONS_KEY, text: nextSections }]
|
|
20912
|
+
});
|
|
20913
|
+
}
|
|
20914
|
+
value = JSON.stringify(folded.store);
|
|
20915
|
+
}
|
|
20916
|
+
}
|
|
20271
20917
|
stylesRef.current = value;
|
|
20272
20918
|
applyStylesToDom(parseStyleStore(value));
|
|
20273
20919
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: STYLE_STORE_KEY, text: value }] });
|
|
20274
|
-
postToParentRef.current({
|
|
20920
|
+
postToParentRef.current({
|
|
20921
|
+
type: "ow:ai-styles-applied",
|
|
20922
|
+
previous,
|
|
20923
|
+
value,
|
|
20924
|
+
...previousSections !== void 0 ? { previousSections } : {}
|
|
20925
|
+
});
|
|
20275
20926
|
};
|
|
20276
20927
|
window.addEventListener("message", handleAiSetStyles);
|
|
20277
20928
|
const handleGetBrand = (e) => {
|
|
@@ -20310,6 +20961,7 @@ function OhhwellsBridge() {
|
|
|
20310
20961
|
if (!entries) return;
|
|
20311
20962
|
const orderJson = JSON.stringify(entries);
|
|
20312
20963
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
20964
|
+
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20313
20965
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
20314
20966
|
aiSectionApiRef.current?.clear();
|
|
20315
20967
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20318,6 +20970,7 @@ function OhhwellsBridge() {
|
|
|
20318
20970
|
const actionId = newInstanceId();
|
|
20319
20971
|
pendingDeleteUndoRef.current = {
|
|
20320
20972
|
actionId,
|
|
20973
|
+
sectionInstanceId: instanceId,
|
|
20321
20974
|
restore: () => {
|
|
20322
20975
|
const restoredEntries = getPageSectionOrderEntries(
|
|
20323
20976
|
editContentRef.current[SECTION_ORDER_KEY],
|
|
@@ -20327,6 +20980,7 @@ function OhhwellsBridge() {
|
|
|
20327
20980
|
if (!restored) return;
|
|
20328
20981
|
const restoredJson = JSON.stringify(restored);
|
|
20329
20982
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: restoredJson };
|
|
20983
|
+
setAiSectionOrder(restoredJson, window.location.pathname);
|
|
20330
20984
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: restoredJson }] });
|
|
20331
20985
|
window.dispatchEvent(new Event("resize"));
|
|
20332
20986
|
const restoreHeight = document.body.scrollHeight;
|
|
@@ -20343,6 +20997,34 @@ function OhhwellsBridge() {
|
|
|
20343
20997
|
});
|
|
20344
20998
|
};
|
|
20345
20999
|
window.addEventListener("message", handleDeleteSection);
|
|
21000
|
+
const handleDuplicateSection = (e) => {
|
|
21001
|
+
if (e.data?.type !== "ow:duplicate-section") return;
|
|
21002
|
+
const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
|
|
21003
|
+
if (!instanceId) return;
|
|
21004
|
+
const newId = newInstanceId();
|
|
21005
|
+
const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname);
|
|
21006
|
+
const result = duplicateSectionInstance(instanceId, newId, window.location.pathname, currentEntries);
|
|
21007
|
+
if (!result) return;
|
|
21008
|
+
const { entries, keyRekeys } = result;
|
|
21009
|
+
const orderJson = JSON.stringify(entries);
|
|
21010
|
+
const nodes = [{ key: SECTION_ORDER_KEY, text: orderJson }];
|
|
21011
|
+
for (const { from, to } of keyRekeys) {
|
|
21012
|
+
const inherited = editContentRef.current[from];
|
|
21013
|
+
if (inherited !== void 0) nodes.push({ key: to, text: inherited });
|
|
21014
|
+
}
|
|
21015
|
+
editContentRef.current = {
|
|
21016
|
+
...editContentRef.current,
|
|
21017
|
+
...Object.fromEntries(nodes.map(({ key, text }) => [key, text]))
|
|
21018
|
+
};
|
|
21019
|
+
setAiSectionOrder(orderJson, window.location.pathname);
|
|
21020
|
+
postToParentRef.current({ type: "ow:change", nodes });
|
|
21021
|
+
window.dispatchEvent(new Event("resize"));
|
|
21022
|
+
const duplicateHeight = document.body.scrollHeight;
|
|
21023
|
+
if (duplicateHeight > 50) postToParentRef.current({ type: "ow:height", height: duplicateHeight });
|
|
21024
|
+
const clone = document.querySelector(`[data-ohw-instance="${CSS.escape(newId)}"]`);
|
|
21025
|
+
if (clone) aiSectionApiRef.current?.selectFromElement(clone);
|
|
21026
|
+
};
|
|
21027
|
+
window.addEventListener("message", handleDuplicateSection);
|
|
20346
21028
|
const handleDeactivate = (e) => {
|
|
20347
21029
|
if (e.data?.type !== "ow:deactivate") return;
|
|
20348
21030
|
if (document.documentElement.hasAttribute("data-ohw-panel-dragging")) return;
|
|
@@ -20352,6 +21034,12 @@ function OhhwellsBridge() {
|
|
|
20352
21034
|
closeLinkPopoverRef.current();
|
|
20353
21035
|
return;
|
|
20354
21036
|
}
|
|
21037
|
+
if (floatingPanelOpenRef.current) {
|
|
21038
|
+
setFloatingPanelRef.current(null);
|
|
21039
|
+
deselectRef.current();
|
|
21040
|
+
deactivateRef.current();
|
|
21041
|
+
return;
|
|
21042
|
+
}
|
|
20355
21043
|
deselectRef.current();
|
|
20356
21044
|
deactivateRef.current();
|
|
20357
21045
|
clearMediaSelectionRef.current();
|
|
@@ -20597,6 +21285,10 @@ function OhhwellsBridge() {
|
|
|
20597
21285
|
};
|
|
20598
21286
|
const handleSave = (e) => {
|
|
20599
21287
|
if (e.data?.type !== "ow:save") return;
|
|
21288
|
+
const pendingUndo = pendingDeleteUndoRef.current;
|
|
21289
|
+
const reapExclude = /* @__PURE__ */ new Set();
|
|
21290
|
+
if (pendingUndo?.sectionInstanceId) reapExclude.add(pendingUndo.sectionInstanceId);
|
|
21291
|
+
const reapNodes = reapCommittedAiSections(reapExclude);
|
|
20600
21292
|
const nodes = collectEditableNodes(editContentRef.current);
|
|
20601
21293
|
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
20602
21294
|
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
@@ -20616,6 +21308,11 @@ function OhhwellsBridge() {
|
|
|
20616
21308
|
const text = specs.length ? JSON.stringify(specs) : editContentRef.current[fieldsKey(formKey)];
|
|
20617
21309
|
if (text) nodes.push({ key: fieldsKey(formKey), type: "text", text });
|
|
20618
21310
|
});
|
|
21311
|
+
for (const reapNode of reapNodes) {
|
|
21312
|
+
if (reapNode.key.startsWith(AI_SLOT_KEY_PREFIX) && !nodes.some((n) => n.key === reapNode.key)) {
|
|
21313
|
+
nodes.push({ key: reapNode.key, type: "text", text: reapNode.text });
|
|
21314
|
+
}
|
|
21315
|
+
}
|
|
20619
21316
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
20620
21317
|
};
|
|
20621
21318
|
const handleInsertSection = (e) => {
|
|
@@ -20626,8 +21323,12 @@ function OhhwellsBridge() {
|
|
|
20626
21323
|
if (inserted) {
|
|
20627
21324
|
const tracker = getSectionsTracker();
|
|
20628
21325
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
|
|
20629
|
-
const
|
|
20630
|
-
|
|
21326
|
+
const reportHeight = () => {
|
|
21327
|
+
const h = document.body.scrollHeight;
|
|
21328
|
+
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
21329
|
+
};
|
|
21330
|
+
reportHeight();
|
|
21331
|
+
setTimeout(reportHeight, 500);
|
|
20631
21332
|
}
|
|
20632
21333
|
};
|
|
20633
21334
|
const handleSwitchSchedule = (e) => {
|
|
@@ -21029,11 +21730,12 @@ function OhhwellsBridge() {
|
|
|
21029
21730
|
window.removeEventListener("message", handleMoveSection);
|
|
21030
21731
|
window.removeEventListener("message", handlePanelDragging);
|
|
21031
21732
|
window.removeEventListener("message", handleDeleteSection);
|
|
21733
|
+
window.removeEventListener("message", handleDuplicateSection);
|
|
21032
21734
|
window.removeEventListener("message", handleDeactivate);
|
|
21033
|
-
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
21034
21735
|
window.removeEventListener("message", handleToastAction);
|
|
21035
21736
|
window.removeEventListener("message", handleFormCount);
|
|
21036
21737
|
window.removeEventListener("message", handleUiEscape);
|
|
21738
|
+
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
21037
21739
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
21038
21740
|
autoSaveTimers.current.clear();
|
|
21039
21741
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
@@ -21236,7 +21938,7 @@ function OhhwellsBridge() {
|
|
|
21236
21938
|
postToParent2({
|
|
21237
21939
|
type: "ow:ready",
|
|
21238
21940
|
version: "1",
|
|
21239
|
-
bridgeVersion: "0.1.
|
|
21941
|
+
bridgeVersion: "0.1.86",
|
|
21240
21942
|
path: pathname,
|
|
21241
21943
|
nodes: collectEditableNodes(editContentRef.current),
|
|
21242
21944
|
sections
|
|
@@ -22155,6 +22857,59 @@ function OhhwellsBridge() {
|
|
|
22155
22857
|
) : null
|
|
22156
22858
|
] });
|
|
22157
22859
|
}
|
|
22860
|
+
|
|
22861
|
+
// src/ui/EmptySection.tsx
|
|
22862
|
+
var import_link = __toESM(require("next/link"), 1);
|
|
22863
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
22864
|
+
function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
|
|
22865
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
22866
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
22867
|
+
"p",
|
|
22868
|
+
{
|
|
22869
|
+
style: {
|
|
22870
|
+
fontFamily: "var(--brand-font-body)",
|
|
22871
|
+
fontSize: "0.75rem",
|
|
22872
|
+
fontWeight: 500,
|
|
22873
|
+
letterSpacing: "0.15em",
|
|
22874
|
+
textTransform: "uppercase",
|
|
22875
|
+
color: "var(--brand-accent)",
|
|
22876
|
+
marginBottom: "1.5rem"
|
|
22877
|
+
},
|
|
22878
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_link.default, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
|
|
22879
|
+
}
|
|
22880
|
+
),
|
|
22881
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
22882
|
+
"h1",
|
|
22883
|
+
{
|
|
22884
|
+
style: {
|
|
22885
|
+
fontFamily: "var(--brand-font-heading)",
|
|
22886
|
+
fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
|
|
22887
|
+
lineHeight: 1.1,
|
|
22888
|
+
letterSpacing: "-0.025em",
|
|
22889
|
+
color: "var(--brand-text)",
|
|
22890
|
+
marginBottom: "1rem"
|
|
22891
|
+
},
|
|
22892
|
+
...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
|
|
22893
|
+
children: title
|
|
22894
|
+
}
|
|
22895
|
+
),
|
|
22896
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
22897
|
+
"p",
|
|
22898
|
+
{
|
|
22899
|
+
style: {
|
|
22900
|
+
fontFamily: "var(--brand-font-body)",
|
|
22901
|
+
fontSize: "1rem",
|
|
22902
|
+
lineHeight: 1.7,
|
|
22903
|
+
fontWeight: 300,
|
|
22904
|
+
color: "var(--brand-text-muted)",
|
|
22905
|
+
maxWidth: "340px"
|
|
22906
|
+
},
|
|
22907
|
+
...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
|
|
22908
|
+
children: "This page doesn't have any content yet."
|
|
22909
|
+
}
|
|
22910
|
+
)
|
|
22911
|
+
] });
|
|
22912
|
+
}
|
|
22158
22913
|
// Annotate the CommonJS export names for ESM import in node:
|
|
22159
22914
|
0 && (module.exports = {
|
|
22160
22915
|
AI_DEFAULT_BRAND,
|
|
@@ -22172,6 +22927,7 @@ function OhhwellsBridge() {
|
|
|
22172
22927
|
DropdownMenuItem,
|
|
22173
22928
|
DropdownMenuSeparator,
|
|
22174
22929
|
DropdownMenuTrigger,
|
|
22930
|
+
EmptySection,
|
|
22175
22931
|
ItemActionToolbar,
|
|
22176
22932
|
ItemInteractionLayer,
|
|
22177
22933
|
LinkEditorPanel,
|