@ohhwells/bridge 0.1.155 → 0.1.157-next.420
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/README.md +1 -1
- package/dist/index.cjs +1022 -846
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -1
- package/dist/index.d.ts +61 -1
- package/dist/index.js +1056 -868
- package/dist/index.js.map +1 -1
- package/dist/pages.cjs +1 -1
- package/dist/pages.cjs.map +1 -1
- package/dist/pages.js +1 -1
- package/dist/pages.js.map +1 -1
- package/dist/styles.css +116 -0
- package/package.json +4 -3
package/dist/index.cjs
CHANGED
|
@@ -64,6 +64,7 @@ __export(index_exports, {
|
|
|
64
64
|
OhwLoaderSurface: () => OhwLoaderSurface,
|
|
65
65
|
SITE_OG_IMAGE_KEY: () => SITE_OG_IMAGE_KEY,
|
|
66
66
|
SchedulingWidget: () => SchedulingWidget,
|
|
67
|
+
TEMPLATE_LOGO_ATTR: () => TEMPLATE_LOGO_ATTR,
|
|
67
68
|
Toggle: () => Toggle,
|
|
68
69
|
ToggleGroup: () => ToggleGroup,
|
|
69
70
|
ToggleGroupItem: () => ToggleGroupItem,
|
|
@@ -83,6 +84,7 @@ __export(index_exports, {
|
|
|
83
84
|
foldAlignIntoTrees: () => foldAlignIntoTrees,
|
|
84
85
|
getEditModeInitialState: () => getEditModeInitialState,
|
|
85
86
|
hasMountedContentNodes: () => hasMountedContentNodes,
|
|
87
|
+
indexCollectionItems: () => indexCollectionItems,
|
|
86
88
|
insertFooterHours: () => insertFooterHours,
|
|
87
89
|
isEditSessionActive: () => isEditSessionActive,
|
|
88
90
|
isPlainLeftClick: () => isPlainLeftClick,
|
|
@@ -90,11 +92,13 @@ __export(index_exports, {
|
|
|
90
92
|
isRenderableTree: () => isRenderableTree,
|
|
91
93
|
isStickySearchParam: () => isStickySearchParam,
|
|
92
94
|
isValidUrl: () => isValidUrl,
|
|
95
|
+
matchCollectionItemClick: () => matchCollectionItemClick,
|
|
93
96
|
nextViableSlide: () => nextViableSlide,
|
|
94
97
|
parseAiFooterState: () => parseAiFooterState,
|
|
95
98
|
parseAiSectionsState: () => parseAiSectionsState,
|
|
96
99
|
parseTarget: () => parseTarget,
|
|
97
100
|
recordOverriddenPaths: () => recordOverriddenPaths,
|
|
101
|
+
releaseTemplateLogoIfReplaced: () => releaseTemplateLogoIfReplaced,
|
|
98
102
|
removeFooterBlock: () => removeFooterBlock,
|
|
99
103
|
resetOverriddenPathsCache: () => resetOverriddenPathsCache,
|
|
100
104
|
resolveFooterCopyright: () => resolveFooterCopyright,
|
|
@@ -516,11 +520,37 @@ function logoTextElement(root) {
|
|
|
516
520
|
);
|
|
517
521
|
return hasOwnText ? root : null;
|
|
518
522
|
}
|
|
523
|
+
var TEMPLATE_LOGO_ATTR = "data-ohw-template-logo";
|
|
524
|
+
function releaseTemplateLogoIfReplaced(img, url) {
|
|
525
|
+
if (!img.hasAttribute(TEMPLATE_LOGO_ATTR)) return;
|
|
526
|
+
let incoming = url;
|
|
527
|
+
try {
|
|
528
|
+
incoming = new URL(url, document.baseURI).href;
|
|
529
|
+
} catch {
|
|
530
|
+
}
|
|
531
|
+
if (incoming !== img.src) img.removeAttribute(TEMPLATE_LOGO_ATTR);
|
|
532
|
+
}
|
|
533
|
+
function logoImage(root, selector) {
|
|
534
|
+
if (root instanceof HTMLImageElement && root.matches(selector)) return root;
|
|
535
|
+
return root.querySelector(selector);
|
|
536
|
+
}
|
|
519
537
|
function logoRootImage(root) {
|
|
520
|
-
const img = root
|
|
538
|
+
const img = logoImage(root, `img:not([${TEMPLATE_LOGO_ATTR}])`);
|
|
521
539
|
const src = img?.getAttribute("src")?.trim() ?? "";
|
|
522
540
|
return img && src && img.style.display !== "none" ? img : null;
|
|
523
541
|
}
|
|
542
|
+
function templateLogoImage(root) {
|
|
543
|
+
const img = logoImage(root, `img[${TEMPLATE_LOGO_ATTR}]`);
|
|
544
|
+
return img && img.style.display !== "none" ? img : null;
|
|
545
|
+
}
|
|
546
|
+
function createWordmark(root) {
|
|
547
|
+
const el = document.createElement("span");
|
|
548
|
+
el.setAttribute("data-ohw-editable", "plain");
|
|
549
|
+
el.setAttribute("data-ohw-key", textKeyForRoot(root));
|
|
550
|
+
if (root instanceof HTMLImageElement) root.parentNode?.insertBefore(el, root.nextSibling);
|
|
551
|
+
else root.appendChild(el);
|
|
552
|
+
return el;
|
|
553
|
+
}
|
|
524
554
|
function applyLogoIdentity(text, isPlaceholder) {
|
|
525
555
|
const display = resolveLogoDisplayText(text);
|
|
526
556
|
const placeholder = isPlaceholder || !text.trim() || display === PLACEHOLDER_BUSINESS_NAME;
|
|
@@ -539,7 +569,9 @@ function applyLogoIdentity(text, isPlaceholder) {
|
|
|
539
569
|
if (placeholder) el.setAttribute("data-ohw-placeholder", "");
|
|
540
570
|
else el.removeAttribute("data-ohw-placeholder");
|
|
541
571
|
if (logoRootImage(el)) return;
|
|
542
|
-
const
|
|
572
|
+
const templateMark = placeholder ? null : templateLogoImage(el);
|
|
573
|
+
if (templateMark) templateMark.style.display = "none";
|
|
574
|
+
const textEl = logoTextElement(el) ?? (templateMark ? createWordmark(el) : null);
|
|
543
575
|
if (textEl && textEl.textContent !== display) textEl.textContent = display;
|
|
544
576
|
});
|
|
545
577
|
return display;
|
|
@@ -571,6 +603,7 @@ function applyLogoImage(url, alt, placement) {
|
|
|
571
603
|
}
|
|
572
604
|
img.removeAttribute("srcset");
|
|
573
605
|
img.removeAttribute("sizes");
|
|
606
|
+
img.removeAttribute(TEMPLATE_LOGO_ATTR);
|
|
574
607
|
img.src = url;
|
|
575
608
|
img.alt = displayAlt;
|
|
576
609
|
img.style.display = "block";
|
|
@@ -590,10 +623,7 @@ function applyLogoImage(url, alt, placement) {
|
|
|
590
623
|
img.style.display = "none";
|
|
591
624
|
}
|
|
592
625
|
if (!textEl) {
|
|
593
|
-
textEl =
|
|
594
|
-
textEl.setAttribute("data-ohw-editable", "plain");
|
|
595
|
-
textEl.setAttribute("data-ohw-key", textKey);
|
|
596
|
-
root.appendChild(textEl);
|
|
626
|
+
textEl = createWordmark(root);
|
|
597
627
|
}
|
|
598
628
|
textEl.style.display = "";
|
|
599
629
|
if (textEl.textContent !== displayAlt) textEl.textContent = displayAlt;
|
|
@@ -6652,6 +6682,21 @@ function pricingCardFeatureCount(tree, index) {
|
|
|
6652
6682
|
const target = findPricingCollection(tree)?.children?.[index];
|
|
6653
6683
|
return target ? pricingFeatureList(target).length : 0;
|
|
6654
6684
|
}
|
|
6685
|
+
function prevailingFeatureIcon(features) {
|
|
6686
|
+
const counts = /* @__PURE__ */ new Map();
|
|
6687
|
+
for (const row of features) {
|
|
6688
|
+
const key = `${row.icon ?? ""}|${row.iconColor ?? ""}`;
|
|
6689
|
+
const entry = counts.get(key) ?? { count: 0, ...row.icon ? { icon: row.icon } : {}, ...row.iconColor ? { iconColor: row.iconColor } : {} };
|
|
6690
|
+
entry.count += 1;
|
|
6691
|
+
counts.set(key, entry);
|
|
6692
|
+
}
|
|
6693
|
+
let best = null;
|
|
6694
|
+
for (const entry of counts.values()) {
|
|
6695
|
+
if (!best || entry.count > best.count) best = entry;
|
|
6696
|
+
}
|
|
6697
|
+
if (!best) return {};
|
|
6698
|
+
return { ...best.icon ? { icon: best.icon } : {}, ...best.iconColor ? { iconColor: best.iconColor } : {} };
|
|
6699
|
+
}
|
|
6655
6700
|
function addPricingCardFeature(tree, index, text) {
|
|
6656
6701
|
return withPricingCollection(tree, (collection) => {
|
|
6657
6702
|
const children = collection.children;
|
|
@@ -6660,7 +6705,7 @@ function addPricingCardFeature(tree, index, text) {
|
|
|
6660
6705
|
const features = pricingFeatureList(target);
|
|
6661
6706
|
if (features.length >= PRICING_FEATURES_MAX) return false;
|
|
6662
6707
|
target.slots = target.slots ?? {};
|
|
6663
|
-
target.slots.features = [...features, { text }];
|
|
6708
|
+
target.slots.features = [...features, { text, ...prevailingFeatureIcon(features) }];
|
|
6664
6709
|
return true;
|
|
6665
6710
|
});
|
|
6666
6711
|
}
|
|
@@ -6847,6 +6892,7 @@ function applyBrandChrome(content) {
|
|
|
6847
6892
|
if (el.textContent !== name) el.textContent = name;
|
|
6848
6893
|
if (el.getAttribute("title") !== name) el.setAttribute("title", name);
|
|
6849
6894
|
});
|
|
6895
|
+
applyLogoIdentity(name, false);
|
|
6850
6896
|
}
|
|
6851
6897
|
const title = content[BRAND_TITLE_KEY];
|
|
6852
6898
|
if (typeof title === "string" && title.length > 0) {
|
|
@@ -7859,7 +7905,7 @@ var AI_MOBILE_CSS = [
|
|
|
7859
7905
|
// page's first section. Top only (bottom needs no nav clearance); ~96px approximates the
|
|
7860
7906
|
// template nav's own height (measured ~94px) — there's no shared `--ohw-header-h` var to read
|
|
7861
7907
|
// an exact figure from (no live measurement exists), so this is a safe approximation, not a
|
|
7862
|
-
// pixel-exact fit. Horizontal spacing already comes from `data-ai-
|
|
7908
|
+
// pixel-exact fit. Horizontal spacing already comes from `data-ai-section-inner`.
|
|
7863
7909
|
'[data-ai-overlay-clearance] [data-ai-overlap-layer="overlay"]{padding-top:96px}',
|
|
7864
7910
|
// A full-bleed carousel's height is pure arithmetic: it spans the whole window, so 16/9 turns
|
|
7865
7911
|
// window width straight into height. Measured at 16/9 it came out ~90% of the viewport at EVERY
|
|
@@ -7875,8 +7921,10 @@ var AI_MOBILE_CSS = [
|
|
|
7875
7921
|
"[data-ai-section]{overflow-x:hidden}",
|
|
7876
7922
|
// `:not([data-ai-full-bleed])`: this `!important` gutter beat the inline `padding: 0` that a
|
|
7877
7923
|
// full-bleed section's container sets, so a carousel/media hero that is edge-to-edge on desktop
|
|
7878
|
-
// still got a 20px band of section background down both sides on a phone.
|
|
7879
|
-
|
|
7924
|
+
// still got a 20px band of section background down both sides on a phone. The footer's own
|
|
7925
|
+
// container keeps the unguarded rule below — `data-ai-full-bleed` can never appear on it.
|
|
7926
|
+
"[data-ai-section-inner]:not([data-ai-full-bleed]){padding:0 20px !important}",
|
|
7927
|
+
"[data-ai-container]{padding:0 20px !important}",
|
|
7880
7928
|
"[data-ai-row]{display:flex !important;flex-direction:column !important;align-items:stretch !important}",
|
|
7881
7929
|
"[data-ai-cell]{width:100%;min-width:0}",
|
|
7882
7930
|
// The rule above turns every row into a COLUMN flex container on phones, which silently breaks
|
|
@@ -8081,6 +8129,31 @@ function pricingCardEmphasis(featured, ctx, hasBg) {
|
|
|
8081
8129
|
function textAttrs(ctx, path) {
|
|
8082
8130
|
return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
|
|
8083
8131
|
}
|
|
8132
|
+
var AI_RESPONSIVE_CSS = [
|
|
8133
|
+
"@media (max-width: 960px) {",
|
|
8134
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
|
|
8135
|
+
' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
|
|
8136
|
+
"}",
|
|
8137
|
+
"@media (max-width: 640px) {",
|
|
8138
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
|
|
8139
|
+
" [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
|
|
8140
|
+
// Group containers flatten to a column on phones; span placements come along for free.
|
|
8141
|
+
// `:not([data-ai-group="overlap"])` for the same reason as the twin pair in AI_MOBILE_CSS — see
|
|
8142
|
+
// the comment there. This sheet's copy is the narrower selector, so without the exemption it
|
|
8143
|
+
// flattens an `overlap` hero below 640px even though the other rule stands down: measured a 390px
|
|
8144
|
+
// viewport with the heading/CTA in flow *under* the image, 219px of section background where the
|
|
8145
|
+
// layered text used to be.
|
|
8146
|
+
' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) { display: flex !important; flex-direction: column !important; }',
|
|
8147
|
+
' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) > * { grid-column: auto !important; }',
|
|
8148
|
+
// `:not([data-ai-full-bleed])` for the same reason as the twin rule in AI_MOBILE_CSS: this one
|
|
8149
|
+
// is narrower (0,2,0 vs 0,1,0) and also `!important`, so without the guard it wins outright and
|
|
8150
|
+
// a full-bleed hero gets its 20px side band back below 640px only — the one width where the
|
|
8151
|
+
// other rule had already been taught to stand down.
|
|
8152
|
+
" [data-ai-responsive] [data-ai-section-inner]:not([data-ai-full-bleed]) { padding-left: 20px !important; padding-right: 20px !important; }",
|
|
8153
|
+
" [data-ai-responsive] { overflow-x: hidden; }",
|
|
8154
|
+
" [data-ai-responsive] img { max-width: 100%; }",
|
|
8155
|
+
"}"
|
|
8156
|
+
].join("\n");
|
|
8084
8157
|
var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
8085
8158
|
function MediaBox({
|
|
8086
8159
|
refValue,
|
|
@@ -8135,7 +8208,7 @@ function MediaBox({
|
|
|
8135
8208
|
position: fill ? "absolute" : void 0,
|
|
8136
8209
|
inset: fill ? 0 : void 0,
|
|
8137
8210
|
width: fill ? "100%" : fixedSize ? "auto" : "100%",
|
|
8138
|
-
height: fill ? "100%" : void 0,
|
|
8211
|
+
height: fill ? "100%" : fixedSize ? height : void 0,
|
|
8139
8212
|
aspectRatio: fill ? void 0 : aspectRatio,
|
|
8140
8213
|
minHeight: fill || fixedSize ? void 0 : height ?? (aspectRatio ? void 0 : 180),
|
|
8141
8214
|
borderRadius: radius,
|
|
@@ -9631,7 +9704,7 @@ function CollectionBlock({ node, ctx, path }) {
|
|
|
9631
9704
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
9632
9705
|
"div",
|
|
9633
9706
|
{
|
|
9634
|
-
"data-ai-grid":
|
|
9707
|
+
"data-ai-grid": String(itemsPerRow),
|
|
9635
9708
|
"data-ohw-pricing-collection": isPricing ? "" : void 0,
|
|
9636
9709
|
style: {
|
|
9637
9710
|
display: "grid",
|
|
@@ -9933,7 +10006,7 @@ function renderNode(node, ctx, path, ambientAlign) {
|
|
|
9933
10006
|
},
|
|
9934
10007
|
children: [
|
|
9935
10008
|
i > 0 && ctx.heroOverlapFullBleed ? (
|
|
9936
|
-
// The section's `data-ai-
|
|
10009
|
+
// The section's `data-ai-section-inner` gave up its max-width/gutter so the base
|
|
9937
10010
|
// layer (this group's i===0 sibling) can span edge-to-edge — reintroduced here,
|
|
9938
10011
|
// scoped to just the overlay text, so a heading/copy/CTA stack doesn't stretch
|
|
9939
10012
|
// the full section width instead of reading at the usual content width.
|
|
@@ -10352,6 +10425,7 @@ function AiTreeRenderer({
|
|
|
10352
10425
|
...fillHeight ? { "data-ai-fill-height": "" } : {},
|
|
10353
10426
|
...needsOverlayClearance ? { "data-ai-overlay-clearance": "" } : {},
|
|
10354
10427
|
...bgAttrs,
|
|
10428
|
+
"data-ai-responsive": "",
|
|
10355
10429
|
style: {
|
|
10356
10430
|
position: "relative",
|
|
10357
10431
|
padding: `${padCss} 0`,
|
|
@@ -10365,12 +10439,13 @@ function AiTreeRenderer({
|
|
|
10365
10439
|
...fillHeight ? { display: "grid" } : {}
|
|
10366
10440
|
},
|
|
10367
10441
|
children: [
|
|
10368
|
-
|
|
10442
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
|
|
10369
10443
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
|
|
10444
|
+
isOverlay && backgroundUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
|
|
10370
10445
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
10371
10446
|
"div",
|
|
10372
10447
|
{
|
|
10373
|
-
"data-ai-
|
|
10448
|
+
"data-ai-section-inner": "",
|
|
10374
10449
|
...fullBleedMedia ? { "data-ai-full-bleed": "" } : {},
|
|
10375
10450
|
style: {
|
|
10376
10451
|
position: "relative",
|
|
@@ -10387,7 +10462,7 @@ function AiTreeRenderer({
|
|
|
10387
10462
|
children: tree.rows.map((row, r2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
10388
10463
|
"div",
|
|
10389
10464
|
{
|
|
10390
|
-
"data-ai-
|
|
10465
|
+
"data-ai-columns": "",
|
|
10391
10466
|
style: {
|
|
10392
10467
|
display: "grid",
|
|
10393
10468
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
@@ -11049,9 +11124,10 @@ function applyAiSectionsToDom(state, options) {
|
|
|
11049
11124
|
if (existing && existing.serialized === serialized && existing.container.isConnected) {
|
|
11050
11125
|
continue;
|
|
11051
11126
|
}
|
|
11052
|
-
const isNewMount = !existing || !existing.container.isConnected;
|
|
11053
11127
|
let container = existing?.container;
|
|
11128
|
+
let isNewMount = false;
|
|
11054
11129
|
if (!container || !container.isConnected) {
|
|
11130
|
+
isNewMount = true;
|
|
11055
11131
|
existing?.root.unmount();
|
|
11056
11132
|
container?.remove();
|
|
11057
11133
|
container = document.createElement("div");
|
|
@@ -11695,6 +11771,172 @@ function useLinkHrefGuardian(...deps) {
|
|
|
11695
11771
|
}, deps);
|
|
11696
11772
|
}
|
|
11697
11773
|
|
|
11774
|
+
// src/ui/link-modal/linkModal.utils.ts
|
|
11775
|
+
function parseTarget(target) {
|
|
11776
|
+
if (!target) return { pageRoute: "", sectionId: null };
|
|
11777
|
+
const hashIndex = target.indexOf("#");
|
|
11778
|
+
if (hashIndex === -1) return { pageRoute: target, sectionId: null };
|
|
11779
|
+
return {
|
|
11780
|
+
pageRoute: target.slice(0, hashIndex),
|
|
11781
|
+
sectionId: target.slice(hashIndex + 1) || null
|
|
11782
|
+
};
|
|
11783
|
+
}
|
|
11784
|
+
function normalizePath(path) {
|
|
11785
|
+
const trimmed = path.trim();
|
|
11786
|
+
if (!trimmed) return "/";
|
|
11787
|
+
try {
|
|
11788
|
+
if (/^https?:\/\//i.test(trimmed)) {
|
|
11789
|
+
return new URL(trimmed).pathname || "/";
|
|
11790
|
+
}
|
|
11791
|
+
} catch {
|
|
11792
|
+
}
|
|
11793
|
+
const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
11794
|
+
if (withSlash.length > 1 && withSlash.endsWith("/")) return withSlash.slice(0, -1);
|
|
11795
|
+
return withSlash;
|
|
11796
|
+
}
|
|
11797
|
+
function findPageByPath(pages, path) {
|
|
11798
|
+
const normalized = normalizePath(path);
|
|
11799
|
+
return pages.find((p) => normalizePath(p.path) === normalized);
|
|
11800
|
+
}
|
|
11801
|
+
function inferPageTitleFromPath(path) {
|
|
11802
|
+
const normalized = normalizePath(path);
|
|
11803
|
+
if (normalized === "/") return "Home";
|
|
11804
|
+
const segment = normalized.split("/").filter(Boolean).pop() ?? "";
|
|
11805
|
+
if (!segment) return "Home";
|
|
11806
|
+
return segment.split("-").filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
11807
|
+
}
|
|
11808
|
+
function isInternalPath(route) {
|
|
11809
|
+
const trimmed = route.trim();
|
|
11810
|
+
if (!trimmed) return false;
|
|
11811
|
+
if (/^https?:\/\//i.test(trimmed)) return false;
|
|
11812
|
+
if (trimmed.startsWith("/")) return true;
|
|
11813
|
+
if (trimmed.includes(" ") || trimmed.includes(".")) return false;
|
|
11814
|
+
return true;
|
|
11815
|
+
}
|
|
11816
|
+
function resolvePage(route, pages) {
|
|
11817
|
+
const found = findPageByPath(pages, route);
|
|
11818
|
+
if (found) return { path: found.path, title: found.title };
|
|
11819
|
+
return { path: normalizePath(route), title: inferPageTitleFromPath(route) };
|
|
11820
|
+
}
|
|
11821
|
+
function getSectionsForPath(sectionsByPath, pageRoute) {
|
|
11822
|
+
if (!sectionsByPath) return [];
|
|
11823
|
+
const normalized = normalizePath(pageRoute);
|
|
11824
|
+
return sectionsByPath[normalized] ?? sectionsByPath[pageRoute] ?? [];
|
|
11825
|
+
}
|
|
11826
|
+
function buildTarget(page, section) {
|
|
11827
|
+
if (section) return `${page.path}#${section.id}`;
|
|
11828
|
+
return page.path;
|
|
11829
|
+
}
|
|
11830
|
+
function isValidUrl(urlString) {
|
|
11831
|
+
try {
|
|
11832
|
+
const url = new URL(urlString);
|
|
11833
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return false;
|
|
11834
|
+
const hostname = url.hostname;
|
|
11835
|
+
if (!hostname || hostname.length === 0) return false;
|
|
11836
|
+
if (hostname.includes(" ")) return false;
|
|
11837
|
+
if (hostname === "localhost") return true;
|
|
11838
|
+
if (!hostname.includes(".")) return false;
|
|
11839
|
+
if (!/[a-z]/i.test(hostname)) return false;
|
|
11840
|
+
return true;
|
|
11841
|
+
} catch {
|
|
11842
|
+
return false;
|
|
11843
|
+
}
|
|
11844
|
+
}
|
|
11845
|
+
function normalizeUrl(value) {
|
|
11846
|
+
const trimmed = value.trim();
|
|
11847
|
+
if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) return trimmed;
|
|
11848
|
+
return `https://${trimmed}`;
|
|
11849
|
+
}
|
|
11850
|
+
function validateUrlInput(value, pages, allPages) {
|
|
11851
|
+
const trimmed = value.trim();
|
|
11852
|
+
if (!trimmed) return "";
|
|
11853
|
+
const exactPage = allPages.find((p) => p.title.toLowerCase() === trimmed.toLowerCase());
|
|
11854
|
+
if (exactPage) return "";
|
|
11855
|
+
const hasPrefixMatch = pages.some((p) => p.title.toLowerCase().startsWith(trimmed.toLowerCase()));
|
|
11856
|
+
if (hasPrefixMatch) {
|
|
11857
|
+
return "Select a page from the list or enter a valid URL";
|
|
11858
|
+
}
|
|
11859
|
+
const hasScheme = /^https?:\/\//i.test(trimmed);
|
|
11860
|
+
if (!hasScheme && !trimmed.includes(".")) {
|
|
11861
|
+
return "Please enter a valid URL (e.g., https://example.com)";
|
|
11862
|
+
}
|
|
11863
|
+
if (!isValidUrl(normalizeUrl(trimmed))) {
|
|
11864
|
+
return "Please enter a valid URL (e.g., https://example.com)";
|
|
11865
|
+
}
|
|
11866
|
+
return "";
|
|
11867
|
+
}
|
|
11868
|
+
function getEditModeInitialState(target, pages, sections) {
|
|
11869
|
+
const empty = {
|
|
11870
|
+
searchValue: "",
|
|
11871
|
+
selectedPage: null,
|
|
11872
|
+
selectedSection: null,
|
|
11873
|
+
step: "input"
|
|
11874
|
+
};
|
|
11875
|
+
if (!target) return empty;
|
|
11876
|
+
if (isValidUrl(normalizeUrl(target))) {
|
|
11877
|
+
return { searchValue: target, selectedPage: null, selectedSection: null, step: "input" };
|
|
11878
|
+
}
|
|
11879
|
+
const { pageRoute, sectionId } = parseTarget(target);
|
|
11880
|
+
if (sectionId) {
|
|
11881
|
+
if (isInternalPath(pageRoute)) {
|
|
11882
|
+
const page = resolvePage(pageRoute, pages);
|
|
11883
|
+
const sec = sections.find((s) => s.id === sectionId);
|
|
11884
|
+
return {
|
|
11885
|
+
searchValue: page.title,
|
|
11886
|
+
selectedPage: page,
|
|
11887
|
+
selectedSection: sec ? { id: sec.id, label: sec.label } : null,
|
|
11888
|
+
step: "input"
|
|
11889
|
+
};
|
|
11890
|
+
}
|
|
11891
|
+
return { searchValue: pageRoute || target, selectedPage: null, selectedSection: null, step: "input" };
|
|
11892
|
+
}
|
|
11893
|
+
if (isInternalPath(pageRoute)) {
|
|
11894
|
+
const page = resolvePage(pageRoute, pages);
|
|
11895
|
+
return {
|
|
11896
|
+
searchValue: page.title,
|
|
11897
|
+
selectedPage: page,
|
|
11898
|
+
selectedSection: null,
|
|
11899
|
+
step: "input"
|
|
11900
|
+
};
|
|
11901
|
+
}
|
|
11902
|
+
return { searchValue: target, selectedPage: null, selectedSection: null, step: "input" };
|
|
11903
|
+
}
|
|
11904
|
+
function filterAvailablePages(pages, existingTargets) {
|
|
11905
|
+
const taken = new Set(existingTargets);
|
|
11906
|
+
return pages.filter((p) => !taken.has(p.path));
|
|
11907
|
+
}
|
|
11908
|
+
|
|
11909
|
+
// src/lib/collection-item-click.ts
|
|
11910
|
+
function indexCollectionItems(pages) {
|
|
11911
|
+
const index = /* @__PURE__ */ new Map();
|
|
11912
|
+
for (const page of pages) {
|
|
11913
|
+
if (page.kind !== "COLLECTION_ITEM" || !page.collection || !page.path) continue;
|
|
11914
|
+
index.set(normalizePath(page.path), { path: page.path, collection: page.collection });
|
|
11915
|
+
}
|
|
11916
|
+
return index;
|
|
11917
|
+
}
|
|
11918
|
+
function pathOfHref(href) {
|
|
11919
|
+
const trimmed = href.trim();
|
|
11920
|
+
if (!trimmed || trimmed.startsWith("#")) return null;
|
|
11921
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed) && !/^https?:/i.test(trimmed)) return null;
|
|
11922
|
+
const withoutHash = trimmed.split("#")[0];
|
|
11923
|
+
const withoutQuery = withoutHash.split("?")[0];
|
|
11924
|
+
if (!withoutQuery) return null;
|
|
11925
|
+
return normalizePath(withoutQuery);
|
|
11926
|
+
}
|
|
11927
|
+
function matchCollectionItemClick(target, index) {
|
|
11928
|
+
if (!target || index.size === 0) return null;
|
|
11929
|
+
const text = target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
|
|
11930
|
+
if (!text) return null;
|
|
11931
|
+
const anchor = text.closest("a");
|
|
11932
|
+
if (!anchor || anchor.closest(CTA_BUTTON_SELECTOR)) return null;
|
|
11933
|
+
const href = anchor.getAttribute("href");
|
|
11934
|
+
if (!href) return null;
|
|
11935
|
+
const path = pathOfHref(href);
|
|
11936
|
+
if (!path) return null;
|
|
11937
|
+
return index.get(path) ?? null;
|
|
11938
|
+
}
|
|
11939
|
+
|
|
11698
11940
|
// src/lib/sticky-search-params.ts
|
|
11699
11941
|
var STICKY_EXACT = /* @__PURE__ */ new Set([
|
|
11700
11942
|
// Site identity. Required in local dev and in the canvas editor's iframe, where there is no
|
|
@@ -17044,7 +17286,7 @@ function apiBase() {
|
|
|
17044
17286
|
function bridgeVersion() {
|
|
17045
17287
|
try {
|
|
17046
17288
|
if (true) {
|
|
17047
|
-
return "0.1.
|
|
17289
|
+
return "0.1.157-next.420";
|
|
17048
17290
|
}
|
|
17049
17291
|
} catch {
|
|
17050
17292
|
}
|
|
@@ -17058,7 +17300,7 @@ function stampBridgeVersionOnDocument() {
|
|
|
17058
17300
|
return;
|
|
17059
17301
|
}
|
|
17060
17302
|
try {
|
|
17061
|
-
const v = true ? "0.1.
|
|
17303
|
+
const v = true ? "0.1.157-next.420" : "";
|
|
17062
17304
|
if (v) {
|
|
17063
17305
|
document.documentElement.setAttribute("data-ohw-bridge-version", v);
|
|
17064
17306
|
window.__OHW_BRIDGE_VERSION__ = v;
|
|
@@ -17066,6 +17308,7 @@ function stampBridgeVersionOnDocument() {
|
|
|
17066
17308
|
} catch {
|
|
17067
17309
|
}
|
|
17068
17310
|
}
|
|
17311
|
+
var TRANSIENT_CONTENT_FETCH = /^(Failed to fetch|Load failed|NetworkError when attempting to fetch resource\.?|fetch failed|The user aborted a request\.?|The operation was aborted\.?)$/i;
|
|
17069
17312
|
var RECOVERABLE_PAGE_ERROR = /Minified React error #(?:418|419|421|422|423|425)\b|Hydration failed because the initial UI does not match|Text content does not match server-rendered HTML|There was an error while hydrating|did not match\. Server:/i;
|
|
17070
17313
|
function isVercelPreviewHost() {
|
|
17071
17314
|
if (typeof location === "undefined") {
|
|
@@ -17083,6 +17326,9 @@ function reportOutageBeacon(args) {
|
|
|
17083
17326
|
if (args.reason === "page_error" && args.detail && RECOVERABLE_PAGE_ERROR.test(args.detail)) {
|
|
17084
17327
|
return;
|
|
17085
17328
|
}
|
|
17329
|
+
if (args.reason === "content_fetch_failed" && args.detail && TRANSIENT_CONTENT_FETCH.test(args.detail.trim())) {
|
|
17330
|
+
return;
|
|
17331
|
+
}
|
|
17086
17332
|
const key = `${args.subdomain}|${args.reason}`;
|
|
17087
17333
|
const now = Date.now();
|
|
17088
17334
|
const prev = lastSent.get(key) || 0;
|
|
@@ -17732,6 +17978,7 @@ function MediaOverlay({
|
|
|
17732
17978
|
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
17733
17979
|
);
|
|
17734
17980
|
}, [isVideo]);
|
|
17981
|
+
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
17735
17982
|
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
17736
17983
|
const box = {
|
|
17737
17984
|
position: "fixed",
|
|
@@ -17830,11 +18077,10 @@ function MediaOverlay({
|
|
|
17830
18077
|
className: "flex items-center justify-center cursor-pointer",
|
|
17831
18078
|
style: {
|
|
17832
18079
|
...box,
|
|
17833
|
-
//
|
|
17834
|
-
//
|
|
17835
|
-
//
|
|
17836
|
-
|
|
17837
|
-
pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
|
|
18080
|
+
// Visual only. `pointer-events: auto` on this full-bleed rect covered the navbar
|
|
18081
|
+
// (hero bg includes the absolute TopNav) and swallowed CTA press-drag. Text overlay
|
|
18082
|
+
// and cueOnly also need clicks to fall through — Replace / video controls opt back in.
|
|
18083
|
+
pointerEvents: "none",
|
|
17838
18084
|
// Selected: a firm component ring with no wash, so the image reads as chosen rather
|
|
17839
18085
|
// than hovered. Hover keeps the existing tinted preview.
|
|
17840
18086
|
boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
@@ -17861,17 +18107,17 @@ function MediaOverlay({
|
|
|
17861
18107
|
},
|
|
17862
18108
|
children: [
|
|
17863
18109
|
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
17864
|
-
|
|
18110
|
+
replaceLabel
|
|
17865
18111
|
]
|
|
17866
18112
|
}
|
|
17867
18113
|
),
|
|
17868
|
-
replaceMode
|
|
18114
|
+
showChrome && replaceMode !== "none" && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
17869
18115
|
Button,
|
|
17870
18116
|
{
|
|
17871
18117
|
"data-ohw-media-overlay": "",
|
|
17872
18118
|
variant: "outline",
|
|
17873
18119
|
size: "sm",
|
|
17874
|
-
"aria-label":
|
|
18120
|
+
"aria-label": replaceLabel,
|
|
17875
18121
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
17876
18122
|
style: {
|
|
17877
18123
|
...OVERLAY_BUTTON_STYLE,
|
|
@@ -17894,7 +18140,7 @@ function MediaOverlay({
|
|
|
17894
18140
|
},
|
|
17895
18141
|
children: [
|
|
17896
18142
|
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
17897
|
-
replaceMode === "full" ?
|
|
18143
|
+
replaceMode === "full" ? replaceLabel : null
|
|
17898
18144
|
]
|
|
17899
18145
|
}
|
|
17900
18146
|
)
|
|
@@ -18404,7 +18650,7 @@ function AiSectionOverlay({
|
|
|
18404
18650
|
|
|
18405
18651
|
// src/ui/ai-section/AiMediaStripOverlay.tsx
|
|
18406
18652
|
var import_react10 = require("react");
|
|
18407
|
-
var
|
|
18653
|
+
var import_lucide_react9 = require("lucide-react");
|
|
18408
18654
|
|
|
18409
18655
|
// src/lib/ai-media-strip-tree.ts
|
|
18410
18656
|
var MEDIA_STRIP_ITEM_MIN = 1;
|
|
@@ -18518,14 +18764,6 @@ function setMediaStripItemAsset(tree, index, assetId) {
|
|
|
18518
18764
|
return true;
|
|
18519
18765
|
});
|
|
18520
18766
|
}
|
|
18521
|
-
function setMediaStripItemAlt(tree, index, alt) {
|
|
18522
|
-
return withMediaStrip(tree, (block) => {
|
|
18523
|
-
const items = block.items;
|
|
18524
|
-
if (index < 0 || index >= items.length) return false;
|
|
18525
|
-
items[index] = { ...items[index], alt };
|
|
18526
|
-
return true;
|
|
18527
|
-
});
|
|
18528
|
-
}
|
|
18529
18767
|
function setMediaStripItemLink(tree, index, link) {
|
|
18530
18768
|
return withMediaStrip(tree, (block) => {
|
|
18531
18769
|
const items = block.items;
|
|
@@ -18543,11 +18781,117 @@ function setMediaStripItemLink(tree, index, link) {
|
|
|
18543
18781
|
});
|
|
18544
18782
|
}
|
|
18545
18783
|
|
|
18546
|
-
// src/ui/
|
|
18784
|
+
// src/ui/dialog.tsx
|
|
18785
|
+
var React9 = __toESM(require("react"), 1);
|
|
18786
|
+
var import_radix_ui6 = require("radix-ui");
|
|
18787
|
+
var import_lucide_react8 = require("lucide-react");
|
|
18547
18788
|
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
18548
|
-
|
|
18549
|
-
|
|
18550
|
-
|
|
18789
|
+
function Dialog2({
|
|
18790
|
+
...props
|
|
18791
|
+
}) {
|
|
18792
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_radix_ui6.Dialog.Root, { "data-slot": "dialog", ...props });
|
|
18793
|
+
}
|
|
18794
|
+
function DialogPortal({
|
|
18795
|
+
...props
|
|
18796
|
+
}) {
|
|
18797
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_radix_ui6.Dialog.Portal, { ...props });
|
|
18798
|
+
}
|
|
18799
|
+
function DialogOverlay({
|
|
18800
|
+
className,
|
|
18801
|
+
...props
|
|
18802
|
+
}) {
|
|
18803
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18804
|
+
import_radix_ui6.Dialog.Overlay,
|
|
18805
|
+
{
|
|
18806
|
+
"data-slot": "dialog-overlay",
|
|
18807
|
+
"data-ohw-link-modal-root": "",
|
|
18808
|
+
className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
|
|
18809
|
+
...props
|
|
18810
|
+
}
|
|
18811
|
+
);
|
|
18812
|
+
}
|
|
18813
|
+
var DialogContent = React9.forwardRef(
|
|
18814
|
+
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
18815
|
+
const positionMode = container ? "absolute" : "fixed";
|
|
18816
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(DialogPortal, { container: container ?? void 0, children: [
|
|
18817
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
18818
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
18819
|
+
import_radix_ui6.Dialog.Content,
|
|
18820
|
+
{
|
|
18821
|
+
ref,
|
|
18822
|
+
"data-slot": "dialog-content",
|
|
18823
|
+
className: cn(
|
|
18824
|
+
positionMode,
|
|
18825
|
+
"left-1/2 top-1/2 z-[2147483647] flex w-full max-w-[448px] -translate-x-1/2 -translate-y-1/2 flex-col overflow-visible",
|
|
18826
|
+
"rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
|
|
18827
|
+
container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
|
|
18828
|
+
className
|
|
18829
|
+
),
|
|
18830
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
18831
|
+
...props,
|
|
18832
|
+
children: [
|
|
18833
|
+
children,
|
|
18834
|
+
showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18835
|
+
import_radix_ui6.Dialog.Close,
|
|
18836
|
+
{
|
|
18837
|
+
type: "button",
|
|
18838
|
+
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
18839
|
+
"aria-label": "Close",
|
|
18840
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react8.X, { size: 16, "aria-hidden": true })
|
|
18841
|
+
}
|
|
18842
|
+
) : null
|
|
18843
|
+
]
|
|
18844
|
+
}
|
|
18845
|
+
)
|
|
18846
|
+
] });
|
|
18847
|
+
}
|
|
18848
|
+
);
|
|
18849
|
+
DialogContent.displayName = import_radix_ui6.Dialog.Content.displayName;
|
|
18850
|
+
function DialogHeader({
|
|
18851
|
+
className,
|
|
18852
|
+
...props
|
|
18853
|
+
}) {
|
|
18854
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
18855
|
+
}
|
|
18856
|
+
function DialogFooter({
|
|
18857
|
+
className,
|
|
18858
|
+
...props
|
|
18859
|
+
}) {
|
|
18860
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18861
|
+
"div",
|
|
18862
|
+
{
|
|
18863
|
+
className: cn("flex items-center justify-end gap-2", className),
|
|
18864
|
+
...props
|
|
18865
|
+
}
|
|
18866
|
+
);
|
|
18867
|
+
}
|
|
18868
|
+
var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18869
|
+
import_radix_ui6.Dialog.Title,
|
|
18870
|
+
{
|
|
18871
|
+
ref,
|
|
18872
|
+
className: cn(
|
|
18873
|
+
"text-lg font-semibold leading-none tracking-tight text-card-foreground",
|
|
18874
|
+
className
|
|
18875
|
+
),
|
|
18876
|
+
...props
|
|
18877
|
+
}
|
|
18878
|
+
));
|
|
18879
|
+
DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
|
|
18880
|
+
var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18881
|
+
import_radix_ui6.Dialog.Description,
|
|
18882
|
+
{
|
|
18883
|
+
ref,
|
|
18884
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
18885
|
+
...props
|
|
18886
|
+
}
|
|
18887
|
+
));
|
|
18888
|
+
DialogDescription.displayName = import_radix_ui6.Dialog.Description.displayName;
|
|
18889
|
+
var DialogClose = import_radix_ui6.Dialog.Close;
|
|
18890
|
+
|
|
18891
|
+
// src/ui/ai-section/AiMediaStripOverlay.tsx
|
|
18892
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
18893
|
+
var PRIMARY3 = "var(--ohw-primary, #0885FE)";
|
|
18894
|
+
var CHROME_SELECTOR = "[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-link-modal-root], [data-ohw-section-picker], [data-ohw-ai-review], [data-ohw-more-menu]";
|
|
18551
18895
|
function findMediaStripItemElement(sectionId, index) {
|
|
18552
18896
|
const sectionEl = findByInstanceId(sectionId);
|
|
18553
18897
|
if (!sectionEl) return null;
|
|
@@ -18557,14 +18901,35 @@ function findMediaStripItemElement(sectionId, index) {
|
|
|
18557
18901
|
}
|
|
18558
18902
|
return null;
|
|
18559
18903
|
}
|
|
18560
|
-
function
|
|
18561
|
-
|
|
18904
|
+
function itemRefFromTarget(target) {
|
|
18905
|
+
if (!(target instanceof Element)) return null;
|
|
18906
|
+
if (target.closest(CHROME_SELECTOR)) return null;
|
|
18907
|
+
const itemEl = target.closest("[data-ohw-media-strip-item]");
|
|
18908
|
+
if (!itemEl) return null;
|
|
18909
|
+
const sectionEl = itemEl.closest("[data-ohw-section]");
|
|
18910
|
+
const unit = sectionEl ? movableUnit(sectionEl) : null;
|
|
18911
|
+
const sectionId = unit ? instanceIdOf(unit) || null : null;
|
|
18912
|
+
const index = Number(itemEl.dataset.ohwMediaStripIndex);
|
|
18913
|
+
if (!sectionId || Number.isNaN(index)) return null;
|
|
18914
|
+
return { sectionId, index };
|
|
18915
|
+
}
|
|
18916
|
+
function sameRef(a, b) {
|
|
18917
|
+
return a?.sectionId === b?.sectionId && a?.index === b?.index;
|
|
18918
|
+
}
|
|
18919
|
+
function rectOf(el) {
|
|
18562
18920
|
if (!el) return null;
|
|
18563
18921
|
const r2 = el.getBoundingClientRect();
|
|
18564
18922
|
if (r2.width <= 0 || r2.height <= 0) return null;
|
|
18565
18923
|
return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
|
|
18566
18924
|
}
|
|
18567
|
-
function
|
|
18925
|
+
function readRect2(ref) {
|
|
18926
|
+
return rectOf(ref && findMediaStripItemElement(ref.sectionId, ref.index));
|
|
18927
|
+
}
|
|
18928
|
+
function readStripRect(ref) {
|
|
18929
|
+
const item = ref && findMediaStripItemElement(ref.sectionId, ref.index);
|
|
18930
|
+
return rectOf(item?.closest("[data-ohw-media-strip]") ?? item);
|
|
18931
|
+
}
|
|
18932
|
+
function useLiveItemRect(ref, strip = false) {
|
|
18568
18933
|
const [rect, setRect] = (0, import_react10.useState)(null);
|
|
18569
18934
|
(0, import_react10.useEffect)(() => {
|
|
18570
18935
|
if (!ref) {
|
|
@@ -18572,7 +18937,7 @@ function useLiveItemRect(ref) {
|
|
|
18572
18937
|
return;
|
|
18573
18938
|
}
|
|
18574
18939
|
const update = () => {
|
|
18575
|
-
const next = readRect2(ref);
|
|
18940
|
+
const next = strip ? readStripRect(ref) : readRect2(ref);
|
|
18576
18941
|
setRect(
|
|
18577
18942
|
(prev) => prev && next && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
|
|
18578
18943
|
);
|
|
@@ -18587,9 +18952,49 @@ function useLiveItemRect(ref) {
|
|
|
18587
18952
|
window.removeEventListener("resize", update);
|
|
18588
18953
|
clearInterval(interval);
|
|
18589
18954
|
};
|
|
18590
|
-
}, [ref?.sectionId, ref?.index]);
|
|
18955
|
+
}, [ref?.sectionId, ref?.index, strip]);
|
|
18591
18956
|
return rect;
|
|
18592
18957
|
}
|
|
18958
|
+
var TOOLBAR_STRIP_GAP = 52;
|
|
18959
|
+
var TOOLBAR_STRIP_GAP_MOBILE = 42;
|
|
18960
|
+
var TOOLBAR_EDGE_MARGIN2 = 4;
|
|
18961
|
+
function StripToolbarSlot({ stripRect, children }) {
|
|
18962
|
+
const slotRef = (0, import_react10.useRef)(null);
|
|
18963
|
+
const [shift, setShift] = (0, import_react10.useState)(0);
|
|
18964
|
+
const centerX = stripRect.left + stripRect.width / 2;
|
|
18965
|
+
(0, import_react10.useLayoutEffect)(() => {
|
|
18966
|
+
const slot = slotRef.current;
|
|
18967
|
+
if (!slot) return;
|
|
18968
|
+
const clamp = () => {
|
|
18969
|
+
const w = slot.offsetWidth;
|
|
18970
|
+
if (w <= 0) return;
|
|
18971
|
+
const half = w / 2;
|
|
18972
|
+
const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
|
|
18973
|
+
setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
|
|
18974
|
+
};
|
|
18975
|
+
clamp();
|
|
18976
|
+
const ro = new ResizeObserver(clamp);
|
|
18977
|
+
ro.observe(slot);
|
|
18978
|
+
return () => ro.disconnect();
|
|
18979
|
+
}, [centerX, children]);
|
|
18980
|
+
const mobile = window.innerWidth <= 480;
|
|
18981
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
18982
|
+
"div",
|
|
18983
|
+
{
|
|
18984
|
+
ref: slotRef,
|
|
18985
|
+
"data-ohw-bridge": "",
|
|
18986
|
+
"data-ohw-item-interaction": "",
|
|
18987
|
+
className: "pointer-events-auto fixed",
|
|
18988
|
+
style: {
|
|
18989
|
+
top: stripRect.top - (mobile ? TOOLBAR_STRIP_GAP_MOBILE : TOOLBAR_STRIP_GAP),
|
|
18990
|
+
left: centerX + shift,
|
|
18991
|
+
transform: "translate(-50%, -100%)",
|
|
18992
|
+
zIndex: 2147483645
|
|
18993
|
+
},
|
|
18994
|
+
children
|
|
18995
|
+
}
|
|
18996
|
+
);
|
|
18997
|
+
}
|
|
18593
18998
|
function requestValidateTree(postToParent2, tree) {
|
|
18594
18999
|
return new Promise((resolve) => {
|
|
18595
19000
|
const id = `ai-validate-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -18626,116 +19031,72 @@ function requestAssetPick(postToParent2) {
|
|
|
18626
19031
|
postToParent2({ type: "ow:asset-pick", id });
|
|
18627
19032
|
});
|
|
18628
19033
|
}
|
|
18629
|
-
function
|
|
19034
|
+
function ToolbarAction({
|
|
18630
19035
|
label,
|
|
18631
19036
|
onClick,
|
|
18632
|
-
disabled,
|
|
18633
|
-
active
|
|
19037
|
+
disabled = false,
|
|
19038
|
+
active = false,
|
|
19039
|
+
children
|
|
18634
19040
|
}) {
|
|
18635
|
-
|
|
18636
|
-
|
|
18637
|
-
{
|
|
18638
|
-
|
|
18639
|
-
|
|
18640
|
-
disabled,
|
|
18641
|
-
style: {
|
|
18642
|
-
height: 28,
|
|
18643
|
-
padding: "0 10px",
|
|
18644
|
-
display: "inline-flex",
|
|
18645
|
-
alignItems: "center",
|
|
18646
|
-
gap: 4,
|
|
18647
|
-
borderRadius: 999,
|
|
18648
|
-
border: "none",
|
|
18649
|
-
cursor: disabled ? "default" : "pointer",
|
|
18650
|
-
background: active ? OHW_BLUE_DARK : "#ffffff",
|
|
18651
|
-
color: active ? "#ffffff" : OHW_BLUE_DARK,
|
|
18652
|
-
opacity: disabled ? 0.4 : 1,
|
|
18653
|
-
fontSize: 12,
|
|
18654
|
-
lineHeight: "16px",
|
|
18655
|
-
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
18656
|
-
whiteSpace: "nowrap",
|
|
18657
|
-
flex: "0 0 auto"
|
|
18658
|
-
},
|
|
18659
|
-
children: label
|
|
18660
|
-
}
|
|
18661
|
-
);
|
|
19041
|
+
const button = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, active, onClick, className: "size-8", children });
|
|
19042
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
|
|
19043
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "inline-flex", children: button }) : button }),
|
|
19044
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
|
|
19045
|
+
] });
|
|
18662
19046
|
}
|
|
18663
|
-
function
|
|
18664
|
-
|
|
18665
|
-
|
|
18666
|
-
|
|
18667
|
-
|
|
18668
|
-
|
|
18669
|
-
|
|
18670
|
-
|
|
18671
|
-
|
|
18672
|
-
|
|
18673
|
-
|
|
18674
|
-
|
|
18675
|
-
|
|
18676
|
-
|
|
18677
|
-
|
|
18678
|
-
|
|
18679
|
-
|
|
18680
|
-
|
|
18681
|
-
|
|
18682
|
-
|
|
18683
|
-
|
|
18684
|
-
|
|
18685
|
-
|
|
18686
|
-
|
|
18687
|
-
|
|
18688
|
-
|
|
18689
|
-
|
|
18690
|
-
|
|
18691
|
-
|
|
18692
|
-
},
|
|
18693
|
-
children: "Alt"
|
|
18694
|
-
}
|
|
18695
|
-
),
|
|
18696
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18697
|
-
"input",
|
|
19047
|
+
function ToolbarSeparator() {
|
|
19048
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
|
|
19049
|
+
}
|
|
19050
|
+
function OptionMenu({
|
|
19051
|
+
label,
|
|
19052
|
+
value,
|
|
19053
|
+
options,
|
|
19054
|
+
onChange
|
|
19055
|
+
}) {
|
|
19056
|
+
const current = options.find((o) => o.value === value) ?? options[0];
|
|
19057
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
19058
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-xs text-muted-foreground", children: label }),
|
|
19059
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(DropdownMenu, { modal: false, children: [
|
|
19060
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
19061
|
+
"button",
|
|
19062
|
+
{
|
|
19063
|
+
type: "button",
|
|
19064
|
+
"aria-label": label,
|
|
19065
|
+
className: "inline-flex h-8 min-w-[76px] items-center gap-[7px] rounded-[6px] bg-transparent px-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted data-[state=open]:bg-muted",
|
|
19066
|
+
children: [
|
|
19067
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "flex-1 text-left", children: current.label }),
|
|
19068
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ChevronDown, { size: 16, style: { pointerEvents: "none" } })
|
|
19069
|
+
]
|
|
19070
|
+
}
|
|
19071
|
+
) }),
|
|
19072
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[132px] min-w-[132px] p-1", children: options.map((option) => {
|
|
19073
|
+
const selected = option.value === value;
|
|
19074
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
19075
|
+
DropdownMenuItem,
|
|
18698
19076
|
{
|
|
18699
|
-
|
|
18700
|
-
|
|
18701
|
-
|
|
18702
|
-
|
|
18703
|
-
|
|
18704
|
-
|
|
18705
|
-
|
|
18706
|
-
|
|
18707
|
-
|
|
18708
|
-
|
|
18709
|
-
|
|
18710
|
-
|
|
18711
|
-
|
|
18712
|
-
|
|
18713
|
-
"aria-label": "Image alt text",
|
|
18714
|
-
style: {
|
|
18715
|
-
flex: 1,
|
|
18716
|
-
minWidth: 0,
|
|
18717
|
-
border: "none",
|
|
18718
|
-
outline: "none",
|
|
18719
|
-
background: "transparent",
|
|
18720
|
-
fontSize: 12,
|
|
18721
|
-
lineHeight: "16px",
|
|
18722
|
-
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
18723
|
-
color: "#1f2937"
|
|
18724
|
-
}
|
|
18725
|
-
}
|
|
18726
|
-
)
|
|
18727
|
-
]
|
|
18728
|
-
}
|
|
18729
|
-
);
|
|
19077
|
+
role: "menuitemradio",
|
|
19078
|
+
"aria-checked": selected,
|
|
19079
|
+
onSelect: () => onChange(option.value),
|
|
19080
|
+
className: cn("grid grid-cols-[1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
|
|
19081
|
+
children: [
|
|
19082
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: option.label }),
|
|
19083
|
+
selected && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Check, { size: 16, className: "text-bridge-primary" })
|
|
19084
|
+
]
|
|
19085
|
+
},
|
|
19086
|
+
option.value
|
|
19087
|
+
);
|
|
19088
|
+
}) })
|
|
19089
|
+
] })
|
|
19090
|
+
] });
|
|
18730
19091
|
}
|
|
18731
19092
|
var VARIANTS = [
|
|
18732
19093
|
{ value: "logos", label: "Logos" },
|
|
18733
19094
|
{ value: "reel", label: "Reel" }
|
|
18734
19095
|
];
|
|
18735
19096
|
var ALIGNS = [
|
|
18736
|
-
{ value: "left", label: "
|
|
18737
|
-
{ value: "center", label: "
|
|
18738
|
-
{ value: "right", label: "
|
|
19097
|
+
{ value: "left", label: "Align left", Icon: import_lucide_react9.AlignLeft },
|
|
19098
|
+
{ value: "center", label: "Align center", Icon: import_lucide_react9.AlignCenter },
|
|
19099
|
+
{ value: "right", label: "Align right", Icon: import_lucide_react9.AlignRight }
|
|
18739
19100
|
];
|
|
18740
19101
|
var HOVERS = [
|
|
18741
19102
|
{ value: "none", label: "None" },
|
|
@@ -18743,104 +19104,104 @@ var HOVERS = [
|
|
|
18743
19104
|
{ value: "zoom", label: "Zoom" },
|
|
18744
19105
|
{ value: "fade", label: "Fade" }
|
|
18745
19106
|
];
|
|
18746
|
-
var TREATMENTS = [
|
|
18747
|
-
{ value: "color", label: "Color" },
|
|
18748
|
-
{ value: "grayscale", label: "Grayscale" }
|
|
18749
|
-
];
|
|
18750
19107
|
var HTTP_URL_RE = /^https?:\/\/\S+$/i;
|
|
18751
|
-
function
|
|
18752
|
-
|
|
19108
|
+
function LinkModal({
|
|
19109
|
+
href,
|
|
19110
|
+
linkTarget,
|
|
19111
|
+
onClose,
|
|
19112
|
+
onSave
|
|
19113
|
+
}) {
|
|
19114
|
+
const [draft, setDraft] = (0, import_react10.useState)(href);
|
|
19115
|
+
const [newTab, setNewTab] = (0, import_react10.useState)(linkTarget !== "same-tab");
|
|
18753
19116
|
const [invalid, setInvalid] = (0, import_react10.useState)(false);
|
|
18754
|
-
|
|
18755
|
-
setDraft(value);
|
|
18756
|
-
setInvalid(false);
|
|
18757
|
-
}, [value]);
|
|
18758
|
-
const commit = () => {
|
|
19117
|
+
const save = () => {
|
|
18759
19118
|
const next = draft.trim();
|
|
18760
|
-
if (next
|
|
18761
|
-
|
|
18762
|
-
|
|
18763
|
-
onCommit(next);
|
|
18764
|
-
};
|
|
18765
|
-
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
18766
|
-
"div",
|
|
18767
|
-
{
|
|
18768
|
-
style: {
|
|
18769
|
-
display: "flex",
|
|
18770
|
-
alignItems: "center",
|
|
18771
|
-
gap: 6,
|
|
18772
|
-
height: 28,
|
|
18773
|
-
padding: "0 12px",
|
|
18774
|
-
borderRadius: 999,
|
|
18775
|
-
background: "#ffffff",
|
|
18776
|
-
width: "100%",
|
|
18777
|
-
maxWidth: 260,
|
|
18778
|
-
boxSizing: "border-box",
|
|
18779
|
-
boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
|
|
18780
|
-
},
|
|
18781
|
-
children: [
|
|
18782
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18783
|
-
"span",
|
|
18784
|
-
{
|
|
18785
|
-
style: {
|
|
18786
|
-
flex: "0 0 auto",
|
|
18787
|
-
color: OHW_BLUE_DARK,
|
|
18788
|
-
fontSize: 10,
|
|
18789
|
-
fontWeight: 700,
|
|
18790
|
-
textTransform: "uppercase",
|
|
18791
|
-
letterSpacing: 0.4
|
|
18792
|
-
},
|
|
18793
|
-
children: "Link"
|
|
18794
|
-
}
|
|
18795
|
-
),
|
|
18796
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18797
|
-
"input",
|
|
18798
|
-
{
|
|
18799
|
-
type: "text",
|
|
18800
|
-
inputMode: "url",
|
|
18801
|
-
value: draft,
|
|
18802
|
-
onChange: (e) => setDraft(e.target.value),
|
|
18803
|
-
onBlur: commit,
|
|
18804
|
-
onKeyDown: (e) => {
|
|
18805
|
-
if (e.key === "Enter") e.currentTarget.blur();
|
|
18806
|
-
if (e.key === "Escape") {
|
|
18807
|
-
setDraft(value);
|
|
18808
|
-
setInvalid(false);
|
|
18809
|
-
e.currentTarget.blur();
|
|
18810
|
-
}
|
|
18811
|
-
},
|
|
18812
|
-
placeholder: "https://example.com",
|
|
18813
|
-
"aria-label": "Image link URL",
|
|
18814
|
-
"aria-invalid": invalid,
|
|
18815
|
-
style: {
|
|
18816
|
-
flex: 1,
|
|
18817
|
-
minWidth: 0,
|
|
18818
|
-
border: "none",
|
|
18819
|
-
outline: "none",
|
|
18820
|
-
background: "transparent",
|
|
18821
|
-
fontSize: 12,
|
|
18822
|
-
lineHeight: "16px",
|
|
18823
|
-
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
18824
|
-
color: "#1f2937"
|
|
18825
|
-
}
|
|
18826
|
-
}
|
|
18827
|
-
)
|
|
18828
|
-
]
|
|
19119
|
+
if (next && !HTTP_URL_RE.test(next)) {
|
|
19120
|
+
setInvalid(true);
|
|
19121
|
+
return;
|
|
18829
19122
|
}
|
|
18830
|
-
|
|
19123
|
+
onSave(next, newTab ? "new-tab" : "same-tab");
|
|
19124
|
+
onClose();
|
|
19125
|
+
};
|
|
19126
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Dialog2, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(DialogContent, { "data-ohw-link-modal-root": "", className: "max-w-[400px] gap-4 p-5", children: [
|
|
19127
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DialogTitle, { className: "text-base", children: "Image link" }) }),
|
|
19128
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-3", children: [
|
|
19129
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19130
|
+
"input",
|
|
19131
|
+
{
|
|
19132
|
+
autoFocus: true,
|
|
19133
|
+
type: "text",
|
|
19134
|
+
inputMode: "url",
|
|
19135
|
+
value: draft,
|
|
19136
|
+
onChange: (e) => {
|
|
19137
|
+
setDraft(e.target.value);
|
|
19138
|
+
setInvalid(false);
|
|
19139
|
+
},
|
|
19140
|
+
onKeyDown: (e) => {
|
|
19141
|
+
if (e.key === "Enter") save();
|
|
19142
|
+
},
|
|
19143
|
+
placeholder: "https://example.com",
|
|
19144
|
+
"aria-label": "Image link URL",
|
|
19145
|
+
"aria-invalid": invalid,
|
|
19146
|
+
className: cn(
|
|
19147
|
+
"h-9 w-full rounded-[6px] border border-border bg-background px-3 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/70 focus:border-bridge-primary",
|
|
19148
|
+
invalid && "border-destructive focus:border-destructive"
|
|
19149
|
+
)
|
|
19150
|
+
}
|
|
19151
|
+
),
|
|
19152
|
+
invalid && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-xs text-destructive", children: "Enter a full URL starting with http:// or https://" }),
|
|
19153
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex items-center gap-2 text-[13px] text-foreground", children: [
|
|
19154
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "checkbox", checked: newTab, onChange: (e) => setNewTab(e.target.checked) }),
|
|
19155
|
+
"Open in new tab"
|
|
19156
|
+
] })
|
|
19157
|
+
] }),
|
|
19158
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(DialogFooter, { children: [
|
|
19159
|
+
href && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19160
|
+
"button",
|
|
19161
|
+
{
|
|
19162
|
+
type: "button",
|
|
19163
|
+
onClick: () => {
|
|
19164
|
+
onSave("", "new-tab");
|
|
19165
|
+
onClose();
|
|
19166
|
+
},
|
|
19167
|
+
className: "mr-auto rounded-[6px] px-3 py-2 text-[13px] font-medium text-destructive transition-colors hover:bg-muted",
|
|
19168
|
+
children: "Remove link"
|
|
19169
|
+
}
|
|
19170
|
+
),
|
|
19171
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19172
|
+
"button",
|
|
19173
|
+
{
|
|
19174
|
+
type: "button",
|
|
19175
|
+
onClick: onClose,
|
|
19176
|
+
className: "rounded-[6px] px-3 py-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted",
|
|
19177
|
+
children: "Cancel"
|
|
19178
|
+
}
|
|
19179
|
+
),
|
|
19180
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19181
|
+
"button",
|
|
19182
|
+
{
|
|
19183
|
+
type: "button",
|
|
19184
|
+
onClick: save,
|
|
19185
|
+
className: "rounded-[6px] bg-bridge-primary px-3 py-2 text-[13px] font-medium text-primary-foreground transition-opacity hover:opacity-90",
|
|
19186
|
+
children: "Save"
|
|
19187
|
+
}
|
|
19188
|
+
)
|
|
19189
|
+
] })
|
|
19190
|
+
] }) });
|
|
18831
19191
|
}
|
|
18832
19192
|
function MediaStripToolbar({
|
|
18833
19193
|
entry,
|
|
18834
19194
|
index,
|
|
18835
19195
|
pending,
|
|
18836
19196
|
error,
|
|
19197
|
+
itemEditOn,
|
|
19198
|
+
onToggleItemEdit,
|
|
18837
19199
|
onSetVariant,
|
|
18838
19200
|
onSetAlign,
|
|
18839
19201
|
onSetHover,
|
|
18840
19202
|
onSetTreatment,
|
|
18841
19203
|
onResize,
|
|
18842
|
-
|
|
18843
|
-
onSetLink,
|
|
19204
|
+
onOpenLink,
|
|
18844
19205
|
onAddItem,
|
|
18845
19206
|
onRemoveItem,
|
|
18846
19207
|
onChangeImage,
|
|
@@ -18849,81 +19210,102 @@ function MediaStripToolbar({
|
|
|
18849
19210
|
}) {
|
|
18850
19211
|
const items = mediaStripItems(entry.tree);
|
|
18851
19212
|
const itemCount = items.length;
|
|
18852
|
-
const currentAlt = items[index]?.alt ?? "";
|
|
18853
|
-
const currentHref = items[index]?.href ?? "";
|
|
18854
|
-
const currentTarget = items[index]?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
|
|
18855
19213
|
const slots = findMediaStripSlots(entry.tree);
|
|
18856
19214
|
const variant = slots?.variant === "reel" ? "reel" : "logos";
|
|
18857
19215
|
const align = slots?.align === "left" || slots?.align === "right" ? slots.align : "center";
|
|
18858
19216
|
const hover = slots?.hover === "none" || slots?.hover === "lift" || slots?.hover === "zoom" || slots?.hover === "fade" ? slots.hover : "lift";
|
|
18859
19217
|
const treatment = slots?.treatment === "color" || slots?.treatment === "grayscale" ? slots.treatment : variant === "logos" ? "grayscale" : "color";
|
|
18860
19218
|
const sizeValue = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
|
|
18861
|
-
const
|
|
18862
|
-
const
|
|
18863
|
-
|
|
18864
|
-
gap: 6,
|
|
18865
|
-
flexWrap: "nowrap",
|
|
18866
|
-
justifyContent: "center",
|
|
18867
|
-
overflowX: "auto",
|
|
18868
|
-
WebkitOverflowScrolling: "touch",
|
|
18869
|
-
width: "100%",
|
|
18870
|
-
scrollbarWidth: "none"
|
|
18871
|
-
} : { display: "flex", gap: 6, flexWrap: "nowrap", justifyContent: "center" };
|
|
18872
|
-
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
19219
|
+
const mobile = window.innerWidth <= 480;
|
|
19220
|
+
const gatedLabel = (label) => itemEditOn ? label : "Turn on the star to edit this image";
|
|
19221
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
18873
19222
|
"div",
|
|
18874
19223
|
{
|
|
18875
19224
|
"data-ohw-bridge": "",
|
|
18876
19225
|
"data-ohw-toolbar": "",
|
|
18877
19226
|
onMouseDown: (e) => e.stopPropagation(),
|
|
18878
|
-
|
|
18879
|
-
|
|
18880
|
-
flexDirection: "column",
|
|
18881
|
-
gap: 6,
|
|
18882
|
-
alignItems: "center",
|
|
18883
|
-
background: OHW_BLUE,
|
|
18884
|
-
padding: 8,
|
|
18885
|
-
borderRadius: 12,
|
|
18886
|
-
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
18887
|
-
pointerEvents: pending ? "none" : "auto",
|
|
18888
|
-
opacity: pending ? 0.6 : 1,
|
|
18889
|
-
maxWidth: isMobile ? "calc(100vw - 24px)" : "none"
|
|
18890
|
-
},
|
|
19227
|
+
className: cn("flex flex-col items-center gap-1.5 font-sans", pending && "pointer-events-none opacity-60"),
|
|
19228
|
+
style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
|
|
18891
19229
|
children: [
|
|
18892
|
-
/* @__PURE__ */ (0,
|
|
18893
|
-
|
|
18894
|
-
|
|
18895
|
-
|
|
18896
|
-
|
|
18897
|
-
|
|
18898
|
-
|
|
18899
|
-
|
|
18900
|
-
|
|
18901
|
-
|
|
18902
|
-
|
|
18903
|
-
|
|
18904
|
-
|
|
18905
|
-
|
|
18906
|
-
|
|
18907
|
-
|
|
18908
|
-
|
|
18909
|
-
|
|
18910
|
-
|
|
18911
|
-
|
|
18912
|
-
|
|
18913
|
-
|
|
18914
|
-
|
|
18915
|
-
|
|
18916
|
-
|
|
18917
|
-
|
|
18918
|
-
|
|
18919
|
-
|
|
18920
|
-
|
|
18921
|
-
|
|
18922
|
-
|
|
18923
|
-
|
|
19230
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
19231
|
+
"div",
|
|
19232
|
+
{
|
|
19233
|
+
className: cn(
|
|
19234
|
+
"flex items-center gap-1 rounded-[10px] border border-border bg-background p-1 whitespace-nowrap",
|
|
19235
|
+
"shadow-[0px_10px_15px_-3px_rgba(0,0,0,0.1),0px_4px_6px_-4px_rgba(0,0,0,0.1)]",
|
|
19236
|
+
mobile ? "flex-wrap justify-center" : "flex-nowrap"
|
|
19237
|
+
),
|
|
19238
|
+
children: [
|
|
19239
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
|
|
19240
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19241
|
+
CustomToolbarButton,
|
|
19242
|
+
{
|
|
19243
|
+
type: "button",
|
|
19244
|
+
"aria-label": itemEditOn ? "Done editing this image" : "Edit this image",
|
|
19245
|
+
"aria-pressed": itemEditOn,
|
|
19246
|
+
onClick: onToggleItemEdit,
|
|
19247
|
+
className: "group size-8",
|
|
19248
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19249
|
+
import_lucide_react9.Star,
|
|
19250
|
+
{
|
|
19251
|
+
size: 16,
|
|
19252
|
+
fill: "currentColor",
|
|
19253
|
+
strokeWidth: 0,
|
|
19254
|
+
className: cn(
|
|
19255
|
+
"transition-colors",
|
|
19256
|
+
itemEditOn ? "text-[#f59e0b] group-hover:text-[#d97706]" : "text-[#d6d3d1] group-hover:text-[#fbbf24]"
|
|
19257
|
+
),
|
|
19258
|
+
style: { pointerEvents: "none" }
|
|
19259
|
+
}
|
|
19260
|
+
)
|
|
19261
|
+
}
|
|
19262
|
+
) }),
|
|
19263
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: itemEditOn ? "Done editing this image" : "Edit this image" })
|
|
19264
|
+
] }),
|
|
19265
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19266
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: gatedLabel("Change image"), onClick: onChangeImage, disabled: !itemEditOn, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Image, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19267
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: gatedLabel("Link"), onClick: onOpenLink, disabled: !itemEditOn, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Link, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19268
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: gatedLabel("Move left"), onClick: onMoveLeft, disabled: !itemEditOn || index <= 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ArrowLeft, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19269
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19270
|
+
ToolbarAction,
|
|
19271
|
+
{
|
|
19272
|
+
label: gatedLabel("Move right"),
|
|
19273
|
+
onClick: onMoveRight,
|
|
19274
|
+
disabled: !itemEditOn || index >= itemCount - 1,
|
|
19275
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ArrowRight, { size: 16, style: { pointerEvents: "none" } })
|
|
19276
|
+
}
|
|
19277
|
+
),
|
|
19278
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: gatedLabel("Remove image"), onClick: onRemoveItem, disabled: !itemEditOn || itemCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ImageMinus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19279
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19280
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(OptionMenu, { label: "Layout", value: variant, options: VARIANTS, onChange: onSetVariant }),
|
|
19281
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(OptionMenu, { label: "Hover", value: hover, options: HOVERS, onChange: onSetHover }),
|
|
19282
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19283
|
+
ToolbarAction,
|
|
19284
|
+
{
|
|
19285
|
+
label: treatment === "grayscale" ? "Show in color" : "Show grayscale",
|
|
19286
|
+
active: treatment === "grayscale",
|
|
19287
|
+
onClick: () => onSetTreatment(treatment === "grayscale" ? "color" : "grayscale"),
|
|
19288
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Palette, { size: 16, style: { pointerEvents: "none" } })
|
|
19289
|
+
}
|
|
19290
|
+
),
|
|
19291
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19292
|
+
ALIGNS.map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label, active: align === value, onClick: () => onSetAlign(value), children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Icon, { size: 16, style: { pointerEvents: "none" } }) }, value)),
|
|
19293
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19294
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Smaller", onClick: () => onResize(-8), children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Minus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19295
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "min-w-[40px] text-center text-xs tabular-nums text-muted-foreground", children: [
|
|
19296
|
+
sizeValue,
|
|
19297
|
+
"px"
|
|
19298
|
+
] }),
|
|
19299
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Larger", onClick: () => onResize(8), children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Plus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19300
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19301
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Add image", onClick: onAddItem, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ImagePlus, { size: 16, style: { pointerEvents: "none" } }) })
|
|
19302
|
+
]
|
|
19303
|
+
}
|
|
19304
|
+
),
|
|
19305
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
|
|
18924
19306
|
]
|
|
18925
19307
|
}
|
|
18926
|
-
);
|
|
19308
|
+
) });
|
|
18927
19309
|
}
|
|
18928
19310
|
function findMediaStripSlots(tree) {
|
|
18929
19311
|
const stack = tree.rows.flatMap((row) => row.blocks);
|
|
@@ -18942,31 +19324,23 @@ function AiMediaStripOverlay({
|
|
|
18942
19324
|
}) {
|
|
18943
19325
|
const [hover, setHover] = (0, import_react10.useState)(null);
|
|
18944
19326
|
const [active, setActive] = (0, import_react10.useState)(null);
|
|
19327
|
+
const [itemEditOn, setItemEditOn] = (0, import_react10.useState)(false);
|
|
19328
|
+
const [linkOpen, setLinkOpen] = (0, import_react10.useState)(false);
|
|
18945
19329
|
const [pending, setPending] = (0, import_react10.useState)(false);
|
|
18946
19330
|
const [error, setError] = (0, import_react10.useState)(null);
|
|
18947
19331
|
const activeRef = (0, import_react10.useRef)(null);
|
|
18948
19332
|
activeRef.current = active;
|
|
19333
|
+
const linkOpenRef = (0, import_react10.useRef)(false);
|
|
19334
|
+
linkOpenRef.current = linkOpen;
|
|
18949
19335
|
(0, import_react10.useEffect)(() => {
|
|
18950
19336
|
const onMove = (e) => {
|
|
19337
|
+
const ref = itemRefFromTarget(e.target);
|
|
18951
19338
|
const t = e.target;
|
|
18952
|
-
|
|
18953
|
-
|
|
18954
|
-
|
|
18955
|
-
|
|
18956
|
-
|
|
18957
|
-
if (!itemEl) {
|
|
18958
|
-
setHover(null);
|
|
18959
|
-
return;
|
|
18960
|
-
}
|
|
18961
|
-
const sectionEl = itemEl.closest("[data-ohw-section]");
|
|
18962
|
-
const unit = sectionEl ? movableUnit(sectionEl) : null;
|
|
18963
|
-
const sectionId = unit ? instanceIdOf(unit) || null : null;
|
|
18964
|
-
const index = Number(itemEl.dataset.ohwMediaStripIndex);
|
|
18965
|
-
if (!sectionId || Number.isNaN(index)) {
|
|
18966
|
-
setHover(null);
|
|
18967
|
-
return;
|
|
18968
|
-
}
|
|
18969
|
-
setHover({ sectionId, index });
|
|
19339
|
+
const overEditable = Boolean(t?.closest?.("[data-ohw-editable]"));
|
|
19340
|
+
setHover((prev) => {
|
|
19341
|
+
const next = ref && !overEditable ? ref : null;
|
|
19342
|
+
return sameRef(prev, next) ? prev : next;
|
|
19343
|
+
});
|
|
18970
19344
|
};
|
|
18971
19345
|
const onLeave = () => setHover(null);
|
|
18972
19346
|
document.addEventListener("mousemove", onMove, { passive: true });
|
|
@@ -18978,23 +19352,25 @@ function AiMediaStripOverlay({
|
|
|
18978
19352
|
}, []);
|
|
18979
19353
|
(0, import_react10.useEffect)(() => {
|
|
18980
19354
|
const onClick = (e) => {
|
|
18981
|
-
const current = activeRef.current;
|
|
18982
|
-
if (!current) return;
|
|
18983
19355
|
const t = e.target;
|
|
18984
|
-
if (!(t instanceof
|
|
18985
|
-
if (t.closest(
|
|
18986
|
-
const
|
|
18987
|
-
if (
|
|
18988
|
-
|
|
19356
|
+
if (!(t instanceof Element)) return;
|
|
19357
|
+
if (t.closest(CHROME_SELECTOR)) return;
|
|
19358
|
+
const ref = itemRefFromTarget(t);
|
|
19359
|
+
if (sameRef(activeRef.current, ref)) return;
|
|
19360
|
+
if (ref) clearInteractionChromeRef.current();
|
|
19361
|
+
setItemEditOn(false);
|
|
18989
19362
|
setError(null);
|
|
19363
|
+
setActive(ref);
|
|
18990
19364
|
};
|
|
18991
19365
|
document.addEventListener("click", onClick, true);
|
|
18992
19366
|
return () => document.removeEventListener("click", onClick, true);
|
|
18993
|
-
}, []);
|
|
19367
|
+
}, [clearInteractionChromeRef]);
|
|
18994
19368
|
(0, import_react10.useEffect)(() => {
|
|
18995
19369
|
const onBlur = () => {
|
|
18996
19370
|
if (!activeRef.current) return;
|
|
18997
19371
|
setActive(null);
|
|
19372
|
+
setItemEditOn(false);
|
|
19373
|
+
setLinkOpen(false);
|
|
18998
19374
|
setError(null);
|
|
18999
19375
|
};
|
|
19000
19376
|
window.addEventListener("blur", onBlur);
|
|
@@ -19004,7 +19380,10 @@ function AiMediaStripOverlay({
|
|
|
19004
19380
|
const onKeyDown = (e) => {
|
|
19005
19381
|
if (e.key !== "Escape") return;
|
|
19006
19382
|
if (!activeRef.current) return;
|
|
19383
|
+
if (linkOpenRef.current) return;
|
|
19384
|
+
if (document.querySelector('[data-ohw-more-menu][data-state="open"]')) return;
|
|
19007
19385
|
setActive(null);
|
|
19386
|
+
setItemEditOn(false);
|
|
19008
19387
|
setError(null);
|
|
19009
19388
|
};
|
|
19010
19389
|
document.addEventListener("keydown", onKeyDown);
|
|
@@ -19038,137 +19417,133 @@ function AiMediaStripOverlay({
|
|
|
19038
19417
|
tree: nextTree,
|
|
19039
19418
|
label: entry.label,
|
|
19040
19419
|
media: extraMedia ? { ...entry.media, ...extraMedia } : entry.media,
|
|
19041
|
-
...entry.brand ? { brand: entry.brand } : {}
|
|
19420
|
+
...entry.brand ? { brand: entry.brand } : {},
|
|
19421
|
+
// The user is already looking at the strip they just edited — recentering the viewport
|
|
19422
|
+
// on every edit reads as the section jumping around.
|
|
19423
|
+
skipScrollIntoView: true
|
|
19042
19424
|
});
|
|
19043
19425
|
return true;
|
|
19044
19426
|
},
|
|
19045
19427
|
[findEntry, postToParent2, applyTreeLocalRef]
|
|
19046
19428
|
);
|
|
19047
19429
|
const activeEntry = active ? findEntry(active.sectionId) : null;
|
|
19048
|
-
const hoverHandleRect = useLiveItemRect(!active && hover ? hover : null);
|
|
19049
19430
|
const activeItemRect = useLiveItemRect(active);
|
|
19050
|
-
const
|
|
19051
|
-
const
|
|
19052
|
-
|
|
19053
|
-
|
|
19054
|
-
|
|
19055
|
-
|
|
19056
|
-
|
|
19057
|
-
|
|
19058
|
-
|
|
19059
|
-
|
|
19060
|
-
|
|
19061
|
-
|
|
19062
|
-
|
|
19063
|
-
|
|
19064
|
-
|
|
19065
|
-
|
|
19066
|
-
|
|
19067
|
-
|
|
19068
|
-
|
|
19069
|
-
|
|
19070
|
-
|
|
19071
|
-
|
|
19072
|
-
|
|
19073
|
-
|
|
19074
|
-
|
|
19075
|
-
|
|
19076
|
-
|
|
19077
|
-
|
|
19078
|
-
|
|
19079
|
-
|
|
19080
|
-
|
|
19081
|
-
|
|
19082
|
-
|
|
19083
|
-
|
|
19084
|
-
activeItemRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19085
|
-
ItemInteractionLayer,
|
|
19086
|
-
{
|
|
19087
|
-
rect: activeItemRect,
|
|
19088
|
-
state: toolbarState,
|
|
19089
|
-
toolbar: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19090
|
-
MediaStripToolbar,
|
|
19091
|
-
{
|
|
19092
|
-
entry: activeEntry,
|
|
19093
|
-
index: active.index,
|
|
19094
|
-
pending,
|
|
19095
|
-
error,
|
|
19096
|
-
onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
|
|
19097
|
-
onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
|
|
19098
|
-
onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
|
|
19099
|
-
onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
|
|
19100
|
-
onResize: (delta) => {
|
|
19101
|
-
const slots = findMediaStripSlots(activeEntry.tree);
|
|
19102
|
-
const variant = slots?.variant === "reel" ? "reel" : "logos";
|
|
19103
|
-
const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
|
|
19104
|
-
void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
|
|
19105
|
-
},
|
|
19106
|
-
onSetAlt: (alt) => {
|
|
19107
|
-
void runMutation(active.sectionId, (tree) => setMediaStripItemAlt(tree, active.index, alt));
|
|
19108
|
-
},
|
|
19109
|
-
onSetLink: (href, linkTarget) => {
|
|
19431
|
+
const activeStripRect = useLiveItemRect(active, true);
|
|
19432
|
+
const hoverRect = useLiveItemRect(hover && !sameRef(hover, active) ? hover : null);
|
|
19433
|
+
const activeItems = activeEntry ? mediaStripItems(activeEntry.tree) : [];
|
|
19434
|
+
const activeItem = active ? activeItems[active.index] : void 0;
|
|
19435
|
+
const activeHref = activeItem?.href ?? "";
|
|
19436
|
+
const activeTarget = activeItem?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
|
|
19437
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
19438
|
+
hoverRect && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
|
|
19439
|
+
activeItemRect && activeStripRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
19440
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: activeItemRect, state: "active-top" }),
|
|
19441
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StripToolbarSlot, { stripRect: activeStripRect, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19442
|
+
MediaStripToolbar,
|
|
19443
|
+
{
|
|
19444
|
+
entry: activeEntry,
|
|
19445
|
+
index: active.index,
|
|
19446
|
+
pending,
|
|
19447
|
+
error,
|
|
19448
|
+
itemEditOn,
|
|
19449
|
+
onToggleItemEdit: () => setItemEditOn((on) => !on),
|
|
19450
|
+
onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
|
|
19451
|
+
onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
|
|
19452
|
+
onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
|
|
19453
|
+
onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
|
|
19454
|
+
onResize: (delta) => {
|
|
19455
|
+
const slots = findMediaStripSlots(activeEntry.tree);
|
|
19456
|
+
const variant = slots?.variant === "reel" ? "reel" : "logos";
|
|
19457
|
+
const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
|
|
19458
|
+
void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
|
|
19459
|
+
},
|
|
19460
|
+
onOpenLink: () => setLinkOpen(true),
|
|
19461
|
+
onAddItem: () => {
|
|
19462
|
+
void requestAssetPick(postToParent2).then((picked) => {
|
|
19463
|
+
if (!picked) return;
|
|
19464
|
+
const item = { assetId: picked.assetId, alt: "Logo" };
|
|
19110
19465
|
void runMutation(
|
|
19111
19466
|
active.sectionId,
|
|
19112
|
-
(tree) =>
|
|
19113
|
-
|
|
19114
|
-
|
|
19115
|
-
|
|
19116
|
-
void requestAssetPick(postToParent2).then((picked) => {
|
|
19117
|
-
if (!picked) return;
|
|
19118
|
-
const item = { assetId: picked.assetId, alt: "Logo" };
|
|
19119
|
-
void runMutation(
|
|
19120
|
-
active.sectionId,
|
|
19121
|
-
(tree) => addMediaStripItem(tree, item, active.index),
|
|
19122
|
-
{ [picked.assetId]: picked.url }
|
|
19123
|
-
).then((applied) => {
|
|
19124
|
-
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
19125
|
-
});
|
|
19467
|
+
(tree) => addMediaStripItem(tree, item, active.index),
|
|
19468
|
+
{ [picked.assetId]: picked.url }
|
|
19469
|
+
).then((applied) => {
|
|
19470
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
19126
19471
|
});
|
|
19127
|
-
}
|
|
19128
|
-
|
|
19129
|
-
|
|
19130
|
-
|
|
19131
|
-
|
|
19132
|
-
|
|
19133
|
-
|
|
19134
|
-
|
|
19135
|
-
|
|
19136
|
-
});
|
|
19137
|
-
},
|
|
19138
|
-
onRemoveItem: () => {
|
|
19139
|
-
void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
|
|
19140
|
-
(applied) => {
|
|
19141
|
-
if (applied) setActive(null);
|
|
19142
|
-
}
|
|
19143
|
-
);
|
|
19144
|
-
},
|
|
19145
|
-
onMoveLeft: () => {
|
|
19146
|
-
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
|
|
19147
|
-
(applied) => {
|
|
19148
|
-
if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
|
|
19149
|
-
}
|
|
19150
|
-
);
|
|
19151
|
-
},
|
|
19152
|
-
onMoveRight: () => {
|
|
19153
|
-
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
|
|
19154
|
-
(applied) => {
|
|
19155
|
-
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
19156
|
-
}
|
|
19472
|
+
});
|
|
19473
|
+
},
|
|
19474
|
+
onChangeImage: () => {
|
|
19475
|
+
void requestAssetPick(postToParent2).then((picked) => {
|
|
19476
|
+
if (!picked) return;
|
|
19477
|
+
void runMutation(
|
|
19478
|
+
active.sectionId,
|
|
19479
|
+
(tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
|
|
19480
|
+
{ [picked.assetId]: picked.url }
|
|
19157
19481
|
);
|
|
19158
|
-
}
|
|
19482
|
+
});
|
|
19483
|
+
},
|
|
19484
|
+
onRemoveItem: () => {
|
|
19485
|
+
void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
|
|
19486
|
+
(applied) => {
|
|
19487
|
+
if (applied) setActive(null);
|
|
19488
|
+
}
|
|
19489
|
+
);
|
|
19490
|
+
},
|
|
19491
|
+
onMoveLeft: () => {
|
|
19492
|
+
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
|
|
19493
|
+
(applied) => {
|
|
19494
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
|
|
19495
|
+
}
|
|
19496
|
+
);
|
|
19497
|
+
},
|
|
19498
|
+
onMoveRight: () => {
|
|
19499
|
+
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
|
|
19500
|
+
(applied) => {
|
|
19501
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
19502
|
+
}
|
|
19503
|
+
);
|
|
19159
19504
|
}
|
|
19160
|
-
|
|
19161
|
-
}
|
|
19162
|
-
|
|
19505
|
+
}
|
|
19506
|
+
) }),
|
|
19507
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19508
|
+
"div",
|
|
19509
|
+
{
|
|
19510
|
+
"data-ohw-bridge": "",
|
|
19511
|
+
"data-ohw-item-interaction": "",
|
|
19512
|
+
"aria-hidden": true,
|
|
19513
|
+
className: "pointer-events-none fixed rounded-[4px] px-[7px] py-[3px] font-sans text-[11px] font-medium leading-none text-primary-foreground whitespace-nowrap",
|
|
19514
|
+
style: {
|
|
19515
|
+
top: activeItemRect.top + activeItemRect.height + 10,
|
|
19516
|
+
left: activeItemRect.left - 5,
|
|
19517
|
+
background: PRIMARY3,
|
|
19518
|
+
zIndex: 2147483644
|
|
19519
|
+
},
|
|
19520
|
+
children: "Media item"
|
|
19521
|
+
}
|
|
19522
|
+
),
|
|
19523
|
+
linkOpen && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19524
|
+
LinkModal,
|
|
19525
|
+
{
|
|
19526
|
+
href: activeHref,
|
|
19527
|
+
linkTarget: activeTarget,
|
|
19528
|
+
onClose: () => setLinkOpen(false),
|
|
19529
|
+
onSave: (href, linkTarget) => {
|
|
19530
|
+
void runMutation(
|
|
19531
|
+
active.sectionId,
|
|
19532
|
+
(tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
|
|
19533
|
+
);
|
|
19534
|
+
}
|
|
19535
|
+
}
|
|
19536
|
+
)
|
|
19537
|
+
] })
|
|
19163
19538
|
] });
|
|
19164
19539
|
}
|
|
19165
19540
|
|
|
19166
19541
|
// src/ui/ai-section/AiPricingCardOverlay.tsx
|
|
19167
19542
|
var import_react11 = require("react");
|
|
19168
|
-
var
|
|
19169
|
-
var
|
|
19543
|
+
var import_lucide_react10 = require("lucide-react");
|
|
19544
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
19170
19545
|
var PRIMARY4 = "var(--ohw-primary, #0885FE)";
|
|
19171
|
-
var
|
|
19546
|
+
var CHROME_SELECTOR2 = "[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-link-modal-root], [data-ohw-section-picker], [data-ohw-ai-review], [data-ohw-more-menu]";
|
|
19172
19547
|
function findPricingCardElement(sectionId, index) {
|
|
19173
19548
|
const sectionEl = findByInstanceId(sectionId);
|
|
19174
19549
|
if (!sectionEl) return null;
|
|
@@ -19180,7 +19555,7 @@ function findPricingCardElement(sectionId, index) {
|
|
|
19180
19555
|
}
|
|
19181
19556
|
function cardRefFromTarget(target) {
|
|
19182
19557
|
if (!(target instanceof Element)) return null;
|
|
19183
|
-
if (target.closest(
|
|
19558
|
+
if (target.closest(CHROME_SELECTOR2)) return null;
|
|
19184
19559
|
const cardEl = target.closest("[data-ohw-pricing-card]");
|
|
19185
19560
|
if (!cardEl) return null;
|
|
19186
19561
|
const sectionEl = cardEl.closest("[data-ohw-section]");
|
|
@@ -19190,21 +19565,21 @@ function cardRefFromTarget(target) {
|
|
|
19190
19565
|
if (!sectionId || Number.isNaN(index)) return null;
|
|
19191
19566
|
return { sectionId, index };
|
|
19192
19567
|
}
|
|
19193
|
-
function
|
|
19568
|
+
function sameRef2(a, b) {
|
|
19194
19569
|
return a?.sectionId === b?.sectionId && a?.index === b?.index;
|
|
19195
19570
|
}
|
|
19196
|
-
function
|
|
19571
|
+
function rectOf2(el) {
|
|
19197
19572
|
if (!el) return null;
|
|
19198
19573
|
const r2 = el.getBoundingClientRect();
|
|
19199
19574
|
if (r2.width <= 0 || r2.height <= 0) return null;
|
|
19200
19575
|
return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
|
|
19201
19576
|
}
|
|
19202
19577
|
function readRect3(ref) {
|
|
19203
|
-
return
|
|
19578
|
+
return rectOf2(ref && findPricingCardElement(ref.sectionId, ref.index));
|
|
19204
19579
|
}
|
|
19205
19580
|
function readGridRect(ref) {
|
|
19206
19581
|
const card = ref && findPricingCardElement(ref.sectionId, ref.index);
|
|
19207
|
-
return
|
|
19582
|
+
return rectOf2(card?.closest("[data-ohw-pricing-collection]") ?? card);
|
|
19208
19583
|
}
|
|
19209
19584
|
function useLiveCardRect(ref, grid = false) {
|
|
19210
19585
|
const [rect, setRect] = (0, import_react11.useState)(null);
|
|
@@ -19234,7 +19609,7 @@ function useLiveCardRect(ref, grid = false) {
|
|
|
19234
19609
|
}
|
|
19235
19610
|
var TOOLBAR_GRID_GAP = 52;
|
|
19236
19611
|
var TOOLBAR_GRID_GAP_MOBILE = 42;
|
|
19237
|
-
var
|
|
19612
|
+
var TOOLBAR_EDGE_MARGIN3 = 4;
|
|
19238
19613
|
function GridToolbarSlot({ gridRect, children }) {
|
|
19239
19614
|
const slotRef = (0, import_react11.useRef)(null);
|
|
19240
19615
|
const [shift, setShift] = (0, import_react11.useState)(0);
|
|
@@ -19246,7 +19621,7 @@ function GridToolbarSlot({ gridRect, children }) {
|
|
|
19246
19621
|
const w = slot.offsetWidth;
|
|
19247
19622
|
if (w <= 0) return;
|
|
19248
19623
|
const half = w / 2;
|
|
19249
|
-
const clamped = Math.max(
|
|
19624
|
+
const clamped = Math.max(TOOLBAR_EDGE_MARGIN3 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN3 - half));
|
|
19250
19625
|
setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
|
|
19251
19626
|
};
|
|
19252
19627
|
clamp();
|
|
@@ -19255,7 +19630,7 @@ function GridToolbarSlot({ gridRect, children }) {
|
|
|
19255
19630
|
return () => ro.disconnect();
|
|
19256
19631
|
}, [centerX, children]);
|
|
19257
19632
|
const mobile = window.innerWidth <= 480;
|
|
19258
|
-
return /* @__PURE__ */ (0,
|
|
19633
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19259
19634
|
"div",
|
|
19260
19635
|
{
|
|
19261
19636
|
ref: slotRef,
|
|
@@ -19290,7 +19665,7 @@ function requestValidateTree2(postToParent2, tree) {
|
|
|
19290
19665
|
});
|
|
19291
19666
|
}
|
|
19292
19667
|
function StyleSwatch({ style }) {
|
|
19293
|
-
return /* @__PURE__ */ (0,
|
|
19668
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19294
19669
|
"span",
|
|
19295
19670
|
{
|
|
19296
19671
|
"aria-hidden": true,
|
|
@@ -19304,35 +19679,35 @@ function StyleSwatch({ style }) {
|
|
|
19304
19679
|
);
|
|
19305
19680
|
}
|
|
19306
19681
|
function ButtonGlyph() {
|
|
19307
|
-
return /* @__PURE__ */ (0,
|
|
19308
|
-
/* @__PURE__ */ (0,
|
|
19309
|
-
/* @__PURE__ */ (0,
|
|
19682
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("svg", { width: "18", height: "12", viewBox: "0 0 18 12", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
|
|
19683
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("rect", { x: "0.75", y: "0.75", width: "16.5", height: "10.5", rx: "3", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
19684
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M5.5 6H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
19310
19685
|
] });
|
|
19311
19686
|
}
|
|
19312
19687
|
function FeatureGlyph({ mode }) {
|
|
19313
|
-
return /* @__PURE__ */ (0,
|
|
19314
|
-
/* @__PURE__ */ (0,
|
|
19315
|
-
/* @__PURE__ */ (0,
|
|
19316
|
-
/* @__PURE__ */ (0,
|
|
19317
|
-
/* @__PURE__ */ (0,
|
|
19318
|
-
/* @__PURE__ */ (0,
|
|
19319
|
-
mode === "add" && /* @__PURE__ */ (0,
|
|
19688
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
|
|
19689
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("circle", { cx: "8", cy: "8", r: "7.25", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
19690
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M5 8.2L7.2 10.3L11 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
19691
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("circle", { cx: "13.5", cy: "13.5", r: "4.25", fill: "var(--ohw-background, #ffffff)", stroke: "var(--ohw-background, #ffffff)", strokeWidth: "1" }),
|
|
19692
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("circle", { cx: "13.5", cy: "13.5", r: "3.75", fill: "var(--ohw-background, #ffffff)", stroke: PRIMARY4, strokeWidth: "1" }),
|
|
19693
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M11.5 13.5H15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" }),
|
|
19694
|
+
mode === "add" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M13.5 11.5V15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" })
|
|
19320
19695
|
] });
|
|
19321
19696
|
}
|
|
19322
|
-
function
|
|
19697
|
+
function ToolbarAction2({
|
|
19323
19698
|
label,
|
|
19324
19699
|
onClick,
|
|
19325
19700
|
disabled = false,
|
|
19326
19701
|
children
|
|
19327
19702
|
}) {
|
|
19328
|
-
const button = /* @__PURE__ */ (0,
|
|
19329
|
-
return /* @__PURE__ */ (0,
|
|
19330
|
-
/* @__PURE__ */ (0,
|
|
19331
|
-
/* @__PURE__ */ (0,
|
|
19703
|
+
const button = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, onClick, className: "size-8", children });
|
|
19704
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Tooltip, { children: [
|
|
19705
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "inline-flex", children: button }) : button }),
|
|
19706
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
|
|
19332
19707
|
] });
|
|
19333
19708
|
}
|
|
19334
|
-
function
|
|
19335
|
-
return /* @__PURE__ */ (0,
|
|
19709
|
+
function ToolbarSeparator2() {
|
|
19710
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
|
|
19336
19711
|
}
|
|
19337
19712
|
function CardStyleMenu({
|
|
19338
19713
|
value,
|
|
@@ -19340,7 +19715,7 @@ function CardStyleMenu({
|
|
|
19340
19715
|
disabled = false
|
|
19341
19716
|
}) {
|
|
19342
19717
|
const current = PRICING_CARD_STYLES.find((s) => s.value === value) ?? PRICING_CARD_STYLES[0];
|
|
19343
|
-
const trigger = /* @__PURE__ */ (0,
|
|
19718
|
+
const trigger = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
19344
19719
|
"button",
|
|
19345
19720
|
{
|
|
19346
19721
|
type: "button",
|
|
@@ -19351,28 +19726,28 @@ function CardStyleMenu({
|
|
|
19351
19726
|
disabled && "cursor-not-allowed opacity-40 hover:bg-transparent"
|
|
19352
19727
|
),
|
|
19353
19728
|
children: [
|
|
19354
|
-
/* @__PURE__ */ (0,
|
|
19355
|
-
/* @__PURE__ */ (0,
|
|
19356
|
-
/* @__PURE__ */ (0,
|
|
19729
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(StyleSwatch, { style: current.value }),
|
|
19730
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "flex-1 text-left", children: current.label }),
|
|
19731
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.ChevronDown, { size: 16, style: { pointerEvents: "none" } })
|
|
19357
19732
|
]
|
|
19358
19733
|
}
|
|
19359
19734
|
);
|
|
19360
19735
|
if (disabled) {
|
|
19361
|
-
return /* @__PURE__ */ (0,
|
|
19362
|
-
/* @__PURE__ */ (0,
|
|
19363
|
-
/* @__PURE__ */ (0,
|
|
19364
|
-
/* @__PURE__ */ (0,
|
|
19365
|
-
/* @__PURE__ */ (0,
|
|
19736
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
19737
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
|
|
19738
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Tooltip, { children: [
|
|
19739
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "inline-flex", children: trigger }) }),
|
|
19740
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
|
|
19366
19741
|
] })
|
|
19367
19742
|
] });
|
|
19368
19743
|
}
|
|
19369
|
-
return /* @__PURE__ */ (0,
|
|
19370
|
-
/* @__PURE__ */ (0,
|
|
19371
|
-
/* @__PURE__ */ (0,
|
|
19372
|
-
/* @__PURE__ */ (0,
|
|
19373
|
-
/* @__PURE__ */ (0,
|
|
19744
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
19745
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
|
|
19746
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DropdownMenu, { modal: false, children: [
|
|
19747
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DropdownMenuTrigger, { asChild: true, children: trigger }),
|
|
19748
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
|
|
19374
19749
|
const selected = style.value === value;
|
|
19375
|
-
return /* @__PURE__ */ (0,
|
|
19750
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
19376
19751
|
DropdownMenuItem,
|
|
19377
19752
|
{
|
|
19378
19753
|
role: "menuitemradio",
|
|
@@ -19380,9 +19755,9 @@ function CardStyleMenu({
|
|
|
19380
19755
|
onSelect: () => onChange(style.value),
|
|
19381
19756
|
className: cn("grid grid-cols-[18px_1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
|
|
19382
19757
|
children: [
|
|
19383
|
-
/* @__PURE__ */ (0,
|
|
19384
|
-
/* @__PURE__ */ (0,
|
|
19385
|
-
selected && /* @__PURE__ */ (0,
|
|
19758
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(StyleSwatch, { style: style.value }),
|
|
19759
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: style.label }),
|
|
19760
|
+
selected && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.Check, { size: 16, className: "text-bridge-primary" })
|
|
19386
19761
|
]
|
|
19387
19762
|
},
|
|
19388
19763
|
style.value
|
|
@@ -19412,7 +19787,7 @@ function PricingCardToolbar({
|
|
|
19412
19787
|
const style = pricingCardStyle(entry.tree, index);
|
|
19413
19788
|
const featuredTag = pricingCardFeaturedTag(entry.tree, index);
|
|
19414
19789
|
const mobile = window.innerWidth <= 480;
|
|
19415
|
-
return /* @__PURE__ */ (0,
|
|
19790
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
19416
19791
|
"div",
|
|
19417
19792
|
{
|
|
19418
19793
|
"data-ohw-bridge": "",
|
|
@@ -19424,7 +19799,7 @@ function PricingCardToolbar({
|
|
|
19424
19799
|
),
|
|
19425
19800
|
style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
|
|
19426
19801
|
children: [
|
|
19427
|
-
/* @__PURE__ */ (0,
|
|
19802
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
19428
19803
|
"div",
|
|
19429
19804
|
{
|
|
19430
19805
|
className: cn(
|
|
@@ -19433,8 +19808,8 @@ function PricingCardToolbar({
|
|
|
19433
19808
|
mobile ? "flex-wrap justify-center" : "flex-nowrap"
|
|
19434
19809
|
),
|
|
19435
19810
|
children: [
|
|
19436
|
-
/* @__PURE__ */ (0,
|
|
19437
|
-
/* @__PURE__ */ (0,
|
|
19811
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Tooltip, { children: [
|
|
19812
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19438
19813
|
CustomToolbarButton,
|
|
19439
19814
|
{
|
|
19440
19815
|
type: "button",
|
|
@@ -19442,8 +19817,8 @@ function PricingCardToolbar({
|
|
|
19442
19817
|
"aria-pressed": featuredTag,
|
|
19443
19818
|
onClick: () => onSetFeaturedTag(!featuredTag),
|
|
19444
19819
|
className: "group size-8",
|
|
19445
|
-
children: /* @__PURE__ */ (0,
|
|
19446
|
-
|
|
19820
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19821
|
+
import_lucide_react10.Star,
|
|
19447
19822
|
{
|
|
19448
19823
|
size: 16,
|
|
19449
19824
|
fill: "currentColor",
|
|
@@ -19457,25 +19832,25 @@ function PricingCardToolbar({
|
|
|
19457
19832
|
)
|
|
19458
19833
|
}
|
|
19459
19834
|
) }),
|
|
19460
|
-
/* @__PURE__ */ (0,
|
|
19835
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
|
|
19461
19836
|
] }),
|
|
19462
|
-
/* @__PURE__ */ (0,
|
|
19463
|
-
/* @__PURE__ */ (0,
|
|
19464
|
-
/* @__PURE__ */ (0,
|
|
19465
|
-
/* @__PURE__ */ (0,
|
|
19466
|
-
/* @__PURE__ */ (0,
|
|
19467
|
-
/* @__PURE__ */ (0,
|
|
19468
|
-
/* @__PURE__ */ (0,
|
|
19837
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarSeparator2, {}),
|
|
19838
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
|
|
19839
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarSeparator2, {}),
|
|
19840
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ButtonGlyph, {}) }),
|
|
19841
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "relative inline-flex", children: [
|
|
19842
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ButtonGlyph, {}),
|
|
19843
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.Minus, { size: 10, strokeWidth: 2.5, className: "absolute -right-1.5 -top-1.5 rounded-full bg-background text-bridge-primary" })
|
|
19469
19844
|
] }) }),
|
|
19470
|
-
/* @__PURE__ */ (0,
|
|
19471
|
-
/* @__PURE__ */ (0,
|
|
19472
|
-
/* @__PURE__ */ (0,
|
|
19473
|
-
/* @__PURE__ */ (0,
|
|
19474
|
-
/* @__PURE__ */ (0,
|
|
19845
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Add feature", onClick: onAddFeature, disabled: featureCount >= 10, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(FeatureGlyph, { mode: "add" }) }),
|
|
19846
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Remove feature", onClick: onRemoveFeature, disabled: featureCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(FeatureGlyph, { mode: "remove" }) }),
|
|
19847
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarSeparator2, {}),
|
|
19848
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Add tier", onClick: onAddTier, disabled: collectionCount >= 4, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.Plus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19849
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Remove tier", onClick: onRemoveTier, disabled: collectionCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.Minus, { size: 16, style: { pointerEvents: "none" } }) })
|
|
19475
19850
|
]
|
|
19476
19851
|
}
|
|
19477
19852
|
),
|
|
19478
|
-
error && /* @__PURE__ */ (0,
|
|
19853
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
|
|
19479
19854
|
]
|
|
19480
19855
|
}
|
|
19481
19856
|
) });
|
|
@@ -19509,7 +19884,7 @@ function AiPricingCardOverlay({
|
|
|
19509
19884
|
const overEditable = Boolean(t?.closest?.("[data-ohw-editable], [data-ohw-role], a, button"));
|
|
19510
19885
|
setHover((prev) => {
|
|
19511
19886
|
const next = ref && !overEditable ? ref : null;
|
|
19512
|
-
return
|
|
19887
|
+
return sameRef2(prev, next) ? prev : next;
|
|
19513
19888
|
});
|
|
19514
19889
|
};
|
|
19515
19890
|
const onLeave = () => setHover(null);
|
|
@@ -19524,10 +19899,10 @@ function AiPricingCardOverlay({
|
|
|
19524
19899
|
const onClick = (e) => {
|
|
19525
19900
|
const t = e.target;
|
|
19526
19901
|
if (!(t instanceof Element)) return;
|
|
19527
|
-
if (t.closest(
|
|
19902
|
+
if (t.closest(CHROME_SELECTOR2)) return;
|
|
19528
19903
|
const ref = cardRefFromTarget(t);
|
|
19529
|
-
setActive((prev) =>
|
|
19530
|
-
if (!ref || !
|
|
19904
|
+
setActive((prev) => sameRef2(prev, ref) ? prev : ref);
|
|
19905
|
+
if (!ref || !sameRef2(activeRef.current, ref)) setError(null);
|
|
19531
19906
|
};
|
|
19532
19907
|
document.addEventListener("click", onClick, true);
|
|
19533
19908
|
return () => document.removeEventListener("click", onClick, true);
|
|
@@ -19592,12 +19967,12 @@ function AiPricingCardOverlay({
|
|
|
19592
19967
|
const activeEntry = active ? findEntry(active.sectionId) : null;
|
|
19593
19968
|
const activeCardRect = useLiveCardRect(active);
|
|
19594
19969
|
const activeGridRect = useLiveCardRect(active, true);
|
|
19595
|
-
const hoverRect = useLiveCardRect(hover && !
|
|
19596
|
-
return /* @__PURE__ */ (0,
|
|
19597
|
-
hoverRect && /* @__PURE__ */ (0,
|
|
19598
|
-
activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ (0,
|
|
19599
|
-
/* @__PURE__ */ (0,
|
|
19600
|
-
/* @__PURE__ */ (0,
|
|
19970
|
+
const hoverRect = useLiveCardRect(hover && !sameRef2(hover, active) ? hover : null);
|
|
19971
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
19972
|
+
hoverRect && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
|
|
19973
|
+
activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
19974
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ItemInteractionLayer, { rect: activeCardRect, state: "active-top" }),
|
|
19975
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GridToolbarSlot, { gridRect: activeGridRect, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19601
19976
|
PricingCardToolbar,
|
|
19602
19977
|
{
|
|
19603
19978
|
entry: activeEntry,
|
|
@@ -19625,7 +20000,7 @@ function AiPricingCardOverlay({
|
|
|
19625
20000
|
onRemoveFeature: () => runMutation(active.sectionId, (tree) => removePricingCardFeature(tree, active.index))
|
|
19626
20001
|
}
|
|
19627
20002
|
) }),
|
|
19628
|
-
/* @__PURE__ */ (0,
|
|
20003
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19629
20004
|
"div",
|
|
19630
20005
|
{
|
|
19631
20006
|
"data-ohw-bridge": "",
|
|
@@ -19647,7 +20022,7 @@ function AiPricingCardOverlay({
|
|
|
19647
20022
|
|
|
19648
20023
|
// src/ui/ai-section/AiVideoOverlay.tsx
|
|
19649
20024
|
var import_react12 = require("react");
|
|
19650
|
-
var
|
|
20025
|
+
var import_lucide_react11 = require("lucide-react");
|
|
19651
20026
|
|
|
19652
20027
|
// src/lib/ai-video-tree.ts
|
|
19653
20028
|
function resolveVideoBlock(tree, path) {
|
|
@@ -19718,10 +20093,10 @@ function extractYouTubeId(input) {
|
|
|
19718
20093
|
}
|
|
19719
20094
|
|
|
19720
20095
|
// src/ui/ai-section/AiVideoOverlay.tsx
|
|
19721
|
-
var
|
|
20096
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
19722
20097
|
var PRIMARY5 = "#0885FE";
|
|
19723
|
-
var
|
|
19724
|
-
var
|
|
20098
|
+
var OHW_BLUE = `var(--ohw-primary, ${PRIMARY5})`;
|
|
20099
|
+
var OHW_BLUE_DARK = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY5}) 60%, #000000)`;
|
|
19725
20100
|
function findVideoBlockElement(sectionId, path) {
|
|
19726
20101
|
const sectionEl = findByInstanceId(sectionId);
|
|
19727
20102
|
if (!sectionEl) return null;
|
|
@@ -19781,12 +20156,12 @@ function requestValidateTree3(postToParent2, tree) {
|
|
|
19781
20156
|
postToParent2({ type: "ow:ai-validate-tree-request", id, tree });
|
|
19782
20157
|
});
|
|
19783
20158
|
}
|
|
19784
|
-
function
|
|
20159
|
+
function Pill({
|
|
19785
20160
|
label,
|
|
19786
20161
|
onClick,
|
|
19787
20162
|
disabled
|
|
19788
20163
|
}) {
|
|
19789
|
-
return /* @__PURE__ */ (0,
|
|
20164
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
19790
20165
|
"button",
|
|
19791
20166
|
{
|
|
19792
20167
|
type: "button",
|
|
@@ -19802,7 +20177,7 @@ function Pill2({
|
|
|
19802
20177
|
border: "none",
|
|
19803
20178
|
cursor: disabled ? "default" : "pointer",
|
|
19804
20179
|
background: "#ffffff",
|
|
19805
|
-
color:
|
|
20180
|
+
color: OHW_BLUE_DARK,
|
|
19806
20181
|
opacity: disabled ? 0.4 : 1,
|
|
19807
20182
|
fontSize: 12,
|
|
19808
20183
|
lineHeight: "16px",
|
|
@@ -19845,8 +20220,8 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
19845
20220
|
onCommit(id);
|
|
19846
20221
|
}
|
|
19847
20222
|
};
|
|
19848
|
-
return /* @__PURE__ */ (0,
|
|
19849
|
-
/* @__PURE__ */ (0,
|
|
20223
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 4, width: "100%", maxWidth: 280 }, children: [
|
|
20224
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
19850
20225
|
"div",
|
|
19851
20226
|
{
|
|
19852
20227
|
style: {
|
|
@@ -19862,12 +20237,12 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
19862
20237
|
boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
|
|
19863
20238
|
},
|
|
19864
20239
|
children: [
|
|
19865
|
-
/* @__PURE__ */ (0,
|
|
20240
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
19866
20241
|
"span",
|
|
19867
20242
|
{
|
|
19868
20243
|
style: {
|
|
19869
20244
|
flex: "0 0 auto",
|
|
19870
|
-
color:
|
|
20245
|
+
color: OHW_BLUE_DARK,
|
|
19871
20246
|
fontSize: 10,
|
|
19872
20247
|
lineHeight: "16px",
|
|
19873
20248
|
fontWeight: 700,
|
|
@@ -19877,7 +20252,7 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
19877
20252
|
children: "Video"
|
|
19878
20253
|
}
|
|
19879
20254
|
),
|
|
19880
|
-
/* @__PURE__ */ (0,
|
|
20255
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
19881
20256
|
"input",
|
|
19882
20257
|
{
|
|
19883
20258
|
type: "text",
|
|
@@ -19914,7 +20289,7 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
19914
20289
|
]
|
|
19915
20290
|
}
|
|
19916
20291
|
),
|
|
19917
|
-
invalid && /* @__PURE__ */ (0,
|
|
20292
|
+
invalid && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, textAlign: "center" }, children: "That doesn't look like a YouTube link \u2014 try pasting the video URL again." })
|
|
19918
20293
|
] });
|
|
19919
20294
|
}
|
|
19920
20295
|
function VideoToolbar({
|
|
@@ -19924,7 +20299,7 @@ function VideoToolbar({
|
|
|
19924
20299
|
onSetVideoId,
|
|
19925
20300
|
onRemove
|
|
19926
20301
|
}) {
|
|
19927
|
-
return /* @__PURE__ */ (0,
|
|
20302
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
19928
20303
|
"div",
|
|
19929
20304
|
{
|
|
19930
20305
|
"data-ohw-bridge": "",
|
|
@@ -19936,7 +20311,7 @@ function VideoToolbar({
|
|
|
19936
20311
|
gap: 6,
|
|
19937
20312
|
alignItems: "center",
|
|
19938
20313
|
width: 280,
|
|
19939
|
-
background:
|
|
20314
|
+
background: OHW_BLUE,
|
|
19940
20315
|
padding: 8,
|
|
19941
20316
|
borderRadius: 12,
|
|
19942
20317
|
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
@@ -19944,9 +20319,9 @@ function VideoToolbar({
|
|
|
19944
20319
|
opacity: pending ? 0.6 : 1
|
|
19945
20320
|
},
|
|
19946
20321
|
children: [
|
|
19947
|
-
/* @__PURE__ */ (0,
|
|
19948
|
-
/* @__PURE__ */ (0,
|
|
19949
|
-
error && /* @__PURE__ */ (0,
|
|
20322
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(VideoUrlInput, { value: videoId, onCommit: onSetVideoId }),
|
|
20323
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Pill, { label: "Remove video", onClick: onRemove, disabled: !videoId }),
|
|
20324
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
|
|
19950
20325
|
]
|
|
19951
20326
|
}
|
|
19952
20327
|
);
|
|
@@ -20066,8 +20441,8 @@ function AiVideoOverlay({
|
|
|
20066
20441
|
const activeBlockRect = useLiveBlockRect(active);
|
|
20067
20442
|
const TOOLBAR_APPROX_H = 90;
|
|
20068
20443
|
const toolbarState = activeBlockRect && activeBlockRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
|
|
20069
|
-
return /* @__PURE__ */ (0,
|
|
20070
|
-
hoverHandleRect && hover && /* @__PURE__ */ (0,
|
|
20444
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
20445
|
+
hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20071
20446
|
"button",
|
|
20072
20447
|
{
|
|
20073
20448
|
type: "button",
|
|
@@ -20095,15 +20470,15 @@ function AiVideoOverlay({
|
|
|
20095
20470
|
fontSize: 14,
|
|
20096
20471
|
fontWeight: 700
|
|
20097
20472
|
},
|
|
20098
|
-
children: /* @__PURE__ */ (0,
|
|
20473
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.Star, { size: 14, style: { pointerEvents: "none" } })
|
|
20099
20474
|
}
|
|
20100
20475
|
),
|
|
20101
|
-
activeBlockRect && active && activeEntry && /* @__PURE__ */ (0,
|
|
20476
|
+
activeBlockRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20102
20477
|
ItemInteractionLayer,
|
|
20103
20478
|
{
|
|
20104
20479
|
rect: activeBlockRect,
|
|
20105
20480
|
state: toolbarState,
|
|
20106
|
-
toolbar: /* @__PURE__ */ (0,
|
|
20481
|
+
toolbar: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20107
20482
|
VideoToolbar,
|
|
20108
20483
|
{
|
|
20109
20484
|
videoId: videoIdAt(activeEntry.tree, active.path),
|
|
@@ -20127,7 +20502,7 @@ function AiVideoOverlay({
|
|
|
20127
20502
|
|
|
20128
20503
|
// src/ui/ai-section/AiFadeCarouselOverlay.tsx
|
|
20129
20504
|
var import_react13 = require("react");
|
|
20130
|
-
var
|
|
20505
|
+
var import_lucide_react12 = require("lucide-react");
|
|
20131
20506
|
|
|
20132
20507
|
// src/lib/ai-carousel-tree.ts
|
|
20133
20508
|
function isCarouselBlock(node) {
|
|
@@ -20178,10 +20553,10 @@ function setCarouselAutoplay(tree, on) {
|
|
|
20178
20553
|
}
|
|
20179
20554
|
|
|
20180
20555
|
// src/ui/ai-section/AiFadeCarouselOverlay.tsx
|
|
20181
|
-
var
|
|
20556
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
20182
20557
|
var PRIMARY6 = "#0885FE";
|
|
20183
|
-
var
|
|
20184
|
-
var
|
|
20558
|
+
var OHW_BLUE2 = `var(--ohw-primary, ${PRIMARY6})`;
|
|
20559
|
+
var OHW_BLUE_DARK2 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY6}) 60%, #000000)`;
|
|
20185
20560
|
function findCarouselItemElement(sectionId, index) {
|
|
20186
20561
|
const sectionEl = findByInstanceId(sectionId);
|
|
20187
20562
|
if (!sectionEl) return null;
|
|
@@ -20260,8 +20635,8 @@ function requestAssetPick2(postToParent2) {
|
|
|
20260
20635
|
postToParent2({ type: "ow:asset-pick", id });
|
|
20261
20636
|
});
|
|
20262
20637
|
}
|
|
20263
|
-
function
|
|
20264
|
-
return /* @__PURE__ */ (0,
|
|
20638
|
+
function Pill2({ label, onClick, disabled }) {
|
|
20639
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
20265
20640
|
"button",
|
|
20266
20641
|
{
|
|
20267
20642
|
type: "button",
|
|
@@ -20277,7 +20652,7 @@ function Pill3({ label, onClick, disabled }) {
|
|
|
20277
20652
|
border: "none",
|
|
20278
20653
|
cursor: disabled ? "default" : "pointer",
|
|
20279
20654
|
background: "#ffffff",
|
|
20280
|
-
color:
|
|
20655
|
+
color: OHW_BLUE_DARK2,
|
|
20281
20656
|
opacity: disabled ? 0.4 : 1,
|
|
20282
20657
|
fontSize: 12,
|
|
20283
20658
|
lineHeight: "16px",
|
|
@@ -20295,7 +20670,7 @@ function TogglePill({
|
|
|
20295
20670
|
onToggle,
|
|
20296
20671
|
disabled
|
|
20297
20672
|
}) {
|
|
20298
|
-
return /* @__PURE__ */ (0,
|
|
20673
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
20299
20674
|
"button",
|
|
20300
20675
|
{
|
|
20301
20676
|
type: "button",
|
|
@@ -20314,7 +20689,7 @@ function TogglePill({
|
|
|
20314
20689
|
border: "none",
|
|
20315
20690
|
cursor: disabled ? "default" : "pointer",
|
|
20316
20691
|
background: "#ffffff",
|
|
20317
|
-
color:
|
|
20692
|
+
color: OHW_BLUE_DARK2,
|
|
20318
20693
|
opacity: disabled ? 0.4 : 1,
|
|
20319
20694
|
fontSize: 12,
|
|
20320
20695
|
lineHeight: "16px",
|
|
@@ -20324,7 +20699,7 @@ function TogglePill({
|
|
|
20324
20699
|
},
|
|
20325
20700
|
children: [
|
|
20326
20701
|
label,
|
|
20327
|
-
/* @__PURE__ */ (0,
|
|
20702
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
20328
20703
|
"span",
|
|
20329
20704
|
{
|
|
20330
20705
|
"aria-hidden": true,
|
|
@@ -20337,10 +20712,10 @@ function TogglePill({
|
|
|
20337
20712
|
// Off is a grey track, not a washed-out blue: the pill's own white background already
|
|
20338
20713
|
// carries the brand colour in the text, and a pale blue track next to it read as
|
|
20339
20714
|
// "disabled control" rather than "switch that is off".
|
|
20340
|
-
background: on ?
|
|
20715
|
+
background: on ? OHW_BLUE_DARK2 : "#CBD5E1",
|
|
20341
20716
|
transition: "background 120ms ease"
|
|
20342
20717
|
},
|
|
20343
|
-
children: /* @__PURE__ */ (0,
|
|
20718
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
20344
20719
|
"span",
|
|
20345
20720
|
{
|
|
20346
20721
|
style: {
|
|
@@ -20369,7 +20744,7 @@ function CarouselSlideToolbar({
|
|
|
20369
20744
|
onChangeImage,
|
|
20370
20745
|
onToggleAutoplay
|
|
20371
20746
|
}) {
|
|
20372
|
-
return /* @__PURE__ */ (0,
|
|
20747
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
20373
20748
|
"div",
|
|
20374
20749
|
{
|
|
20375
20750
|
"data-ohw-bridge": "",
|
|
@@ -20380,7 +20755,7 @@ function CarouselSlideToolbar({
|
|
|
20380
20755
|
flexDirection: "column",
|
|
20381
20756
|
gap: 6,
|
|
20382
20757
|
alignItems: "center",
|
|
20383
|
-
background:
|
|
20758
|
+
background: OHW_BLUE2,
|
|
20384
20759
|
padding: 8,
|
|
20385
20760
|
borderRadius: 12,
|
|
20386
20761
|
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
@@ -20392,11 +20767,11 @@ function CarouselSlideToolbar({
|
|
|
20392
20767
|
pointerEvents: pending ? "none" : "auto"
|
|
20393
20768
|
},
|
|
20394
20769
|
children: [
|
|
20395
|
-
/* @__PURE__ */ (0,
|
|
20396
|
-
/* @__PURE__ */ (0,
|
|
20397
|
-
/* @__PURE__ */ (0,
|
|
20770
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
|
|
20771
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Pill2, { label: "Change Image", onClick: onChangeImage }),
|
|
20772
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
|
|
20398
20773
|
] }),
|
|
20399
|
-
error && /* @__PURE__ */ (0,
|
|
20774
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
|
|
20400
20775
|
]
|
|
20401
20776
|
}
|
|
20402
20777
|
);
|
|
@@ -20536,8 +20911,8 @@ function AiFadeCarouselOverlay({
|
|
|
20536
20911
|
const activeItemRect = useLiveItemRect2(active);
|
|
20537
20912
|
const TOOLBAR_APPROX_H = 90;
|
|
20538
20913
|
const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
|
|
20539
|
-
return /* @__PURE__ */ (0,
|
|
20540
|
-
hoverHandleRect && hover && /* @__PURE__ */ (0,
|
|
20914
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
20915
|
+
hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
20541
20916
|
"button",
|
|
20542
20917
|
{
|
|
20543
20918
|
type: "button",
|
|
@@ -20566,10 +20941,10 @@ function AiFadeCarouselOverlay({
|
|
|
20566
20941
|
fontSize: 14,
|
|
20567
20942
|
fontWeight: 700
|
|
20568
20943
|
},
|
|
20569
|
-
children: /* @__PURE__ */ (0,
|
|
20944
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.Star, { size: 14, style: { pointerEvents: "none" } })
|
|
20570
20945
|
}
|
|
20571
20946
|
),
|
|
20572
|
-
swapping && /* @__PURE__ */ (0,
|
|
20947
|
+
swapping && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
20573
20948
|
"div",
|
|
20574
20949
|
{
|
|
20575
20950
|
ref: skeletonRef,
|
|
@@ -20587,15 +20962,15 @@ function AiFadeCarouselOverlay({
|
|
|
20587
20962
|
zIndex: 2147483646,
|
|
20588
20963
|
pointerEvents: "none"
|
|
20589
20964
|
},
|
|
20590
|
-
children: /* @__PURE__ */ (0,
|
|
20965
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("style", { children: MEDIA_SKELETON_CSS })
|
|
20591
20966
|
}
|
|
20592
20967
|
),
|
|
20593
|
-
activeItemRect && active && activeEntry && /* @__PURE__ */ (0,
|
|
20968
|
+
activeItemRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
20594
20969
|
ItemInteractionLayer,
|
|
20595
20970
|
{
|
|
20596
20971
|
rect: activeItemRect,
|
|
20597
20972
|
state: toolbarState,
|
|
20598
|
-
toolbar: /* @__PURE__ */ (0,
|
|
20973
|
+
toolbar: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
20599
20974
|
CarouselSlideToolbar,
|
|
20600
20975
|
{
|
|
20601
20976
|
pending,
|
|
@@ -20714,141 +21089,6 @@ function isEditSessionActive() {
|
|
|
20714
21089
|
return new URLSearchParams(q).get("mode") === "edit";
|
|
20715
21090
|
}
|
|
20716
21091
|
|
|
20717
|
-
// src/ui/link-modal/linkModal.utils.ts
|
|
20718
|
-
function parseTarget(target) {
|
|
20719
|
-
if (!target) return { pageRoute: "", sectionId: null };
|
|
20720
|
-
const hashIndex = target.indexOf("#");
|
|
20721
|
-
if (hashIndex === -1) return { pageRoute: target, sectionId: null };
|
|
20722
|
-
return {
|
|
20723
|
-
pageRoute: target.slice(0, hashIndex),
|
|
20724
|
-
sectionId: target.slice(hashIndex + 1) || null
|
|
20725
|
-
};
|
|
20726
|
-
}
|
|
20727
|
-
function normalizePath(path) {
|
|
20728
|
-
const trimmed = path.trim();
|
|
20729
|
-
if (!trimmed) return "/";
|
|
20730
|
-
try {
|
|
20731
|
-
if (/^https?:\/\//i.test(trimmed)) {
|
|
20732
|
-
return new URL(trimmed).pathname || "/";
|
|
20733
|
-
}
|
|
20734
|
-
} catch {
|
|
20735
|
-
}
|
|
20736
|
-
const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
20737
|
-
if (withSlash.length > 1 && withSlash.endsWith("/")) return withSlash.slice(0, -1);
|
|
20738
|
-
return withSlash;
|
|
20739
|
-
}
|
|
20740
|
-
function findPageByPath(pages, path) {
|
|
20741
|
-
const normalized = normalizePath(path);
|
|
20742
|
-
return pages.find((p) => normalizePath(p.path) === normalized);
|
|
20743
|
-
}
|
|
20744
|
-
function inferPageTitleFromPath(path) {
|
|
20745
|
-
const normalized = normalizePath(path);
|
|
20746
|
-
if (normalized === "/") return "Home";
|
|
20747
|
-
const segment = normalized.split("/").filter(Boolean).pop() ?? "";
|
|
20748
|
-
if (!segment) return "Home";
|
|
20749
|
-
return segment.split("-").filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
20750
|
-
}
|
|
20751
|
-
function isInternalPath(route) {
|
|
20752
|
-
const trimmed = route.trim();
|
|
20753
|
-
if (!trimmed) return false;
|
|
20754
|
-
if (/^https?:\/\//i.test(trimmed)) return false;
|
|
20755
|
-
if (trimmed.startsWith("/")) return true;
|
|
20756
|
-
if (trimmed.includes(" ") || trimmed.includes(".")) return false;
|
|
20757
|
-
return true;
|
|
20758
|
-
}
|
|
20759
|
-
function resolvePage(route, pages) {
|
|
20760
|
-
const found = findPageByPath(pages, route);
|
|
20761
|
-
if (found) return { path: found.path, title: found.title };
|
|
20762
|
-
return { path: normalizePath(route), title: inferPageTitleFromPath(route) };
|
|
20763
|
-
}
|
|
20764
|
-
function getSectionsForPath(sectionsByPath, pageRoute) {
|
|
20765
|
-
if (!sectionsByPath) return [];
|
|
20766
|
-
const normalized = normalizePath(pageRoute);
|
|
20767
|
-
return sectionsByPath[normalized] ?? sectionsByPath[pageRoute] ?? [];
|
|
20768
|
-
}
|
|
20769
|
-
function buildTarget(page, section) {
|
|
20770
|
-
if (section) return `${page.path}#${section.id}`;
|
|
20771
|
-
return page.path;
|
|
20772
|
-
}
|
|
20773
|
-
function isValidUrl(urlString) {
|
|
20774
|
-
try {
|
|
20775
|
-
const url = new URL(urlString);
|
|
20776
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") return false;
|
|
20777
|
-
const hostname = url.hostname;
|
|
20778
|
-
if (!hostname || hostname.length === 0) return false;
|
|
20779
|
-
if (hostname.includes(" ")) return false;
|
|
20780
|
-
if (hostname === "localhost") return true;
|
|
20781
|
-
if (!hostname.includes(".")) return false;
|
|
20782
|
-
if (!/[a-z]/i.test(hostname)) return false;
|
|
20783
|
-
return true;
|
|
20784
|
-
} catch {
|
|
20785
|
-
return false;
|
|
20786
|
-
}
|
|
20787
|
-
}
|
|
20788
|
-
function normalizeUrl(value) {
|
|
20789
|
-
const trimmed = value.trim();
|
|
20790
|
-
if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) return trimmed;
|
|
20791
|
-
return `https://${trimmed}`;
|
|
20792
|
-
}
|
|
20793
|
-
function validateUrlInput(value, pages, allPages) {
|
|
20794
|
-
const trimmed = value.trim();
|
|
20795
|
-
if (!trimmed) return "";
|
|
20796
|
-
const exactPage = allPages.find((p) => p.title.toLowerCase() === trimmed.toLowerCase());
|
|
20797
|
-
if (exactPage) return "";
|
|
20798
|
-
const hasPrefixMatch = pages.some((p) => p.title.toLowerCase().startsWith(trimmed.toLowerCase()));
|
|
20799
|
-
if (hasPrefixMatch) {
|
|
20800
|
-
return "Select a page from the list or enter a valid URL";
|
|
20801
|
-
}
|
|
20802
|
-
const hasScheme = /^https?:\/\//i.test(trimmed);
|
|
20803
|
-
if (!hasScheme && !trimmed.includes(".")) {
|
|
20804
|
-
return "Please enter a valid URL (e.g., https://example.com)";
|
|
20805
|
-
}
|
|
20806
|
-
if (!isValidUrl(normalizeUrl(trimmed))) {
|
|
20807
|
-
return "Please enter a valid URL (e.g., https://example.com)";
|
|
20808
|
-
}
|
|
20809
|
-
return "";
|
|
20810
|
-
}
|
|
20811
|
-
function getEditModeInitialState(target, pages, sections) {
|
|
20812
|
-
const empty = {
|
|
20813
|
-
searchValue: "",
|
|
20814
|
-
selectedPage: null,
|
|
20815
|
-
selectedSection: null,
|
|
20816
|
-
step: "input"
|
|
20817
|
-
};
|
|
20818
|
-
if (!target) return empty;
|
|
20819
|
-
if (isValidUrl(normalizeUrl(target))) {
|
|
20820
|
-
return { searchValue: target, selectedPage: null, selectedSection: null, step: "input" };
|
|
20821
|
-
}
|
|
20822
|
-
const { pageRoute, sectionId } = parseTarget(target);
|
|
20823
|
-
if (sectionId) {
|
|
20824
|
-
if (isInternalPath(pageRoute)) {
|
|
20825
|
-
const page = resolvePage(pageRoute, pages);
|
|
20826
|
-
const sec = sections.find((s) => s.id === sectionId);
|
|
20827
|
-
return {
|
|
20828
|
-
searchValue: page.title,
|
|
20829
|
-
selectedPage: page,
|
|
20830
|
-
selectedSection: sec ? { id: sec.id, label: sec.label } : null,
|
|
20831
|
-
step: "input"
|
|
20832
|
-
};
|
|
20833
|
-
}
|
|
20834
|
-
return { searchValue: pageRoute || target, selectedPage: null, selectedSection: null, step: "input" };
|
|
20835
|
-
}
|
|
20836
|
-
if (isInternalPath(pageRoute)) {
|
|
20837
|
-
const page = resolvePage(pageRoute, pages);
|
|
20838
|
-
return {
|
|
20839
|
-
searchValue: page.title,
|
|
20840
|
-
selectedPage: page,
|
|
20841
|
-
selectedSection: null,
|
|
20842
|
-
step: "input"
|
|
20843
|
-
};
|
|
20844
|
-
}
|
|
20845
|
-
return { searchValue: target, selectedPage: null, selectedSection: null, step: "input" };
|
|
20846
|
-
}
|
|
20847
|
-
function filterAvailablePages(pages, existingTargets) {
|
|
20848
|
-
const taken = new Set(existingTargets);
|
|
20849
|
-
return pages.filter((p) => !taken.has(p.path));
|
|
20850
|
-
}
|
|
20851
|
-
|
|
20852
21092
|
// src/lib/prefetch-sections.ts
|
|
20853
21093
|
function buildPageFetchUrl(path) {
|
|
20854
21094
|
const normalized = normalizePath(path);
|
|
@@ -20948,113 +21188,6 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
|
|
|
20948
21188
|
// src/ui/link-modal/LinkPopover.tsx
|
|
20949
21189
|
var import_react17 = require("react");
|
|
20950
21190
|
|
|
20951
|
-
// src/ui/dialog.tsx
|
|
20952
|
-
var React9 = __toESM(require("react"), 1);
|
|
20953
|
-
var import_radix_ui6 = require("radix-ui");
|
|
20954
|
-
var import_lucide_react12 = require("lucide-react");
|
|
20955
|
-
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
20956
|
-
function Dialog2({
|
|
20957
|
-
...props
|
|
20958
|
-
}) {
|
|
20959
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_radix_ui6.Dialog.Root, { "data-slot": "dialog", ...props });
|
|
20960
|
-
}
|
|
20961
|
-
function DialogPortal({
|
|
20962
|
-
...props
|
|
20963
|
-
}) {
|
|
20964
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_radix_ui6.Dialog.Portal, { ...props });
|
|
20965
|
-
}
|
|
20966
|
-
function DialogOverlay({
|
|
20967
|
-
className,
|
|
20968
|
-
...props
|
|
20969
|
-
}) {
|
|
20970
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
20971
|
-
import_radix_ui6.Dialog.Overlay,
|
|
20972
|
-
{
|
|
20973
|
-
"data-slot": "dialog-overlay",
|
|
20974
|
-
"data-ohw-link-modal-root": "",
|
|
20975
|
-
className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
|
|
20976
|
-
...props
|
|
20977
|
-
}
|
|
20978
|
-
);
|
|
20979
|
-
}
|
|
20980
|
-
var DialogContent = React9.forwardRef(
|
|
20981
|
-
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
20982
|
-
const positionMode = container ? "absolute" : "fixed";
|
|
20983
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DialogPortal, { container: container ?? void 0, children: [
|
|
20984
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
20985
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
20986
|
-
import_radix_ui6.Dialog.Content,
|
|
20987
|
-
{
|
|
20988
|
-
ref,
|
|
20989
|
-
"data-slot": "dialog-content",
|
|
20990
|
-
className: cn(
|
|
20991
|
-
positionMode,
|
|
20992
|
-
"left-1/2 top-1/2 z-[2147483647] flex w-full max-w-[448px] -translate-x-1/2 -translate-y-1/2 flex-col overflow-visible",
|
|
20993
|
-
"rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
|
|
20994
|
-
container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
|
|
20995
|
-
className
|
|
20996
|
-
),
|
|
20997
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
20998
|
-
...props,
|
|
20999
|
-
children: [
|
|
21000
|
-
children,
|
|
21001
|
-
showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
21002
|
-
import_radix_ui6.Dialog.Close,
|
|
21003
|
-
{
|
|
21004
|
-
type: "button",
|
|
21005
|
-
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
21006
|
-
"aria-label": "Close",
|
|
21007
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.X, { size: 16, "aria-hidden": true })
|
|
21008
|
-
}
|
|
21009
|
-
) : null
|
|
21010
|
-
]
|
|
21011
|
-
}
|
|
21012
|
-
)
|
|
21013
|
-
] });
|
|
21014
|
-
}
|
|
21015
|
-
);
|
|
21016
|
-
DialogContent.displayName = import_radix_ui6.Dialog.Content.displayName;
|
|
21017
|
-
function DialogHeader({
|
|
21018
|
-
className,
|
|
21019
|
-
...props
|
|
21020
|
-
}) {
|
|
21021
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
21022
|
-
}
|
|
21023
|
-
function DialogFooter({
|
|
21024
|
-
className,
|
|
21025
|
-
...props
|
|
21026
|
-
}) {
|
|
21027
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
21028
|
-
"div",
|
|
21029
|
-
{
|
|
21030
|
-
className: cn("flex items-center justify-end gap-2", className),
|
|
21031
|
-
...props
|
|
21032
|
-
}
|
|
21033
|
-
);
|
|
21034
|
-
}
|
|
21035
|
-
var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
21036
|
-
import_radix_ui6.Dialog.Title,
|
|
21037
|
-
{
|
|
21038
|
-
ref,
|
|
21039
|
-
className: cn(
|
|
21040
|
-
"text-lg font-semibold leading-none tracking-tight text-card-foreground",
|
|
21041
|
-
className
|
|
21042
|
-
),
|
|
21043
|
-
...props
|
|
21044
|
-
}
|
|
21045
|
-
));
|
|
21046
|
-
DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
|
|
21047
|
-
var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
21048
|
-
import_radix_ui6.Dialog.Description,
|
|
21049
|
-
{
|
|
21050
|
-
ref,
|
|
21051
|
-
className: cn("text-sm text-muted-foreground", className),
|
|
21052
|
-
...props
|
|
21053
|
-
}
|
|
21054
|
-
));
|
|
21055
|
-
DialogDescription.displayName = import_radix_ui6.Dialog.Description.displayName;
|
|
21056
|
-
var DialogClose = import_radix_ui6.Dialog.Close;
|
|
21057
|
-
|
|
21058
21191
|
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
21059
21192
|
var import_lucide_react16 = require("lucide-react");
|
|
21060
21193
|
|
|
@@ -22158,6 +22291,7 @@ function shouldUseDevFixtures() {
|
|
|
22158
22291
|
function getLogoElement(el) {
|
|
22159
22292
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
22160
22293
|
if (marked) return marked;
|
|
22294
|
+
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
22161
22295
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
22162
22296
|
if (!root) return null;
|
|
22163
22297
|
const anchor = el.closest("a");
|
|
@@ -23994,6 +24128,7 @@ function applyEditableImageSrc(img, url) {
|
|
|
23994
24128
|
img.removeAttribute("srcset");
|
|
23995
24129
|
img.removeAttribute("sizes");
|
|
23996
24130
|
if (img.loading === "lazy") img.loading = "eager";
|
|
24131
|
+
releaseTemplateLogoIfReplaced(img, url);
|
|
23997
24132
|
img.src = url;
|
|
23998
24133
|
}
|
|
23999
24134
|
function fadeInBgImage(el, url, onReady) {
|
|
@@ -24738,7 +24873,7 @@ function getNavigationSelectionParent(el) {
|
|
|
24738
24873
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
24739
24874
|
return resolveFooterLinksContainerFrom(el);
|
|
24740
24875
|
}
|
|
24741
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
24876
|
+
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)) {
|
|
24742
24877
|
return getNavigationRoot(el);
|
|
24743
24878
|
}
|
|
24744
24879
|
return null;
|
|
@@ -24960,7 +25095,6 @@ var ICONS = {
|
|
|
24960
25095
|
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"/>',
|
|
24961
25096
|
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"/>'
|
|
24962
25097
|
};
|
|
24963
|
-
var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
|
|
24964
25098
|
var SELECTION_CHROME_GAP2 = 4;
|
|
24965
25099
|
var TOOLBAR_STROKE_GAP2 = 4;
|
|
24966
25100
|
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
@@ -25058,7 +25192,7 @@ function applyVisibleViewport(el, parentScroll) {
|
|
|
25058
25192
|
el.style.top = `${top}px`;
|
|
25059
25193
|
el.style.height = `${height}px`;
|
|
25060
25194
|
}
|
|
25061
|
-
var
|
|
25195
|
+
var TOOLBAR_EDGE_MARGIN4 = 4;
|
|
25062
25196
|
function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
25063
25197
|
const isAbove = transform.includes("translateY(-100%)");
|
|
25064
25198
|
let visualTop = isAbove ? top - approxH : top;
|
|
@@ -25085,8 +25219,8 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
|
25085
25219
|
function clampToolbarLeft(centerX, toolbarWidth) {
|
|
25086
25220
|
const half = toolbarWidth / 2;
|
|
25087
25221
|
return Math.max(
|
|
25088
|
-
|
|
25089
|
-
Math.min(centerX, window.innerWidth -
|
|
25222
|
+
TOOLBAR_EDGE_MARGIN4 + half,
|
|
25223
|
+
Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN4 - half)
|
|
25090
25224
|
);
|
|
25091
25225
|
}
|
|
25092
25226
|
function calcToolbarPos(rect, parentScroll, toolbarW = 306) {
|
|
@@ -25966,21 +26100,6 @@ function OhhwellsBridge() {
|
|
|
25966
26100
|
const [isItemDragging, setIsItemDragging] = (0, import_react21.useState)(false);
|
|
25967
26101
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react21.useState)(false);
|
|
25968
26102
|
isFooterFrameSelectionRef.current = isFooterFrameSelection;
|
|
25969
|
-
const [floatingPanel, setFloatingPanel] = (0, import_react21.useState)(null);
|
|
25970
|
-
const floatingPanelOpenRef = (0, import_react21.useRef)(false);
|
|
25971
|
-
floatingPanelOpenRef.current = floatingPanel !== null;
|
|
25972
|
-
const floatingPanelRef = (0, import_react21.useRef)(null);
|
|
25973
|
-
floatingPanelRef.current = floatingPanel;
|
|
25974
|
-
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react21.useState)(null);
|
|
25975
|
-
const buttonCollectionDragRef = (0, import_react21.useRef)(null);
|
|
25976
|
-
const buttonDropInsertIndexRef = (0, import_react21.useRef)(null);
|
|
25977
|
-
const [buttonDropSlots, setButtonDropSlots] = (0, import_react21.useState)([]);
|
|
25978
|
-
const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react21.useState)(null);
|
|
25979
|
-
const buttonPointerDragRef = (0, import_react21.useRef)(null);
|
|
25980
|
-
const [buttonStyleTick, setButtonStyleTick] = (0, import_react21.useState)(0);
|
|
25981
|
-
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react21.useState)(null);
|
|
25982
|
-
const [editorViewport, setEditorViewport] = (0, import_react21.useState)("desktop");
|
|
25983
|
-
const [parentScrollSnap, setParentScrollSnap] = (0, import_react21.useState)(null);
|
|
25984
26103
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react21.useState)(null);
|
|
25985
26104
|
const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react21.useState)(null);
|
|
25986
26105
|
const footerDragRef = (0, import_react21.useRef)(null);
|
|
@@ -26006,7 +26125,23 @@ function OhhwellsBridge() {
|
|
|
26006
26125
|
const stylesRef = (0, import_react21.useRef)("");
|
|
26007
26126
|
const appliedDrawerRef = (0, import_react21.useRef)(null);
|
|
26008
26127
|
const pendingDeleteUndoRef = (0, import_react21.useRef)(null);
|
|
26128
|
+
const [floatingPanel, setFloatingPanel] = (0, import_react21.useState)(null);
|
|
26129
|
+
const floatingPanelOpenRef = (0, import_react21.useRef)(false);
|
|
26130
|
+
const floatingPanelRef = (0, import_react21.useRef)(null);
|
|
26131
|
+
floatingPanelRef.current = floatingPanel;
|
|
26132
|
+
const setFloatingPanelRef = (0, import_react21.useRef)(setFloatingPanel);
|
|
26133
|
+
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react21.useState)(null);
|
|
26134
|
+
const buttonCollectionDragRef = (0, import_react21.useRef)(null);
|
|
26135
|
+
const buttonDropInsertIndexRef = (0, import_react21.useRef)(null);
|
|
26136
|
+
const [buttonDropSlots, setButtonDropSlots] = (0, import_react21.useState)([]);
|
|
26137
|
+
const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react21.useState)(null);
|
|
26138
|
+
const buttonPointerDragRef = (0, import_react21.useRef)(null);
|
|
26139
|
+
const [buttonStyleTick, setButtonStyleTick] = (0, import_react21.useState)(0);
|
|
26140
|
+
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react21.useState)(null);
|
|
26141
|
+
const [editorViewport, setEditorViewport] = (0, import_react21.useState)("desktop");
|
|
26142
|
+
const [parentScrollSnap, setParentScrollSnap] = (0, import_react21.useState)(null);
|
|
26009
26143
|
const [sitePages, setSitePages] = (0, import_react21.useState)([]);
|
|
26144
|
+
const collectionItemsRef = (0, import_react21.useRef)(/* @__PURE__ */ new Map());
|
|
26010
26145
|
const [sectionsByPath, setSectionsByPath] = (0, import_react21.useState)({});
|
|
26011
26146
|
const sectionsPrefetchGenRef = (0, import_react21.useRef)(0);
|
|
26012
26147
|
const setLinkPopoverRef = (0, import_react21.useRef)(setLinkPopover);
|
|
@@ -26014,7 +26149,18 @@ function OhhwellsBridge() {
|
|
|
26014
26149
|
const linkPopoverOpenRef = (0, import_react21.useRef)(false);
|
|
26015
26150
|
const linkPopoverGraceUntilRef = (0, import_react21.useRef)(0);
|
|
26016
26151
|
setLinkPopoverRef.current = setLinkPopover;
|
|
26152
|
+
setFloatingPanelRef.current = setFloatingPanel;
|
|
26017
26153
|
linkPopoverSessionRef.current = linkPopover;
|
|
26154
|
+
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
26155
|
+
(0, import_react21.useEffect)(() => {
|
|
26156
|
+
const syncViewport = () => {
|
|
26157
|
+
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
26158
|
+
setEditorViewport((prev) => prev === next ? prev : next);
|
|
26159
|
+
};
|
|
26160
|
+
syncViewport();
|
|
26161
|
+
window.addEventListener("resize", syncViewport);
|
|
26162
|
+
return () => window.removeEventListener("resize", syncViewport);
|
|
26163
|
+
}, []);
|
|
26018
26164
|
(0, import_react21.useEffect)(() => {
|
|
26019
26165
|
setSectionOrderPersistHandler((entries) => {
|
|
26020
26166
|
const currentPath = window.location.pathname;
|
|
@@ -26150,10 +26296,12 @@ function OhhwellsBridge() {
|
|
|
26150
26296
|
const onSitePages = (e) => {
|
|
26151
26297
|
if (e.data?.type !== "ow:site-pages" || !Array.isArray(e.data.pages)) return;
|
|
26152
26298
|
if (useFixtures) return;
|
|
26153
|
-
const
|
|
26299
|
+
const incoming = e.data.pages;
|
|
26300
|
+
const mapped = incoming.map((p) => ({
|
|
26154
26301
|
path: p.path,
|
|
26155
26302
|
title: p.title
|
|
26156
26303
|
}));
|
|
26304
|
+
collectionItemsRef.current = indexCollectionItems(incoming);
|
|
26157
26305
|
setSitePages(mapped);
|
|
26158
26306
|
runSectionsPrefetchRef.current(mapped);
|
|
26159
26307
|
};
|
|
@@ -27709,6 +27857,7 @@ function OhhwellsBridge() {
|
|
|
27709
27857
|
applyAiFooterFromContent(content);
|
|
27710
27858
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
27711
27859
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
27860
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
27712
27861
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
27713
27862
|
}
|
|
27714
27863
|
applyBrandChrome(content);
|
|
@@ -27719,12 +27868,12 @@ function OhhwellsBridge() {
|
|
|
27719
27868
|
if (key === "__ohw_sections") continue;
|
|
27720
27869
|
if (key === AI_SECTIONS_KEY) continue;
|
|
27721
27870
|
if (key === AI_FOOTER_KEY) continue;
|
|
27871
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
27872
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27722
27873
|
if (key === BRAND_KIT_KEY) continue;
|
|
27723
27874
|
if (key === STYLE_STORE_KEY) continue;
|
|
27724
27875
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
27725
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
27726
27876
|
if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
|
|
27727
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27728
27877
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
27729
27878
|
continue;
|
|
27730
27879
|
}
|
|
@@ -27955,17 +28104,18 @@ function OhhwellsBridge() {
|
|
|
27955
28104
|
}
|
|
27956
28105
|
applyAiFooterFromContent(content);
|
|
27957
28106
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
28107
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
27958
28108
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
27959
28109
|
}
|
|
27960
28110
|
for (const [key, val] of Object.entries(content)) {
|
|
27961
28111
|
if (key === "__ohw_sections") continue;
|
|
27962
28112
|
if (key === AI_SECTIONS_KEY) continue;
|
|
27963
28113
|
if (key === AI_FOOTER_KEY) continue;
|
|
28114
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
28115
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27964
28116
|
if (key === BRAND_KIT_KEY) continue;
|
|
27965
28117
|
if (key === STYLE_STORE_KEY) continue;
|
|
27966
28118
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
27967
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
27968
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27969
28119
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
27970
28120
|
continue;
|
|
27971
28121
|
}
|
|
@@ -28232,26 +28382,11 @@ function OhhwellsBridge() {
|
|
|
28232
28382
|
const t2 = setTimeout(measure, 500);
|
|
28233
28383
|
const ro = new ResizeObserver(schedule);
|
|
28234
28384
|
ro.observe(document.body);
|
|
28235
|
-
let lastWidth = window.innerWidth;
|
|
28236
|
-
let resizeTimers = [];
|
|
28237
|
-
const clearResizeTimers = () => {
|
|
28238
|
-
resizeTimers.forEach(clearTimeout);
|
|
28239
|
-
resizeTimers = [];
|
|
28240
|
-
};
|
|
28241
|
-
const handleResize = () => {
|
|
28242
|
-
if (window.innerWidth === lastWidth) return;
|
|
28243
|
-
lastWidth = window.innerWidth;
|
|
28244
|
-
clearResizeTimers();
|
|
28245
|
-
resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
|
|
28246
|
-
};
|
|
28247
|
-
window.addEventListener("resize", handleResize);
|
|
28248
28385
|
return () => {
|
|
28249
28386
|
clearTimeout(t1);
|
|
28250
28387
|
clearTimeout(t2);
|
|
28251
28388
|
if (raf != null) cancelAnimationFrame(raf);
|
|
28252
28389
|
ro.disconnect();
|
|
28253
|
-
clearResizeTimers();
|
|
28254
|
-
window.removeEventListener("resize", handleResize);
|
|
28255
28390
|
};
|
|
28256
28391
|
}, [pathname, isEditMode, postToParent2]);
|
|
28257
28392
|
(0, import_react21.useEffect)(() => {
|
|
@@ -28548,6 +28683,13 @@ function OhhwellsBridge() {
|
|
|
28548
28683
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
28549
28684
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
28550
28685
|
if (isInsideLinkEditor(target)) return;
|
|
28686
|
+
if (isInsideFloatingPanel(target)) return;
|
|
28687
|
+
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
28688
|
+
if (target.closest(
|
|
28689
|
+
'[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
|
|
28690
|
+
)) {
|
|
28691
|
+
return;
|
|
28692
|
+
}
|
|
28551
28693
|
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
28552
28694
|
clearMediaSelectionRef.current();
|
|
28553
28695
|
}
|
|
@@ -28571,11 +28713,15 @@ function OhhwellsBridge() {
|
|
|
28571
28713
|
return;
|
|
28572
28714
|
}
|
|
28573
28715
|
}
|
|
28574
|
-
|
|
28575
|
-
if (
|
|
28576
|
-
|
|
28577
|
-
|
|
28578
|
-
|
|
28716
|
+
const collectionItem = matchCollectionItemClick(target, collectionItemsRef.current);
|
|
28717
|
+
if (collectionItem) {
|
|
28718
|
+
e.preventDefault();
|
|
28719
|
+
e.stopPropagation();
|
|
28720
|
+
postToParentRef.current({
|
|
28721
|
+
type: "ow:collection-item-selected",
|
|
28722
|
+
path: collectionItem.path,
|
|
28723
|
+
collection: collectionItem.collection
|
|
28724
|
+
});
|
|
28579
28725
|
return;
|
|
28580
28726
|
}
|
|
28581
28727
|
{
|
|
@@ -28731,9 +28877,13 @@ function OhhwellsBridge() {
|
|
|
28731
28877
|
if (isIconEditable(editable) && !getSocialItem(editable)) {
|
|
28732
28878
|
e.preventDefault();
|
|
28733
28879
|
e.stopPropagation();
|
|
28734
|
-
selectIconElementRef.current(editable);
|
|
28735
28880
|
const aiIcon = editable.hasAttribute("data-ai-icon");
|
|
28736
28881
|
const featureIcon = aiIcon && /\.features\.\d+\.icon$/.test(editable.dataset.ohwKey ?? "");
|
|
28882
|
+
if (aiIcon) {
|
|
28883
|
+
aiSectionApiRef.current?.selectFromElement(editable);
|
|
28884
|
+
} else {
|
|
28885
|
+
selectIconElementRef.current(editable);
|
|
28886
|
+
}
|
|
28737
28887
|
postToParentRef.current({
|
|
28738
28888
|
type: "ow:icon-pick",
|
|
28739
28889
|
key: editable.dataset.ohwKey ?? "",
|
|
@@ -28961,6 +29111,9 @@ function OhhwellsBridge() {
|
|
|
28961
29111
|
setHoveredItemRect(null);
|
|
28962
29112
|
hoveredNavContainerRef.current = null;
|
|
28963
29113
|
setHoveredNavContainerRect(null);
|
|
29114
|
+
siblingHintElRef.current = null;
|
|
29115
|
+
setSiblingHintRect(null);
|
|
29116
|
+
setSiblingHintRects([]);
|
|
28964
29117
|
return;
|
|
28965
29118
|
}
|
|
28966
29119
|
{
|
|
@@ -29081,7 +29234,6 @@ function OhhwellsBridge() {
|
|
|
29081
29234
|
hoveredNavContainerRef.current = null;
|
|
29082
29235
|
setHoveredNavContainerRect(null);
|
|
29083
29236
|
hoveredItemElRef.current = editable;
|
|
29084
|
-
setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
|
|
29085
29237
|
}
|
|
29086
29238
|
}
|
|
29087
29239
|
}
|
|
@@ -29791,7 +29943,11 @@ function OhhwellsBridge() {
|
|
|
29791
29943
|
};
|
|
29792
29944
|
const handleMouseMove = (e) => {
|
|
29793
29945
|
const { clientX, clientY } = e;
|
|
29794
|
-
if (pointOwnedByFloatingPanel(clientX, clientY))
|
|
29946
|
+
if (pointOwnedByFloatingPanel(clientX, clientY)) {
|
|
29947
|
+
dismissImageHover();
|
|
29948
|
+
clearImageHover();
|
|
29949
|
+
return;
|
|
29950
|
+
}
|
|
29795
29951
|
if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
|
|
29796
29952
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
29797
29953
|
formHoverElRef.current = null;
|
|
@@ -29820,7 +29976,12 @@ function OhhwellsBridge() {
|
|
|
29820
29976
|
setHoveredItemRect(null);
|
|
29821
29977
|
hoveredNavContainerRef.current = null;
|
|
29822
29978
|
setHoveredNavContainerRect(null);
|
|
29979
|
+
siblingHintElRef.current = null;
|
|
29980
|
+
setSiblingHintRect(null);
|
|
29981
|
+
setSiblingHintRects([]);
|
|
29823
29982
|
dismissImageHover();
|
|
29983
|
+
clearImageHover();
|
|
29984
|
+
setSectionGap(null);
|
|
29824
29985
|
return;
|
|
29825
29986
|
}
|
|
29826
29987
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
@@ -29832,7 +29993,11 @@ function OhhwellsBridge() {
|
|
|
29832
29993
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
29833
29994
|
const { clientX, clientY } = e.data;
|
|
29834
29995
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
29835
|
-
if (pointOwnedByFloatingPanel(clientX, clientY))
|
|
29996
|
+
if (pointOwnedByFloatingPanel(clientX, clientY)) {
|
|
29997
|
+
dismissImageHover();
|
|
29998
|
+
clearImageHover();
|
|
29999
|
+
return;
|
|
30000
|
+
}
|
|
29836
30001
|
if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
|
|
29837
30002
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
29838
30003
|
probeSectionGapAt(clientX, clientY);
|
|
@@ -30212,6 +30377,7 @@ function OhhwellsBridge() {
|
|
|
30212
30377
|
applyAiFooterFromContent(content);
|
|
30213
30378
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
30214
30379
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
30380
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
30215
30381
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
30216
30382
|
}
|
|
30217
30383
|
applyBrandChrome(content);
|
|
@@ -30226,12 +30392,12 @@ function OhhwellsBridge() {
|
|
|
30226
30392
|
}
|
|
30227
30393
|
if (key === AI_SECTIONS_KEY) continue;
|
|
30228
30394
|
if (key === AI_FOOTER_KEY) continue;
|
|
30395
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
30396
|
+
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
30229
30397
|
if (key === BRAND_KIT_KEY) continue;
|
|
30230
30398
|
if (key === STYLE_STORE_KEY) continue;
|
|
30231
30399
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
30232
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
30233
30400
|
if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
|
|
30234
|
-
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
30235
30401
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
30236
30402
|
continue;
|
|
30237
30403
|
}
|
|
@@ -30867,6 +31033,12 @@ function OhhwellsBridge() {
|
|
|
30867
31033
|
closeLinkPopoverRef.current();
|
|
30868
31034
|
return;
|
|
30869
31035
|
}
|
|
31036
|
+
if (floatingPanelOpenRef.current) {
|
|
31037
|
+
setFloatingPanelRef.current(null);
|
|
31038
|
+
deselectRef.current();
|
|
31039
|
+
deactivateRef.current();
|
|
31040
|
+
return;
|
|
31041
|
+
}
|
|
30870
31042
|
deselectRef.current();
|
|
30871
31043
|
deactivateRef.current();
|
|
30872
31044
|
clearMediaSelectionRef.current();
|
|
@@ -31696,10 +31868,10 @@ function OhhwellsBridge() {
|
|
|
31696
31868
|
window.removeEventListener("message", handleDuplicateSection);
|
|
31697
31869
|
window.removeEventListener("message", handleDeactivate);
|
|
31698
31870
|
window.removeEventListener("message", handleSelectNav);
|
|
31699
|
-
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
31700
31871
|
window.removeEventListener("message", handleToastAction);
|
|
31701
31872
|
window.removeEventListener("message", handleFormCount);
|
|
31702
31873
|
window.removeEventListener("message", handleUiEscape);
|
|
31874
|
+
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
31703
31875
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
31704
31876
|
autoSaveTimers.current.clear();
|
|
31705
31877
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
@@ -31993,7 +32165,7 @@ function OhhwellsBridge() {
|
|
|
31993
32165
|
postToParent2({
|
|
31994
32166
|
type: "ow:ready",
|
|
31995
32167
|
version: "1",
|
|
31996
|
-
bridgeVersion: "0.1.
|
|
32168
|
+
bridgeVersion: "0.1.157-next.420",
|
|
31997
32169
|
path: pathname,
|
|
31998
32170
|
nodes: collectEditableNodes(editContentRef.current),
|
|
31999
32171
|
sections
|
|
@@ -33200,6 +33372,7 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
|
|
|
33200
33372
|
OhwLoaderSurface,
|
|
33201
33373
|
SITE_OG_IMAGE_KEY,
|
|
33202
33374
|
SchedulingWidget,
|
|
33375
|
+
TEMPLATE_LOGO_ATTR,
|
|
33203
33376
|
Toggle,
|
|
33204
33377
|
ToggleGroup,
|
|
33205
33378
|
ToggleGroupItem,
|
|
@@ -33219,6 +33392,7 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
|
|
|
33219
33392
|
foldAlignIntoTrees,
|
|
33220
33393
|
getEditModeInitialState,
|
|
33221
33394
|
hasMountedContentNodes,
|
|
33395
|
+
indexCollectionItems,
|
|
33222
33396
|
insertFooterHours,
|
|
33223
33397
|
isEditSessionActive,
|
|
33224
33398
|
isPlainLeftClick,
|
|
@@ -33226,11 +33400,13 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
|
|
|
33226
33400
|
isRenderableTree,
|
|
33227
33401
|
isStickySearchParam,
|
|
33228
33402
|
isValidUrl,
|
|
33403
|
+
matchCollectionItemClick,
|
|
33229
33404
|
nextViableSlide,
|
|
33230
33405
|
parseAiFooterState,
|
|
33231
33406
|
parseAiSectionsState,
|
|
33232
33407
|
parseTarget,
|
|
33233
33408
|
recordOverriddenPaths,
|
|
33409
|
+
releaseTemplateLogoIfReplaced,
|
|
33234
33410
|
removeFooterBlock,
|
|
33235
33411
|
resetOverriddenPathsCache,
|
|
33236
33412
|
resolveFooterCopyright,
|