@ohhwells/bridge 0.1.152 → 0.1.153-next.417
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1188 -882
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -1
- package/dist/index.d.ts +31 -1
- package/dist/index.js +1251 -931
- 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 +3 -3
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/OhhwellsBridge.tsx
|
|
4
|
-
import React12, { useCallback as useCallback12, useEffect as useEffect17, useLayoutEffect as
|
|
4
|
+
import React12, { useCallback as useCallback12, useEffect as useEffect17, useLayoutEffect as useLayoutEffect7, useRef as useRef14, useState as useState18 } from "react";
|
|
5
5
|
import { createRoot as createRoot3 } from "react-dom/client";
|
|
6
6
|
import { flushSync as flushSync3 } from "react-dom";
|
|
7
7
|
|
|
@@ -6542,6 +6542,21 @@ function pricingCardFeatureCount(tree, index) {
|
|
|
6542
6542
|
const target = findPricingCollection(tree)?.children?.[index];
|
|
6543
6543
|
return target ? pricingFeatureList(target).length : 0;
|
|
6544
6544
|
}
|
|
6545
|
+
function prevailingFeatureIcon(features) {
|
|
6546
|
+
const counts = /* @__PURE__ */ new Map();
|
|
6547
|
+
for (const row of features) {
|
|
6548
|
+
const key = `${row.icon ?? ""}|${row.iconColor ?? ""}`;
|
|
6549
|
+
const entry = counts.get(key) ?? { count: 0, ...row.icon ? { icon: row.icon } : {}, ...row.iconColor ? { iconColor: row.iconColor } : {} };
|
|
6550
|
+
entry.count += 1;
|
|
6551
|
+
counts.set(key, entry);
|
|
6552
|
+
}
|
|
6553
|
+
let best = null;
|
|
6554
|
+
for (const entry of counts.values()) {
|
|
6555
|
+
if (!best || entry.count > best.count) best = entry;
|
|
6556
|
+
}
|
|
6557
|
+
if (!best) return {};
|
|
6558
|
+
return { ...best.icon ? { icon: best.icon } : {}, ...best.iconColor ? { iconColor: best.iconColor } : {} };
|
|
6559
|
+
}
|
|
6545
6560
|
function addPricingCardFeature(tree, index, text) {
|
|
6546
6561
|
return withPricingCollection(tree, (collection) => {
|
|
6547
6562
|
const children = collection.children;
|
|
@@ -6550,7 +6565,7 @@ function addPricingCardFeature(tree, index, text) {
|
|
|
6550
6565
|
const features = pricingFeatureList(target);
|
|
6551
6566
|
if (features.length >= PRICING_FEATURES_MAX) return false;
|
|
6552
6567
|
target.slots = target.slots ?? {};
|
|
6553
|
-
target.slots.features = [...features, { text }];
|
|
6568
|
+
target.slots.features = [...features, { text, ...prevailingFeatureIcon(features) }];
|
|
6554
6569
|
return true;
|
|
6555
6570
|
});
|
|
6556
6571
|
}
|
|
@@ -7161,6 +7176,21 @@ function applyCustomCodeToHead(content) {
|
|
|
7161
7176
|
if (beforeNodes.length > 0) document.head.append(...beforeNodes);
|
|
7162
7177
|
}
|
|
7163
7178
|
|
|
7179
|
+
// src/lib/selectNavContainer.ts
|
|
7180
|
+
function isOnScreen(el) {
|
|
7181
|
+
const rect = el.getBoundingClientRect();
|
|
7182
|
+
if (rect.width <= 0 || rect.height <= 0) return false;
|
|
7183
|
+
if (el.offsetParent !== null) return true;
|
|
7184
|
+
return getComputedStyle(el).position === "fixed";
|
|
7185
|
+
}
|
|
7186
|
+
function findSelectableNavContainer(doc = document) {
|
|
7187
|
+
const visible = Array.from(doc.querySelectorAll("[data-ohw-nav-container]")).filter(isOnScreen);
|
|
7188
|
+
if (visible.length === 0) return null;
|
|
7189
|
+
return visible.reduce(
|
|
7190
|
+
(best, el) => el.getBoundingClientRect().top < best.getBoundingClientRect().top ? el : best
|
|
7191
|
+
);
|
|
7192
|
+
}
|
|
7193
|
+
|
|
7164
7194
|
// src/ui/ai-tree/aiSectionsManager.tsx
|
|
7165
7195
|
import { flushSync } from "react-dom";
|
|
7166
7196
|
import { createRoot } from "react-dom/client";
|
|
@@ -7734,7 +7764,7 @@ var AI_MOBILE_CSS = [
|
|
|
7734
7764
|
// page's first section. Top only (bottom needs no nav clearance); ~96px approximates the
|
|
7735
7765
|
// template nav's own height (measured ~94px) — there's no shared `--ohw-header-h` var to read
|
|
7736
7766
|
// an exact figure from (no live measurement exists), so this is a safe approximation, not a
|
|
7737
|
-
// pixel-exact fit. Horizontal spacing already comes from `data-ai-
|
|
7767
|
+
// pixel-exact fit. Horizontal spacing already comes from `data-ai-section-inner`.
|
|
7738
7768
|
'[data-ai-overlay-clearance] [data-ai-overlap-layer="overlay"]{padding-top:96px}',
|
|
7739
7769
|
// A full-bleed carousel's height is pure arithmetic: it spans the whole window, so 16/9 turns
|
|
7740
7770
|
// window width straight into height. Measured at 16/9 it came out ~90% of the viewport at EVERY
|
|
@@ -7750,8 +7780,10 @@ var AI_MOBILE_CSS = [
|
|
|
7750
7780
|
"[data-ai-section]{overflow-x:hidden}",
|
|
7751
7781
|
// `:not([data-ai-full-bleed])`: this `!important` gutter beat the inline `padding: 0` that a
|
|
7752
7782
|
// full-bleed section's container sets, so a carousel/media hero that is edge-to-edge on desktop
|
|
7753
|
-
// still got a 20px band of section background down both sides on a phone.
|
|
7754
|
-
|
|
7783
|
+
// still got a 20px band of section background down both sides on a phone. The footer's own
|
|
7784
|
+
// container keeps the unguarded rule below — `data-ai-full-bleed` can never appear on it.
|
|
7785
|
+
"[data-ai-section-inner]:not([data-ai-full-bleed]){padding:0 20px !important}",
|
|
7786
|
+
"[data-ai-container]{padding:0 20px !important}",
|
|
7755
7787
|
"[data-ai-row]{display:flex !important;flex-direction:column !important;align-items:stretch !important}",
|
|
7756
7788
|
"[data-ai-cell]{width:100%;min-width:0}",
|
|
7757
7789
|
// The rule above turns every row into a COLUMN flex container on phones, which silently breaks
|
|
@@ -7956,6 +7988,31 @@ function pricingCardEmphasis(featured, ctx, hasBg) {
|
|
|
7956
7988
|
function textAttrs(ctx, path) {
|
|
7957
7989
|
return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
|
|
7958
7990
|
}
|
|
7991
|
+
var AI_RESPONSIVE_CSS = [
|
|
7992
|
+
"@media (max-width: 960px) {",
|
|
7993
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
|
|
7994
|
+
' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
|
|
7995
|
+
"}",
|
|
7996
|
+
"@media (max-width: 640px) {",
|
|
7997
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
|
|
7998
|
+
" [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
|
|
7999
|
+
// Group containers flatten to a column on phones; span placements come along for free.
|
|
8000
|
+
// `:not([data-ai-group="overlap"])` for the same reason as the twin pair in AI_MOBILE_CSS — see
|
|
8001
|
+
// the comment there. This sheet's copy is the narrower selector, so without the exemption it
|
|
8002
|
+
// flattens an `overlap` hero below 640px even though the other rule stands down: measured a 390px
|
|
8003
|
+
// viewport with the heading/CTA in flow *under* the image, 219px of section background where the
|
|
8004
|
+
// layered text used to be.
|
|
8005
|
+
' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) { display: flex !important; flex-direction: column !important; }',
|
|
8006
|
+
' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) > * { grid-column: auto !important; }',
|
|
8007
|
+
// `:not([data-ai-full-bleed])` for the same reason as the twin rule in AI_MOBILE_CSS: this one
|
|
8008
|
+
// is narrower (0,2,0 vs 0,1,0) and also `!important`, so without the guard it wins outright and
|
|
8009
|
+
// a full-bleed hero gets its 20px side band back below 640px only — the one width where the
|
|
8010
|
+
// other rule had already been taught to stand down.
|
|
8011
|
+
" [data-ai-responsive] [data-ai-section-inner]:not([data-ai-full-bleed]) { padding-left: 20px !important; padding-right: 20px !important; }",
|
|
8012
|
+
" [data-ai-responsive] { overflow-x: hidden; }",
|
|
8013
|
+
" [data-ai-responsive] img { max-width: 100%; }",
|
|
8014
|
+
"}"
|
|
8015
|
+
].join("\n");
|
|
7959
8016
|
var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
7960
8017
|
function MediaBox({
|
|
7961
8018
|
refValue,
|
|
@@ -8010,7 +8067,7 @@ function MediaBox({
|
|
|
8010
8067
|
position: fill ? "absolute" : void 0,
|
|
8011
8068
|
inset: fill ? 0 : void 0,
|
|
8012
8069
|
width: fill ? "100%" : fixedSize ? "auto" : "100%",
|
|
8013
|
-
height: fill ? "100%" : void 0,
|
|
8070
|
+
height: fill ? "100%" : fixedSize ? height : void 0,
|
|
8014
8071
|
aspectRatio: fill ? void 0 : aspectRatio,
|
|
8015
8072
|
minHeight: fill || fixedSize ? void 0 : height ?? (aspectRatio ? void 0 : 180),
|
|
8016
8073
|
borderRadius: radius,
|
|
@@ -9506,7 +9563,7 @@ function CollectionBlock({ node, ctx, path }) {
|
|
|
9506
9563
|
return /* @__PURE__ */ jsx(
|
|
9507
9564
|
"div",
|
|
9508
9565
|
{
|
|
9509
|
-
"data-ai-grid":
|
|
9566
|
+
"data-ai-grid": String(itemsPerRow),
|
|
9510
9567
|
"data-ohw-pricing-collection": isPricing ? "" : void 0,
|
|
9511
9568
|
style: {
|
|
9512
9569
|
display: "grid",
|
|
@@ -9808,7 +9865,7 @@ function renderNode(node, ctx, path, ambientAlign) {
|
|
|
9808
9865
|
},
|
|
9809
9866
|
children: [
|
|
9810
9867
|
i > 0 && ctx.heroOverlapFullBleed ? (
|
|
9811
|
-
// The section's `data-ai-
|
|
9868
|
+
// The section's `data-ai-section-inner` gave up its max-width/gutter so the base
|
|
9812
9869
|
// layer (this group's i===0 sibling) can span edge-to-edge — reintroduced here,
|
|
9813
9870
|
// scoped to just the overlay text, so a heading/copy/CTA stack doesn't stretch
|
|
9814
9871
|
// the full section width instead of reading at the usual content width.
|
|
@@ -10227,6 +10284,7 @@ function AiTreeRenderer({
|
|
|
10227
10284
|
...fillHeight ? { "data-ai-fill-height": "" } : {},
|
|
10228
10285
|
...needsOverlayClearance ? { "data-ai-overlay-clearance": "" } : {},
|
|
10229
10286
|
...bgAttrs,
|
|
10287
|
+
"data-ai-responsive": "",
|
|
10230
10288
|
style: {
|
|
10231
10289
|
position: "relative",
|
|
10232
10290
|
padding: `${padCss} 0`,
|
|
@@ -10240,12 +10298,13 @@ function AiTreeRenderer({
|
|
|
10240
10298
|
...fillHeight ? { display: "grid" } : {}
|
|
10241
10299
|
},
|
|
10242
10300
|
children: [
|
|
10243
|
-
|
|
10301
|
+
/* @__PURE__ */ jsx("style", { children: AI_RESPONSIVE_CSS }),
|
|
10244
10302
|
/* @__PURE__ */ jsx("style", { children: AI_MOBILE_CSS }),
|
|
10303
|
+
isOverlay && backgroundUrl && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
|
|
10245
10304
|
/* @__PURE__ */ jsx(
|
|
10246
10305
|
"div",
|
|
10247
10306
|
{
|
|
10248
|
-
"data-ai-
|
|
10307
|
+
"data-ai-section-inner": "",
|
|
10249
10308
|
...fullBleedMedia ? { "data-ai-full-bleed": "" } : {},
|
|
10250
10309
|
style: {
|
|
10251
10310
|
position: "relative",
|
|
@@ -10262,7 +10321,7 @@ function AiTreeRenderer({
|
|
|
10262
10321
|
children: tree.rows.map((row, r2) => /* @__PURE__ */ jsx(
|
|
10263
10322
|
"div",
|
|
10264
10323
|
{
|
|
10265
|
-
"data-ai-
|
|
10324
|
+
"data-ai-columns": "",
|
|
10266
10325
|
style: {
|
|
10267
10326
|
display: "grid",
|
|
10268
10327
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
@@ -10924,9 +10983,10 @@ function applyAiSectionsToDom(state, options) {
|
|
|
10924
10983
|
if (existing && existing.serialized === serialized && existing.container.isConnected) {
|
|
10925
10984
|
continue;
|
|
10926
10985
|
}
|
|
10927
|
-
const isNewMount = !existing || !existing.container.isConnected;
|
|
10928
10986
|
let container = existing?.container;
|
|
10987
|
+
let isNewMount = false;
|
|
10929
10988
|
if (!container || !container.isConnected) {
|
|
10989
|
+
isNewMount = true;
|
|
10930
10990
|
existing?.root.unmount();
|
|
10931
10991
|
container?.remove();
|
|
10932
10992
|
container = document.createElement("div");
|
|
@@ -11570,6 +11630,172 @@ function useLinkHrefGuardian(...deps) {
|
|
|
11570
11630
|
}, deps);
|
|
11571
11631
|
}
|
|
11572
11632
|
|
|
11633
|
+
// src/ui/link-modal/linkModal.utils.ts
|
|
11634
|
+
function parseTarget(target) {
|
|
11635
|
+
if (!target) return { pageRoute: "", sectionId: null };
|
|
11636
|
+
const hashIndex = target.indexOf("#");
|
|
11637
|
+
if (hashIndex === -1) return { pageRoute: target, sectionId: null };
|
|
11638
|
+
return {
|
|
11639
|
+
pageRoute: target.slice(0, hashIndex),
|
|
11640
|
+
sectionId: target.slice(hashIndex + 1) || null
|
|
11641
|
+
};
|
|
11642
|
+
}
|
|
11643
|
+
function normalizePath(path) {
|
|
11644
|
+
const trimmed = path.trim();
|
|
11645
|
+
if (!trimmed) return "/";
|
|
11646
|
+
try {
|
|
11647
|
+
if (/^https?:\/\//i.test(trimmed)) {
|
|
11648
|
+
return new URL(trimmed).pathname || "/";
|
|
11649
|
+
}
|
|
11650
|
+
} catch {
|
|
11651
|
+
}
|
|
11652
|
+
const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
11653
|
+
if (withSlash.length > 1 && withSlash.endsWith("/")) return withSlash.slice(0, -1);
|
|
11654
|
+
return withSlash;
|
|
11655
|
+
}
|
|
11656
|
+
function findPageByPath(pages, path) {
|
|
11657
|
+
const normalized = normalizePath(path);
|
|
11658
|
+
return pages.find((p) => normalizePath(p.path) === normalized);
|
|
11659
|
+
}
|
|
11660
|
+
function inferPageTitleFromPath(path) {
|
|
11661
|
+
const normalized = normalizePath(path);
|
|
11662
|
+
if (normalized === "/") return "Home";
|
|
11663
|
+
const segment = normalized.split("/").filter(Boolean).pop() ?? "";
|
|
11664
|
+
if (!segment) return "Home";
|
|
11665
|
+
return segment.split("-").filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
11666
|
+
}
|
|
11667
|
+
function isInternalPath(route) {
|
|
11668
|
+
const trimmed = route.trim();
|
|
11669
|
+
if (!trimmed) return false;
|
|
11670
|
+
if (/^https?:\/\//i.test(trimmed)) return false;
|
|
11671
|
+
if (trimmed.startsWith("/")) return true;
|
|
11672
|
+
if (trimmed.includes(" ") || trimmed.includes(".")) return false;
|
|
11673
|
+
return true;
|
|
11674
|
+
}
|
|
11675
|
+
function resolvePage(route, pages) {
|
|
11676
|
+
const found = findPageByPath(pages, route);
|
|
11677
|
+
if (found) return { path: found.path, title: found.title };
|
|
11678
|
+
return { path: normalizePath(route), title: inferPageTitleFromPath(route) };
|
|
11679
|
+
}
|
|
11680
|
+
function getSectionsForPath(sectionsByPath, pageRoute) {
|
|
11681
|
+
if (!sectionsByPath) return [];
|
|
11682
|
+
const normalized = normalizePath(pageRoute);
|
|
11683
|
+
return sectionsByPath[normalized] ?? sectionsByPath[pageRoute] ?? [];
|
|
11684
|
+
}
|
|
11685
|
+
function buildTarget(page, section) {
|
|
11686
|
+
if (section) return `${page.path}#${section.id}`;
|
|
11687
|
+
return page.path;
|
|
11688
|
+
}
|
|
11689
|
+
function isValidUrl(urlString) {
|
|
11690
|
+
try {
|
|
11691
|
+
const url = new URL(urlString);
|
|
11692
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return false;
|
|
11693
|
+
const hostname = url.hostname;
|
|
11694
|
+
if (!hostname || hostname.length === 0) return false;
|
|
11695
|
+
if (hostname.includes(" ")) return false;
|
|
11696
|
+
if (hostname === "localhost") return true;
|
|
11697
|
+
if (!hostname.includes(".")) return false;
|
|
11698
|
+
if (!/[a-z]/i.test(hostname)) return false;
|
|
11699
|
+
return true;
|
|
11700
|
+
} catch {
|
|
11701
|
+
return false;
|
|
11702
|
+
}
|
|
11703
|
+
}
|
|
11704
|
+
function normalizeUrl(value) {
|
|
11705
|
+
const trimmed = value.trim();
|
|
11706
|
+
if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) return trimmed;
|
|
11707
|
+
return `https://${trimmed}`;
|
|
11708
|
+
}
|
|
11709
|
+
function validateUrlInput(value, pages, allPages) {
|
|
11710
|
+
const trimmed = value.trim();
|
|
11711
|
+
if (!trimmed) return "";
|
|
11712
|
+
const exactPage = allPages.find((p) => p.title.toLowerCase() === trimmed.toLowerCase());
|
|
11713
|
+
if (exactPage) return "";
|
|
11714
|
+
const hasPrefixMatch = pages.some((p) => p.title.toLowerCase().startsWith(trimmed.toLowerCase()));
|
|
11715
|
+
if (hasPrefixMatch) {
|
|
11716
|
+
return "Select a page from the list or enter a valid URL";
|
|
11717
|
+
}
|
|
11718
|
+
const hasScheme = /^https?:\/\//i.test(trimmed);
|
|
11719
|
+
if (!hasScheme && !trimmed.includes(".")) {
|
|
11720
|
+
return "Please enter a valid URL (e.g., https://example.com)";
|
|
11721
|
+
}
|
|
11722
|
+
if (!isValidUrl(normalizeUrl(trimmed))) {
|
|
11723
|
+
return "Please enter a valid URL (e.g., https://example.com)";
|
|
11724
|
+
}
|
|
11725
|
+
return "";
|
|
11726
|
+
}
|
|
11727
|
+
function getEditModeInitialState(target, pages, sections) {
|
|
11728
|
+
const empty = {
|
|
11729
|
+
searchValue: "",
|
|
11730
|
+
selectedPage: null,
|
|
11731
|
+
selectedSection: null,
|
|
11732
|
+
step: "input"
|
|
11733
|
+
};
|
|
11734
|
+
if (!target) return empty;
|
|
11735
|
+
if (isValidUrl(normalizeUrl(target))) {
|
|
11736
|
+
return { searchValue: target, selectedPage: null, selectedSection: null, step: "input" };
|
|
11737
|
+
}
|
|
11738
|
+
const { pageRoute, sectionId } = parseTarget(target);
|
|
11739
|
+
if (sectionId) {
|
|
11740
|
+
if (isInternalPath(pageRoute)) {
|
|
11741
|
+
const page = resolvePage(pageRoute, pages);
|
|
11742
|
+
const sec = sections.find((s) => s.id === sectionId);
|
|
11743
|
+
return {
|
|
11744
|
+
searchValue: page.title,
|
|
11745
|
+
selectedPage: page,
|
|
11746
|
+
selectedSection: sec ? { id: sec.id, label: sec.label } : null,
|
|
11747
|
+
step: "input"
|
|
11748
|
+
};
|
|
11749
|
+
}
|
|
11750
|
+
return { searchValue: pageRoute || target, selectedPage: null, selectedSection: null, step: "input" };
|
|
11751
|
+
}
|
|
11752
|
+
if (isInternalPath(pageRoute)) {
|
|
11753
|
+
const page = resolvePage(pageRoute, pages);
|
|
11754
|
+
return {
|
|
11755
|
+
searchValue: page.title,
|
|
11756
|
+
selectedPage: page,
|
|
11757
|
+
selectedSection: null,
|
|
11758
|
+
step: "input"
|
|
11759
|
+
};
|
|
11760
|
+
}
|
|
11761
|
+
return { searchValue: target, selectedPage: null, selectedSection: null, step: "input" };
|
|
11762
|
+
}
|
|
11763
|
+
function filterAvailablePages(pages, existingTargets) {
|
|
11764
|
+
const taken = new Set(existingTargets);
|
|
11765
|
+
return pages.filter((p) => !taken.has(p.path));
|
|
11766
|
+
}
|
|
11767
|
+
|
|
11768
|
+
// src/lib/collection-item-click.ts
|
|
11769
|
+
function indexCollectionItems(pages) {
|
|
11770
|
+
const index = /* @__PURE__ */ new Map();
|
|
11771
|
+
for (const page of pages) {
|
|
11772
|
+
if (page.kind !== "COLLECTION_ITEM" || !page.collection || !page.path) continue;
|
|
11773
|
+
index.set(normalizePath(page.path), { path: page.path, collection: page.collection });
|
|
11774
|
+
}
|
|
11775
|
+
return index;
|
|
11776
|
+
}
|
|
11777
|
+
function pathOfHref(href) {
|
|
11778
|
+
const trimmed = href.trim();
|
|
11779
|
+
if (!trimmed || trimmed.startsWith("#")) return null;
|
|
11780
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed) && !/^https?:/i.test(trimmed)) return null;
|
|
11781
|
+
const withoutHash = trimmed.split("#")[0];
|
|
11782
|
+
const withoutQuery = withoutHash.split("?")[0];
|
|
11783
|
+
if (!withoutQuery) return null;
|
|
11784
|
+
return normalizePath(withoutQuery);
|
|
11785
|
+
}
|
|
11786
|
+
function matchCollectionItemClick(target, index) {
|
|
11787
|
+
if (!target || index.size === 0) return null;
|
|
11788
|
+
const text = target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
|
|
11789
|
+
if (!text) return null;
|
|
11790
|
+
const anchor = text.closest("a");
|
|
11791
|
+
if (!anchor || anchor.closest(CTA_BUTTON_SELECTOR)) return null;
|
|
11792
|
+
const href = anchor.getAttribute("href");
|
|
11793
|
+
if (!href) return null;
|
|
11794
|
+
const path = pathOfHref(href);
|
|
11795
|
+
if (!path) return null;
|
|
11796
|
+
return index.get(path) ?? null;
|
|
11797
|
+
}
|
|
11798
|
+
|
|
11573
11799
|
// src/lib/sticky-search-params.ts
|
|
11574
11800
|
var STICKY_EXACT = /* @__PURE__ */ new Set([
|
|
11575
11801
|
// Site identity. Required in local dev and in the canvas editor's iframe, where there is no
|
|
@@ -16910,6 +17136,107 @@ function bindPublishedForms(apiUrl, subdomain, content = {}) {
|
|
|
16910
17136
|
);
|
|
16911
17137
|
}
|
|
16912
17138
|
|
|
17139
|
+
// src/lib/outage-beacon.ts
|
|
17140
|
+
var DEDUP_MS = 5 * 60 * 1e3;
|
|
17141
|
+
var lastSent = /* @__PURE__ */ new Map();
|
|
17142
|
+
function apiBase() {
|
|
17143
|
+
return process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
17144
|
+
}
|
|
17145
|
+
function bridgeVersion() {
|
|
17146
|
+
try {
|
|
17147
|
+
if (true) {
|
|
17148
|
+
return "0.1.153-next.417";
|
|
17149
|
+
}
|
|
17150
|
+
} catch {
|
|
17151
|
+
}
|
|
17152
|
+
if (typeof document !== "undefined") {
|
|
17153
|
+
return document.documentElement.getAttribute("data-ohw-bridge-version") || void 0;
|
|
17154
|
+
}
|
|
17155
|
+
return void 0;
|
|
17156
|
+
}
|
|
17157
|
+
function stampBridgeVersionOnDocument() {
|
|
17158
|
+
if (typeof document === "undefined") {
|
|
17159
|
+
return;
|
|
17160
|
+
}
|
|
17161
|
+
try {
|
|
17162
|
+
const v = true ? "0.1.153-next.417" : "";
|
|
17163
|
+
if (v) {
|
|
17164
|
+
document.documentElement.setAttribute("data-ohw-bridge-version", v);
|
|
17165
|
+
window.__OHW_BRIDGE_VERSION__ = v;
|
|
17166
|
+
}
|
|
17167
|
+
} catch {
|
|
17168
|
+
}
|
|
17169
|
+
}
|
|
17170
|
+
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;
|
|
17171
|
+
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;
|
|
17172
|
+
function isVercelPreviewHost() {
|
|
17173
|
+
if (typeof location === "undefined") {
|
|
17174
|
+
return false;
|
|
17175
|
+
}
|
|
17176
|
+
return location.hostname.toLowerCase().endsWith(".vercel.ohhwells.site");
|
|
17177
|
+
}
|
|
17178
|
+
function reportOutageBeacon(args) {
|
|
17179
|
+
if (typeof window === "undefined" || !args.subdomain) {
|
|
17180
|
+
return;
|
|
17181
|
+
}
|
|
17182
|
+
if (isVercelPreviewHost()) {
|
|
17183
|
+
return;
|
|
17184
|
+
}
|
|
17185
|
+
if (args.reason === "page_error" && args.detail && RECOVERABLE_PAGE_ERROR.test(args.detail)) {
|
|
17186
|
+
return;
|
|
17187
|
+
}
|
|
17188
|
+
if (args.reason === "content_fetch_failed" && args.detail && TRANSIENT_CONTENT_FETCH.test(args.detail.trim())) {
|
|
17189
|
+
return;
|
|
17190
|
+
}
|
|
17191
|
+
const key = `${args.subdomain}|${args.reason}`;
|
|
17192
|
+
const now = Date.now();
|
|
17193
|
+
const prev = lastSent.get(key) || 0;
|
|
17194
|
+
if (now - prev < DEDUP_MS) {
|
|
17195
|
+
return;
|
|
17196
|
+
}
|
|
17197
|
+
lastSent.set(key, now);
|
|
17198
|
+
const body = JSON.stringify({
|
|
17199
|
+
subdomain: args.subdomain,
|
|
17200
|
+
reason: args.reason,
|
|
17201
|
+
detail: args.detail?.slice(0, 300),
|
|
17202
|
+
templateId: args.templateId,
|
|
17203
|
+
bridgeVersion: bridgeVersion(),
|
|
17204
|
+
href: typeof location !== "undefined" ? location.href : void 0
|
|
17205
|
+
});
|
|
17206
|
+
const url = `${apiBase()}/api/public/sites/outage-beacon`;
|
|
17207
|
+
try {
|
|
17208
|
+
if (typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function") {
|
|
17209
|
+
const blob = new Blob([body], { type: "application/json" });
|
|
17210
|
+
if (navigator.sendBeacon(url, blob)) {
|
|
17211
|
+
return;
|
|
17212
|
+
}
|
|
17213
|
+
}
|
|
17214
|
+
void fetch(url, {
|
|
17215
|
+
method: "POST",
|
|
17216
|
+
headers: { "Content-Type": "application/json" },
|
|
17217
|
+
body,
|
|
17218
|
+
keepalive: true,
|
|
17219
|
+
cache: "no-store"
|
|
17220
|
+
}).catch(() => {
|
|
17221
|
+
});
|
|
17222
|
+
} catch {
|
|
17223
|
+
}
|
|
17224
|
+
}
|
|
17225
|
+
function armLoaderHangBeacon(subdomain, fetchState, hangMs = 15e3) {
|
|
17226
|
+
if (!subdomain || fetchState !== "loading") {
|
|
17227
|
+
return () => {
|
|
17228
|
+
};
|
|
17229
|
+
}
|
|
17230
|
+
const timer = window.setTimeout(() => {
|
|
17231
|
+
reportOutageBeacon({
|
|
17232
|
+
subdomain,
|
|
17233
|
+
reason: "loader_stuck",
|
|
17234
|
+
detail: `fetchState still loading after ${hangMs}ms`
|
|
17235
|
+
});
|
|
17236
|
+
}, hangMs);
|
|
17237
|
+
return () => window.clearTimeout(timer);
|
|
17238
|
+
}
|
|
17239
|
+
|
|
16913
17240
|
// src/lib/form-fields.ts
|
|
16914
17241
|
var FIELD_DEFAULTS = {
|
|
16915
17242
|
"short-text": { label: "Short text", placeholder: "Type placeholder text..." },
|
|
@@ -17510,6 +17837,7 @@ function MediaOverlay({
|
|
|
17510
17837
|
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
17511
17838
|
);
|
|
17512
17839
|
}, [isVideo]);
|
|
17840
|
+
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
17513
17841
|
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
17514
17842
|
const box = {
|
|
17515
17843
|
position: "fixed",
|
|
@@ -17608,11 +17936,10 @@ function MediaOverlay({
|
|
|
17608
17936
|
className: "flex items-center justify-center cursor-pointer",
|
|
17609
17937
|
style: {
|
|
17610
17938
|
...box,
|
|
17611
|
-
//
|
|
17612
|
-
//
|
|
17613
|
-
//
|
|
17614
|
-
|
|
17615
|
-
pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
|
|
17939
|
+
// Visual only. `pointer-events: auto` on this full-bleed rect covered the navbar
|
|
17940
|
+
// (hero bg includes the absolute TopNav) and swallowed CTA press-drag. Text overlay
|
|
17941
|
+
// and cueOnly also need clicks to fall through — Replace / video controls opt back in.
|
|
17942
|
+
pointerEvents: "none",
|
|
17616
17943
|
// Selected: a firm component ring with no wash, so the image reads as chosen rather
|
|
17617
17944
|
// than hovered. Hover keeps the existing tinted preview.
|
|
17618
17945
|
boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
@@ -17639,17 +17966,17 @@ function MediaOverlay({
|
|
|
17639
17966
|
},
|
|
17640
17967
|
children: [
|
|
17641
17968
|
isVideo ? /* @__PURE__ */ jsx17(Film, { size: 14 }) : /* @__PURE__ */ jsx17(ImageIcon, { size: 14 }),
|
|
17642
|
-
|
|
17969
|
+
replaceLabel
|
|
17643
17970
|
]
|
|
17644
17971
|
}
|
|
17645
17972
|
),
|
|
17646
|
-
replaceMode
|
|
17973
|
+
showChrome && replaceMode !== "none" && /* @__PURE__ */ jsxs8(
|
|
17647
17974
|
Button,
|
|
17648
17975
|
{
|
|
17649
17976
|
"data-ohw-media-overlay": "",
|
|
17650
17977
|
variant: "outline",
|
|
17651
17978
|
size: "sm",
|
|
17652
|
-
"aria-label":
|
|
17979
|
+
"aria-label": replaceLabel,
|
|
17653
17980
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
17654
17981
|
style: {
|
|
17655
17982
|
...OVERLAY_BUTTON_STYLE,
|
|
@@ -17672,7 +17999,7 @@ function MediaOverlay({
|
|
|
17672
17999
|
},
|
|
17673
18000
|
children: [
|
|
17674
18001
|
isVideo ? /* @__PURE__ */ jsx17(Film, { size: 14 }) : /* @__PURE__ */ jsx17(ImageIcon, { size: 14 }),
|
|
17675
|
-
replaceMode === "full" ?
|
|
18002
|
+
replaceMode === "full" ? replaceLabel : null
|
|
17676
18003
|
]
|
|
17677
18004
|
}
|
|
17678
18005
|
)
|
|
@@ -18181,8 +18508,24 @@ function AiSectionOverlay({
|
|
|
18181
18508
|
}
|
|
18182
18509
|
|
|
18183
18510
|
// src/ui/ai-section/AiMediaStripOverlay.tsx
|
|
18184
|
-
import { useCallback as useCallback3, useEffect as useEffect6, useRef as useRef5, useState as useState8 } from "react";
|
|
18185
|
-
import {
|
|
18511
|
+
import { useCallback as useCallback3, useEffect as useEffect6, useLayoutEffect as useLayoutEffect4, useRef as useRef5, useState as useState8 } from "react";
|
|
18512
|
+
import {
|
|
18513
|
+
AlignCenter,
|
|
18514
|
+
AlignLeft,
|
|
18515
|
+
AlignRight,
|
|
18516
|
+
ArrowLeft as ArrowLeft2,
|
|
18517
|
+
ArrowRight as ArrowRight2,
|
|
18518
|
+
Check as Check2,
|
|
18519
|
+
ChevronDown as ChevronDown3,
|
|
18520
|
+
Image as ImageIcon2,
|
|
18521
|
+
ImageMinus,
|
|
18522
|
+
ImagePlus,
|
|
18523
|
+
Link as LinkIcon,
|
|
18524
|
+
Minus,
|
|
18525
|
+
Palette,
|
|
18526
|
+
Plus as Plus2,
|
|
18527
|
+
Star
|
|
18528
|
+
} from "lucide-react";
|
|
18186
18529
|
|
|
18187
18530
|
// src/lib/ai-media-strip-tree.ts
|
|
18188
18531
|
var MEDIA_STRIP_ITEM_MIN = 1;
|
|
@@ -18296,14 +18639,6 @@ function setMediaStripItemAsset(tree, index, assetId) {
|
|
|
18296
18639
|
return true;
|
|
18297
18640
|
});
|
|
18298
18641
|
}
|
|
18299
|
-
function setMediaStripItemAlt(tree, index, alt) {
|
|
18300
|
-
return withMediaStrip(tree, (block) => {
|
|
18301
|
-
const items = block.items;
|
|
18302
|
-
if (index < 0 || index >= items.length) return false;
|
|
18303
|
-
items[index] = { ...items[index], alt };
|
|
18304
|
-
return true;
|
|
18305
|
-
});
|
|
18306
|
-
}
|
|
18307
18642
|
function setMediaStripItemLink(tree, index, link) {
|
|
18308
18643
|
return withMediaStrip(tree, (block) => {
|
|
18309
18644
|
const items = block.items;
|
|
@@ -18321,39 +18656,166 @@ function setMediaStripItemLink(tree, index, link) {
|
|
|
18321
18656
|
});
|
|
18322
18657
|
}
|
|
18323
18658
|
|
|
18324
|
-
// src/ui/
|
|
18325
|
-
import
|
|
18326
|
-
|
|
18327
|
-
|
|
18328
|
-
|
|
18329
|
-
function
|
|
18330
|
-
|
|
18331
|
-
|
|
18332
|
-
|
|
18333
|
-
for (const el of Array.from(items)) {
|
|
18334
|
-
if (Number(el.dataset.ohwMediaStripIndex) === index) return el;
|
|
18335
|
-
}
|
|
18336
|
-
return null;
|
|
18659
|
+
// src/ui/dialog.tsx
|
|
18660
|
+
import * as React9 from "react";
|
|
18661
|
+
import { Dialog as DialogPrimitive } from "radix-ui";
|
|
18662
|
+
import { X as X2 } from "lucide-react";
|
|
18663
|
+
import { jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
18664
|
+
function Dialog2({
|
|
18665
|
+
...props
|
|
18666
|
+
}) {
|
|
18667
|
+
return /* @__PURE__ */ jsx20(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
|
|
18337
18668
|
}
|
|
18338
|
-
function
|
|
18339
|
-
|
|
18340
|
-
|
|
18341
|
-
|
|
18342
|
-
if (r2.width <= 0 || r2.height <= 0) return null;
|
|
18343
|
-
return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
|
|
18669
|
+
function DialogPortal({
|
|
18670
|
+
...props
|
|
18671
|
+
}) {
|
|
18672
|
+
return /* @__PURE__ */ jsx20(DialogPrimitive.Portal, { ...props });
|
|
18344
18673
|
}
|
|
18345
|
-
function
|
|
18346
|
-
|
|
18347
|
-
|
|
18348
|
-
|
|
18349
|
-
|
|
18350
|
-
|
|
18674
|
+
function DialogOverlay({
|
|
18675
|
+
className,
|
|
18676
|
+
...props
|
|
18677
|
+
}) {
|
|
18678
|
+
return /* @__PURE__ */ jsx20(
|
|
18679
|
+
DialogPrimitive.Overlay,
|
|
18680
|
+
{
|
|
18681
|
+
"data-slot": "dialog-overlay",
|
|
18682
|
+
"data-ohw-link-modal-root": "",
|
|
18683
|
+
className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
|
|
18684
|
+
...props
|
|
18351
18685
|
}
|
|
18352
|
-
|
|
18353
|
-
|
|
18354
|
-
|
|
18355
|
-
|
|
18356
|
-
|
|
18686
|
+
);
|
|
18687
|
+
}
|
|
18688
|
+
var DialogContent = React9.forwardRef(
|
|
18689
|
+
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
18690
|
+
const positionMode = container ? "absolute" : "fixed";
|
|
18691
|
+
return /* @__PURE__ */ jsxs11(DialogPortal, { container: container ?? void 0, children: [
|
|
18692
|
+
/* @__PURE__ */ jsx20(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
18693
|
+
/* @__PURE__ */ jsxs11(
|
|
18694
|
+
DialogPrimitive.Content,
|
|
18695
|
+
{
|
|
18696
|
+
ref,
|
|
18697
|
+
"data-slot": "dialog-content",
|
|
18698
|
+
className: cn(
|
|
18699
|
+
positionMode,
|
|
18700
|
+
"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",
|
|
18701
|
+
"rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
|
|
18702
|
+
container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
|
|
18703
|
+
className
|
|
18704
|
+
),
|
|
18705
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
18706
|
+
...props,
|
|
18707
|
+
children: [
|
|
18708
|
+
children,
|
|
18709
|
+
showCloseButton ? /* @__PURE__ */ jsx20(
|
|
18710
|
+
DialogPrimitive.Close,
|
|
18711
|
+
{
|
|
18712
|
+
type: "button",
|
|
18713
|
+
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
18714
|
+
"aria-label": "Close",
|
|
18715
|
+
children: /* @__PURE__ */ jsx20(X2, { size: 16, "aria-hidden": true })
|
|
18716
|
+
}
|
|
18717
|
+
) : null
|
|
18718
|
+
]
|
|
18719
|
+
}
|
|
18720
|
+
)
|
|
18721
|
+
] });
|
|
18722
|
+
}
|
|
18723
|
+
);
|
|
18724
|
+
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
18725
|
+
function DialogHeader({
|
|
18726
|
+
className,
|
|
18727
|
+
...props
|
|
18728
|
+
}) {
|
|
18729
|
+
return /* @__PURE__ */ jsx20("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
18730
|
+
}
|
|
18731
|
+
function DialogFooter({
|
|
18732
|
+
className,
|
|
18733
|
+
...props
|
|
18734
|
+
}) {
|
|
18735
|
+
return /* @__PURE__ */ jsx20(
|
|
18736
|
+
"div",
|
|
18737
|
+
{
|
|
18738
|
+
className: cn("flex items-center justify-end gap-2", className),
|
|
18739
|
+
...props
|
|
18740
|
+
}
|
|
18741
|
+
);
|
|
18742
|
+
}
|
|
18743
|
+
var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
|
|
18744
|
+
DialogPrimitive.Title,
|
|
18745
|
+
{
|
|
18746
|
+
ref,
|
|
18747
|
+
className: cn(
|
|
18748
|
+
"text-lg font-semibold leading-none tracking-tight text-card-foreground",
|
|
18749
|
+
className
|
|
18750
|
+
),
|
|
18751
|
+
...props
|
|
18752
|
+
}
|
|
18753
|
+
));
|
|
18754
|
+
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
18755
|
+
var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
|
|
18756
|
+
DialogPrimitive.Description,
|
|
18757
|
+
{
|
|
18758
|
+
ref,
|
|
18759
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
18760
|
+
...props
|
|
18761
|
+
}
|
|
18762
|
+
));
|
|
18763
|
+
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
18764
|
+
var DialogClose = DialogPrimitive.Close;
|
|
18765
|
+
|
|
18766
|
+
// src/ui/ai-section/AiMediaStripOverlay.tsx
|
|
18767
|
+
import { Fragment as Fragment7, jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
18768
|
+
var PRIMARY3 = "var(--ohw-primary, #0885FE)";
|
|
18769
|
+
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]";
|
|
18770
|
+
function findMediaStripItemElement(sectionId, index) {
|
|
18771
|
+
const sectionEl = findByInstanceId(sectionId);
|
|
18772
|
+
if (!sectionEl) return null;
|
|
18773
|
+
const items = sectionEl.querySelectorAll("[data-ohw-media-strip-item]");
|
|
18774
|
+
for (const el of Array.from(items)) {
|
|
18775
|
+
if (Number(el.dataset.ohwMediaStripIndex) === index) return el;
|
|
18776
|
+
}
|
|
18777
|
+
return null;
|
|
18778
|
+
}
|
|
18779
|
+
function itemRefFromTarget(target) {
|
|
18780
|
+
if (!(target instanceof Element)) return null;
|
|
18781
|
+
if (target.closest(CHROME_SELECTOR)) return null;
|
|
18782
|
+
const itemEl = target.closest("[data-ohw-media-strip-item]");
|
|
18783
|
+
if (!itemEl) return null;
|
|
18784
|
+
const sectionEl = itemEl.closest("[data-ohw-section]");
|
|
18785
|
+
const unit = sectionEl ? movableUnit(sectionEl) : null;
|
|
18786
|
+
const sectionId = unit ? instanceIdOf(unit) || null : null;
|
|
18787
|
+
const index = Number(itemEl.dataset.ohwMediaStripIndex);
|
|
18788
|
+
if (!sectionId || Number.isNaN(index)) return null;
|
|
18789
|
+
return { sectionId, index };
|
|
18790
|
+
}
|
|
18791
|
+
function sameRef(a, b) {
|
|
18792
|
+
return a?.sectionId === b?.sectionId && a?.index === b?.index;
|
|
18793
|
+
}
|
|
18794
|
+
function rectOf(el) {
|
|
18795
|
+
if (!el) return null;
|
|
18796
|
+
const r2 = el.getBoundingClientRect();
|
|
18797
|
+
if (r2.width <= 0 || r2.height <= 0) return null;
|
|
18798
|
+
return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
|
|
18799
|
+
}
|
|
18800
|
+
function readRect2(ref) {
|
|
18801
|
+
return rectOf(ref && findMediaStripItemElement(ref.sectionId, ref.index));
|
|
18802
|
+
}
|
|
18803
|
+
function readStripRect(ref) {
|
|
18804
|
+
const item = ref && findMediaStripItemElement(ref.sectionId, ref.index);
|
|
18805
|
+
return rectOf(item?.closest("[data-ohw-media-strip]") ?? item);
|
|
18806
|
+
}
|
|
18807
|
+
function useLiveItemRect(ref, strip = false) {
|
|
18808
|
+
const [rect, setRect] = useState8(null);
|
|
18809
|
+
useEffect6(() => {
|
|
18810
|
+
if (!ref) {
|
|
18811
|
+
setRect(null);
|
|
18812
|
+
return;
|
|
18813
|
+
}
|
|
18814
|
+
const update = () => {
|
|
18815
|
+
const next = strip ? readStripRect(ref) : readRect2(ref);
|
|
18816
|
+
setRect(
|
|
18817
|
+
(prev) => prev && next && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
|
|
18818
|
+
);
|
|
18357
18819
|
};
|
|
18358
18820
|
update();
|
|
18359
18821
|
const opts = { capture: true, passive: true };
|
|
@@ -18365,9 +18827,49 @@ function useLiveItemRect(ref) {
|
|
|
18365
18827
|
window.removeEventListener("resize", update);
|
|
18366
18828
|
clearInterval(interval);
|
|
18367
18829
|
};
|
|
18368
|
-
}, [ref?.sectionId, ref?.index]);
|
|
18830
|
+
}, [ref?.sectionId, ref?.index, strip]);
|
|
18369
18831
|
return rect;
|
|
18370
18832
|
}
|
|
18833
|
+
var TOOLBAR_STRIP_GAP = 52;
|
|
18834
|
+
var TOOLBAR_STRIP_GAP_MOBILE = 42;
|
|
18835
|
+
var TOOLBAR_EDGE_MARGIN2 = 4;
|
|
18836
|
+
function StripToolbarSlot({ stripRect, children }) {
|
|
18837
|
+
const slotRef = useRef5(null);
|
|
18838
|
+
const [shift, setShift] = useState8(0);
|
|
18839
|
+
const centerX = stripRect.left + stripRect.width / 2;
|
|
18840
|
+
useLayoutEffect4(() => {
|
|
18841
|
+
const slot = slotRef.current;
|
|
18842
|
+
if (!slot) return;
|
|
18843
|
+
const clamp = () => {
|
|
18844
|
+
const w = slot.offsetWidth;
|
|
18845
|
+
if (w <= 0) return;
|
|
18846
|
+
const half = w / 2;
|
|
18847
|
+
const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
|
|
18848
|
+
setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
|
|
18849
|
+
};
|
|
18850
|
+
clamp();
|
|
18851
|
+
const ro = new ResizeObserver(clamp);
|
|
18852
|
+
ro.observe(slot);
|
|
18853
|
+
return () => ro.disconnect();
|
|
18854
|
+
}, [centerX, children]);
|
|
18855
|
+
const mobile = window.innerWidth <= 480;
|
|
18856
|
+
return /* @__PURE__ */ jsx21(
|
|
18857
|
+
"div",
|
|
18858
|
+
{
|
|
18859
|
+
ref: slotRef,
|
|
18860
|
+
"data-ohw-bridge": "",
|
|
18861
|
+
"data-ohw-item-interaction": "",
|
|
18862
|
+
className: "pointer-events-auto fixed",
|
|
18863
|
+
style: {
|
|
18864
|
+
top: stripRect.top - (mobile ? TOOLBAR_STRIP_GAP_MOBILE : TOOLBAR_STRIP_GAP),
|
|
18865
|
+
left: centerX + shift,
|
|
18866
|
+
transform: "translate(-50%, -100%)",
|
|
18867
|
+
zIndex: 2147483645
|
|
18868
|
+
},
|
|
18869
|
+
children
|
|
18870
|
+
}
|
|
18871
|
+
);
|
|
18872
|
+
}
|
|
18371
18873
|
function requestValidateTree(postToParent2, tree) {
|
|
18372
18874
|
return new Promise((resolve) => {
|
|
18373
18875
|
const id = `ai-validate-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -18404,116 +18906,72 @@ function requestAssetPick(postToParent2) {
|
|
|
18404
18906
|
postToParent2({ type: "ow:asset-pick", id });
|
|
18405
18907
|
});
|
|
18406
18908
|
}
|
|
18407
|
-
function
|
|
18909
|
+
function ToolbarAction({
|
|
18408
18910
|
label,
|
|
18409
18911
|
onClick,
|
|
18410
|
-
disabled,
|
|
18411
|
-
active
|
|
18912
|
+
disabled = false,
|
|
18913
|
+
active = false,
|
|
18914
|
+
children
|
|
18412
18915
|
}) {
|
|
18413
|
-
|
|
18414
|
-
|
|
18415
|
-
{
|
|
18416
|
-
|
|
18417
|
-
|
|
18418
|
-
disabled,
|
|
18419
|
-
style: {
|
|
18420
|
-
height: 28,
|
|
18421
|
-
padding: "0 10px",
|
|
18422
|
-
display: "inline-flex",
|
|
18423
|
-
alignItems: "center",
|
|
18424
|
-
gap: 4,
|
|
18425
|
-
borderRadius: 999,
|
|
18426
|
-
border: "none",
|
|
18427
|
-
cursor: disabled ? "default" : "pointer",
|
|
18428
|
-
background: active ? OHW_BLUE_DARK : "#ffffff",
|
|
18429
|
-
color: active ? "#ffffff" : OHW_BLUE_DARK,
|
|
18430
|
-
opacity: disabled ? 0.4 : 1,
|
|
18431
|
-
fontSize: 12,
|
|
18432
|
-
lineHeight: "16px",
|
|
18433
|
-
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
18434
|
-
whiteSpace: "nowrap",
|
|
18435
|
-
flex: "0 0 auto"
|
|
18436
|
-
},
|
|
18437
|
-
children: label
|
|
18438
|
-
}
|
|
18439
|
-
);
|
|
18916
|
+
const button = /* @__PURE__ */ jsx21(CustomToolbarButton, { type: "button", "aria-label": label, disabled, active, onClick, className: "size-8", children });
|
|
18917
|
+
return /* @__PURE__ */ jsxs12(Tooltip, { children: [
|
|
18918
|
+
/* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx21("span", { className: "inline-flex", children: button }) : button }),
|
|
18919
|
+
/* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
|
|
18920
|
+
] });
|
|
18440
18921
|
}
|
|
18441
|
-
function
|
|
18442
|
-
|
|
18443
|
-
|
|
18444
|
-
|
|
18445
|
-
|
|
18446
|
-
|
|
18447
|
-
|
|
18448
|
-
|
|
18449
|
-
|
|
18450
|
-
|
|
18451
|
-
|
|
18452
|
-
|
|
18453
|
-
|
|
18454
|
-
|
|
18455
|
-
|
|
18456
|
-
|
|
18457
|
-
|
|
18458
|
-
|
|
18459
|
-
|
|
18460
|
-
|
|
18461
|
-
|
|
18462
|
-
|
|
18463
|
-
|
|
18464
|
-
|
|
18465
|
-
|
|
18466
|
-
|
|
18467
|
-
|
|
18468
|
-
|
|
18469
|
-
|
|
18470
|
-
},
|
|
18471
|
-
children: "Alt"
|
|
18472
|
-
}
|
|
18473
|
-
),
|
|
18474
|
-
/* @__PURE__ */ jsx20(
|
|
18475
|
-
"input",
|
|
18922
|
+
function ToolbarSeparator() {
|
|
18923
|
+
return /* @__PURE__ */ jsx21("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
|
|
18924
|
+
}
|
|
18925
|
+
function OptionMenu({
|
|
18926
|
+
label,
|
|
18927
|
+
value,
|
|
18928
|
+
options,
|
|
18929
|
+
onChange
|
|
18930
|
+
}) {
|
|
18931
|
+
const current = options.find((o) => o.value === value) ?? options[0];
|
|
18932
|
+
return /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
18933
|
+
/* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground", children: label }),
|
|
18934
|
+
/* @__PURE__ */ jsxs12(DropdownMenu, { modal: false, children: [
|
|
18935
|
+
/* @__PURE__ */ jsx21(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs12(
|
|
18936
|
+
"button",
|
|
18937
|
+
{
|
|
18938
|
+
type: "button",
|
|
18939
|
+
"aria-label": label,
|
|
18940
|
+
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",
|
|
18941
|
+
children: [
|
|
18942
|
+
/* @__PURE__ */ jsx21("span", { className: "flex-1 text-left", children: current.label }),
|
|
18943
|
+
/* @__PURE__ */ jsx21(ChevronDown3, { size: 16, style: { pointerEvents: "none" } })
|
|
18944
|
+
]
|
|
18945
|
+
}
|
|
18946
|
+
) }),
|
|
18947
|
+
/* @__PURE__ */ jsx21(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[132px] min-w-[132px] p-1", children: options.map((option) => {
|
|
18948
|
+
const selected = option.value === value;
|
|
18949
|
+
return /* @__PURE__ */ jsxs12(
|
|
18950
|
+
DropdownMenuItem,
|
|
18476
18951
|
{
|
|
18477
|
-
|
|
18478
|
-
|
|
18479
|
-
|
|
18480
|
-
|
|
18481
|
-
|
|
18482
|
-
|
|
18483
|
-
|
|
18484
|
-
|
|
18485
|
-
|
|
18486
|
-
|
|
18487
|
-
|
|
18488
|
-
|
|
18489
|
-
|
|
18490
|
-
|
|
18491
|
-
"aria-label": "Image alt text",
|
|
18492
|
-
style: {
|
|
18493
|
-
flex: 1,
|
|
18494
|
-
minWidth: 0,
|
|
18495
|
-
border: "none",
|
|
18496
|
-
outline: "none",
|
|
18497
|
-
background: "transparent",
|
|
18498
|
-
fontSize: 12,
|
|
18499
|
-
lineHeight: "16px",
|
|
18500
|
-
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
18501
|
-
color: "#1f2937"
|
|
18502
|
-
}
|
|
18503
|
-
}
|
|
18504
|
-
)
|
|
18505
|
-
]
|
|
18506
|
-
}
|
|
18507
|
-
);
|
|
18952
|
+
role: "menuitemradio",
|
|
18953
|
+
"aria-checked": selected,
|
|
18954
|
+
onSelect: () => onChange(option.value),
|
|
18955
|
+
className: cn("grid grid-cols-[1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
|
|
18956
|
+
children: [
|
|
18957
|
+
/* @__PURE__ */ jsx21("span", { children: option.label }),
|
|
18958
|
+
selected && /* @__PURE__ */ jsx21(Check2, { size: 16, className: "text-bridge-primary" })
|
|
18959
|
+
]
|
|
18960
|
+
},
|
|
18961
|
+
option.value
|
|
18962
|
+
);
|
|
18963
|
+
}) })
|
|
18964
|
+
] })
|
|
18965
|
+
] });
|
|
18508
18966
|
}
|
|
18509
18967
|
var VARIANTS = [
|
|
18510
18968
|
{ value: "logos", label: "Logos" },
|
|
18511
18969
|
{ value: "reel", label: "Reel" }
|
|
18512
18970
|
];
|
|
18513
18971
|
var ALIGNS = [
|
|
18514
|
-
{ value: "left", label: "
|
|
18515
|
-
{ value: "center", label: "
|
|
18516
|
-
{ value: "right", label: "
|
|
18972
|
+
{ value: "left", label: "Align left", Icon: AlignLeft },
|
|
18973
|
+
{ value: "center", label: "Align center", Icon: AlignCenter },
|
|
18974
|
+
{ value: "right", label: "Align right", Icon: AlignRight }
|
|
18517
18975
|
];
|
|
18518
18976
|
var HOVERS = [
|
|
18519
18977
|
{ value: "none", label: "None" },
|
|
@@ -18521,104 +18979,104 @@ var HOVERS = [
|
|
|
18521
18979
|
{ value: "zoom", label: "Zoom" },
|
|
18522
18980
|
{ value: "fade", label: "Fade" }
|
|
18523
18981
|
];
|
|
18524
|
-
var TREATMENTS = [
|
|
18525
|
-
{ value: "color", label: "Color" },
|
|
18526
|
-
{ value: "grayscale", label: "Grayscale" }
|
|
18527
|
-
];
|
|
18528
18982
|
var HTTP_URL_RE = /^https?:\/\/\S+$/i;
|
|
18529
|
-
function
|
|
18530
|
-
|
|
18983
|
+
function LinkModal({
|
|
18984
|
+
href,
|
|
18985
|
+
linkTarget,
|
|
18986
|
+
onClose,
|
|
18987
|
+
onSave
|
|
18988
|
+
}) {
|
|
18989
|
+
const [draft, setDraft] = useState8(href);
|
|
18990
|
+
const [newTab, setNewTab] = useState8(linkTarget !== "same-tab");
|
|
18531
18991
|
const [invalid, setInvalid] = useState8(false);
|
|
18532
|
-
|
|
18533
|
-
setDraft(value);
|
|
18534
|
-
setInvalid(false);
|
|
18535
|
-
}, [value]);
|
|
18536
|
-
const commit = () => {
|
|
18992
|
+
const save = () => {
|
|
18537
18993
|
const next = draft.trim();
|
|
18538
|
-
if (next
|
|
18539
|
-
|
|
18540
|
-
|
|
18541
|
-
onCommit(next);
|
|
18542
|
-
};
|
|
18543
|
-
return /* @__PURE__ */ jsxs11(
|
|
18544
|
-
"div",
|
|
18545
|
-
{
|
|
18546
|
-
style: {
|
|
18547
|
-
display: "flex",
|
|
18548
|
-
alignItems: "center",
|
|
18549
|
-
gap: 6,
|
|
18550
|
-
height: 28,
|
|
18551
|
-
padding: "0 12px",
|
|
18552
|
-
borderRadius: 999,
|
|
18553
|
-
background: "#ffffff",
|
|
18554
|
-
width: "100%",
|
|
18555
|
-
maxWidth: 260,
|
|
18556
|
-
boxSizing: "border-box",
|
|
18557
|
-
boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
|
|
18558
|
-
},
|
|
18559
|
-
children: [
|
|
18560
|
-
/* @__PURE__ */ jsx20(
|
|
18561
|
-
"span",
|
|
18562
|
-
{
|
|
18563
|
-
style: {
|
|
18564
|
-
flex: "0 0 auto",
|
|
18565
|
-
color: OHW_BLUE_DARK,
|
|
18566
|
-
fontSize: 10,
|
|
18567
|
-
fontWeight: 700,
|
|
18568
|
-
textTransform: "uppercase",
|
|
18569
|
-
letterSpacing: 0.4
|
|
18570
|
-
},
|
|
18571
|
-
children: "Link"
|
|
18572
|
-
}
|
|
18573
|
-
),
|
|
18574
|
-
/* @__PURE__ */ jsx20(
|
|
18575
|
-
"input",
|
|
18576
|
-
{
|
|
18577
|
-
type: "text",
|
|
18578
|
-
inputMode: "url",
|
|
18579
|
-
value: draft,
|
|
18580
|
-
onChange: (e) => setDraft(e.target.value),
|
|
18581
|
-
onBlur: commit,
|
|
18582
|
-
onKeyDown: (e) => {
|
|
18583
|
-
if (e.key === "Enter") e.currentTarget.blur();
|
|
18584
|
-
if (e.key === "Escape") {
|
|
18585
|
-
setDraft(value);
|
|
18586
|
-
setInvalid(false);
|
|
18587
|
-
e.currentTarget.blur();
|
|
18588
|
-
}
|
|
18589
|
-
},
|
|
18590
|
-
placeholder: "https://example.com",
|
|
18591
|
-
"aria-label": "Image link URL",
|
|
18592
|
-
"aria-invalid": invalid,
|
|
18593
|
-
style: {
|
|
18594
|
-
flex: 1,
|
|
18595
|
-
minWidth: 0,
|
|
18596
|
-
border: "none",
|
|
18597
|
-
outline: "none",
|
|
18598
|
-
background: "transparent",
|
|
18599
|
-
fontSize: 12,
|
|
18600
|
-
lineHeight: "16px",
|
|
18601
|
-
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
18602
|
-
color: "#1f2937"
|
|
18603
|
-
}
|
|
18604
|
-
}
|
|
18605
|
-
)
|
|
18606
|
-
]
|
|
18994
|
+
if (next && !HTTP_URL_RE.test(next)) {
|
|
18995
|
+
setInvalid(true);
|
|
18996
|
+
return;
|
|
18607
18997
|
}
|
|
18608
|
-
|
|
18998
|
+
onSave(next, newTab ? "new-tab" : "same-tab");
|
|
18999
|
+
onClose();
|
|
19000
|
+
};
|
|
19001
|
+
return /* @__PURE__ */ jsx21(Dialog2, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxs12(DialogContent, { "data-ohw-link-modal-root": "", className: "max-w-[400px] gap-4 p-5", children: [
|
|
19002
|
+
/* @__PURE__ */ jsx21(DialogHeader, { children: /* @__PURE__ */ jsx21(DialogTitle, { className: "text-base", children: "Image link" }) }),
|
|
19003
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-3", children: [
|
|
19004
|
+
/* @__PURE__ */ jsx21(
|
|
19005
|
+
"input",
|
|
19006
|
+
{
|
|
19007
|
+
autoFocus: true,
|
|
19008
|
+
type: "text",
|
|
19009
|
+
inputMode: "url",
|
|
19010
|
+
value: draft,
|
|
19011
|
+
onChange: (e) => {
|
|
19012
|
+
setDraft(e.target.value);
|
|
19013
|
+
setInvalid(false);
|
|
19014
|
+
},
|
|
19015
|
+
onKeyDown: (e) => {
|
|
19016
|
+
if (e.key === "Enter") save();
|
|
19017
|
+
},
|
|
19018
|
+
placeholder: "https://example.com",
|
|
19019
|
+
"aria-label": "Image link URL",
|
|
19020
|
+
"aria-invalid": invalid,
|
|
19021
|
+
className: cn(
|
|
19022
|
+
"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",
|
|
19023
|
+
invalid && "border-destructive focus:border-destructive"
|
|
19024
|
+
)
|
|
19025
|
+
}
|
|
19026
|
+
),
|
|
19027
|
+
invalid && /* @__PURE__ */ jsx21("p", { className: "text-xs text-destructive", children: "Enter a full URL starting with http:// or https://" }),
|
|
19028
|
+
/* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-2 text-[13px] text-foreground", children: [
|
|
19029
|
+
/* @__PURE__ */ jsx21("input", { type: "checkbox", checked: newTab, onChange: (e) => setNewTab(e.target.checked) }),
|
|
19030
|
+
"Open in new tab"
|
|
19031
|
+
] })
|
|
19032
|
+
] }),
|
|
19033
|
+
/* @__PURE__ */ jsxs12(DialogFooter, { children: [
|
|
19034
|
+
href && /* @__PURE__ */ jsx21(
|
|
19035
|
+
"button",
|
|
19036
|
+
{
|
|
19037
|
+
type: "button",
|
|
19038
|
+
onClick: () => {
|
|
19039
|
+
onSave("", "new-tab");
|
|
19040
|
+
onClose();
|
|
19041
|
+
},
|
|
19042
|
+
className: "mr-auto rounded-[6px] px-3 py-2 text-[13px] font-medium text-destructive transition-colors hover:bg-muted",
|
|
19043
|
+
children: "Remove link"
|
|
19044
|
+
}
|
|
19045
|
+
),
|
|
19046
|
+
/* @__PURE__ */ jsx21(
|
|
19047
|
+
"button",
|
|
19048
|
+
{
|
|
19049
|
+
type: "button",
|
|
19050
|
+
onClick: onClose,
|
|
19051
|
+
className: "rounded-[6px] px-3 py-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted",
|
|
19052
|
+
children: "Cancel"
|
|
19053
|
+
}
|
|
19054
|
+
),
|
|
19055
|
+
/* @__PURE__ */ jsx21(
|
|
19056
|
+
"button",
|
|
19057
|
+
{
|
|
19058
|
+
type: "button",
|
|
19059
|
+
onClick: save,
|
|
19060
|
+
className: "rounded-[6px] bg-bridge-primary px-3 py-2 text-[13px] font-medium text-primary-foreground transition-opacity hover:opacity-90",
|
|
19061
|
+
children: "Save"
|
|
19062
|
+
}
|
|
19063
|
+
)
|
|
19064
|
+
] })
|
|
19065
|
+
] }) });
|
|
18609
19066
|
}
|
|
18610
19067
|
function MediaStripToolbar({
|
|
18611
19068
|
entry,
|
|
18612
19069
|
index,
|
|
18613
19070
|
pending,
|
|
18614
19071
|
error,
|
|
19072
|
+
itemEditOn,
|
|
19073
|
+
onToggleItemEdit,
|
|
18615
19074
|
onSetVariant,
|
|
18616
19075
|
onSetAlign,
|
|
18617
19076
|
onSetHover,
|
|
18618
19077
|
onSetTreatment,
|
|
18619
19078
|
onResize,
|
|
18620
|
-
|
|
18621
|
-
onSetLink,
|
|
19079
|
+
onOpenLink,
|
|
18622
19080
|
onAddItem,
|
|
18623
19081
|
onRemoveItem,
|
|
18624
19082
|
onChangeImage,
|
|
@@ -18627,81 +19085,102 @@ function MediaStripToolbar({
|
|
|
18627
19085
|
}) {
|
|
18628
19086
|
const items = mediaStripItems(entry.tree);
|
|
18629
19087
|
const itemCount = items.length;
|
|
18630
|
-
const currentAlt = items[index]?.alt ?? "";
|
|
18631
|
-
const currentHref = items[index]?.href ?? "";
|
|
18632
|
-
const currentTarget = items[index]?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
|
|
18633
19088
|
const slots = findMediaStripSlots(entry.tree);
|
|
18634
19089
|
const variant = slots?.variant === "reel" ? "reel" : "logos";
|
|
18635
19090
|
const align = slots?.align === "left" || slots?.align === "right" ? slots.align : "center";
|
|
18636
19091
|
const hover = slots?.hover === "none" || slots?.hover === "lift" || slots?.hover === "zoom" || slots?.hover === "fade" ? slots.hover : "lift";
|
|
18637
19092
|
const treatment = slots?.treatment === "color" || slots?.treatment === "grayscale" ? slots.treatment : variant === "logos" ? "grayscale" : "color";
|
|
18638
19093
|
const sizeValue = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
|
|
18639
|
-
const
|
|
18640
|
-
const
|
|
18641
|
-
|
|
18642
|
-
gap: 6,
|
|
18643
|
-
flexWrap: "nowrap",
|
|
18644
|
-
justifyContent: "center",
|
|
18645
|
-
overflowX: "auto",
|
|
18646
|
-
WebkitOverflowScrolling: "touch",
|
|
18647
|
-
width: "100%",
|
|
18648
|
-
scrollbarWidth: "none"
|
|
18649
|
-
} : { display: "flex", gap: 6, flexWrap: "nowrap", justifyContent: "center" };
|
|
18650
|
-
return /* @__PURE__ */ jsxs11(
|
|
19094
|
+
const mobile = window.innerWidth <= 480;
|
|
19095
|
+
const gatedLabel = (label) => itemEditOn ? label : "Turn on the star to edit this image";
|
|
19096
|
+
return /* @__PURE__ */ jsx21(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs12(
|
|
18651
19097
|
"div",
|
|
18652
19098
|
{
|
|
18653
19099
|
"data-ohw-bridge": "",
|
|
18654
19100
|
"data-ohw-toolbar": "",
|
|
18655
19101
|
onMouseDown: (e) => e.stopPropagation(),
|
|
18656
|
-
|
|
18657
|
-
|
|
18658
|
-
flexDirection: "column",
|
|
18659
|
-
gap: 6,
|
|
18660
|
-
alignItems: "center",
|
|
18661
|
-
background: OHW_BLUE,
|
|
18662
|
-
padding: 8,
|
|
18663
|
-
borderRadius: 12,
|
|
18664
|
-
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
18665
|
-
pointerEvents: pending ? "none" : "auto",
|
|
18666
|
-
opacity: pending ? 0.6 : 1,
|
|
18667
|
-
maxWidth: isMobile ? "calc(100vw - 24px)" : "none"
|
|
18668
|
-
},
|
|
19102
|
+
className: cn("flex flex-col items-center gap-1.5 font-sans", pending && "pointer-events-none opacity-60"),
|
|
19103
|
+
style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
|
|
18669
19104
|
children: [
|
|
18670
|
-
/* @__PURE__ */
|
|
18671
|
-
|
|
18672
|
-
|
|
18673
|
-
|
|
18674
|
-
|
|
18675
|
-
|
|
18676
|
-
|
|
18677
|
-
|
|
18678
|
-
|
|
18679
|
-
|
|
18680
|
-
|
|
18681
|
-
|
|
18682
|
-
|
|
18683
|
-
|
|
18684
|
-
|
|
18685
|
-
|
|
18686
|
-
|
|
18687
|
-
|
|
18688
|
-
|
|
18689
|
-
|
|
18690
|
-
|
|
18691
|
-
|
|
18692
|
-
|
|
18693
|
-
|
|
18694
|
-
|
|
18695
|
-
|
|
18696
|
-
|
|
18697
|
-
|
|
18698
|
-
|
|
18699
|
-
|
|
18700
|
-
|
|
18701
|
-
|
|
19105
|
+
/* @__PURE__ */ jsxs12(
|
|
19106
|
+
"div",
|
|
19107
|
+
{
|
|
19108
|
+
className: cn(
|
|
19109
|
+
"flex items-center gap-1 rounded-[10px] border border-border bg-background p-1 whitespace-nowrap",
|
|
19110
|
+
"shadow-[0px_10px_15px_-3px_rgba(0,0,0,0.1),0px_4px_6px_-4px_rgba(0,0,0,0.1)]",
|
|
19111
|
+
mobile ? "flex-wrap justify-center" : "flex-nowrap"
|
|
19112
|
+
),
|
|
19113
|
+
children: [
|
|
19114
|
+
/* @__PURE__ */ jsxs12(Tooltip, { children: [
|
|
19115
|
+
/* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx21(
|
|
19116
|
+
CustomToolbarButton,
|
|
19117
|
+
{
|
|
19118
|
+
type: "button",
|
|
19119
|
+
"aria-label": itemEditOn ? "Done editing this image" : "Edit this image",
|
|
19120
|
+
"aria-pressed": itemEditOn,
|
|
19121
|
+
onClick: onToggleItemEdit,
|
|
19122
|
+
className: "group size-8",
|
|
19123
|
+
children: /* @__PURE__ */ jsx21(
|
|
19124
|
+
Star,
|
|
19125
|
+
{
|
|
19126
|
+
size: 16,
|
|
19127
|
+
fill: "currentColor",
|
|
19128
|
+
strokeWidth: 0,
|
|
19129
|
+
className: cn(
|
|
19130
|
+
"transition-colors",
|
|
19131
|
+
itemEditOn ? "text-[#f59e0b] group-hover:text-[#d97706]" : "text-[#d6d3d1] group-hover:text-[#fbbf24]"
|
|
19132
|
+
),
|
|
19133
|
+
style: { pointerEvents: "none" }
|
|
19134
|
+
}
|
|
19135
|
+
)
|
|
19136
|
+
}
|
|
19137
|
+
) }),
|
|
19138
|
+
/* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: itemEditOn ? "Done editing this image" : "Edit this image" })
|
|
19139
|
+
] }),
|
|
19140
|
+
/* @__PURE__ */ jsx21(ToolbarSeparator, {}),
|
|
19141
|
+
/* @__PURE__ */ jsx21(ToolbarAction, { label: gatedLabel("Change image"), onClick: onChangeImage, disabled: !itemEditOn, children: /* @__PURE__ */ jsx21(ImageIcon2, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19142
|
+
/* @__PURE__ */ jsx21(ToolbarAction, { label: gatedLabel("Link"), onClick: onOpenLink, disabled: !itemEditOn, children: /* @__PURE__ */ jsx21(LinkIcon, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19143
|
+
/* @__PURE__ */ jsx21(ToolbarAction, { label: gatedLabel("Move left"), onClick: onMoveLeft, disabled: !itemEditOn || index <= 0, children: /* @__PURE__ */ jsx21(ArrowLeft2, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19144
|
+
/* @__PURE__ */ jsx21(
|
|
19145
|
+
ToolbarAction,
|
|
19146
|
+
{
|
|
19147
|
+
label: gatedLabel("Move right"),
|
|
19148
|
+
onClick: onMoveRight,
|
|
19149
|
+
disabled: !itemEditOn || index >= itemCount - 1,
|
|
19150
|
+
children: /* @__PURE__ */ jsx21(ArrowRight2, { size: 16, style: { pointerEvents: "none" } })
|
|
19151
|
+
}
|
|
19152
|
+
),
|
|
19153
|
+
/* @__PURE__ */ jsx21(ToolbarAction, { label: gatedLabel("Remove image"), onClick: onRemoveItem, disabled: !itemEditOn || itemCount <= 1, children: /* @__PURE__ */ jsx21(ImageMinus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19154
|
+
/* @__PURE__ */ jsx21(ToolbarSeparator, {}),
|
|
19155
|
+
/* @__PURE__ */ jsx21(OptionMenu, { label: "Layout", value: variant, options: VARIANTS, onChange: onSetVariant }),
|
|
19156
|
+
/* @__PURE__ */ jsx21(OptionMenu, { label: "Hover", value: hover, options: HOVERS, onChange: onSetHover }),
|
|
19157
|
+
/* @__PURE__ */ jsx21(
|
|
19158
|
+
ToolbarAction,
|
|
19159
|
+
{
|
|
19160
|
+
label: treatment === "grayscale" ? "Show in color" : "Show grayscale",
|
|
19161
|
+
active: treatment === "grayscale",
|
|
19162
|
+
onClick: () => onSetTreatment(treatment === "grayscale" ? "color" : "grayscale"),
|
|
19163
|
+
children: /* @__PURE__ */ jsx21(Palette, { size: 16, style: { pointerEvents: "none" } })
|
|
19164
|
+
}
|
|
19165
|
+
),
|
|
19166
|
+
/* @__PURE__ */ jsx21(ToolbarSeparator, {}),
|
|
19167
|
+
ALIGNS.map(({ value, label, Icon }) => /* @__PURE__ */ jsx21(ToolbarAction, { label, active: align === value, onClick: () => onSetAlign(value), children: /* @__PURE__ */ jsx21(Icon, { size: 16, style: { pointerEvents: "none" } }) }, value)),
|
|
19168
|
+
/* @__PURE__ */ jsx21(ToolbarSeparator, {}),
|
|
19169
|
+
/* @__PURE__ */ jsx21(ToolbarAction, { label: "Smaller", onClick: () => onResize(-8), children: /* @__PURE__ */ jsx21(Minus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19170
|
+
/* @__PURE__ */ jsxs12("span", { className: "min-w-[40px] text-center text-xs tabular-nums text-muted-foreground", children: [
|
|
19171
|
+
sizeValue,
|
|
19172
|
+
"px"
|
|
19173
|
+
] }),
|
|
19174
|
+
/* @__PURE__ */ jsx21(ToolbarAction, { label: "Larger", onClick: () => onResize(8), children: /* @__PURE__ */ jsx21(Plus2, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19175
|
+
/* @__PURE__ */ jsx21(ToolbarSeparator, {}),
|
|
19176
|
+
/* @__PURE__ */ jsx21(ToolbarAction, { label: "Add image", onClick: onAddItem, children: /* @__PURE__ */ jsx21(ImagePlus, { size: 16, style: { pointerEvents: "none" } }) })
|
|
19177
|
+
]
|
|
19178
|
+
}
|
|
19179
|
+
),
|
|
19180
|
+
error && /* @__PURE__ */ jsx21("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
|
|
18702
19181
|
]
|
|
18703
19182
|
}
|
|
18704
|
-
);
|
|
19183
|
+
) });
|
|
18705
19184
|
}
|
|
18706
19185
|
function findMediaStripSlots(tree) {
|
|
18707
19186
|
const stack = tree.rows.flatMap((row) => row.blocks);
|
|
@@ -18720,31 +19199,23 @@ function AiMediaStripOverlay({
|
|
|
18720
19199
|
}) {
|
|
18721
19200
|
const [hover, setHover] = useState8(null);
|
|
18722
19201
|
const [active, setActive] = useState8(null);
|
|
19202
|
+
const [itemEditOn, setItemEditOn] = useState8(false);
|
|
19203
|
+
const [linkOpen, setLinkOpen] = useState8(false);
|
|
18723
19204
|
const [pending, setPending] = useState8(false);
|
|
18724
19205
|
const [error, setError] = useState8(null);
|
|
18725
19206
|
const activeRef = useRef5(null);
|
|
18726
19207
|
activeRef.current = active;
|
|
19208
|
+
const linkOpenRef = useRef5(false);
|
|
19209
|
+
linkOpenRef.current = linkOpen;
|
|
18727
19210
|
useEffect6(() => {
|
|
18728
19211
|
const onMove = (e) => {
|
|
19212
|
+
const ref = itemRefFromTarget(e.target);
|
|
18729
19213
|
const t = e.target;
|
|
18730
|
-
|
|
18731
|
-
|
|
18732
|
-
|
|
18733
|
-
|
|
18734
|
-
|
|
18735
|
-
if (!itemEl) {
|
|
18736
|
-
setHover(null);
|
|
18737
|
-
return;
|
|
18738
|
-
}
|
|
18739
|
-
const sectionEl = itemEl.closest("[data-ohw-section]");
|
|
18740
|
-
const unit = sectionEl ? movableUnit(sectionEl) : null;
|
|
18741
|
-
const sectionId = unit ? instanceIdOf(unit) || null : null;
|
|
18742
|
-
const index = Number(itemEl.dataset.ohwMediaStripIndex);
|
|
18743
|
-
if (!sectionId || Number.isNaN(index)) {
|
|
18744
|
-
setHover(null);
|
|
18745
|
-
return;
|
|
18746
|
-
}
|
|
18747
|
-
setHover({ sectionId, index });
|
|
19214
|
+
const overEditable = Boolean(t?.closest?.("[data-ohw-editable]"));
|
|
19215
|
+
setHover((prev) => {
|
|
19216
|
+
const next = ref && !overEditable ? ref : null;
|
|
19217
|
+
return sameRef(prev, next) ? prev : next;
|
|
19218
|
+
});
|
|
18748
19219
|
};
|
|
18749
19220
|
const onLeave = () => setHover(null);
|
|
18750
19221
|
document.addEventListener("mousemove", onMove, { passive: true });
|
|
@@ -18756,23 +19227,25 @@ function AiMediaStripOverlay({
|
|
|
18756
19227
|
}, []);
|
|
18757
19228
|
useEffect6(() => {
|
|
18758
19229
|
const onClick = (e) => {
|
|
18759
|
-
const current = activeRef.current;
|
|
18760
|
-
if (!current) return;
|
|
18761
19230
|
const t = e.target;
|
|
18762
|
-
if (!(t instanceof
|
|
18763
|
-
if (t.closest(
|
|
18764
|
-
const
|
|
18765
|
-
if (
|
|
18766
|
-
|
|
19231
|
+
if (!(t instanceof Element)) return;
|
|
19232
|
+
if (t.closest(CHROME_SELECTOR)) return;
|
|
19233
|
+
const ref = itemRefFromTarget(t);
|
|
19234
|
+
if (sameRef(activeRef.current, ref)) return;
|
|
19235
|
+
if (ref) clearInteractionChromeRef.current();
|
|
19236
|
+
setItemEditOn(false);
|
|
18767
19237
|
setError(null);
|
|
19238
|
+
setActive(ref);
|
|
18768
19239
|
};
|
|
18769
19240
|
document.addEventListener("click", onClick, true);
|
|
18770
19241
|
return () => document.removeEventListener("click", onClick, true);
|
|
18771
|
-
}, []);
|
|
19242
|
+
}, [clearInteractionChromeRef]);
|
|
18772
19243
|
useEffect6(() => {
|
|
18773
19244
|
const onBlur = () => {
|
|
18774
19245
|
if (!activeRef.current) return;
|
|
18775
19246
|
setActive(null);
|
|
19247
|
+
setItemEditOn(false);
|
|
19248
|
+
setLinkOpen(false);
|
|
18776
19249
|
setError(null);
|
|
18777
19250
|
};
|
|
18778
19251
|
window.addEventListener("blur", onBlur);
|
|
@@ -18782,7 +19255,10 @@ function AiMediaStripOverlay({
|
|
|
18782
19255
|
const onKeyDown = (e) => {
|
|
18783
19256
|
if (e.key !== "Escape") return;
|
|
18784
19257
|
if (!activeRef.current) return;
|
|
19258
|
+
if (linkOpenRef.current) return;
|
|
19259
|
+
if (document.querySelector('[data-ohw-more-menu][data-state="open"]')) return;
|
|
18785
19260
|
setActive(null);
|
|
19261
|
+
setItemEditOn(false);
|
|
18786
19262
|
setError(null);
|
|
18787
19263
|
};
|
|
18788
19264
|
document.addEventListener("keydown", onKeyDown);
|
|
@@ -18816,137 +19292,133 @@ function AiMediaStripOverlay({
|
|
|
18816
19292
|
tree: nextTree,
|
|
18817
19293
|
label: entry.label,
|
|
18818
19294
|
media: extraMedia ? { ...entry.media, ...extraMedia } : entry.media,
|
|
18819
|
-
...entry.brand ? { brand: entry.brand } : {}
|
|
19295
|
+
...entry.brand ? { brand: entry.brand } : {},
|
|
19296
|
+
// The user is already looking at the strip they just edited — recentering the viewport
|
|
19297
|
+
// on every edit reads as the section jumping around.
|
|
19298
|
+
skipScrollIntoView: true
|
|
18820
19299
|
});
|
|
18821
19300
|
return true;
|
|
18822
19301
|
},
|
|
18823
19302
|
[findEntry, postToParent2, applyTreeLocalRef]
|
|
18824
19303
|
);
|
|
18825
19304
|
const activeEntry = active ? findEntry(active.sectionId) : null;
|
|
18826
|
-
const hoverHandleRect = useLiveItemRect(!active && hover ? hover : null);
|
|
18827
19305
|
const activeItemRect = useLiveItemRect(active);
|
|
18828
|
-
const
|
|
18829
|
-
const
|
|
18830
|
-
|
|
18831
|
-
|
|
18832
|
-
|
|
18833
|
-
|
|
18834
|
-
|
|
18835
|
-
|
|
18836
|
-
|
|
18837
|
-
|
|
18838
|
-
|
|
18839
|
-
|
|
18840
|
-
|
|
18841
|
-
|
|
18842
|
-
|
|
18843
|
-
|
|
18844
|
-
|
|
18845
|
-
|
|
18846
|
-
|
|
18847
|
-
|
|
18848
|
-
|
|
18849
|
-
|
|
18850
|
-
|
|
18851
|
-
|
|
18852
|
-
|
|
18853
|
-
|
|
18854
|
-
|
|
18855
|
-
|
|
18856
|
-
|
|
18857
|
-
|
|
18858
|
-
|
|
18859
|
-
|
|
18860
|
-
|
|
18861
|
-
|
|
18862
|
-
activeItemRect && active && activeEntry && /* @__PURE__ */ jsx20(
|
|
18863
|
-
ItemInteractionLayer,
|
|
18864
|
-
{
|
|
18865
|
-
rect: activeItemRect,
|
|
18866
|
-
state: toolbarState,
|
|
18867
|
-
toolbar: /* @__PURE__ */ jsx20(
|
|
18868
|
-
MediaStripToolbar,
|
|
18869
|
-
{
|
|
18870
|
-
entry: activeEntry,
|
|
18871
|
-
index: active.index,
|
|
18872
|
-
pending,
|
|
18873
|
-
error,
|
|
18874
|
-
onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
|
|
18875
|
-
onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
|
|
18876
|
-
onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
|
|
18877
|
-
onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
|
|
18878
|
-
onResize: (delta) => {
|
|
18879
|
-
const slots = findMediaStripSlots(activeEntry.tree);
|
|
18880
|
-
const variant = slots?.variant === "reel" ? "reel" : "logos";
|
|
18881
|
-
const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
|
|
18882
|
-
void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
|
|
18883
|
-
},
|
|
18884
|
-
onSetAlt: (alt) => {
|
|
18885
|
-
void runMutation(active.sectionId, (tree) => setMediaStripItemAlt(tree, active.index, alt));
|
|
18886
|
-
},
|
|
18887
|
-
onSetLink: (href, linkTarget) => {
|
|
19306
|
+
const activeStripRect = useLiveItemRect(active, true);
|
|
19307
|
+
const hoverRect = useLiveItemRect(hover && !sameRef(hover, active) ? hover : null);
|
|
19308
|
+
const activeItems = activeEntry ? mediaStripItems(activeEntry.tree) : [];
|
|
19309
|
+
const activeItem = active ? activeItems[active.index] : void 0;
|
|
19310
|
+
const activeHref = activeItem?.href ?? "";
|
|
19311
|
+
const activeTarget = activeItem?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
|
|
19312
|
+
return /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
19313
|
+
hoverRect && /* @__PURE__ */ jsx21(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
|
|
19314
|
+
activeItemRect && activeStripRect && active && activeEntry && /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
19315
|
+
/* @__PURE__ */ jsx21(ItemInteractionLayer, { rect: activeItemRect, state: "active-top" }),
|
|
19316
|
+
/* @__PURE__ */ jsx21(StripToolbarSlot, { stripRect: activeStripRect, children: /* @__PURE__ */ jsx21(
|
|
19317
|
+
MediaStripToolbar,
|
|
19318
|
+
{
|
|
19319
|
+
entry: activeEntry,
|
|
19320
|
+
index: active.index,
|
|
19321
|
+
pending,
|
|
19322
|
+
error,
|
|
19323
|
+
itemEditOn,
|
|
19324
|
+
onToggleItemEdit: () => setItemEditOn((on) => !on),
|
|
19325
|
+
onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
|
|
19326
|
+
onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
|
|
19327
|
+
onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
|
|
19328
|
+
onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
|
|
19329
|
+
onResize: (delta) => {
|
|
19330
|
+
const slots = findMediaStripSlots(activeEntry.tree);
|
|
19331
|
+
const variant = slots?.variant === "reel" ? "reel" : "logos";
|
|
19332
|
+
const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
|
|
19333
|
+
void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
|
|
19334
|
+
},
|
|
19335
|
+
onOpenLink: () => setLinkOpen(true),
|
|
19336
|
+
onAddItem: () => {
|
|
19337
|
+
void requestAssetPick(postToParent2).then((picked) => {
|
|
19338
|
+
if (!picked) return;
|
|
19339
|
+
const item = { assetId: picked.assetId, alt: "Logo" };
|
|
18888
19340
|
void runMutation(
|
|
18889
19341
|
active.sectionId,
|
|
18890
|
-
(tree) =>
|
|
18891
|
-
|
|
18892
|
-
|
|
18893
|
-
|
|
18894
|
-
void requestAssetPick(postToParent2).then((picked) => {
|
|
18895
|
-
if (!picked) return;
|
|
18896
|
-
const item = { assetId: picked.assetId, alt: "Logo" };
|
|
18897
|
-
void runMutation(
|
|
18898
|
-
active.sectionId,
|
|
18899
|
-
(tree) => addMediaStripItem(tree, item, active.index),
|
|
18900
|
-
{ [picked.assetId]: picked.url }
|
|
18901
|
-
).then((applied) => {
|
|
18902
|
-
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
18903
|
-
});
|
|
19342
|
+
(tree) => addMediaStripItem(tree, item, active.index),
|
|
19343
|
+
{ [picked.assetId]: picked.url }
|
|
19344
|
+
).then((applied) => {
|
|
19345
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
18904
19346
|
});
|
|
18905
|
-
}
|
|
18906
|
-
|
|
18907
|
-
|
|
18908
|
-
|
|
18909
|
-
|
|
18910
|
-
|
|
18911
|
-
|
|
18912
|
-
|
|
18913
|
-
|
|
18914
|
-
});
|
|
18915
|
-
},
|
|
18916
|
-
onRemoveItem: () => {
|
|
18917
|
-
void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
|
|
18918
|
-
(applied) => {
|
|
18919
|
-
if (applied) setActive(null);
|
|
18920
|
-
}
|
|
18921
|
-
);
|
|
18922
|
-
},
|
|
18923
|
-
onMoveLeft: () => {
|
|
18924
|
-
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
|
|
18925
|
-
(applied) => {
|
|
18926
|
-
if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
|
|
18927
|
-
}
|
|
18928
|
-
);
|
|
18929
|
-
},
|
|
18930
|
-
onMoveRight: () => {
|
|
18931
|
-
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
|
|
18932
|
-
(applied) => {
|
|
18933
|
-
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
18934
|
-
}
|
|
19347
|
+
});
|
|
19348
|
+
},
|
|
19349
|
+
onChangeImage: () => {
|
|
19350
|
+
void requestAssetPick(postToParent2).then((picked) => {
|
|
19351
|
+
if (!picked) return;
|
|
19352
|
+
void runMutation(
|
|
19353
|
+
active.sectionId,
|
|
19354
|
+
(tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
|
|
19355
|
+
{ [picked.assetId]: picked.url }
|
|
18935
19356
|
);
|
|
18936
|
-
}
|
|
19357
|
+
});
|
|
19358
|
+
},
|
|
19359
|
+
onRemoveItem: () => {
|
|
19360
|
+
void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
|
|
19361
|
+
(applied) => {
|
|
19362
|
+
if (applied) setActive(null);
|
|
19363
|
+
}
|
|
19364
|
+
);
|
|
19365
|
+
},
|
|
19366
|
+
onMoveLeft: () => {
|
|
19367
|
+
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
|
|
19368
|
+
(applied) => {
|
|
19369
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
|
|
19370
|
+
}
|
|
19371
|
+
);
|
|
19372
|
+
},
|
|
19373
|
+
onMoveRight: () => {
|
|
19374
|
+
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
|
|
19375
|
+
(applied) => {
|
|
19376
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
19377
|
+
}
|
|
19378
|
+
);
|
|
19379
|
+
}
|
|
19380
|
+
}
|
|
19381
|
+
) }),
|
|
19382
|
+
/* @__PURE__ */ jsx21(
|
|
19383
|
+
"div",
|
|
19384
|
+
{
|
|
19385
|
+
"data-ohw-bridge": "",
|
|
19386
|
+
"data-ohw-item-interaction": "",
|
|
19387
|
+
"aria-hidden": true,
|
|
19388
|
+
className: "pointer-events-none fixed rounded-[4px] px-[7px] py-[3px] font-sans text-[11px] font-medium leading-none text-primary-foreground whitespace-nowrap",
|
|
19389
|
+
style: {
|
|
19390
|
+
top: activeItemRect.top + activeItemRect.height + 10,
|
|
19391
|
+
left: activeItemRect.left - 5,
|
|
19392
|
+
background: PRIMARY3,
|
|
19393
|
+
zIndex: 2147483644
|
|
19394
|
+
},
|
|
19395
|
+
children: "Media item"
|
|
19396
|
+
}
|
|
19397
|
+
),
|
|
19398
|
+
linkOpen && /* @__PURE__ */ jsx21(
|
|
19399
|
+
LinkModal,
|
|
19400
|
+
{
|
|
19401
|
+
href: activeHref,
|
|
19402
|
+
linkTarget: activeTarget,
|
|
19403
|
+
onClose: () => setLinkOpen(false),
|
|
19404
|
+
onSave: (href, linkTarget) => {
|
|
19405
|
+
void runMutation(
|
|
19406
|
+
active.sectionId,
|
|
19407
|
+
(tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
|
|
19408
|
+
);
|
|
18937
19409
|
}
|
|
18938
|
-
|
|
18939
|
-
|
|
18940
|
-
)
|
|
19410
|
+
}
|
|
19411
|
+
)
|
|
19412
|
+
] })
|
|
18941
19413
|
] });
|
|
18942
19414
|
}
|
|
18943
19415
|
|
|
18944
19416
|
// src/ui/ai-section/AiPricingCardOverlay.tsx
|
|
18945
|
-
import { useCallback as useCallback4, useEffect as useEffect7, useLayoutEffect as
|
|
18946
|
-
import { Check as
|
|
18947
|
-
import { Fragment as Fragment8, jsx as
|
|
19417
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useLayoutEffect as useLayoutEffect5, useRef as useRef6, useState as useState9 } from "react";
|
|
19418
|
+
import { Check as Check3, ChevronDown as ChevronDown4, Minus as Minus2, Plus as Plus3, Star as Star2 } from "lucide-react";
|
|
19419
|
+
import { Fragment as Fragment8, jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
18948
19420
|
var PRIMARY4 = "var(--ohw-primary, #0885FE)";
|
|
18949
|
-
var
|
|
19421
|
+
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]";
|
|
18950
19422
|
function findPricingCardElement(sectionId, index) {
|
|
18951
19423
|
const sectionEl = findByInstanceId(sectionId);
|
|
18952
19424
|
if (!sectionEl) return null;
|
|
@@ -18958,7 +19430,7 @@ function findPricingCardElement(sectionId, index) {
|
|
|
18958
19430
|
}
|
|
18959
19431
|
function cardRefFromTarget(target) {
|
|
18960
19432
|
if (!(target instanceof Element)) return null;
|
|
18961
|
-
if (target.closest(
|
|
19433
|
+
if (target.closest(CHROME_SELECTOR2)) return null;
|
|
18962
19434
|
const cardEl = target.closest("[data-ohw-pricing-card]");
|
|
18963
19435
|
if (!cardEl) return null;
|
|
18964
19436
|
const sectionEl = cardEl.closest("[data-ohw-section]");
|
|
@@ -18968,21 +19440,21 @@ function cardRefFromTarget(target) {
|
|
|
18968
19440
|
if (!sectionId || Number.isNaN(index)) return null;
|
|
18969
19441
|
return { sectionId, index };
|
|
18970
19442
|
}
|
|
18971
|
-
function
|
|
19443
|
+
function sameRef2(a, b) {
|
|
18972
19444
|
return a?.sectionId === b?.sectionId && a?.index === b?.index;
|
|
18973
19445
|
}
|
|
18974
|
-
function
|
|
19446
|
+
function rectOf2(el) {
|
|
18975
19447
|
if (!el) return null;
|
|
18976
19448
|
const r2 = el.getBoundingClientRect();
|
|
18977
19449
|
if (r2.width <= 0 || r2.height <= 0) return null;
|
|
18978
19450
|
return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
|
|
18979
19451
|
}
|
|
18980
19452
|
function readRect3(ref) {
|
|
18981
|
-
return
|
|
19453
|
+
return rectOf2(ref && findPricingCardElement(ref.sectionId, ref.index));
|
|
18982
19454
|
}
|
|
18983
19455
|
function readGridRect(ref) {
|
|
18984
19456
|
const card = ref && findPricingCardElement(ref.sectionId, ref.index);
|
|
18985
|
-
return
|
|
19457
|
+
return rectOf2(card?.closest("[data-ohw-pricing-collection]") ?? card);
|
|
18986
19458
|
}
|
|
18987
19459
|
function useLiveCardRect(ref, grid = false) {
|
|
18988
19460
|
const [rect, setRect] = useState9(null);
|
|
@@ -19012,19 +19484,19 @@ function useLiveCardRect(ref, grid = false) {
|
|
|
19012
19484
|
}
|
|
19013
19485
|
var TOOLBAR_GRID_GAP = 52;
|
|
19014
19486
|
var TOOLBAR_GRID_GAP_MOBILE = 42;
|
|
19015
|
-
var
|
|
19487
|
+
var TOOLBAR_EDGE_MARGIN3 = 4;
|
|
19016
19488
|
function GridToolbarSlot({ gridRect, children }) {
|
|
19017
19489
|
const slotRef = useRef6(null);
|
|
19018
19490
|
const [shift, setShift] = useState9(0);
|
|
19019
19491
|
const centerX = gridRect.left + gridRect.width / 2;
|
|
19020
|
-
|
|
19492
|
+
useLayoutEffect5(() => {
|
|
19021
19493
|
const slot = slotRef.current;
|
|
19022
19494
|
if (!slot) return;
|
|
19023
19495
|
const clamp = () => {
|
|
19024
19496
|
const w = slot.offsetWidth;
|
|
19025
19497
|
if (w <= 0) return;
|
|
19026
19498
|
const half = w / 2;
|
|
19027
|
-
const clamped = Math.max(
|
|
19499
|
+
const clamped = Math.max(TOOLBAR_EDGE_MARGIN3 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN3 - half));
|
|
19028
19500
|
setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
|
|
19029
19501
|
};
|
|
19030
19502
|
clamp();
|
|
@@ -19033,7 +19505,7 @@ function GridToolbarSlot({ gridRect, children }) {
|
|
|
19033
19505
|
return () => ro.disconnect();
|
|
19034
19506
|
}, [centerX, children]);
|
|
19035
19507
|
const mobile = window.innerWidth <= 480;
|
|
19036
|
-
return /* @__PURE__ */
|
|
19508
|
+
return /* @__PURE__ */ jsx22(
|
|
19037
19509
|
"div",
|
|
19038
19510
|
{
|
|
19039
19511
|
ref: slotRef,
|
|
@@ -19068,7 +19540,7 @@ function requestValidateTree2(postToParent2, tree) {
|
|
|
19068
19540
|
});
|
|
19069
19541
|
}
|
|
19070
19542
|
function StyleSwatch({ style }) {
|
|
19071
|
-
return /* @__PURE__ */
|
|
19543
|
+
return /* @__PURE__ */ jsx22(
|
|
19072
19544
|
"span",
|
|
19073
19545
|
{
|
|
19074
19546
|
"aria-hidden": true,
|
|
@@ -19082,35 +19554,35 @@ function StyleSwatch({ style }) {
|
|
|
19082
19554
|
);
|
|
19083
19555
|
}
|
|
19084
19556
|
function ButtonGlyph() {
|
|
19085
|
-
return /* @__PURE__ */
|
|
19086
|
-
/* @__PURE__ */
|
|
19087
|
-
/* @__PURE__ */
|
|
19557
|
+
return /* @__PURE__ */ jsxs13("svg", { width: "18", height: "12", viewBox: "0 0 18 12", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
|
|
19558
|
+
/* @__PURE__ */ jsx22("rect", { x: "0.75", y: "0.75", width: "16.5", height: "10.5", rx: "3", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
19559
|
+
/* @__PURE__ */ jsx22("path", { d: "M5.5 6H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
19088
19560
|
] });
|
|
19089
19561
|
}
|
|
19090
19562
|
function FeatureGlyph({ mode }) {
|
|
19091
|
-
return /* @__PURE__ */
|
|
19092
|
-
/* @__PURE__ */
|
|
19093
|
-
/* @__PURE__ */
|
|
19094
|
-
/* @__PURE__ */
|
|
19095
|
-
/* @__PURE__ */
|
|
19096
|
-
/* @__PURE__ */
|
|
19097
|
-
mode === "add" && /* @__PURE__ */
|
|
19563
|
+
return /* @__PURE__ */ jsxs13("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
|
|
19564
|
+
/* @__PURE__ */ jsx22("circle", { cx: "8", cy: "8", r: "7.25", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
19565
|
+
/* @__PURE__ */ jsx22("path", { d: "M5 8.2L7.2 10.3L11 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
19566
|
+
/* @__PURE__ */ jsx22("circle", { cx: "13.5", cy: "13.5", r: "4.25", fill: "var(--ohw-background, #ffffff)", stroke: "var(--ohw-background, #ffffff)", strokeWidth: "1" }),
|
|
19567
|
+
/* @__PURE__ */ jsx22("circle", { cx: "13.5", cy: "13.5", r: "3.75", fill: "var(--ohw-background, #ffffff)", stroke: PRIMARY4, strokeWidth: "1" }),
|
|
19568
|
+
/* @__PURE__ */ jsx22("path", { d: "M11.5 13.5H15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" }),
|
|
19569
|
+
mode === "add" && /* @__PURE__ */ jsx22("path", { d: "M13.5 11.5V15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" })
|
|
19098
19570
|
] });
|
|
19099
19571
|
}
|
|
19100
|
-
function
|
|
19572
|
+
function ToolbarAction2({
|
|
19101
19573
|
label,
|
|
19102
19574
|
onClick,
|
|
19103
19575
|
disabled = false,
|
|
19104
19576
|
children
|
|
19105
19577
|
}) {
|
|
19106
|
-
const button = /* @__PURE__ */
|
|
19107
|
-
return /* @__PURE__ */
|
|
19108
|
-
/* @__PURE__ */
|
|
19109
|
-
/* @__PURE__ */
|
|
19578
|
+
const button = /* @__PURE__ */ jsx22(CustomToolbarButton, { type: "button", "aria-label": label, disabled, onClick, className: "size-8", children });
|
|
19579
|
+
return /* @__PURE__ */ jsxs13(Tooltip, { children: [
|
|
19580
|
+
/* @__PURE__ */ jsx22(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx22("span", { className: "inline-flex", children: button }) : button }),
|
|
19581
|
+
/* @__PURE__ */ jsx22(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
|
|
19110
19582
|
] });
|
|
19111
19583
|
}
|
|
19112
|
-
function
|
|
19113
|
-
return /* @__PURE__ */
|
|
19584
|
+
function ToolbarSeparator2() {
|
|
19585
|
+
return /* @__PURE__ */ jsx22("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
|
|
19114
19586
|
}
|
|
19115
19587
|
function CardStyleMenu({
|
|
19116
19588
|
value,
|
|
@@ -19118,7 +19590,7 @@ function CardStyleMenu({
|
|
|
19118
19590
|
disabled = false
|
|
19119
19591
|
}) {
|
|
19120
19592
|
const current = PRICING_CARD_STYLES.find((s) => s.value === value) ?? PRICING_CARD_STYLES[0];
|
|
19121
|
-
const trigger = /* @__PURE__ */
|
|
19593
|
+
const trigger = /* @__PURE__ */ jsxs13(
|
|
19122
19594
|
"button",
|
|
19123
19595
|
{
|
|
19124
19596
|
type: "button",
|
|
@@ -19129,28 +19601,28 @@ function CardStyleMenu({
|
|
|
19129
19601
|
disabled && "cursor-not-allowed opacity-40 hover:bg-transparent"
|
|
19130
19602
|
),
|
|
19131
19603
|
children: [
|
|
19132
|
-
/* @__PURE__ */
|
|
19133
|
-
/* @__PURE__ */
|
|
19134
|
-
/* @__PURE__ */
|
|
19604
|
+
/* @__PURE__ */ jsx22(StyleSwatch, { style: current.value }),
|
|
19605
|
+
/* @__PURE__ */ jsx22("span", { className: "flex-1 text-left", children: current.label }),
|
|
19606
|
+
/* @__PURE__ */ jsx22(ChevronDown4, { size: 16, style: { pointerEvents: "none" } })
|
|
19135
19607
|
]
|
|
19136
19608
|
}
|
|
19137
19609
|
);
|
|
19138
19610
|
if (disabled) {
|
|
19139
|
-
return /* @__PURE__ */
|
|
19140
|
-
/* @__PURE__ */
|
|
19141
|
-
/* @__PURE__ */
|
|
19142
|
-
/* @__PURE__ */
|
|
19143
|
-
/* @__PURE__ */
|
|
19611
|
+
return /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
19612
|
+
/* @__PURE__ */ jsx22("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
|
|
19613
|
+
/* @__PURE__ */ jsxs13(Tooltip, { children: [
|
|
19614
|
+
/* @__PURE__ */ jsx22(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx22("span", { className: "inline-flex", children: trigger }) }),
|
|
19615
|
+
/* @__PURE__ */ jsx22(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
|
|
19144
19616
|
] })
|
|
19145
19617
|
] });
|
|
19146
19618
|
}
|
|
19147
|
-
return /* @__PURE__ */
|
|
19148
|
-
/* @__PURE__ */
|
|
19149
|
-
/* @__PURE__ */
|
|
19150
|
-
/* @__PURE__ */
|
|
19151
|
-
/* @__PURE__ */
|
|
19619
|
+
return /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
19620
|
+
/* @__PURE__ */ jsx22("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
|
|
19621
|
+
/* @__PURE__ */ jsxs13(DropdownMenu, { modal: false, children: [
|
|
19622
|
+
/* @__PURE__ */ jsx22(DropdownMenuTrigger, { asChild: true, children: trigger }),
|
|
19623
|
+
/* @__PURE__ */ jsx22(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
|
|
19152
19624
|
const selected = style.value === value;
|
|
19153
|
-
return /* @__PURE__ */
|
|
19625
|
+
return /* @__PURE__ */ jsxs13(
|
|
19154
19626
|
DropdownMenuItem,
|
|
19155
19627
|
{
|
|
19156
19628
|
role: "menuitemradio",
|
|
@@ -19158,9 +19630,9 @@ function CardStyleMenu({
|
|
|
19158
19630
|
onSelect: () => onChange(style.value),
|
|
19159
19631
|
className: cn("grid grid-cols-[18px_1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
|
|
19160
19632
|
children: [
|
|
19161
|
-
/* @__PURE__ */
|
|
19162
|
-
/* @__PURE__ */
|
|
19163
|
-
selected && /* @__PURE__ */
|
|
19633
|
+
/* @__PURE__ */ jsx22(StyleSwatch, { style: style.value }),
|
|
19634
|
+
/* @__PURE__ */ jsx22("span", { children: style.label }),
|
|
19635
|
+
selected && /* @__PURE__ */ jsx22(Check3, { size: 16, className: "text-bridge-primary" })
|
|
19164
19636
|
]
|
|
19165
19637
|
},
|
|
19166
19638
|
style.value
|
|
@@ -19190,7 +19662,7 @@ function PricingCardToolbar({
|
|
|
19190
19662
|
const style = pricingCardStyle(entry.tree, index);
|
|
19191
19663
|
const featuredTag = pricingCardFeaturedTag(entry.tree, index);
|
|
19192
19664
|
const mobile = window.innerWidth <= 480;
|
|
19193
|
-
return /* @__PURE__ */
|
|
19665
|
+
return /* @__PURE__ */ jsx22(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs13(
|
|
19194
19666
|
"div",
|
|
19195
19667
|
{
|
|
19196
19668
|
"data-ohw-bridge": "",
|
|
@@ -19202,7 +19674,7 @@ function PricingCardToolbar({
|
|
|
19202
19674
|
),
|
|
19203
19675
|
style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
|
|
19204
19676
|
children: [
|
|
19205
|
-
/* @__PURE__ */
|
|
19677
|
+
/* @__PURE__ */ jsxs13(
|
|
19206
19678
|
"div",
|
|
19207
19679
|
{
|
|
19208
19680
|
className: cn(
|
|
@@ -19211,8 +19683,8 @@ function PricingCardToolbar({
|
|
|
19211
19683
|
mobile ? "flex-wrap justify-center" : "flex-nowrap"
|
|
19212
19684
|
),
|
|
19213
19685
|
children: [
|
|
19214
|
-
/* @__PURE__ */
|
|
19215
|
-
/* @__PURE__ */
|
|
19686
|
+
/* @__PURE__ */ jsxs13(Tooltip, { children: [
|
|
19687
|
+
/* @__PURE__ */ jsx22(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx22(
|
|
19216
19688
|
CustomToolbarButton,
|
|
19217
19689
|
{
|
|
19218
19690
|
type: "button",
|
|
@@ -19220,7 +19692,7 @@ function PricingCardToolbar({
|
|
|
19220
19692
|
"aria-pressed": featuredTag,
|
|
19221
19693
|
onClick: () => onSetFeaturedTag(!featuredTag),
|
|
19222
19694
|
className: "group size-8",
|
|
19223
|
-
children: /* @__PURE__ */
|
|
19695
|
+
children: /* @__PURE__ */ jsx22(
|
|
19224
19696
|
Star2,
|
|
19225
19697
|
{
|
|
19226
19698
|
size: 16,
|
|
@@ -19235,25 +19707,25 @@ function PricingCardToolbar({
|
|
|
19235
19707
|
)
|
|
19236
19708
|
}
|
|
19237
19709
|
) }),
|
|
19238
|
-
/* @__PURE__ */
|
|
19710
|
+
/* @__PURE__ */ jsx22(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
|
|
19239
19711
|
] }),
|
|
19240
|
-
/* @__PURE__ */
|
|
19241
|
-
/* @__PURE__ */
|
|
19242
|
-
/* @__PURE__ */
|
|
19243
|
-
/* @__PURE__ */
|
|
19244
|
-
/* @__PURE__ */
|
|
19245
|
-
/* @__PURE__ */
|
|
19246
|
-
/* @__PURE__ */
|
|
19712
|
+
/* @__PURE__ */ jsx22(ToolbarSeparator2, {}),
|
|
19713
|
+
/* @__PURE__ */ jsx22(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
|
|
19714
|
+
/* @__PURE__ */ jsx22(ToolbarSeparator2, {}),
|
|
19715
|
+
/* @__PURE__ */ jsx22(ToolbarAction2, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ jsx22(ButtonGlyph, {}) }),
|
|
19716
|
+
/* @__PURE__ */ jsx22(ToolbarAction2, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ jsxs13("span", { className: "relative inline-flex", children: [
|
|
19717
|
+
/* @__PURE__ */ jsx22(ButtonGlyph, {}),
|
|
19718
|
+
/* @__PURE__ */ jsx22(Minus2, { size: 10, strokeWidth: 2.5, className: "absolute -right-1.5 -top-1.5 rounded-full bg-background text-bridge-primary" })
|
|
19247
19719
|
] }) }),
|
|
19248
|
-
/* @__PURE__ */
|
|
19249
|
-
/* @__PURE__ */
|
|
19250
|
-
/* @__PURE__ */
|
|
19251
|
-
/* @__PURE__ */
|
|
19252
|
-
/* @__PURE__ */
|
|
19720
|
+
/* @__PURE__ */ jsx22(ToolbarAction2, { label: "Add feature", onClick: onAddFeature, disabled: featureCount >= 10, children: /* @__PURE__ */ jsx22(FeatureGlyph, { mode: "add" }) }),
|
|
19721
|
+
/* @__PURE__ */ jsx22(ToolbarAction2, { label: "Remove feature", onClick: onRemoveFeature, disabled: featureCount <= 1, children: /* @__PURE__ */ jsx22(FeatureGlyph, { mode: "remove" }) }),
|
|
19722
|
+
/* @__PURE__ */ jsx22(ToolbarSeparator2, {}),
|
|
19723
|
+
/* @__PURE__ */ jsx22(ToolbarAction2, { label: "Add tier", onClick: onAddTier, disabled: collectionCount >= 4, children: /* @__PURE__ */ jsx22(Plus3, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19724
|
+
/* @__PURE__ */ jsx22(ToolbarAction2, { label: "Remove tier", onClick: onRemoveTier, disabled: collectionCount <= 1, children: /* @__PURE__ */ jsx22(Minus2, { size: 16, style: { pointerEvents: "none" } }) })
|
|
19253
19725
|
]
|
|
19254
19726
|
}
|
|
19255
19727
|
),
|
|
19256
|
-
error && /* @__PURE__ */
|
|
19728
|
+
error && /* @__PURE__ */ jsx22("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
|
|
19257
19729
|
]
|
|
19258
19730
|
}
|
|
19259
19731
|
) });
|
|
@@ -19287,7 +19759,7 @@ function AiPricingCardOverlay({
|
|
|
19287
19759
|
const overEditable = Boolean(t?.closest?.("[data-ohw-editable], [data-ohw-role], a, button"));
|
|
19288
19760
|
setHover((prev) => {
|
|
19289
19761
|
const next = ref && !overEditable ? ref : null;
|
|
19290
|
-
return
|
|
19762
|
+
return sameRef2(prev, next) ? prev : next;
|
|
19291
19763
|
});
|
|
19292
19764
|
};
|
|
19293
19765
|
const onLeave = () => setHover(null);
|
|
@@ -19302,10 +19774,10 @@ function AiPricingCardOverlay({
|
|
|
19302
19774
|
const onClick = (e) => {
|
|
19303
19775
|
const t = e.target;
|
|
19304
19776
|
if (!(t instanceof Element)) return;
|
|
19305
|
-
if (t.closest(
|
|
19777
|
+
if (t.closest(CHROME_SELECTOR2)) return;
|
|
19306
19778
|
const ref = cardRefFromTarget(t);
|
|
19307
|
-
setActive((prev) =>
|
|
19308
|
-
if (!ref || !
|
|
19779
|
+
setActive((prev) => sameRef2(prev, ref) ? prev : ref);
|
|
19780
|
+
if (!ref || !sameRef2(activeRef.current, ref)) setError(null);
|
|
19309
19781
|
};
|
|
19310
19782
|
document.addEventListener("click", onClick, true);
|
|
19311
19783
|
return () => document.removeEventListener("click", onClick, true);
|
|
@@ -19370,12 +19842,12 @@ function AiPricingCardOverlay({
|
|
|
19370
19842
|
const activeEntry = active ? findEntry(active.sectionId) : null;
|
|
19371
19843
|
const activeCardRect = useLiveCardRect(active);
|
|
19372
19844
|
const activeGridRect = useLiveCardRect(active, true);
|
|
19373
|
-
const hoverRect = useLiveCardRect(hover && !
|
|
19374
|
-
return /* @__PURE__ */
|
|
19375
|
-
hoverRect && /* @__PURE__ */
|
|
19376
|
-
activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */
|
|
19377
|
-
/* @__PURE__ */
|
|
19378
|
-
/* @__PURE__ */
|
|
19845
|
+
const hoverRect = useLiveCardRect(hover && !sameRef2(hover, active) ? hover : null);
|
|
19846
|
+
return /* @__PURE__ */ jsxs13(Fragment8, { children: [
|
|
19847
|
+
hoverRect && /* @__PURE__ */ jsx22(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
|
|
19848
|
+
activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ jsxs13(Fragment8, { children: [
|
|
19849
|
+
/* @__PURE__ */ jsx22(ItemInteractionLayer, { rect: activeCardRect, state: "active-top" }),
|
|
19850
|
+
/* @__PURE__ */ jsx22(GridToolbarSlot, { gridRect: activeGridRect, children: /* @__PURE__ */ jsx22(
|
|
19379
19851
|
PricingCardToolbar,
|
|
19380
19852
|
{
|
|
19381
19853
|
entry: activeEntry,
|
|
@@ -19403,7 +19875,7 @@ function AiPricingCardOverlay({
|
|
|
19403
19875
|
onRemoveFeature: () => runMutation(active.sectionId, (tree) => removePricingCardFeature(tree, active.index))
|
|
19404
19876
|
}
|
|
19405
19877
|
) }),
|
|
19406
|
-
/* @__PURE__ */
|
|
19878
|
+
/* @__PURE__ */ jsx22(
|
|
19407
19879
|
"div",
|
|
19408
19880
|
{
|
|
19409
19881
|
"data-ohw-bridge": "",
|
|
@@ -19496,10 +19968,10 @@ function extractYouTubeId(input) {
|
|
|
19496
19968
|
}
|
|
19497
19969
|
|
|
19498
19970
|
// src/ui/ai-section/AiVideoOverlay.tsx
|
|
19499
|
-
import { Fragment as Fragment9, jsx as
|
|
19971
|
+
import { Fragment as Fragment9, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
19500
19972
|
var PRIMARY5 = "#0885FE";
|
|
19501
|
-
var
|
|
19502
|
-
var
|
|
19973
|
+
var OHW_BLUE = `var(--ohw-primary, ${PRIMARY5})`;
|
|
19974
|
+
var OHW_BLUE_DARK = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY5}) 60%, #000000)`;
|
|
19503
19975
|
function findVideoBlockElement(sectionId, path) {
|
|
19504
19976
|
const sectionEl = findByInstanceId(sectionId);
|
|
19505
19977
|
if (!sectionEl) return null;
|
|
@@ -19559,12 +20031,12 @@ function requestValidateTree3(postToParent2, tree) {
|
|
|
19559
20031
|
postToParent2({ type: "ow:ai-validate-tree-request", id, tree });
|
|
19560
20032
|
});
|
|
19561
20033
|
}
|
|
19562
|
-
function
|
|
20034
|
+
function Pill({
|
|
19563
20035
|
label,
|
|
19564
20036
|
onClick,
|
|
19565
20037
|
disabled
|
|
19566
20038
|
}) {
|
|
19567
|
-
return /* @__PURE__ */
|
|
20039
|
+
return /* @__PURE__ */ jsx23(
|
|
19568
20040
|
"button",
|
|
19569
20041
|
{
|
|
19570
20042
|
type: "button",
|
|
@@ -19580,7 +20052,7 @@ function Pill2({
|
|
|
19580
20052
|
border: "none",
|
|
19581
20053
|
cursor: disabled ? "default" : "pointer",
|
|
19582
20054
|
background: "#ffffff",
|
|
19583
|
-
color:
|
|
20055
|
+
color: OHW_BLUE_DARK,
|
|
19584
20056
|
opacity: disabled ? 0.4 : 1,
|
|
19585
20057
|
fontSize: 12,
|
|
19586
20058
|
lineHeight: "16px",
|
|
@@ -19623,8 +20095,8 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
19623
20095
|
onCommit(id);
|
|
19624
20096
|
}
|
|
19625
20097
|
};
|
|
19626
|
-
return /* @__PURE__ */
|
|
19627
|
-
/* @__PURE__ */
|
|
20098
|
+
return /* @__PURE__ */ jsxs14("div", { style: { display: "flex", flexDirection: "column", gap: 4, width: "100%", maxWidth: 280 }, children: [
|
|
20099
|
+
/* @__PURE__ */ jsxs14(
|
|
19628
20100
|
"div",
|
|
19629
20101
|
{
|
|
19630
20102
|
style: {
|
|
@@ -19640,12 +20112,12 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
19640
20112
|
boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
|
|
19641
20113
|
},
|
|
19642
20114
|
children: [
|
|
19643
|
-
/* @__PURE__ */
|
|
20115
|
+
/* @__PURE__ */ jsx23(
|
|
19644
20116
|
"span",
|
|
19645
20117
|
{
|
|
19646
20118
|
style: {
|
|
19647
20119
|
flex: "0 0 auto",
|
|
19648
|
-
color:
|
|
20120
|
+
color: OHW_BLUE_DARK,
|
|
19649
20121
|
fontSize: 10,
|
|
19650
20122
|
lineHeight: "16px",
|
|
19651
20123
|
fontWeight: 700,
|
|
@@ -19655,7 +20127,7 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
19655
20127
|
children: "Video"
|
|
19656
20128
|
}
|
|
19657
20129
|
),
|
|
19658
|
-
/* @__PURE__ */
|
|
20130
|
+
/* @__PURE__ */ jsx23(
|
|
19659
20131
|
"input",
|
|
19660
20132
|
{
|
|
19661
20133
|
type: "text",
|
|
@@ -19692,7 +20164,7 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
19692
20164
|
]
|
|
19693
20165
|
}
|
|
19694
20166
|
),
|
|
19695
|
-
invalid && /* @__PURE__ */
|
|
20167
|
+
invalid && /* @__PURE__ */ jsx23("div", { style: { color: "#FCA5A5", fontSize: 11, textAlign: "center" }, children: "That doesn't look like a YouTube link \u2014 try pasting the video URL again." })
|
|
19696
20168
|
] });
|
|
19697
20169
|
}
|
|
19698
20170
|
function VideoToolbar({
|
|
@@ -19702,7 +20174,7 @@ function VideoToolbar({
|
|
|
19702
20174
|
onSetVideoId,
|
|
19703
20175
|
onRemove
|
|
19704
20176
|
}) {
|
|
19705
|
-
return /* @__PURE__ */
|
|
20177
|
+
return /* @__PURE__ */ jsxs14(
|
|
19706
20178
|
"div",
|
|
19707
20179
|
{
|
|
19708
20180
|
"data-ohw-bridge": "",
|
|
@@ -19714,7 +20186,7 @@ function VideoToolbar({
|
|
|
19714
20186
|
gap: 6,
|
|
19715
20187
|
alignItems: "center",
|
|
19716
20188
|
width: 280,
|
|
19717
|
-
background:
|
|
20189
|
+
background: OHW_BLUE,
|
|
19718
20190
|
padding: 8,
|
|
19719
20191
|
borderRadius: 12,
|
|
19720
20192
|
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
@@ -19722,9 +20194,9 @@ function VideoToolbar({
|
|
|
19722
20194
|
opacity: pending ? 0.6 : 1
|
|
19723
20195
|
},
|
|
19724
20196
|
children: [
|
|
19725
|
-
/* @__PURE__ */
|
|
19726
|
-
/* @__PURE__ */
|
|
19727
|
-
error && /* @__PURE__ */
|
|
20197
|
+
/* @__PURE__ */ jsx23(VideoUrlInput, { value: videoId, onCommit: onSetVideoId }),
|
|
20198
|
+
/* @__PURE__ */ jsx23(Pill, { label: "Remove video", onClick: onRemove, disabled: !videoId }),
|
|
20199
|
+
error && /* @__PURE__ */ jsx23("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
|
|
19728
20200
|
]
|
|
19729
20201
|
}
|
|
19730
20202
|
);
|
|
@@ -19844,8 +20316,8 @@ function AiVideoOverlay({
|
|
|
19844
20316
|
const activeBlockRect = useLiveBlockRect(active);
|
|
19845
20317
|
const TOOLBAR_APPROX_H = 90;
|
|
19846
20318
|
const toolbarState = activeBlockRect && activeBlockRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
|
|
19847
|
-
return /* @__PURE__ */
|
|
19848
|
-
hoverHandleRect && hover && /* @__PURE__ */
|
|
20319
|
+
return /* @__PURE__ */ jsxs14(Fragment9, { children: [
|
|
20320
|
+
hoverHandleRect && hover && /* @__PURE__ */ jsx23(
|
|
19849
20321
|
"button",
|
|
19850
20322
|
{
|
|
19851
20323
|
type: "button",
|
|
@@ -19873,15 +20345,15 @@ function AiVideoOverlay({
|
|
|
19873
20345
|
fontSize: 14,
|
|
19874
20346
|
fontWeight: 700
|
|
19875
20347
|
},
|
|
19876
|
-
children: /* @__PURE__ */
|
|
20348
|
+
children: /* @__PURE__ */ jsx23(Star3, { size: 14, style: { pointerEvents: "none" } })
|
|
19877
20349
|
}
|
|
19878
20350
|
),
|
|
19879
|
-
activeBlockRect && active && activeEntry && /* @__PURE__ */
|
|
20351
|
+
activeBlockRect && active && activeEntry && /* @__PURE__ */ jsx23(
|
|
19880
20352
|
ItemInteractionLayer,
|
|
19881
20353
|
{
|
|
19882
20354
|
rect: activeBlockRect,
|
|
19883
20355
|
state: toolbarState,
|
|
19884
|
-
toolbar: /* @__PURE__ */
|
|
20356
|
+
toolbar: /* @__PURE__ */ jsx23(
|
|
19885
20357
|
VideoToolbar,
|
|
19886
20358
|
{
|
|
19887
20359
|
videoId: videoIdAt(activeEntry.tree, active.path),
|
|
@@ -19956,10 +20428,10 @@ function setCarouselAutoplay(tree, on) {
|
|
|
19956
20428
|
}
|
|
19957
20429
|
|
|
19958
20430
|
// src/ui/ai-section/AiFadeCarouselOverlay.tsx
|
|
19959
|
-
import { Fragment as Fragment10, jsx as
|
|
20431
|
+
import { Fragment as Fragment10, jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
19960
20432
|
var PRIMARY6 = "#0885FE";
|
|
19961
|
-
var
|
|
19962
|
-
var
|
|
20433
|
+
var OHW_BLUE2 = `var(--ohw-primary, ${PRIMARY6})`;
|
|
20434
|
+
var OHW_BLUE_DARK2 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY6}) 60%, #000000)`;
|
|
19963
20435
|
function findCarouselItemElement(sectionId, index) {
|
|
19964
20436
|
const sectionEl = findByInstanceId(sectionId);
|
|
19965
20437
|
if (!sectionEl) return null;
|
|
@@ -20038,8 +20510,8 @@ function requestAssetPick2(postToParent2) {
|
|
|
20038
20510
|
postToParent2({ type: "ow:asset-pick", id });
|
|
20039
20511
|
});
|
|
20040
20512
|
}
|
|
20041
|
-
function
|
|
20042
|
-
return /* @__PURE__ */
|
|
20513
|
+
function Pill2({ label, onClick, disabled }) {
|
|
20514
|
+
return /* @__PURE__ */ jsx24(
|
|
20043
20515
|
"button",
|
|
20044
20516
|
{
|
|
20045
20517
|
type: "button",
|
|
@@ -20055,7 +20527,7 @@ function Pill3({ label, onClick, disabled }) {
|
|
|
20055
20527
|
border: "none",
|
|
20056
20528
|
cursor: disabled ? "default" : "pointer",
|
|
20057
20529
|
background: "#ffffff",
|
|
20058
|
-
color:
|
|
20530
|
+
color: OHW_BLUE_DARK2,
|
|
20059
20531
|
opacity: disabled ? 0.4 : 1,
|
|
20060
20532
|
fontSize: 12,
|
|
20061
20533
|
lineHeight: "16px",
|
|
@@ -20073,7 +20545,7 @@ function TogglePill({
|
|
|
20073
20545
|
onToggle,
|
|
20074
20546
|
disabled
|
|
20075
20547
|
}) {
|
|
20076
|
-
return /* @__PURE__ */
|
|
20548
|
+
return /* @__PURE__ */ jsxs15(
|
|
20077
20549
|
"button",
|
|
20078
20550
|
{
|
|
20079
20551
|
type: "button",
|
|
@@ -20092,7 +20564,7 @@ function TogglePill({
|
|
|
20092
20564
|
border: "none",
|
|
20093
20565
|
cursor: disabled ? "default" : "pointer",
|
|
20094
20566
|
background: "#ffffff",
|
|
20095
|
-
color:
|
|
20567
|
+
color: OHW_BLUE_DARK2,
|
|
20096
20568
|
opacity: disabled ? 0.4 : 1,
|
|
20097
20569
|
fontSize: 12,
|
|
20098
20570
|
lineHeight: "16px",
|
|
@@ -20102,7 +20574,7 @@ function TogglePill({
|
|
|
20102
20574
|
},
|
|
20103
20575
|
children: [
|
|
20104
20576
|
label,
|
|
20105
|
-
/* @__PURE__ */
|
|
20577
|
+
/* @__PURE__ */ jsx24(
|
|
20106
20578
|
"span",
|
|
20107
20579
|
{
|
|
20108
20580
|
"aria-hidden": true,
|
|
@@ -20115,10 +20587,10 @@ function TogglePill({
|
|
|
20115
20587
|
// Off is a grey track, not a washed-out blue: the pill's own white background already
|
|
20116
20588
|
// carries the brand colour in the text, and a pale blue track next to it read as
|
|
20117
20589
|
// "disabled control" rather than "switch that is off".
|
|
20118
|
-
background: on ?
|
|
20590
|
+
background: on ? OHW_BLUE_DARK2 : "#CBD5E1",
|
|
20119
20591
|
transition: "background 120ms ease"
|
|
20120
20592
|
},
|
|
20121
|
-
children: /* @__PURE__ */
|
|
20593
|
+
children: /* @__PURE__ */ jsx24(
|
|
20122
20594
|
"span",
|
|
20123
20595
|
{
|
|
20124
20596
|
style: {
|
|
@@ -20147,7 +20619,7 @@ function CarouselSlideToolbar({
|
|
|
20147
20619
|
onChangeImage,
|
|
20148
20620
|
onToggleAutoplay
|
|
20149
20621
|
}) {
|
|
20150
|
-
return /* @__PURE__ */
|
|
20622
|
+
return /* @__PURE__ */ jsxs15(
|
|
20151
20623
|
"div",
|
|
20152
20624
|
{
|
|
20153
20625
|
"data-ohw-bridge": "",
|
|
@@ -20158,7 +20630,7 @@ function CarouselSlideToolbar({
|
|
|
20158
20630
|
flexDirection: "column",
|
|
20159
20631
|
gap: 6,
|
|
20160
20632
|
alignItems: "center",
|
|
20161
|
-
background:
|
|
20633
|
+
background: OHW_BLUE2,
|
|
20162
20634
|
padding: 8,
|
|
20163
20635
|
borderRadius: 12,
|
|
20164
20636
|
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
@@ -20170,11 +20642,11 @@ function CarouselSlideToolbar({
|
|
|
20170
20642
|
pointerEvents: pending ? "none" : "auto"
|
|
20171
20643
|
},
|
|
20172
20644
|
children: [
|
|
20173
|
-
/* @__PURE__ */
|
|
20174
|
-
/* @__PURE__ */
|
|
20175
|
-
/* @__PURE__ */
|
|
20645
|
+
/* @__PURE__ */ jsxs15("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
|
|
20646
|
+
/* @__PURE__ */ jsx24(Pill2, { label: "Change Image", onClick: onChangeImage }),
|
|
20647
|
+
/* @__PURE__ */ jsx24(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
|
|
20176
20648
|
] }),
|
|
20177
|
-
error && /* @__PURE__ */
|
|
20649
|
+
error && /* @__PURE__ */ jsx24("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
|
|
20178
20650
|
]
|
|
20179
20651
|
}
|
|
20180
20652
|
);
|
|
@@ -20314,8 +20786,8 @@ function AiFadeCarouselOverlay({
|
|
|
20314
20786
|
const activeItemRect = useLiveItemRect2(active);
|
|
20315
20787
|
const TOOLBAR_APPROX_H = 90;
|
|
20316
20788
|
const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
|
|
20317
|
-
return /* @__PURE__ */
|
|
20318
|
-
hoverHandleRect && hover && /* @__PURE__ */
|
|
20789
|
+
return /* @__PURE__ */ jsxs15(Fragment10, { children: [
|
|
20790
|
+
hoverHandleRect && hover && /* @__PURE__ */ jsx24(
|
|
20319
20791
|
"button",
|
|
20320
20792
|
{
|
|
20321
20793
|
type: "button",
|
|
@@ -20344,10 +20816,10 @@ function AiFadeCarouselOverlay({
|
|
|
20344
20816
|
fontSize: 14,
|
|
20345
20817
|
fontWeight: 700
|
|
20346
20818
|
},
|
|
20347
|
-
children: /* @__PURE__ */
|
|
20819
|
+
children: /* @__PURE__ */ jsx24(Star4, { size: 14, style: { pointerEvents: "none" } })
|
|
20348
20820
|
}
|
|
20349
20821
|
),
|
|
20350
|
-
swapping && /* @__PURE__ */
|
|
20822
|
+
swapping && /* @__PURE__ */ jsx24(
|
|
20351
20823
|
"div",
|
|
20352
20824
|
{
|
|
20353
20825
|
ref: skeletonRef,
|
|
@@ -20365,15 +20837,15 @@ function AiFadeCarouselOverlay({
|
|
|
20365
20837
|
zIndex: 2147483646,
|
|
20366
20838
|
pointerEvents: "none"
|
|
20367
20839
|
},
|
|
20368
|
-
children: /* @__PURE__ */
|
|
20840
|
+
children: /* @__PURE__ */ jsx24("style", { children: MEDIA_SKELETON_CSS })
|
|
20369
20841
|
}
|
|
20370
20842
|
),
|
|
20371
|
-
activeItemRect && active && activeEntry && /* @__PURE__ */
|
|
20843
|
+
activeItemRect && active && activeEntry && /* @__PURE__ */ jsx24(
|
|
20372
20844
|
ItemInteractionLayer,
|
|
20373
20845
|
{
|
|
20374
20846
|
rect: activeItemRect,
|
|
20375
20847
|
state: toolbarState,
|
|
20376
|
-
toolbar: /* @__PURE__ */
|
|
20848
|
+
toolbar: /* @__PURE__ */ jsx24(
|
|
20377
20849
|
CarouselSlideToolbar,
|
|
20378
20850
|
{
|
|
20379
20851
|
pending,
|
|
@@ -20441,190 +20913,55 @@ function isPointOverBridgeChrome(x, y) {
|
|
|
20441
20913
|
}
|
|
20442
20914
|
return false;
|
|
20443
20915
|
}
|
|
20444
|
-
var BUTTON_LIKE_SELECTOR = `button, [role="button"], ${CTA_BUTTON_SELECTOR}`;
|
|
20445
|
-
function isButtonLikeElement(el) {
|
|
20446
|
-
return el.matches(BUTTON_LIKE_SELECTOR);
|
|
20447
|
-
}
|
|
20448
|
-
function findClosestButtonLike(target) {
|
|
20449
|
-
return target.closest(BUTTON_LIKE_SELECTOR);
|
|
20450
|
-
}
|
|
20451
|
-
function findButtonAtPoint(x, y, media) {
|
|
20452
|
-
const hits = Array.from(
|
|
20453
|
-
document.querySelectorAll(BUTTON_LIKE_SELECTOR)
|
|
20454
|
-
).filter(
|
|
20455
|
-
(el) => containsPoint(el, x, y) && !(media && el.contains(media)) && // Bridge-injected chrome (e.g. MediaOverlay's own "Replace image" button) is never a
|
|
20456
|
-
// site button. Without this, once the media overlay renders its button lands right
|
|
20457
|
-
// under the cursor, gets detected as "a button on the media", and dismisses the very
|
|
20458
|
-
// overlay it belongs to — which removes the button, so the next hit-test finds nothing
|
|
20459
|
-
// and the overlay reappears. Flip-flops every tick: the "Replace image" button flashes.
|
|
20460
|
-
!el.closest("[data-ohw-bridge]") && // A carousel's own prev/next/dot controls (OHH-796) are `<button>`s in the template's
|
|
20461
|
-
// markup, so the bbox sweep that makes real CTAs win over a full-bleed hero image
|
|
20462
|
-
// (OHH-798) claimed them too and drew the editable-item hover frame around a control
|
|
20463
|
-
// that isn't content. They move the slideshow; there is nothing there to edit.
|
|
20464
|
-
!el.closest("[data-ohw-carousel-control]")
|
|
20465
|
-
);
|
|
20466
|
-
if (hits.length === 0) return null;
|
|
20467
|
-
return hits.reduce((best, el) => best.contains(el) ? el : best);
|
|
20468
|
-
}
|
|
20469
|
-
function findNavbarCtaAtPoint(x, y) {
|
|
20470
|
-
const hits = Array.from(
|
|
20471
|
-
document.querySelectorAll('[data-ohw-role="navbar-button"]')
|
|
20472
|
-
).filter((el) => containsPoint(el, x, y) && !el.closest("[data-ohw-bridge]"));
|
|
20473
|
-
if (hits.length === 0) return null;
|
|
20474
|
-
return hits.reduce((best, el) => best.contains(el) ? el : best);
|
|
20475
|
-
}
|
|
20476
|
-
|
|
20477
|
-
// src/lib/session-search.ts
|
|
20478
|
-
var STORAGE_KEY = "ohw-preserved-search";
|
|
20479
|
-
function readPreservedSearch() {
|
|
20480
|
-
if (typeof window === "undefined") return "";
|
|
20481
|
-
const fromUrl = window.location.search;
|
|
20482
|
-
if (fromUrl && fromUrl !== "?") {
|
|
20483
|
-
sessionStorage.setItem(STORAGE_KEY, fromUrl);
|
|
20484
|
-
return fromUrl;
|
|
20485
|
-
}
|
|
20486
|
-
return sessionStorage.getItem(STORAGE_KEY) ?? "";
|
|
20487
|
-
}
|
|
20488
|
-
function isEditSessionActive() {
|
|
20489
|
-
const search = readPreservedSearch();
|
|
20490
|
-
if (!search || search === "?") return false;
|
|
20491
|
-
const q = search.startsWith("?") ? search.slice(1) : search;
|
|
20492
|
-
return new URLSearchParams(q).get("mode") === "edit";
|
|
20493
|
-
}
|
|
20494
|
-
|
|
20495
|
-
// src/ui/link-modal/linkModal.utils.ts
|
|
20496
|
-
function parseTarget(target) {
|
|
20497
|
-
if (!target) return { pageRoute: "", sectionId: null };
|
|
20498
|
-
const hashIndex = target.indexOf("#");
|
|
20499
|
-
if (hashIndex === -1) return { pageRoute: target, sectionId: null };
|
|
20500
|
-
return {
|
|
20501
|
-
pageRoute: target.slice(0, hashIndex),
|
|
20502
|
-
sectionId: target.slice(hashIndex + 1) || null
|
|
20503
|
-
};
|
|
20504
|
-
}
|
|
20505
|
-
function normalizePath(path) {
|
|
20506
|
-
const trimmed = path.trim();
|
|
20507
|
-
if (!trimmed) return "/";
|
|
20508
|
-
try {
|
|
20509
|
-
if (/^https?:\/\//i.test(trimmed)) {
|
|
20510
|
-
return new URL(trimmed).pathname || "/";
|
|
20511
|
-
}
|
|
20512
|
-
} catch {
|
|
20513
|
-
}
|
|
20514
|
-
const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
20515
|
-
if (withSlash.length > 1 && withSlash.endsWith("/")) return withSlash.slice(0, -1);
|
|
20516
|
-
return withSlash;
|
|
20517
|
-
}
|
|
20518
|
-
function findPageByPath(pages, path) {
|
|
20519
|
-
const normalized = normalizePath(path);
|
|
20520
|
-
return pages.find((p) => normalizePath(p.path) === normalized);
|
|
20521
|
-
}
|
|
20522
|
-
function inferPageTitleFromPath(path) {
|
|
20523
|
-
const normalized = normalizePath(path);
|
|
20524
|
-
if (normalized === "/") return "Home";
|
|
20525
|
-
const segment = normalized.split("/").filter(Boolean).pop() ?? "";
|
|
20526
|
-
if (!segment) return "Home";
|
|
20527
|
-
return segment.split("-").filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
20528
|
-
}
|
|
20529
|
-
function isInternalPath(route) {
|
|
20530
|
-
const trimmed = route.trim();
|
|
20531
|
-
if (!trimmed) return false;
|
|
20532
|
-
if (/^https?:\/\//i.test(trimmed)) return false;
|
|
20533
|
-
if (trimmed.startsWith("/")) return true;
|
|
20534
|
-
if (trimmed.includes(" ") || trimmed.includes(".")) return false;
|
|
20535
|
-
return true;
|
|
20536
|
-
}
|
|
20537
|
-
function resolvePage(route, pages) {
|
|
20538
|
-
const found = findPageByPath(pages, route);
|
|
20539
|
-
if (found) return { path: found.path, title: found.title };
|
|
20540
|
-
return { path: normalizePath(route), title: inferPageTitleFromPath(route) };
|
|
20541
|
-
}
|
|
20542
|
-
function getSectionsForPath(sectionsByPath, pageRoute) {
|
|
20543
|
-
if (!sectionsByPath) return [];
|
|
20544
|
-
const normalized = normalizePath(pageRoute);
|
|
20545
|
-
return sectionsByPath[normalized] ?? sectionsByPath[pageRoute] ?? [];
|
|
20546
|
-
}
|
|
20547
|
-
function buildTarget(page, section) {
|
|
20548
|
-
if (section) return `${page.path}#${section.id}`;
|
|
20549
|
-
return page.path;
|
|
20550
|
-
}
|
|
20551
|
-
function isValidUrl(urlString) {
|
|
20552
|
-
try {
|
|
20553
|
-
const url = new URL(urlString);
|
|
20554
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") return false;
|
|
20555
|
-
const hostname = url.hostname;
|
|
20556
|
-
if (!hostname || hostname.length === 0) return false;
|
|
20557
|
-
if (hostname.includes(" ")) return false;
|
|
20558
|
-
if (hostname === "localhost") return true;
|
|
20559
|
-
if (!hostname.includes(".")) return false;
|
|
20560
|
-
if (!/[a-z]/i.test(hostname)) return false;
|
|
20561
|
-
return true;
|
|
20562
|
-
} catch {
|
|
20563
|
-
return false;
|
|
20564
|
-
}
|
|
20565
|
-
}
|
|
20566
|
-
function normalizeUrl(value) {
|
|
20567
|
-
const trimmed = value.trim();
|
|
20568
|
-
if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) return trimmed;
|
|
20569
|
-
return `https://${trimmed}`;
|
|
20570
|
-
}
|
|
20571
|
-
function validateUrlInput(value, pages, allPages) {
|
|
20572
|
-
const trimmed = value.trim();
|
|
20573
|
-
if (!trimmed) return "";
|
|
20574
|
-
const exactPage = allPages.find((p) => p.title.toLowerCase() === trimmed.toLowerCase());
|
|
20575
|
-
if (exactPage) return "";
|
|
20576
|
-
const hasPrefixMatch = pages.some((p) => p.title.toLowerCase().startsWith(trimmed.toLowerCase()));
|
|
20577
|
-
if (hasPrefixMatch) {
|
|
20578
|
-
return "Select a page from the list or enter a valid URL";
|
|
20579
|
-
}
|
|
20580
|
-
const hasScheme = /^https?:\/\//i.test(trimmed);
|
|
20581
|
-
if (!hasScheme && !trimmed.includes(".")) {
|
|
20582
|
-
return "Please enter a valid URL (e.g., https://example.com)";
|
|
20583
|
-
}
|
|
20584
|
-
if (!isValidUrl(normalizeUrl(trimmed))) {
|
|
20585
|
-
return "Please enter a valid URL (e.g., https://example.com)";
|
|
20586
|
-
}
|
|
20587
|
-
return "";
|
|
20588
|
-
}
|
|
20589
|
-
function getEditModeInitialState(target, pages, sections) {
|
|
20590
|
-
const empty = {
|
|
20591
|
-
searchValue: "",
|
|
20592
|
-
selectedPage: null,
|
|
20593
|
-
selectedSection: null,
|
|
20594
|
-
step: "input"
|
|
20595
|
-
};
|
|
20596
|
-
if (!target) return empty;
|
|
20597
|
-
if (isValidUrl(normalizeUrl(target))) {
|
|
20598
|
-
return { searchValue: target, selectedPage: null, selectedSection: null, step: "input" };
|
|
20599
|
-
}
|
|
20600
|
-
const { pageRoute, sectionId } = parseTarget(target);
|
|
20601
|
-
if (sectionId) {
|
|
20602
|
-
if (isInternalPath(pageRoute)) {
|
|
20603
|
-
const page = resolvePage(pageRoute, pages);
|
|
20604
|
-
const sec = sections.find((s) => s.id === sectionId);
|
|
20605
|
-
return {
|
|
20606
|
-
searchValue: page.title,
|
|
20607
|
-
selectedPage: page,
|
|
20608
|
-
selectedSection: sec ? { id: sec.id, label: sec.label } : null,
|
|
20609
|
-
step: "input"
|
|
20610
|
-
};
|
|
20611
|
-
}
|
|
20612
|
-
return { searchValue: pageRoute || target, selectedPage: null, selectedSection: null, step: "input" };
|
|
20613
|
-
}
|
|
20614
|
-
if (isInternalPath(pageRoute)) {
|
|
20615
|
-
const page = resolvePage(pageRoute, pages);
|
|
20616
|
-
return {
|
|
20617
|
-
searchValue: page.title,
|
|
20618
|
-
selectedPage: page,
|
|
20619
|
-
selectedSection: null,
|
|
20620
|
-
step: "input"
|
|
20621
|
-
};
|
|
20916
|
+
var BUTTON_LIKE_SELECTOR = `button, [role="button"], ${CTA_BUTTON_SELECTOR}`;
|
|
20917
|
+
function isButtonLikeElement(el) {
|
|
20918
|
+
return el.matches(BUTTON_LIKE_SELECTOR);
|
|
20919
|
+
}
|
|
20920
|
+
function findClosestButtonLike(target) {
|
|
20921
|
+
return target.closest(BUTTON_LIKE_SELECTOR);
|
|
20922
|
+
}
|
|
20923
|
+
function findButtonAtPoint(x, y, media) {
|
|
20924
|
+
const hits = Array.from(
|
|
20925
|
+
document.querySelectorAll(BUTTON_LIKE_SELECTOR)
|
|
20926
|
+
).filter(
|
|
20927
|
+
(el) => containsPoint(el, x, y) && !(media && el.contains(media)) && // Bridge-injected chrome (e.g. MediaOverlay's own "Replace image" button) is never a
|
|
20928
|
+
// site button. Without this, once the media overlay renders its button lands right
|
|
20929
|
+
// under the cursor, gets detected as "a button on the media", and dismisses the very
|
|
20930
|
+
// overlay it belongs to — which removes the button, so the next hit-test finds nothing
|
|
20931
|
+
// and the overlay reappears. Flip-flops every tick: the "Replace image" button flashes.
|
|
20932
|
+
!el.closest("[data-ohw-bridge]") && // A carousel's own prev/next/dot controls (OHH-796) are `<button>`s in the template's
|
|
20933
|
+
// markup, so the bbox sweep that makes real CTAs win over a full-bleed hero image
|
|
20934
|
+
// (OHH-798) claimed them too and drew the editable-item hover frame around a control
|
|
20935
|
+
// that isn't content. They move the slideshow; there is nothing there to edit.
|
|
20936
|
+
!el.closest("[data-ohw-carousel-control]")
|
|
20937
|
+
);
|
|
20938
|
+
if (hits.length === 0) return null;
|
|
20939
|
+
return hits.reduce((best, el) => best.contains(el) ? el : best);
|
|
20940
|
+
}
|
|
20941
|
+
function findNavbarCtaAtPoint(x, y) {
|
|
20942
|
+
const hits = Array.from(
|
|
20943
|
+
document.querySelectorAll('[data-ohw-role="navbar-button"]')
|
|
20944
|
+
).filter((el) => containsPoint(el, x, y) && !el.closest("[data-ohw-bridge]"));
|
|
20945
|
+
if (hits.length === 0) return null;
|
|
20946
|
+
return hits.reduce((best, el) => best.contains(el) ? el : best);
|
|
20947
|
+
}
|
|
20948
|
+
|
|
20949
|
+
// src/lib/session-search.ts
|
|
20950
|
+
var STORAGE_KEY = "ohw-preserved-search";
|
|
20951
|
+
function readPreservedSearch() {
|
|
20952
|
+
if (typeof window === "undefined") return "";
|
|
20953
|
+
const fromUrl = window.location.search;
|
|
20954
|
+
if (fromUrl && fromUrl !== "?") {
|
|
20955
|
+
sessionStorage.setItem(STORAGE_KEY, fromUrl);
|
|
20956
|
+
return fromUrl;
|
|
20622
20957
|
}
|
|
20623
|
-
return
|
|
20958
|
+
return sessionStorage.getItem(STORAGE_KEY) ?? "";
|
|
20624
20959
|
}
|
|
20625
|
-
function
|
|
20626
|
-
const
|
|
20627
|
-
|
|
20960
|
+
function isEditSessionActive() {
|
|
20961
|
+
const search = readPreservedSearch();
|
|
20962
|
+
if (!search || search === "?") return false;
|
|
20963
|
+
const q = search.startsWith("?") ? search.slice(1) : search;
|
|
20964
|
+
return new URLSearchParams(q).get("mode") === "edit";
|
|
20628
20965
|
}
|
|
20629
20966
|
|
|
20630
20967
|
// src/lib/prefetch-sections.ts
|
|
@@ -20726,118 +21063,11 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
|
|
|
20726
21063
|
// src/ui/link-modal/LinkPopover.tsx
|
|
20727
21064
|
import { useEffect as useEffect13 } from "react";
|
|
20728
21065
|
|
|
20729
|
-
// src/ui/dialog.tsx
|
|
20730
|
-
import * as React9 from "react";
|
|
20731
|
-
import { Dialog as DialogPrimitive } from "radix-ui";
|
|
20732
|
-
import { X as X2 } from "lucide-react";
|
|
20733
|
-
import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
20734
|
-
function Dialog2({
|
|
20735
|
-
...props
|
|
20736
|
-
}) {
|
|
20737
|
-
return /* @__PURE__ */ jsx24(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
|
|
20738
|
-
}
|
|
20739
|
-
function DialogPortal({
|
|
20740
|
-
...props
|
|
20741
|
-
}) {
|
|
20742
|
-
return /* @__PURE__ */ jsx24(DialogPrimitive.Portal, { ...props });
|
|
20743
|
-
}
|
|
20744
|
-
function DialogOverlay({
|
|
20745
|
-
className,
|
|
20746
|
-
...props
|
|
20747
|
-
}) {
|
|
20748
|
-
return /* @__PURE__ */ jsx24(
|
|
20749
|
-
DialogPrimitive.Overlay,
|
|
20750
|
-
{
|
|
20751
|
-
"data-slot": "dialog-overlay",
|
|
20752
|
-
"data-ohw-link-modal-root": "",
|
|
20753
|
-
className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
|
|
20754
|
-
...props
|
|
20755
|
-
}
|
|
20756
|
-
);
|
|
20757
|
-
}
|
|
20758
|
-
var DialogContent = React9.forwardRef(
|
|
20759
|
-
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
20760
|
-
const positionMode = container ? "absolute" : "fixed";
|
|
20761
|
-
return /* @__PURE__ */ jsxs15(DialogPortal, { container: container ?? void 0, children: [
|
|
20762
|
-
/* @__PURE__ */ jsx24(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
20763
|
-
/* @__PURE__ */ jsxs15(
|
|
20764
|
-
DialogPrimitive.Content,
|
|
20765
|
-
{
|
|
20766
|
-
ref,
|
|
20767
|
-
"data-slot": "dialog-content",
|
|
20768
|
-
className: cn(
|
|
20769
|
-
positionMode,
|
|
20770
|
-
"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",
|
|
20771
|
-
"rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
|
|
20772
|
-
container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
|
|
20773
|
-
className
|
|
20774
|
-
),
|
|
20775
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
20776
|
-
...props,
|
|
20777
|
-
children: [
|
|
20778
|
-
children,
|
|
20779
|
-
showCloseButton ? /* @__PURE__ */ jsx24(
|
|
20780
|
-
DialogPrimitive.Close,
|
|
20781
|
-
{
|
|
20782
|
-
type: "button",
|
|
20783
|
-
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
20784
|
-
"aria-label": "Close",
|
|
20785
|
-
children: /* @__PURE__ */ jsx24(X2, { size: 16, "aria-hidden": true })
|
|
20786
|
-
}
|
|
20787
|
-
) : null
|
|
20788
|
-
]
|
|
20789
|
-
}
|
|
20790
|
-
)
|
|
20791
|
-
] });
|
|
20792
|
-
}
|
|
20793
|
-
);
|
|
20794
|
-
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
20795
|
-
function DialogHeader({
|
|
20796
|
-
className,
|
|
20797
|
-
...props
|
|
20798
|
-
}) {
|
|
20799
|
-
return /* @__PURE__ */ jsx24("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
20800
|
-
}
|
|
20801
|
-
function DialogFooter({
|
|
20802
|
-
className,
|
|
20803
|
-
...props
|
|
20804
|
-
}) {
|
|
20805
|
-
return /* @__PURE__ */ jsx24(
|
|
20806
|
-
"div",
|
|
20807
|
-
{
|
|
20808
|
-
className: cn("flex items-center justify-end gap-2", className),
|
|
20809
|
-
...props
|
|
20810
|
-
}
|
|
20811
|
-
);
|
|
20812
|
-
}
|
|
20813
|
-
var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
|
|
20814
|
-
DialogPrimitive.Title,
|
|
20815
|
-
{
|
|
20816
|
-
ref,
|
|
20817
|
-
className: cn(
|
|
20818
|
-
"text-lg font-semibold leading-none tracking-tight text-card-foreground",
|
|
20819
|
-
className
|
|
20820
|
-
),
|
|
20821
|
-
...props
|
|
20822
|
-
}
|
|
20823
|
-
));
|
|
20824
|
-
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
20825
|
-
var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
|
|
20826
|
-
DialogPrimitive.Description,
|
|
20827
|
-
{
|
|
20828
|
-
ref,
|
|
20829
|
-
className: cn("text-sm text-muted-foreground", className),
|
|
20830
|
-
...props
|
|
20831
|
-
}
|
|
20832
|
-
));
|
|
20833
|
-
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
20834
|
-
var DialogClose = DialogPrimitive.Close;
|
|
20835
|
-
|
|
20836
21066
|
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
20837
21067
|
import { Info, X as X4 } from "lucide-react";
|
|
20838
21068
|
|
|
20839
21069
|
// src/ui/link-modal/DestinationBreadcrumb.tsx
|
|
20840
|
-
import { ArrowRight as
|
|
21070
|
+
import { ArrowRight as ArrowRight3, File, GalleryVertical } from "lucide-react";
|
|
20841
21071
|
import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
20842
21072
|
function DestinationBreadcrumb({
|
|
20843
21073
|
pageTitle,
|
|
@@ -20851,7 +21081,7 @@ function DestinationBreadcrumb({
|
|
|
20851
21081
|
/* @__PURE__ */ jsx25("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
|
|
20852
21082
|
] }),
|
|
20853
21083
|
/* @__PURE__ */ jsx25(
|
|
20854
|
-
|
|
21084
|
+
ArrowRight3,
|
|
20855
21085
|
{
|
|
20856
21086
|
size: 16,
|
|
20857
21087
|
className: "shrink-0 text-muted-foreground",
|
|
@@ -20963,7 +21193,7 @@ function Label({ className, ...props }) {
|
|
|
20963
21193
|
}
|
|
20964
21194
|
|
|
20965
21195
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
20966
|
-
import { ChevronDown as
|
|
21196
|
+
import { ChevronDown as ChevronDown5, File as File2, X as X3 } from "lucide-react";
|
|
20967
21197
|
import { jsx as jsx29, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
20968
21198
|
function FieldChevron({
|
|
20969
21199
|
onClick
|
|
@@ -20976,7 +21206,7 @@ function FieldChevron({
|
|
|
20976
21206
|
onClick,
|
|
20977
21207
|
"aria-label": "Open page list",
|
|
20978
21208
|
tabIndex: -1,
|
|
20979
|
-
children: /* @__PURE__ */ jsx29(
|
|
21209
|
+
children: /* @__PURE__ */ jsx29(ChevronDown5, { size: 16 })
|
|
20980
21210
|
}
|
|
20981
21211
|
);
|
|
20982
21212
|
}
|
|
@@ -21206,7 +21436,7 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
21206
21436
|
// src/ui/link-modal/SectionPickerOverlay.tsx
|
|
21207
21437
|
import { useCallback as useCallback7, useEffect as useEffect11, useMemo as useMemo2, useRef as useRef10, useState as useState13 } from "react";
|
|
21208
21438
|
import { createPortal as createPortal2 } from "react-dom";
|
|
21209
|
-
import { ArrowLeft as
|
|
21439
|
+
import { ArrowLeft as ArrowLeft3, Check as Check4 } from "lucide-react";
|
|
21210
21440
|
import { usePathname, useRouter as useRouter2 } from "next/navigation";
|
|
21211
21441
|
|
|
21212
21442
|
// src/lib/parent-scroll.ts
|
|
@@ -21483,7 +21713,7 @@ function SectionPickerOverlay({
|
|
|
21483
21713
|
className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
|
|
21484
21714
|
onClick: onBack,
|
|
21485
21715
|
children: [
|
|
21486
|
-
/* @__PURE__ */ jsx31(
|
|
21716
|
+
/* @__PURE__ */ jsx31(ArrowLeft3, { className: "size-4 shrink-0", "aria-hidden": true }),
|
|
21487
21717
|
"Back"
|
|
21488
21718
|
]
|
|
21489
21719
|
}
|
|
@@ -21552,7 +21782,7 @@ function SectionPickerOverlay({
|
|
|
21552
21782
|
className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
|
|
21553
21783
|
style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
|
|
21554
21784
|
"aria-hidden": true,
|
|
21555
|
-
children: /* @__PURE__ */ jsx31(
|
|
21785
|
+
children: /* @__PURE__ */ jsx31(Check4, { className: "size-5" })
|
|
21556
21786
|
}
|
|
21557
21787
|
) : null
|
|
21558
21788
|
]
|
|
@@ -21936,6 +22166,7 @@ function shouldUseDevFixtures() {
|
|
|
21936
22166
|
function getLogoElement(el) {
|
|
21937
22167
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
21938
22168
|
if (marked) return marked;
|
|
22169
|
+
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
21939
22170
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
21940
22171
|
if (!root) return null;
|
|
21941
22172
|
const anchor = el.closest("a");
|
|
@@ -22005,7 +22236,7 @@ function addFooterColumnWithPersist({
|
|
|
22005
22236
|
import {
|
|
22006
22237
|
useCallback as useCallback9,
|
|
22007
22238
|
useEffect as useEffect14,
|
|
22008
|
-
useLayoutEffect as
|
|
22239
|
+
useLayoutEffect as useLayoutEffect6,
|
|
22009
22240
|
useRef as useRef11,
|
|
22010
22241
|
useState as useState15
|
|
22011
22242
|
} from "react";
|
|
@@ -22102,7 +22333,7 @@ function FloatingPanel({
|
|
|
22102
22333
|
return () => window.removeEventListener("message", onParentScroll);
|
|
22103
22334
|
}, [open]);
|
|
22104
22335
|
const positionRef = useRef11(position);
|
|
22105
|
-
|
|
22336
|
+
useLayoutEffect6(() => {
|
|
22106
22337
|
if (!open) {
|
|
22107
22338
|
positionRef.current = position;
|
|
22108
22339
|
return;
|
|
@@ -22112,7 +22343,7 @@ function FloatingPanel({
|
|
|
22112
22343
|
}
|
|
22113
22344
|
positionRef.current = position;
|
|
22114
22345
|
}, [open, position, liveScroll, parentScroll]);
|
|
22115
|
-
|
|
22346
|
+
useLayoutEffect6(() => {
|
|
22116
22347
|
if (!open || !panelRef.current) return;
|
|
22117
22348
|
const el = panelRef.current;
|
|
22118
22349
|
const header = el.querySelector("[data-ohw-floating-panel-header]");
|
|
@@ -22321,7 +22552,7 @@ function SocialsDisplayPanel({ display, onChange, className }) {
|
|
|
22321
22552
|
}
|
|
22322
22553
|
|
|
22323
22554
|
// src/ui/button-style-panel.tsx
|
|
22324
|
-
import { Check as
|
|
22555
|
+
import { Check as Check5 } from "lucide-react";
|
|
22325
22556
|
import { jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
22326
22557
|
var SIZE_LABEL = { s: "S", m: "M", l: "L" };
|
|
22327
22558
|
function ButtonStylePanel({
|
|
@@ -22392,7 +22623,7 @@ function ButtonStylePanel({
|
|
|
22392
22623
|
{
|
|
22393
22624
|
className: "absolute right-0.5 top-0.5 flex size-5 items-center justify-center rounded-full bg-primary text-primary-foreground",
|
|
22394
22625
|
"aria-hidden": true,
|
|
22395
|
-
children: /* @__PURE__ */ jsx35(
|
|
22626
|
+
children: /* @__PURE__ */ jsx35(Check5, { className: "size-3", strokeWidth: 3 })
|
|
22396
22627
|
}
|
|
22397
22628
|
) : null
|
|
22398
22629
|
]
|
|
@@ -23417,7 +23648,7 @@ function useSectionDrag({
|
|
|
23417
23648
|
}
|
|
23418
23649
|
|
|
23419
23650
|
// src/ui/footer-container-chrome.tsx
|
|
23420
|
-
import { Plus as
|
|
23651
|
+
import { Plus as Plus4 } from "lucide-react";
|
|
23421
23652
|
import { jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
23422
23653
|
function FooterContainerChrome({
|
|
23423
23654
|
rect,
|
|
@@ -23458,7 +23689,7 @@ function FooterContainerChrome({
|
|
|
23458
23689
|
if (addDisabled) return;
|
|
23459
23690
|
onAdd();
|
|
23460
23691
|
},
|
|
23461
|
-
children: /* @__PURE__ */ jsx36(
|
|
23692
|
+
children: /* @__PURE__ */ jsx36(Plus4, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
23462
23693
|
}
|
|
23463
23694
|
) }),
|
|
23464
23695
|
/* @__PURE__ */ jsx36(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
|
|
@@ -23637,7 +23868,7 @@ function deleteSelectedNavFooterItem(deps) {
|
|
|
23637
23868
|
}
|
|
23638
23869
|
|
|
23639
23870
|
// src/ui/navbar-container-chrome.tsx
|
|
23640
|
-
import { Plus as
|
|
23871
|
+
import { Plus as Plus5 } from "lucide-react";
|
|
23641
23872
|
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
23642
23873
|
function NavbarContainerChrome({
|
|
23643
23874
|
rect,
|
|
@@ -23673,7 +23904,7 @@ function NavbarContainerChrome({
|
|
|
23673
23904
|
e.stopPropagation();
|
|
23674
23905
|
onAdd();
|
|
23675
23906
|
},
|
|
23676
|
-
children: /* @__PURE__ */ jsx37(
|
|
23907
|
+
children: /* @__PURE__ */ jsx37(Plus5, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
23677
23908
|
}
|
|
23678
23909
|
)
|
|
23679
23910
|
}
|
|
@@ -23745,7 +23976,7 @@ function Badge({ className, variant, ...props }) {
|
|
|
23745
23976
|
}
|
|
23746
23977
|
|
|
23747
23978
|
// src/OhhwellsBridge.tsx
|
|
23748
|
-
import { Brush as Brush2, Link as Link2, Plus as
|
|
23979
|
+
import { Brush as Brush2, Link as Link2, Plus as Plus6, Settings } from "lucide-react";
|
|
23749
23980
|
import { Fragment as Fragment13, jsx as jsx40, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
23750
23981
|
var PRIMARY7 = "#0885FE";
|
|
23751
23982
|
var IMAGE_FADE_MS = 300;
|
|
@@ -24522,7 +24753,7 @@ function getNavigationSelectionParent(el) {
|
|
|
24522
24753
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
24523
24754
|
return resolveFooterLinksContainerFrom(el);
|
|
24524
24755
|
}
|
|
24525
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
24756
|
+
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)) {
|
|
24526
24757
|
return getNavigationRoot(el);
|
|
24527
24758
|
}
|
|
24528
24759
|
return null;
|
|
@@ -24744,7 +24975,6 @@ var ICONS = {
|
|
|
24744
24975
|
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"/>',
|
|
24745
24976
|
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"/>'
|
|
24746
24977
|
};
|
|
24747
|
-
var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
|
|
24748
24978
|
var SELECTION_CHROME_GAP2 = 4;
|
|
24749
24979
|
var TOOLBAR_STROKE_GAP2 = 4;
|
|
24750
24980
|
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
@@ -24842,7 +25072,7 @@ function applyVisibleViewport(el, parentScroll) {
|
|
|
24842
25072
|
el.style.top = `${top}px`;
|
|
24843
25073
|
el.style.height = `${height}px`;
|
|
24844
25074
|
}
|
|
24845
|
-
var
|
|
25075
|
+
var TOOLBAR_EDGE_MARGIN4 = 4;
|
|
24846
25076
|
function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
24847
25077
|
const isAbove = transform.includes("translateY(-100%)");
|
|
24848
25078
|
let visualTop = isAbove ? top - approxH : top;
|
|
@@ -24869,8 +25099,8 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
|
24869
25099
|
function clampToolbarLeft(centerX, toolbarWidth) {
|
|
24870
25100
|
const half = toolbarWidth / 2;
|
|
24871
25101
|
return Math.max(
|
|
24872
|
-
|
|
24873
|
-
Math.min(centerX, window.innerWidth -
|
|
25102
|
+
TOOLBAR_EDGE_MARGIN4 + half,
|
|
25103
|
+
Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN4 - half)
|
|
24874
25104
|
);
|
|
24875
25105
|
}
|
|
24876
25106
|
function calcToolbarPos(rect, parentScroll, toolbarW = 306) {
|
|
@@ -25271,7 +25501,7 @@ function OhhwellsBridge() {
|
|
|
25271
25501
|
}, []);
|
|
25272
25502
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
25273
25503
|
const [subdomain, setSubdomain] = useState18(() => resolveSubdomain(subdomainFromQuery));
|
|
25274
|
-
|
|
25504
|
+
useLayoutEffect7(() => {
|
|
25275
25505
|
const next = resolveSubdomain(subdomainFromQuery);
|
|
25276
25506
|
if (next !== subdomain) setSubdomain(next);
|
|
25277
25507
|
if (next) return;
|
|
@@ -25301,6 +25531,34 @@ function OhhwellsBridge() {
|
|
|
25301
25531
|
const [fetchState, setFetchState] = useState18("idle");
|
|
25302
25532
|
const [showBranding, setShowBranding] = useState18(false);
|
|
25303
25533
|
const autoSaveTimers = useRef14(/* @__PURE__ */ new Map());
|
|
25534
|
+
useEffect17(() => {
|
|
25535
|
+
stampBridgeVersionOnDocument();
|
|
25536
|
+
}, []);
|
|
25537
|
+
useEffect17(() => {
|
|
25538
|
+
if (isEditMode) return;
|
|
25539
|
+
return armLoaderHangBeacon(subdomain, fetchState);
|
|
25540
|
+
}, [isEditMode, subdomain, fetchState]);
|
|
25541
|
+
useEffect17(() => {
|
|
25542
|
+
if (isEditMode || !subdomain) return;
|
|
25543
|
+
const onError = (event) => {
|
|
25544
|
+
reportOutageBeacon({
|
|
25545
|
+
subdomain,
|
|
25546
|
+
reason: "page_error",
|
|
25547
|
+
detail: event.message || "window error"
|
|
25548
|
+
});
|
|
25549
|
+
};
|
|
25550
|
+
const onRejection = (event) => {
|
|
25551
|
+
const reason = event.reason;
|
|
25552
|
+
const detail = reason instanceof Error ? reason.message : typeof reason === "string" ? reason : "unhandledrejection";
|
|
25553
|
+
reportOutageBeacon({ subdomain, reason: "page_error", detail });
|
|
25554
|
+
};
|
|
25555
|
+
window.addEventListener("error", onError);
|
|
25556
|
+
window.addEventListener("unhandledrejection", onRejection);
|
|
25557
|
+
return () => {
|
|
25558
|
+
window.removeEventListener("error", onError);
|
|
25559
|
+
window.removeEventListener("unhandledrejection", onRejection);
|
|
25560
|
+
};
|
|
25561
|
+
}, [isEditMode, subdomain]);
|
|
25304
25562
|
const activeElRef = useRef14(null);
|
|
25305
25563
|
const pointerHeldRef = useRef14(false);
|
|
25306
25564
|
const selectedElRef = useRef14(null);
|
|
@@ -25722,21 +25980,6 @@ function OhhwellsBridge() {
|
|
|
25722
25980
|
const [isItemDragging, setIsItemDragging] = useState18(false);
|
|
25723
25981
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = useState18(false);
|
|
25724
25982
|
isFooterFrameSelectionRef.current = isFooterFrameSelection;
|
|
25725
|
-
const [floatingPanel, setFloatingPanel] = useState18(null);
|
|
25726
|
-
const floatingPanelOpenRef = useRef14(false);
|
|
25727
|
-
floatingPanelOpenRef.current = floatingPanel !== null;
|
|
25728
|
-
const floatingPanelRef = useRef14(null);
|
|
25729
|
-
floatingPanelRef.current = floatingPanel;
|
|
25730
|
-
const [floatingPanelPos, setFloatingPanelPos] = useState18(null);
|
|
25731
|
-
const buttonCollectionDragRef = useRef14(null);
|
|
25732
|
-
const buttonDropInsertIndexRef = useRef14(null);
|
|
25733
|
-
const [buttonDropSlots, setButtonDropSlots] = useState18([]);
|
|
25734
|
-
const [activeButtonDropIndex, setActiveButtonDropIndex] = useState18(null);
|
|
25735
|
-
const buttonPointerDragRef = useRef14(null);
|
|
25736
|
-
const [buttonStyleTick, setButtonStyleTick] = useState18(0);
|
|
25737
|
-
const [logoSizeDraft, setLogoSizeDraft] = useState18(null);
|
|
25738
|
-
const [editorViewport, setEditorViewport] = useState18("desktop");
|
|
25739
|
-
const [parentScrollSnap, setParentScrollSnap] = useState18(null);
|
|
25740
25983
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState18(null);
|
|
25741
25984
|
const [footerHeadingVisible, setFooterHeadingVisible] = useState18(null);
|
|
25742
25985
|
const footerDragRef = useRef14(null);
|
|
@@ -25762,7 +26005,23 @@ function OhhwellsBridge() {
|
|
|
25762
26005
|
const stylesRef = useRef14("");
|
|
25763
26006
|
const appliedDrawerRef = useRef14(null);
|
|
25764
26007
|
const pendingDeleteUndoRef = useRef14(null);
|
|
26008
|
+
const [floatingPanel, setFloatingPanel] = useState18(null);
|
|
26009
|
+
const floatingPanelOpenRef = useRef14(false);
|
|
26010
|
+
const floatingPanelRef = useRef14(null);
|
|
26011
|
+
floatingPanelRef.current = floatingPanel;
|
|
26012
|
+
const setFloatingPanelRef = useRef14(setFloatingPanel);
|
|
26013
|
+
const [floatingPanelPos, setFloatingPanelPos] = useState18(null);
|
|
26014
|
+
const buttonCollectionDragRef = useRef14(null);
|
|
26015
|
+
const buttonDropInsertIndexRef = useRef14(null);
|
|
26016
|
+
const [buttonDropSlots, setButtonDropSlots] = useState18([]);
|
|
26017
|
+
const [activeButtonDropIndex, setActiveButtonDropIndex] = useState18(null);
|
|
26018
|
+
const buttonPointerDragRef = useRef14(null);
|
|
26019
|
+
const [buttonStyleTick, setButtonStyleTick] = useState18(0);
|
|
26020
|
+
const [logoSizeDraft, setLogoSizeDraft] = useState18(null);
|
|
26021
|
+
const [editorViewport, setEditorViewport] = useState18("desktop");
|
|
26022
|
+
const [parentScrollSnap, setParentScrollSnap] = useState18(null);
|
|
25765
26023
|
const [sitePages, setSitePages] = useState18([]);
|
|
26024
|
+
const collectionItemsRef = useRef14(/* @__PURE__ */ new Map());
|
|
25766
26025
|
const [sectionsByPath, setSectionsByPath] = useState18({});
|
|
25767
26026
|
const sectionsPrefetchGenRef = useRef14(0);
|
|
25768
26027
|
const setLinkPopoverRef = useRef14(setLinkPopover);
|
|
@@ -25770,7 +26029,18 @@ function OhhwellsBridge() {
|
|
|
25770
26029
|
const linkPopoverOpenRef = useRef14(false);
|
|
25771
26030
|
const linkPopoverGraceUntilRef = useRef14(0);
|
|
25772
26031
|
setLinkPopoverRef.current = setLinkPopover;
|
|
26032
|
+
setFloatingPanelRef.current = setFloatingPanel;
|
|
25773
26033
|
linkPopoverSessionRef.current = linkPopover;
|
|
26034
|
+
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
26035
|
+
useEffect17(() => {
|
|
26036
|
+
const syncViewport = () => {
|
|
26037
|
+
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
26038
|
+
setEditorViewport((prev) => prev === next ? prev : next);
|
|
26039
|
+
};
|
|
26040
|
+
syncViewport();
|
|
26041
|
+
window.addEventListener("resize", syncViewport);
|
|
26042
|
+
return () => window.removeEventListener("resize", syncViewport);
|
|
26043
|
+
}, []);
|
|
25774
26044
|
useEffect17(() => {
|
|
25775
26045
|
setSectionOrderPersistHandler((entries) => {
|
|
25776
26046
|
const currentPath = window.location.pathname;
|
|
@@ -25906,10 +26176,12 @@ function OhhwellsBridge() {
|
|
|
25906
26176
|
const onSitePages = (e) => {
|
|
25907
26177
|
if (e.data?.type !== "ow:site-pages" || !Array.isArray(e.data.pages)) return;
|
|
25908
26178
|
if (useFixtures) return;
|
|
25909
|
-
const
|
|
26179
|
+
const incoming = e.data.pages;
|
|
26180
|
+
const mapped = incoming.map((p) => ({
|
|
25910
26181
|
path: p.path,
|
|
25911
26182
|
title: p.title
|
|
25912
26183
|
}));
|
|
26184
|
+
collectionItemsRef.current = indexCollectionItems(incoming);
|
|
25913
26185
|
setSitePages(mapped);
|
|
25914
26186
|
runSectionsPrefetchRef.current(mapped);
|
|
25915
26187
|
};
|
|
@@ -27438,7 +27710,7 @@ function OhhwellsBridge() {
|
|
|
27438
27710
|
isFooterFrameSelection,
|
|
27439
27711
|
postToParent2
|
|
27440
27712
|
]);
|
|
27441
|
-
|
|
27713
|
+
useLayoutEffect7(() => {
|
|
27442
27714
|
if (!subdomain || isEditMode) {
|
|
27443
27715
|
setFetchState("done");
|
|
27444
27716
|
return;
|
|
@@ -27465,6 +27737,7 @@ function OhhwellsBridge() {
|
|
|
27465
27737
|
applyAiFooterFromContent(content);
|
|
27466
27738
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
27467
27739
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
27740
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
27468
27741
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
27469
27742
|
}
|
|
27470
27743
|
applyBrandChrome(content);
|
|
@@ -27475,12 +27748,12 @@ function OhhwellsBridge() {
|
|
|
27475
27748
|
if (key === "__ohw_sections") continue;
|
|
27476
27749
|
if (key === AI_SECTIONS_KEY) continue;
|
|
27477
27750
|
if (key === AI_FOOTER_KEY) continue;
|
|
27751
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
27752
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27478
27753
|
if (key === BRAND_KIT_KEY) continue;
|
|
27479
27754
|
if (key === STYLE_STORE_KEY) continue;
|
|
27480
27755
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
27481
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
27482
27756
|
if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
|
|
27483
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27484
27757
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
27485
27758
|
continue;
|
|
27486
27759
|
}
|
|
@@ -27557,7 +27830,17 @@ function OhhwellsBridge() {
|
|
|
27557
27830
|
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
27558
27831
|
const initialPath = pathname;
|
|
27559
27832
|
fetchedContentPaths.add(`${subdomain}::${initialPath}`);
|
|
27560
|
-
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) =>
|
|
27833
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => {
|
|
27834
|
+
if (!r2.ok) {
|
|
27835
|
+
reportOutageBeacon({
|
|
27836
|
+
subdomain,
|
|
27837
|
+
reason: "content_fetch_failed",
|
|
27838
|
+
detail: `HTTP ${r2.status}`
|
|
27839
|
+
});
|
|
27840
|
+
return null;
|
|
27841
|
+
}
|
|
27842
|
+
return r2.json();
|
|
27843
|
+
}).then((data) => {
|
|
27561
27844
|
if (cancelled) return;
|
|
27562
27845
|
const content = data?.content ?? {};
|
|
27563
27846
|
const branding = Boolean(data?.showBranding);
|
|
@@ -27566,7 +27849,12 @@ function OhhwellsBridge() {
|
|
|
27566
27849
|
recordOverriddenPaths(subdomain, data?.overriddenPaths);
|
|
27567
27850
|
setShowBranding(branding);
|
|
27568
27851
|
return applyContent(content);
|
|
27569
|
-
}).catch(() => {
|
|
27852
|
+
}).catch((err) => {
|
|
27853
|
+
reportOutageBeacon({
|
|
27854
|
+
subdomain,
|
|
27855
|
+
reason: "content_fetch_failed",
|
|
27856
|
+
detail: err instanceof Error ? err.message : "fetch failed"
|
|
27857
|
+
});
|
|
27570
27858
|
}).finally(() => {
|
|
27571
27859
|
if (!cancelled) setFetchState("done");
|
|
27572
27860
|
});
|
|
@@ -27696,17 +27984,18 @@ function OhhwellsBridge() {
|
|
|
27696
27984
|
}
|
|
27697
27985
|
applyAiFooterFromContent(content);
|
|
27698
27986
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
27987
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
27699
27988
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
27700
27989
|
}
|
|
27701
27990
|
for (const [key, val] of Object.entries(content)) {
|
|
27702
27991
|
if (key === "__ohw_sections") continue;
|
|
27703
27992
|
if (key === AI_SECTIONS_KEY) continue;
|
|
27704
27993
|
if (key === AI_FOOTER_KEY) continue;
|
|
27994
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
27995
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27705
27996
|
if (key === BRAND_KIT_KEY) continue;
|
|
27706
27997
|
if (key === STYLE_STORE_KEY) continue;
|
|
27707
27998
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
27708
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
27709
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27710
27999
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
27711
28000
|
continue;
|
|
27712
28001
|
}
|
|
@@ -27789,7 +28078,7 @@ function OhhwellsBridge() {
|
|
|
27789
28078
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
27790
28079
|
};
|
|
27791
28080
|
}, [subdomain, isEditMode, pathname]);
|
|
27792
|
-
|
|
28081
|
+
useLayoutEffect7(() => {
|
|
27793
28082
|
const el = document.getElementById("ohw-loader");
|
|
27794
28083
|
if (!el) return;
|
|
27795
28084
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
@@ -27973,26 +28262,11 @@ function OhhwellsBridge() {
|
|
|
27973
28262
|
const t2 = setTimeout(measure, 500);
|
|
27974
28263
|
const ro = new ResizeObserver(schedule);
|
|
27975
28264
|
ro.observe(document.body);
|
|
27976
|
-
let lastWidth = window.innerWidth;
|
|
27977
|
-
let resizeTimers = [];
|
|
27978
|
-
const clearResizeTimers = () => {
|
|
27979
|
-
resizeTimers.forEach(clearTimeout);
|
|
27980
|
-
resizeTimers = [];
|
|
27981
|
-
};
|
|
27982
|
-
const handleResize = () => {
|
|
27983
|
-
if (window.innerWidth === lastWidth) return;
|
|
27984
|
-
lastWidth = window.innerWidth;
|
|
27985
|
-
clearResizeTimers();
|
|
27986
|
-
resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
|
|
27987
|
-
};
|
|
27988
|
-
window.addEventListener("resize", handleResize);
|
|
27989
28265
|
return () => {
|
|
27990
28266
|
clearTimeout(t1);
|
|
27991
28267
|
clearTimeout(t2);
|
|
27992
28268
|
if (raf != null) cancelAnimationFrame(raf);
|
|
27993
28269
|
ro.disconnect();
|
|
27994
|
-
clearResizeTimers();
|
|
27995
|
-
window.removeEventListener("resize", handleResize);
|
|
27996
28270
|
};
|
|
27997
28271
|
}, [pathname, isEditMode, postToParent2]);
|
|
27998
28272
|
useEffect17(() => {
|
|
@@ -28289,6 +28563,13 @@ function OhhwellsBridge() {
|
|
|
28289
28563
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
28290
28564
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
28291
28565
|
if (isInsideLinkEditor(target)) return;
|
|
28566
|
+
if (isInsideFloatingPanel(target)) return;
|
|
28567
|
+
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
28568
|
+
if (target.closest(
|
|
28569
|
+
'[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
|
|
28570
|
+
)) {
|
|
28571
|
+
return;
|
|
28572
|
+
}
|
|
28292
28573
|
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
28293
28574
|
clearMediaSelectionRef.current();
|
|
28294
28575
|
}
|
|
@@ -28312,11 +28593,15 @@ function OhhwellsBridge() {
|
|
|
28312
28593
|
return;
|
|
28313
28594
|
}
|
|
28314
28595
|
}
|
|
28315
|
-
|
|
28316
|
-
if (
|
|
28317
|
-
|
|
28318
|
-
|
|
28319
|
-
|
|
28596
|
+
const collectionItem = matchCollectionItemClick(target, collectionItemsRef.current);
|
|
28597
|
+
if (collectionItem) {
|
|
28598
|
+
e.preventDefault();
|
|
28599
|
+
e.stopPropagation();
|
|
28600
|
+
postToParentRef.current({
|
|
28601
|
+
type: "ow:collection-item-selected",
|
|
28602
|
+
path: collectionItem.path,
|
|
28603
|
+
collection: collectionItem.collection
|
|
28604
|
+
});
|
|
28320
28605
|
return;
|
|
28321
28606
|
}
|
|
28322
28607
|
{
|
|
@@ -28472,9 +28757,13 @@ function OhhwellsBridge() {
|
|
|
28472
28757
|
if (isIconEditable(editable) && !getSocialItem(editable)) {
|
|
28473
28758
|
e.preventDefault();
|
|
28474
28759
|
e.stopPropagation();
|
|
28475
|
-
selectIconElementRef.current(editable);
|
|
28476
28760
|
const aiIcon = editable.hasAttribute("data-ai-icon");
|
|
28477
28761
|
const featureIcon = aiIcon && /\.features\.\d+\.icon$/.test(editable.dataset.ohwKey ?? "");
|
|
28762
|
+
if (aiIcon) {
|
|
28763
|
+
aiSectionApiRef.current?.selectFromElement(editable);
|
|
28764
|
+
} else {
|
|
28765
|
+
selectIconElementRef.current(editable);
|
|
28766
|
+
}
|
|
28478
28767
|
postToParentRef.current({
|
|
28479
28768
|
type: "ow:icon-pick",
|
|
28480
28769
|
key: editable.dataset.ohwKey ?? "",
|
|
@@ -28702,6 +28991,9 @@ function OhhwellsBridge() {
|
|
|
28702
28991
|
setHoveredItemRect(null);
|
|
28703
28992
|
hoveredNavContainerRef.current = null;
|
|
28704
28993
|
setHoveredNavContainerRect(null);
|
|
28994
|
+
siblingHintElRef.current = null;
|
|
28995
|
+
setSiblingHintRect(null);
|
|
28996
|
+
setSiblingHintRects([]);
|
|
28705
28997
|
return;
|
|
28706
28998
|
}
|
|
28707
28999
|
{
|
|
@@ -28822,7 +29114,6 @@ function OhhwellsBridge() {
|
|
|
28822
29114
|
hoveredNavContainerRef.current = null;
|
|
28823
29115
|
setHoveredNavContainerRect(null);
|
|
28824
29116
|
hoveredItemElRef.current = editable;
|
|
28825
|
-
setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
|
|
28826
29117
|
}
|
|
28827
29118
|
}
|
|
28828
29119
|
}
|
|
@@ -29532,7 +29823,11 @@ function OhhwellsBridge() {
|
|
|
29532
29823
|
};
|
|
29533
29824
|
const handleMouseMove = (e) => {
|
|
29534
29825
|
const { clientX, clientY } = e;
|
|
29535
|
-
if (pointOwnedByFloatingPanel(clientX, clientY))
|
|
29826
|
+
if (pointOwnedByFloatingPanel(clientX, clientY)) {
|
|
29827
|
+
dismissImageHover();
|
|
29828
|
+
clearImageHover();
|
|
29829
|
+
return;
|
|
29830
|
+
}
|
|
29536
29831
|
if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
|
|
29537
29832
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
29538
29833
|
formHoverElRef.current = null;
|
|
@@ -29561,7 +29856,12 @@ function OhhwellsBridge() {
|
|
|
29561
29856
|
setHoveredItemRect(null);
|
|
29562
29857
|
hoveredNavContainerRef.current = null;
|
|
29563
29858
|
setHoveredNavContainerRect(null);
|
|
29859
|
+
siblingHintElRef.current = null;
|
|
29860
|
+
setSiblingHintRect(null);
|
|
29861
|
+
setSiblingHintRects([]);
|
|
29564
29862
|
dismissImageHover();
|
|
29863
|
+
clearImageHover();
|
|
29864
|
+
setSectionGap(null);
|
|
29565
29865
|
return;
|
|
29566
29866
|
}
|
|
29567
29867
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
@@ -29573,7 +29873,11 @@ function OhhwellsBridge() {
|
|
|
29573
29873
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
29574
29874
|
const { clientX, clientY } = e.data;
|
|
29575
29875
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
29576
|
-
if (pointOwnedByFloatingPanel(clientX, clientY))
|
|
29876
|
+
if (pointOwnedByFloatingPanel(clientX, clientY)) {
|
|
29877
|
+
dismissImageHover();
|
|
29878
|
+
clearImageHover();
|
|
29879
|
+
return;
|
|
29880
|
+
}
|
|
29577
29881
|
if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
|
|
29578
29882
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
29579
29883
|
probeSectionGapAt(clientX, clientY);
|
|
@@ -29953,6 +30257,7 @@ function OhhwellsBridge() {
|
|
|
29953
30257
|
applyAiFooterFromContent(content);
|
|
29954
30258
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
29955
30259
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
30260
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
29956
30261
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
29957
30262
|
}
|
|
29958
30263
|
applyBrandChrome(content);
|
|
@@ -29967,12 +30272,12 @@ function OhhwellsBridge() {
|
|
|
29967
30272
|
}
|
|
29968
30273
|
if (key === AI_SECTIONS_KEY) continue;
|
|
29969
30274
|
if (key === AI_FOOTER_KEY) continue;
|
|
30275
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
30276
|
+
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
29970
30277
|
if (key === BRAND_KIT_KEY) continue;
|
|
29971
30278
|
if (key === STYLE_STORE_KEY) continue;
|
|
29972
30279
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
29973
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
29974
30280
|
if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
|
|
29975
|
-
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
29976
30281
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
29977
30282
|
continue;
|
|
29978
30283
|
}
|
|
@@ -30608,12 +30913,24 @@ function OhhwellsBridge() {
|
|
|
30608
30913
|
closeLinkPopoverRef.current();
|
|
30609
30914
|
return;
|
|
30610
30915
|
}
|
|
30916
|
+
if (floatingPanelOpenRef.current) {
|
|
30917
|
+
setFloatingPanelRef.current(null);
|
|
30918
|
+
deselectRef.current();
|
|
30919
|
+
deactivateRef.current();
|
|
30920
|
+
return;
|
|
30921
|
+
}
|
|
30611
30922
|
deselectRef.current();
|
|
30612
30923
|
deactivateRef.current();
|
|
30613
30924
|
clearMediaSelectionRef.current();
|
|
30614
30925
|
clearIconSelectionRef.current();
|
|
30615
30926
|
};
|
|
30616
30927
|
window.addEventListener("message", handleDeactivate);
|
|
30928
|
+
const handleSelectNav = (e) => {
|
|
30929
|
+
if (e.data?.type !== "ow:select-nav") return;
|
|
30930
|
+
const navContainer = findSelectableNavContainer();
|
|
30931
|
+
if (navContainer) selectFrameRef.current(navContainer);
|
|
30932
|
+
};
|
|
30933
|
+
window.addEventListener("message", handleSelectNav);
|
|
30617
30934
|
const handleToastAction = (e) => {
|
|
30618
30935
|
if (e.data?.type !== "ow:toast-action") return;
|
|
30619
30936
|
const actionId = typeof e.data.actionId === "string" ? e.data.actionId : null;
|
|
@@ -31430,10 +31747,11 @@ function OhhwellsBridge() {
|
|
|
31430
31747
|
window.removeEventListener("message", handleDeleteSection);
|
|
31431
31748
|
window.removeEventListener("message", handleDuplicateSection);
|
|
31432
31749
|
window.removeEventListener("message", handleDeactivate);
|
|
31433
|
-
|
|
31750
|
+
window.removeEventListener("message", handleSelectNav);
|
|
31434
31751
|
window.removeEventListener("message", handleToastAction);
|
|
31435
31752
|
window.removeEventListener("message", handleFormCount);
|
|
31436
31753
|
window.removeEventListener("message", handleUiEscape);
|
|
31754
|
+
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
31437
31755
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
31438
31756
|
autoSaveTimers.current.clear();
|
|
31439
31757
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
@@ -31727,7 +32045,7 @@ function OhhwellsBridge() {
|
|
|
31727
32045
|
postToParent2({
|
|
31728
32046
|
type: "ow:ready",
|
|
31729
32047
|
version: "1",
|
|
31730
|
-
bridgeVersion: "0.1.
|
|
32048
|
+
bridgeVersion: "0.1.153-next.417",
|
|
31731
32049
|
path: pathname,
|
|
31732
32050
|
nodes: collectEditableNodes(editContentRef.current),
|
|
31733
32051
|
sections
|
|
@@ -32462,7 +32780,7 @@ function OhhwellsBridge() {
|
|
|
32462
32780
|
className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
|
|
32463
32781
|
onClick: () => setFieldTypePickerOpen((open) => !open),
|
|
32464
32782
|
"data-ohw-add-field": "",
|
|
32465
|
-
children: /* @__PURE__ */ jsx40(
|
|
32783
|
+
children: /* @__PURE__ */ jsx40(Plus6, { size: 15, "aria-hidden": true })
|
|
32466
32784
|
}
|
|
32467
32785
|
),
|
|
32468
32786
|
/* @__PURE__ */ jsx40("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
@@ -32952,6 +33270,7 @@ export {
|
|
|
32952
33270
|
foldAlignIntoTrees,
|
|
32953
33271
|
getEditModeInitialState,
|
|
32954
33272
|
hasMountedContentNodes,
|
|
33273
|
+
indexCollectionItems,
|
|
32955
33274
|
insertFooterHours,
|
|
32956
33275
|
isEditSessionActive,
|
|
32957
33276
|
isPlainLeftClick,
|
|
@@ -32959,6 +33278,7 @@ export {
|
|
|
32959
33278
|
isRenderableTree,
|
|
32960
33279
|
isStickySearchParam,
|
|
32961
33280
|
isValidUrl,
|
|
33281
|
+
matchCollectionItemClick,
|
|
32962
33282
|
nextViableSlide,
|
|
32963
33283
|
parseAiFooterState,
|
|
32964
33284
|
parseAiSectionsState,
|