@ohhwells/bridge 0.1.152 → 0.1.153-next.415
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 +1186 -884
- 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 +1249 -933
- 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,103 @@ 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.415";
|
|
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.415" : "";
|
|
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 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;
|
|
17171
|
+
function isVercelPreviewHost() {
|
|
17172
|
+
if (typeof location === "undefined") {
|
|
17173
|
+
return false;
|
|
17174
|
+
}
|
|
17175
|
+
return location.hostname.toLowerCase().endsWith(".vercel.ohhwells.site");
|
|
17176
|
+
}
|
|
17177
|
+
function reportOutageBeacon(args) {
|
|
17178
|
+
if (typeof window === "undefined" || !args.subdomain) {
|
|
17179
|
+
return;
|
|
17180
|
+
}
|
|
17181
|
+
if (isVercelPreviewHost()) {
|
|
17182
|
+
return;
|
|
17183
|
+
}
|
|
17184
|
+
if (args.reason === "page_error" && args.detail && RECOVERABLE_PAGE_ERROR.test(args.detail)) {
|
|
17185
|
+
return;
|
|
17186
|
+
}
|
|
17187
|
+
const key = `${args.subdomain}|${args.reason}`;
|
|
17188
|
+
const now = Date.now();
|
|
17189
|
+
const prev = lastSent.get(key) || 0;
|
|
17190
|
+
if (now - prev < DEDUP_MS) {
|
|
17191
|
+
return;
|
|
17192
|
+
}
|
|
17193
|
+
lastSent.set(key, now);
|
|
17194
|
+
const body = JSON.stringify({
|
|
17195
|
+
subdomain: args.subdomain,
|
|
17196
|
+
reason: args.reason,
|
|
17197
|
+
detail: args.detail?.slice(0, 300),
|
|
17198
|
+
templateId: args.templateId,
|
|
17199
|
+
bridgeVersion: bridgeVersion(),
|
|
17200
|
+
href: typeof location !== "undefined" ? location.href : void 0
|
|
17201
|
+
});
|
|
17202
|
+
const url = `${apiBase()}/api/public/sites/outage-beacon`;
|
|
17203
|
+
try {
|
|
17204
|
+
if (typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function") {
|
|
17205
|
+
const blob = new Blob([body], { type: "application/json" });
|
|
17206
|
+
if (navigator.sendBeacon(url, blob)) {
|
|
17207
|
+
return;
|
|
17208
|
+
}
|
|
17209
|
+
}
|
|
17210
|
+
void fetch(url, {
|
|
17211
|
+
method: "POST",
|
|
17212
|
+
headers: { "Content-Type": "application/json" },
|
|
17213
|
+
body,
|
|
17214
|
+
keepalive: true,
|
|
17215
|
+
cache: "no-store"
|
|
17216
|
+
}).catch(() => {
|
|
17217
|
+
});
|
|
17218
|
+
} catch {
|
|
17219
|
+
}
|
|
17220
|
+
}
|
|
17221
|
+
function armLoaderHangBeacon(subdomain, fetchState, hangMs = 15e3) {
|
|
17222
|
+
if (!subdomain || fetchState !== "loading") {
|
|
17223
|
+
return () => {
|
|
17224
|
+
};
|
|
17225
|
+
}
|
|
17226
|
+
const timer = window.setTimeout(() => {
|
|
17227
|
+
reportOutageBeacon({
|
|
17228
|
+
subdomain,
|
|
17229
|
+
reason: "loader_stuck",
|
|
17230
|
+
detail: `fetchState still loading after ${hangMs}ms`
|
|
17231
|
+
});
|
|
17232
|
+
}, hangMs);
|
|
17233
|
+
return () => window.clearTimeout(timer);
|
|
17234
|
+
}
|
|
17235
|
+
|
|
16913
17236
|
// src/lib/form-fields.ts
|
|
16914
17237
|
var FIELD_DEFAULTS = {
|
|
16915
17238
|
"short-text": { label: "Short text", placeholder: "Type placeholder text..." },
|
|
@@ -17510,6 +17833,7 @@ function MediaOverlay({
|
|
|
17510
17833
|
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
17511
17834
|
);
|
|
17512
17835
|
}, [isVideo]);
|
|
17836
|
+
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
17513
17837
|
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
17514
17838
|
const box = {
|
|
17515
17839
|
position: "fixed",
|
|
@@ -17608,11 +17932,10 @@ function MediaOverlay({
|
|
|
17608
17932
|
className: "flex items-center justify-center cursor-pointer",
|
|
17609
17933
|
style: {
|
|
17610
17934
|
...box,
|
|
17611
|
-
//
|
|
17612
|
-
//
|
|
17613
|
-
//
|
|
17614
|
-
|
|
17615
|
-
pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
|
|
17935
|
+
// Visual only. `pointer-events: auto` on this full-bleed rect covered the navbar
|
|
17936
|
+
// (hero bg includes the absolute TopNav) and swallowed CTA press-drag. Text overlay
|
|
17937
|
+
// and cueOnly also need clicks to fall through — Replace / video controls opt back in.
|
|
17938
|
+
pointerEvents: "none",
|
|
17616
17939
|
// Selected: a firm component ring with no wash, so the image reads as chosen rather
|
|
17617
17940
|
// than hovered. Hover keeps the existing tinted preview.
|
|
17618
17941
|
boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
@@ -17639,17 +17962,17 @@ function MediaOverlay({
|
|
|
17639
17962
|
},
|
|
17640
17963
|
children: [
|
|
17641
17964
|
isVideo ? /* @__PURE__ */ jsx17(Film, { size: 14 }) : /* @__PURE__ */ jsx17(ImageIcon, { size: 14 }),
|
|
17642
|
-
|
|
17965
|
+
replaceLabel
|
|
17643
17966
|
]
|
|
17644
17967
|
}
|
|
17645
17968
|
),
|
|
17646
|
-
replaceMode
|
|
17969
|
+
showChrome && replaceMode !== "none" && /* @__PURE__ */ jsxs8(
|
|
17647
17970
|
Button,
|
|
17648
17971
|
{
|
|
17649
17972
|
"data-ohw-media-overlay": "",
|
|
17650
17973
|
variant: "outline",
|
|
17651
17974
|
size: "sm",
|
|
17652
|
-
"aria-label":
|
|
17975
|
+
"aria-label": replaceLabel,
|
|
17653
17976
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
17654
17977
|
style: {
|
|
17655
17978
|
...OVERLAY_BUTTON_STYLE,
|
|
@@ -17672,7 +17995,7 @@ function MediaOverlay({
|
|
|
17672
17995
|
},
|
|
17673
17996
|
children: [
|
|
17674
17997
|
isVideo ? /* @__PURE__ */ jsx17(Film, { size: 14 }) : /* @__PURE__ */ jsx17(ImageIcon, { size: 14 }),
|
|
17675
|
-
replaceMode === "full" ?
|
|
17998
|
+
replaceMode === "full" ? replaceLabel : null
|
|
17676
17999
|
]
|
|
17677
18000
|
}
|
|
17678
18001
|
)
|
|
@@ -18181,8 +18504,24 @@ function AiSectionOverlay({
|
|
|
18181
18504
|
}
|
|
18182
18505
|
|
|
18183
18506
|
// src/ui/ai-section/AiMediaStripOverlay.tsx
|
|
18184
|
-
import { useCallback as useCallback3, useEffect as useEffect6, useRef as useRef5, useState as useState8 } from "react";
|
|
18185
|
-
import {
|
|
18507
|
+
import { useCallback as useCallback3, useEffect as useEffect6, useLayoutEffect as useLayoutEffect4, useRef as useRef5, useState as useState8 } from "react";
|
|
18508
|
+
import {
|
|
18509
|
+
AlignCenter,
|
|
18510
|
+
AlignLeft,
|
|
18511
|
+
AlignRight,
|
|
18512
|
+
ArrowLeft as ArrowLeft2,
|
|
18513
|
+
ArrowRight as ArrowRight2,
|
|
18514
|
+
Check as Check2,
|
|
18515
|
+
ChevronDown as ChevronDown3,
|
|
18516
|
+
Image as ImageIcon2,
|
|
18517
|
+
ImageMinus,
|
|
18518
|
+
ImagePlus,
|
|
18519
|
+
Link as LinkIcon,
|
|
18520
|
+
Minus,
|
|
18521
|
+
Palette,
|
|
18522
|
+
Plus as Plus2,
|
|
18523
|
+
Star
|
|
18524
|
+
} from "lucide-react";
|
|
18186
18525
|
|
|
18187
18526
|
// src/lib/ai-media-strip-tree.ts
|
|
18188
18527
|
var MEDIA_STRIP_ITEM_MIN = 1;
|
|
@@ -18296,14 +18635,6 @@ function setMediaStripItemAsset(tree, index, assetId) {
|
|
|
18296
18635
|
return true;
|
|
18297
18636
|
});
|
|
18298
18637
|
}
|
|
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
18638
|
function setMediaStripItemLink(tree, index, link) {
|
|
18308
18639
|
return withMediaStrip(tree, (block) => {
|
|
18309
18640
|
const items = block.items;
|
|
@@ -18321,41 +18652,168 @@ function setMediaStripItemLink(tree, index, link) {
|
|
|
18321
18652
|
});
|
|
18322
18653
|
}
|
|
18323
18654
|
|
|
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;
|
|
18655
|
+
// src/ui/dialog.tsx
|
|
18656
|
+
import * as React9 from "react";
|
|
18657
|
+
import { Dialog as DialogPrimitive } from "radix-ui";
|
|
18658
|
+
import { X as X2 } from "lucide-react";
|
|
18659
|
+
import { jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
18660
|
+
function Dialog2({
|
|
18661
|
+
...props
|
|
18662
|
+
}) {
|
|
18663
|
+
return /* @__PURE__ */ jsx20(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
|
|
18337
18664
|
}
|
|
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 };
|
|
18665
|
+
function DialogPortal({
|
|
18666
|
+
...props
|
|
18667
|
+
}) {
|
|
18668
|
+
return /* @__PURE__ */ jsx20(DialogPrimitive.Portal, { ...props });
|
|
18344
18669
|
}
|
|
18345
|
-
function
|
|
18346
|
-
|
|
18347
|
-
|
|
18348
|
-
|
|
18349
|
-
|
|
18350
|
-
|
|
18670
|
+
function DialogOverlay({
|
|
18671
|
+
className,
|
|
18672
|
+
...props
|
|
18673
|
+
}) {
|
|
18674
|
+
return /* @__PURE__ */ jsx20(
|
|
18675
|
+
DialogPrimitive.Overlay,
|
|
18676
|
+
{
|
|
18677
|
+
"data-slot": "dialog-overlay",
|
|
18678
|
+
"data-ohw-link-modal-root": "",
|
|
18679
|
+
className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
|
|
18680
|
+
...props
|
|
18351
18681
|
}
|
|
18352
|
-
|
|
18353
|
-
|
|
18354
|
-
|
|
18355
|
-
|
|
18356
|
-
|
|
18357
|
-
|
|
18358
|
-
|
|
18682
|
+
);
|
|
18683
|
+
}
|
|
18684
|
+
var DialogContent = React9.forwardRef(
|
|
18685
|
+
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
18686
|
+
const positionMode = container ? "absolute" : "fixed";
|
|
18687
|
+
return /* @__PURE__ */ jsxs11(DialogPortal, { container: container ?? void 0, children: [
|
|
18688
|
+
/* @__PURE__ */ jsx20(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
18689
|
+
/* @__PURE__ */ jsxs11(
|
|
18690
|
+
DialogPrimitive.Content,
|
|
18691
|
+
{
|
|
18692
|
+
ref,
|
|
18693
|
+
"data-slot": "dialog-content",
|
|
18694
|
+
className: cn(
|
|
18695
|
+
positionMode,
|
|
18696
|
+
"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",
|
|
18697
|
+
"rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
|
|
18698
|
+
container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
|
|
18699
|
+
className
|
|
18700
|
+
),
|
|
18701
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
18702
|
+
...props,
|
|
18703
|
+
children: [
|
|
18704
|
+
children,
|
|
18705
|
+
showCloseButton ? /* @__PURE__ */ jsx20(
|
|
18706
|
+
DialogPrimitive.Close,
|
|
18707
|
+
{
|
|
18708
|
+
type: "button",
|
|
18709
|
+
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
18710
|
+
"aria-label": "Close",
|
|
18711
|
+
children: /* @__PURE__ */ jsx20(X2, { size: 16, "aria-hidden": true })
|
|
18712
|
+
}
|
|
18713
|
+
) : null
|
|
18714
|
+
]
|
|
18715
|
+
}
|
|
18716
|
+
)
|
|
18717
|
+
] });
|
|
18718
|
+
}
|
|
18719
|
+
);
|
|
18720
|
+
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
18721
|
+
function DialogHeader({
|
|
18722
|
+
className,
|
|
18723
|
+
...props
|
|
18724
|
+
}) {
|
|
18725
|
+
return /* @__PURE__ */ jsx20("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
18726
|
+
}
|
|
18727
|
+
function DialogFooter({
|
|
18728
|
+
className,
|
|
18729
|
+
...props
|
|
18730
|
+
}) {
|
|
18731
|
+
return /* @__PURE__ */ jsx20(
|
|
18732
|
+
"div",
|
|
18733
|
+
{
|
|
18734
|
+
className: cn("flex items-center justify-end gap-2", className),
|
|
18735
|
+
...props
|
|
18736
|
+
}
|
|
18737
|
+
);
|
|
18738
|
+
}
|
|
18739
|
+
var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
|
|
18740
|
+
DialogPrimitive.Title,
|
|
18741
|
+
{
|
|
18742
|
+
ref,
|
|
18743
|
+
className: cn(
|
|
18744
|
+
"text-lg font-semibold leading-none tracking-tight text-card-foreground",
|
|
18745
|
+
className
|
|
18746
|
+
),
|
|
18747
|
+
...props
|
|
18748
|
+
}
|
|
18749
|
+
));
|
|
18750
|
+
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
18751
|
+
var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
|
|
18752
|
+
DialogPrimitive.Description,
|
|
18753
|
+
{
|
|
18754
|
+
ref,
|
|
18755
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
18756
|
+
...props
|
|
18757
|
+
}
|
|
18758
|
+
));
|
|
18759
|
+
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
18760
|
+
var DialogClose = DialogPrimitive.Close;
|
|
18761
|
+
|
|
18762
|
+
// src/ui/ai-section/AiMediaStripOverlay.tsx
|
|
18763
|
+
import { Fragment as Fragment7, jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
18764
|
+
var PRIMARY3 = "var(--ohw-primary, #0885FE)";
|
|
18765
|
+
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]";
|
|
18766
|
+
function findMediaStripItemElement(sectionId, index) {
|
|
18767
|
+
const sectionEl = findByInstanceId(sectionId);
|
|
18768
|
+
if (!sectionEl) return null;
|
|
18769
|
+
const items = sectionEl.querySelectorAll("[data-ohw-media-strip-item]");
|
|
18770
|
+
for (const el of Array.from(items)) {
|
|
18771
|
+
if (Number(el.dataset.ohwMediaStripIndex) === index) return el;
|
|
18772
|
+
}
|
|
18773
|
+
return null;
|
|
18774
|
+
}
|
|
18775
|
+
function itemRefFromTarget(target) {
|
|
18776
|
+
if (!(target instanceof Element)) return null;
|
|
18777
|
+
if (target.closest(CHROME_SELECTOR)) return null;
|
|
18778
|
+
const itemEl = target.closest("[data-ohw-media-strip-item]");
|
|
18779
|
+
if (!itemEl) return null;
|
|
18780
|
+
const sectionEl = itemEl.closest("[data-ohw-section]");
|
|
18781
|
+
const unit = sectionEl ? movableUnit(sectionEl) : null;
|
|
18782
|
+
const sectionId = unit ? instanceIdOf(unit) || null : null;
|
|
18783
|
+
const index = Number(itemEl.dataset.ohwMediaStripIndex);
|
|
18784
|
+
if (!sectionId || Number.isNaN(index)) return null;
|
|
18785
|
+
return { sectionId, index };
|
|
18786
|
+
}
|
|
18787
|
+
function sameRef(a, b) {
|
|
18788
|
+
return a?.sectionId === b?.sectionId && a?.index === b?.index;
|
|
18789
|
+
}
|
|
18790
|
+
function rectOf(el) {
|
|
18791
|
+
if (!el) return null;
|
|
18792
|
+
const r2 = el.getBoundingClientRect();
|
|
18793
|
+
if (r2.width <= 0 || r2.height <= 0) return null;
|
|
18794
|
+
return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
|
|
18795
|
+
}
|
|
18796
|
+
function readRect2(ref) {
|
|
18797
|
+
return rectOf(ref && findMediaStripItemElement(ref.sectionId, ref.index));
|
|
18798
|
+
}
|
|
18799
|
+
function readStripRect(ref) {
|
|
18800
|
+
const item = ref && findMediaStripItemElement(ref.sectionId, ref.index);
|
|
18801
|
+
return rectOf(item?.closest("[data-ohw-media-strip]") ?? item);
|
|
18802
|
+
}
|
|
18803
|
+
function useLiveItemRect(ref, strip = false) {
|
|
18804
|
+
const [rect, setRect] = useState8(null);
|
|
18805
|
+
useEffect6(() => {
|
|
18806
|
+
if (!ref) {
|
|
18807
|
+
setRect(null);
|
|
18808
|
+
return;
|
|
18809
|
+
}
|
|
18810
|
+
const update = () => {
|
|
18811
|
+
const next = strip ? readStripRect(ref) : readRect2(ref);
|
|
18812
|
+
setRect(
|
|
18813
|
+
(prev) => prev && next && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
|
|
18814
|
+
);
|
|
18815
|
+
};
|
|
18816
|
+
update();
|
|
18359
18817
|
const opts = { capture: true, passive: true };
|
|
18360
18818
|
window.addEventListener("scroll", update, opts);
|
|
18361
18819
|
window.addEventListener("resize", update);
|
|
@@ -18365,9 +18823,49 @@ function useLiveItemRect(ref) {
|
|
|
18365
18823
|
window.removeEventListener("resize", update);
|
|
18366
18824
|
clearInterval(interval);
|
|
18367
18825
|
};
|
|
18368
|
-
}, [ref?.sectionId, ref?.index]);
|
|
18826
|
+
}, [ref?.sectionId, ref?.index, strip]);
|
|
18369
18827
|
return rect;
|
|
18370
18828
|
}
|
|
18829
|
+
var TOOLBAR_STRIP_GAP = 52;
|
|
18830
|
+
var TOOLBAR_STRIP_GAP_MOBILE = 42;
|
|
18831
|
+
var TOOLBAR_EDGE_MARGIN2 = 4;
|
|
18832
|
+
function StripToolbarSlot({ stripRect, children }) {
|
|
18833
|
+
const slotRef = useRef5(null);
|
|
18834
|
+
const [shift, setShift] = useState8(0);
|
|
18835
|
+
const centerX = stripRect.left + stripRect.width / 2;
|
|
18836
|
+
useLayoutEffect4(() => {
|
|
18837
|
+
const slot = slotRef.current;
|
|
18838
|
+
if (!slot) return;
|
|
18839
|
+
const clamp = () => {
|
|
18840
|
+
const w = slot.offsetWidth;
|
|
18841
|
+
if (w <= 0) return;
|
|
18842
|
+
const half = w / 2;
|
|
18843
|
+
const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
|
|
18844
|
+
setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
|
|
18845
|
+
};
|
|
18846
|
+
clamp();
|
|
18847
|
+
const ro = new ResizeObserver(clamp);
|
|
18848
|
+
ro.observe(slot);
|
|
18849
|
+
return () => ro.disconnect();
|
|
18850
|
+
}, [centerX, children]);
|
|
18851
|
+
const mobile = window.innerWidth <= 480;
|
|
18852
|
+
return /* @__PURE__ */ jsx21(
|
|
18853
|
+
"div",
|
|
18854
|
+
{
|
|
18855
|
+
ref: slotRef,
|
|
18856
|
+
"data-ohw-bridge": "",
|
|
18857
|
+
"data-ohw-item-interaction": "",
|
|
18858
|
+
className: "pointer-events-auto fixed",
|
|
18859
|
+
style: {
|
|
18860
|
+
top: stripRect.top - (mobile ? TOOLBAR_STRIP_GAP_MOBILE : TOOLBAR_STRIP_GAP),
|
|
18861
|
+
left: centerX + shift,
|
|
18862
|
+
transform: "translate(-50%, -100%)",
|
|
18863
|
+
zIndex: 2147483645
|
|
18864
|
+
},
|
|
18865
|
+
children
|
|
18866
|
+
}
|
|
18867
|
+
);
|
|
18868
|
+
}
|
|
18371
18869
|
function requestValidateTree(postToParent2, tree) {
|
|
18372
18870
|
return new Promise((resolve) => {
|
|
18373
18871
|
const id = `ai-validate-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -18404,116 +18902,72 @@ function requestAssetPick(postToParent2) {
|
|
|
18404
18902
|
postToParent2({ type: "ow:asset-pick", id });
|
|
18405
18903
|
});
|
|
18406
18904
|
}
|
|
18407
|
-
function
|
|
18905
|
+
function ToolbarAction({
|
|
18408
18906
|
label,
|
|
18409
18907
|
onClick,
|
|
18410
|
-
disabled,
|
|
18411
|
-
active
|
|
18908
|
+
disabled = false,
|
|
18909
|
+
active = false,
|
|
18910
|
+
children
|
|
18412
18911
|
}) {
|
|
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
|
-
);
|
|
18912
|
+
const button = /* @__PURE__ */ jsx21(CustomToolbarButton, { type: "button", "aria-label": label, disabled, active, onClick, className: "size-8", children });
|
|
18913
|
+
return /* @__PURE__ */ jsxs12(Tooltip, { children: [
|
|
18914
|
+
/* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx21("span", { className: "inline-flex", children: button }) : button }),
|
|
18915
|
+
/* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
|
|
18916
|
+
] });
|
|
18440
18917
|
}
|
|
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",
|
|
18918
|
+
function ToolbarSeparator() {
|
|
18919
|
+
return /* @__PURE__ */ jsx21("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
|
|
18920
|
+
}
|
|
18921
|
+
function OptionMenu({
|
|
18922
|
+
label,
|
|
18923
|
+
value,
|
|
18924
|
+
options,
|
|
18925
|
+
onChange
|
|
18926
|
+
}) {
|
|
18927
|
+
const current = options.find((o) => o.value === value) ?? options[0];
|
|
18928
|
+
return /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
18929
|
+
/* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground", children: label }),
|
|
18930
|
+
/* @__PURE__ */ jsxs12(DropdownMenu, { modal: false, children: [
|
|
18931
|
+
/* @__PURE__ */ jsx21(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs12(
|
|
18932
|
+
"button",
|
|
18933
|
+
{
|
|
18934
|
+
type: "button",
|
|
18935
|
+
"aria-label": label,
|
|
18936
|
+
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",
|
|
18937
|
+
children: [
|
|
18938
|
+
/* @__PURE__ */ jsx21("span", { className: "flex-1 text-left", children: current.label }),
|
|
18939
|
+
/* @__PURE__ */ jsx21(ChevronDown3, { size: 16, style: { pointerEvents: "none" } })
|
|
18940
|
+
]
|
|
18941
|
+
}
|
|
18942
|
+
) }),
|
|
18943
|
+
/* @__PURE__ */ jsx21(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[132px] min-w-[132px] p-1", children: options.map((option) => {
|
|
18944
|
+
const selected = option.value === value;
|
|
18945
|
+
return /* @__PURE__ */ jsxs12(
|
|
18946
|
+
DropdownMenuItem,
|
|
18476
18947
|
{
|
|
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
|
-
);
|
|
18948
|
+
role: "menuitemradio",
|
|
18949
|
+
"aria-checked": selected,
|
|
18950
|
+
onSelect: () => onChange(option.value),
|
|
18951
|
+
className: cn("grid grid-cols-[1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
|
|
18952
|
+
children: [
|
|
18953
|
+
/* @__PURE__ */ jsx21("span", { children: option.label }),
|
|
18954
|
+
selected && /* @__PURE__ */ jsx21(Check2, { size: 16, className: "text-bridge-primary" })
|
|
18955
|
+
]
|
|
18956
|
+
},
|
|
18957
|
+
option.value
|
|
18958
|
+
);
|
|
18959
|
+
}) })
|
|
18960
|
+
] })
|
|
18961
|
+
] });
|
|
18508
18962
|
}
|
|
18509
18963
|
var VARIANTS = [
|
|
18510
18964
|
{ value: "logos", label: "Logos" },
|
|
18511
18965
|
{ value: "reel", label: "Reel" }
|
|
18512
18966
|
];
|
|
18513
18967
|
var ALIGNS = [
|
|
18514
|
-
{ value: "left", label: "
|
|
18515
|
-
{ value: "center", label: "
|
|
18516
|
-
{ value: "right", label: "
|
|
18968
|
+
{ value: "left", label: "Align left", Icon: AlignLeft },
|
|
18969
|
+
{ value: "center", label: "Align center", Icon: AlignCenter },
|
|
18970
|
+
{ value: "right", label: "Align right", Icon: AlignRight }
|
|
18517
18971
|
];
|
|
18518
18972
|
var HOVERS = [
|
|
18519
18973
|
{ value: "none", label: "None" },
|
|
@@ -18521,104 +18975,104 @@ var HOVERS = [
|
|
|
18521
18975
|
{ value: "zoom", label: "Zoom" },
|
|
18522
18976
|
{ value: "fade", label: "Fade" }
|
|
18523
18977
|
];
|
|
18524
|
-
var TREATMENTS = [
|
|
18525
|
-
{ value: "color", label: "Color" },
|
|
18526
|
-
{ value: "grayscale", label: "Grayscale" }
|
|
18527
|
-
];
|
|
18528
18978
|
var HTTP_URL_RE = /^https?:\/\/\S+$/i;
|
|
18529
|
-
function
|
|
18530
|
-
|
|
18979
|
+
function LinkModal({
|
|
18980
|
+
href,
|
|
18981
|
+
linkTarget,
|
|
18982
|
+
onClose,
|
|
18983
|
+
onSave
|
|
18984
|
+
}) {
|
|
18985
|
+
const [draft, setDraft] = useState8(href);
|
|
18986
|
+
const [newTab, setNewTab] = useState8(linkTarget !== "same-tab");
|
|
18531
18987
|
const [invalid, setInvalid] = useState8(false);
|
|
18532
|
-
|
|
18533
|
-
setDraft(value);
|
|
18534
|
-
setInvalid(false);
|
|
18535
|
-
}, [value]);
|
|
18536
|
-
const commit = () => {
|
|
18988
|
+
const save = () => {
|
|
18537
18989
|
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
|
-
]
|
|
18990
|
+
if (next && !HTTP_URL_RE.test(next)) {
|
|
18991
|
+
setInvalid(true);
|
|
18992
|
+
return;
|
|
18607
18993
|
}
|
|
18608
|
-
|
|
18994
|
+
onSave(next, newTab ? "new-tab" : "same-tab");
|
|
18995
|
+
onClose();
|
|
18996
|
+
};
|
|
18997
|
+
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: [
|
|
18998
|
+
/* @__PURE__ */ jsx21(DialogHeader, { children: /* @__PURE__ */ jsx21(DialogTitle, { className: "text-base", children: "Image link" }) }),
|
|
18999
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-3", children: [
|
|
19000
|
+
/* @__PURE__ */ jsx21(
|
|
19001
|
+
"input",
|
|
19002
|
+
{
|
|
19003
|
+
autoFocus: true,
|
|
19004
|
+
type: "text",
|
|
19005
|
+
inputMode: "url",
|
|
19006
|
+
value: draft,
|
|
19007
|
+
onChange: (e) => {
|
|
19008
|
+
setDraft(e.target.value);
|
|
19009
|
+
setInvalid(false);
|
|
19010
|
+
},
|
|
19011
|
+
onKeyDown: (e) => {
|
|
19012
|
+
if (e.key === "Enter") save();
|
|
19013
|
+
},
|
|
19014
|
+
placeholder: "https://example.com",
|
|
19015
|
+
"aria-label": "Image link URL",
|
|
19016
|
+
"aria-invalid": invalid,
|
|
19017
|
+
className: cn(
|
|
19018
|
+
"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",
|
|
19019
|
+
invalid && "border-destructive focus:border-destructive"
|
|
19020
|
+
)
|
|
19021
|
+
}
|
|
19022
|
+
),
|
|
19023
|
+
invalid && /* @__PURE__ */ jsx21("p", { className: "text-xs text-destructive", children: "Enter a full URL starting with http:// or https://" }),
|
|
19024
|
+
/* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-2 text-[13px] text-foreground", children: [
|
|
19025
|
+
/* @__PURE__ */ jsx21("input", { type: "checkbox", checked: newTab, onChange: (e) => setNewTab(e.target.checked) }),
|
|
19026
|
+
"Open in new tab"
|
|
19027
|
+
] })
|
|
19028
|
+
] }),
|
|
19029
|
+
/* @__PURE__ */ jsxs12(DialogFooter, { children: [
|
|
19030
|
+
href && /* @__PURE__ */ jsx21(
|
|
19031
|
+
"button",
|
|
19032
|
+
{
|
|
19033
|
+
type: "button",
|
|
19034
|
+
onClick: () => {
|
|
19035
|
+
onSave("", "new-tab");
|
|
19036
|
+
onClose();
|
|
19037
|
+
},
|
|
19038
|
+
className: "mr-auto rounded-[6px] px-3 py-2 text-[13px] font-medium text-destructive transition-colors hover:bg-muted",
|
|
19039
|
+
children: "Remove link"
|
|
19040
|
+
}
|
|
19041
|
+
),
|
|
19042
|
+
/* @__PURE__ */ jsx21(
|
|
19043
|
+
"button",
|
|
19044
|
+
{
|
|
19045
|
+
type: "button",
|
|
19046
|
+
onClick: onClose,
|
|
19047
|
+
className: "rounded-[6px] px-3 py-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted",
|
|
19048
|
+
children: "Cancel"
|
|
19049
|
+
}
|
|
19050
|
+
),
|
|
19051
|
+
/* @__PURE__ */ jsx21(
|
|
19052
|
+
"button",
|
|
19053
|
+
{
|
|
19054
|
+
type: "button",
|
|
19055
|
+
onClick: save,
|
|
19056
|
+
className: "rounded-[6px] bg-bridge-primary px-3 py-2 text-[13px] font-medium text-primary-foreground transition-opacity hover:opacity-90",
|
|
19057
|
+
children: "Save"
|
|
19058
|
+
}
|
|
19059
|
+
)
|
|
19060
|
+
] })
|
|
19061
|
+
] }) });
|
|
18609
19062
|
}
|
|
18610
19063
|
function MediaStripToolbar({
|
|
18611
19064
|
entry,
|
|
18612
19065
|
index,
|
|
18613
19066
|
pending,
|
|
18614
19067
|
error,
|
|
19068
|
+
itemEditOn,
|
|
19069
|
+
onToggleItemEdit,
|
|
18615
19070
|
onSetVariant,
|
|
18616
19071
|
onSetAlign,
|
|
18617
19072
|
onSetHover,
|
|
18618
19073
|
onSetTreatment,
|
|
18619
19074
|
onResize,
|
|
18620
|
-
|
|
18621
|
-
onSetLink,
|
|
19075
|
+
onOpenLink,
|
|
18622
19076
|
onAddItem,
|
|
18623
19077
|
onRemoveItem,
|
|
18624
19078
|
onChangeImage,
|
|
@@ -18627,81 +19081,102 @@ function MediaStripToolbar({
|
|
|
18627
19081
|
}) {
|
|
18628
19082
|
const items = mediaStripItems(entry.tree);
|
|
18629
19083
|
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
19084
|
const slots = findMediaStripSlots(entry.tree);
|
|
18634
19085
|
const variant = slots?.variant === "reel" ? "reel" : "logos";
|
|
18635
19086
|
const align = slots?.align === "left" || slots?.align === "right" ? slots.align : "center";
|
|
18636
19087
|
const hover = slots?.hover === "none" || slots?.hover === "lift" || slots?.hover === "zoom" || slots?.hover === "fade" ? slots.hover : "lift";
|
|
18637
19088
|
const treatment = slots?.treatment === "color" || slots?.treatment === "grayscale" ? slots.treatment : variant === "logos" ? "grayscale" : "color";
|
|
18638
19089
|
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(
|
|
19090
|
+
const mobile = window.innerWidth <= 480;
|
|
19091
|
+
const gatedLabel = (label) => itemEditOn ? label : "Turn on the star to edit this image";
|
|
19092
|
+
return /* @__PURE__ */ jsx21(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs12(
|
|
18651
19093
|
"div",
|
|
18652
19094
|
{
|
|
18653
19095
|
"data-ohw-bridge": "",
|
|
18654
19096
|
"data-ohw-toolbar": "",
|
|
18655
19097
|
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
|
-
},
|
|
19098
|
+
className: cn("flex flex-col items-center gap-1.5 font-sans", pending && "pointer-events-none opacity-60"),
|
|
19099
|
+
style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
|
|
18669
19100
|
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
|
-
|
|
19101
|
+
/* @__PURE__ */ jsxs12(
|
|
19102
|
+
"div",
|
|
19103
|
+
{
|
|
19104
|
+
className: cn(
|
|
19105
|
+
"flex items-center gap-1 rounded-[10px] border border-border bg-background p-1 whitespace-nowrap",
|
|
19106
|
+
"shadow-[0px_10px_15px_-3px_rgba(0,0,0,0.1),0px_4px_6px_-4px_rgba(0,0,0,0.1)]",
|
|
19107
|
+
mobile ? "flex-wrap justify-center" : "flex-nowrap"
|
|
19108
|
+
),
|
|
19109
|
+
children: [
|
|
19110
|
+
/* @__PURE__ */ jsxs12(Tooltip, { children: [
|
|
19111
|
+
/* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx21(
|
|
19112
|
+
CustomToolbarButton,
|
|
19113
|
+
{
|
|
19114
|
+
type: "button",
|
|
19115
|
+
"aria-label": itemEditOn ? "Done editing this image" : "Edit this image",
|
|
19116
|
+
"aria-pressed": itemEditOn,
|
|
19117
|
+
onClick: onToggleItemEdit,
|
|
19118
|
+
className: "group size-8",
|
|
19119
|
+
children: /* @__PURE__ */ jsx21(
|
|
19120
|
+
Star,
|
|
19121
|
+
{
|
|
19122
|
+
size: 16,
|
|
19123
|
+
fill: "currentColor",
|
|
19124
|
+
strokeWidth: 0,
|
|
19125
|
+
className: cn(
|
|
19126
|
+
"transition-colors",
|
|
19127
|
+
itemEditOn ? "text-[#f59e0b] group-hover:text-[#d97706]" : "text-[#d6d3d1] group-hover:text-[#fbbf24]"
|
|
19128
|
+
),
|
|
19129
|
+
style: { pointerEvents: "none" }
|
|
19130
|
+
}
|
|
19131
|
+
)
|
|
19132
|
+
}
|
|
19133
|
+
) }),
|
|
19134
|
+
/* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: itemEditOn ? "Done editing this image" : "Edit this image" })
|
|
19135
|
+
] }),
|
|
19136
|
+
/* @__PURE__ */ jsx21(ToolbarSeparator, {}),
|
|
19137
|
+
/* @__PURE__ */ jsx21(ToolbarAction, { label: gatedLabel("Change image"), onClick: onChangeImage, disabled: !itemEditOn, children: /* @__PURE__ */ jsx21(ImageIcon2, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19138
|
+
/* @__PURE__ */ jsx21(ToolbarAction, { label: gatedLabel("Link"), onClick: onOpenLink, disabled: !itemEditOn, children: /* @__PURE__ */ jsx21(LinkIcon, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19139
|
+
/* @__PURE__ */ jsx21(ToolbarAction, { label: gatedLabel("Move left"), onClick: onMoveLeft, disabled: !itemEditOn || index <= 0, children: /* @__PURE__ */ jsx21(ArrowLeft2, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19140
|
+
/* @__PURE__ */ jsx21(
|
|
19141
|
+
ToolbarAction,
|
|
19142
|
+
{
|
|
19143
|
+
label: gatedLabel("Move right"),
|
|
19144
|
+
onClick: onMoveRight,
|
|
19145
|
+
disabled: !itemEditOn || index >= itemCount - 1,
|
|
19146
|
+
children: /* @__PURE__ */ jsx21(ArrowRight2, { size: 16, style: { pointerEvents: "none" } })
|
|
19147
|
+
}
|
|
19148
|
+
),
|
|
19149
|
+
/* @__PURE__ */ jsx21(ToolbarAction, { label: gatedLabel("Remove image"), onClick: onRemoveItem, disabled: !itemEditOn || itemCount <= 1, children: /* @__PURE__ */ jsx21(ImageMinus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19150
|
+
/* @__PURE__ */ jsx21(ToolbarSeparator, {}),
|
|
19151
|
+
/* @__PURE__ */ jsx21(OptionMenu, { label: "Layout", value: variant, options: VARIANTS, onChange: onSetVariant }),
|
|
19152
|
+
/* @__PURE__ */ jsx21(OptionMenu, { label: "Hover", value: hover, options: HOVERS, onChange: onSetHover }),
|
|
19153
|
+
/* @__PURE__ */ jsx21(
|
|
19154
|
+
ToolbarAction,
|
|
19155
|
+
{
|
|
19156
|
+
label: treatment === "grayscale" ? "Show in color" : "Show grayscale",
|
|
19157
|
+
active: treatment === "grayscale",
|
|
19158
|
+
onClick: () => onSetTreatment(treatment === "grayscale" ? "color" : "grayscale"),
|
|
19159
|
+
children: /* @__PURE__ */ jsx21(Palette, { size: 16, style: { pointerEvents: "none" } })
|
|
19160
|
+
}
|
|
19161
|
+
),
|
|
19162
|
+
/* @__PURE__ */ jsx21(ToolbarSeparator, {}),
|
|
19163
|
+
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)),
|
|
19164
|
+
/* @__PURE__ */ jsx21(ToolbarSeparator, {}),
|
|
19165
|
+
/* @__PURE__ */ jsx21(ToolbarAction, { label: "Smaller", onClick: () => onResize(-8), children: /* @__PURE__ */ jsx21(Minus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19166
|
+
/* @__PURE__ */ jsxs12("span", { className: "min-w-[40px] text-center text-xs tabular-nums text-muted-foreground", children: [
|
|
19167
|
+
sizeValue,
|
|
19168
|
+
"px"
|
|
19169
|
+
] }),
|
|
19170
|
+
/* @__PURE__ */ jsx21(ToolbarAction, { label: "Larger", onClick: () => onResize(8), children: /* @__PURE__ */ jsx21(Plus2, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19171
|
+
/* @__PURE__ */ jsx21(ToolbarSeparator, {}),
|
|
19172
|
+
/* @__PURE__ */ jsx21(ToolbarAction, { label: "Add image", onClick: onAddItem, children: /* @__PURE__ */ jsx21(ImagePlus, { size: 16, style: { pointerEvents: "none" } }) })
|
|
19173
|
+
]
|
|
19174
|
+
}
|
|
19175
|
+
),
|
|
19176
|
+
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
19177
|
]
|
|
18703
19178
|
}
|
|
18704
|
-
);
|
|
19179
|
+
) });
|
|
18705
19180
|
}
|
|
18706
19181
|
function findMediaStripSlots(tree) {
|
|
18707
19182
|
const stack = tree.rows.flatMap((row) => row.blocks);
|
|
@@ -18720,31 +19195,23 @@ function AiMediaStripOverlay({
|
|
|
18720
19195
|
}) {
|
|
18721
19196
|
const [hover, setHover] = useState8(null);
|
|
18722
19197
|
const [active, setActive] = useState8(null);
|
|
19198
|
+
const [itemEditOn, setItemEditOn] = useState8(false);
|
|
19199
|
+
const [linkOpen, setLinkOpen] = useState8(false);
|
|
18723
19200
|
const [pending, setPending] = useState8(false);
|
|
18724
19201
|
const [error, setError] = useState8(null);
|
|
18725
19202
|
const activeRef = useRef5(null);
|
|
18726
19203
|
activeRef.current = active;
|
|
19204
|
+
const linkOpenRef = useRef5(false);
|
|
19205
|
+
linkOpenRef.current = linkOpen;
|
|
18727
19206
|
useEffect6(() => {
|
|
18728
19207
|
const onMove = (e) => {
|
|
19208
|
+
const ref = itemRefFromTarget(e.target);
|
|
18729
19209
|
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 });
|
|
19210
|
+
const overEditable = Boolean(t?.closest?.("[data-ohw-editable]"));
|
|
19211
|
+
setHover((prev) => {
|
|
19212
|
+
const next = ref && !overEditable ? ref : null;
|
|
19213
|
+
return sameRef(prev, next) ? prev : next;
|
|
19214
|
+
});
|
|
18748
19215
|
};
|
|
18749
19216
|
const onLeave = () => setHover(null);
|
|
18750
19217
|
document.addEventListener("mousemove", onMove, { passive: true });
|
|
@@ -18756,23 +19223,25 @@ function AiMediaStripOverlay({
|
|
|
18756
19223
|
}, []);
|
|
18757
19224
|
useEffect6(() => {
|
|
18758
19225
|
const onClick = (e) => {
|
|
18759
|
-
const current = activeRef.current;
|
|
18760
|
-
if (!current) return;
|
|
18761
19226
|
const t = e.target;
|
|
18762
|
-
if (!(t instanceof
|
|
18763
|
-
if (t.closest(
|
|
18764
|
-
const
|
|
18765
|
-
if (
|
|
18766
|
-
|
|
19227
|
+
if (!(t instanceof Element)) return;
|
|
19228
|
+
if (t.closest(CHROME_SELECTOR)) return;
|
|
19229
|
+
const ref = itemRefFromTarget(t);
|
|
19230
|
+
if (sameRef(activeRef.current, ref)) return;
|
|
19231
|
+
if (ref) clearInteractionChromeRef.current();
|
|
19232
|
+
setItemEditOn(false);
|
|
18767
19233
|
setError(null);
|
|
19234
|
+
setActive(ref);
|
|
18768
19235
|
};
|
|
18769
19236
|
document.addEventListener("click", onClick, true);
|
|
18770
19237
|
return () => document.removeEventListener("click", onClick, true);
|
|
18771
|
-
}, []);
|
|
19238
|
+
}, [clearInteractionChromeRef]);
|
|
18772
19239
|
useEffect6(() => {
|
|
18773
19240
|
const onBlur = () => {
|
|
18774
19241
|
if (!activeRef.current) return;
|
|
18775
19242
|
setActive(null);
|
|
19243
|
+
setItemEditOn(false);
|
|
19244
|
+
setLinkOpen(false);
|
|
18776
19245
|
setError(null);
|
|
18777
19246
|
};
|
|
18778
19247
|
window.addEventListener("blur", onBlur);
|
|
@@ -18782,7 +19251,10 @@ function AiMediaStripOverlay({
|
|
|
18782
19251
|
const onKeyDown = (e) => {
|
|
18783
19252
|
if (e.key !== "Escape") return;
|
|
18784
19253
|
if (!activeRef.current) return;
|
|
19254
|
+
if (linkOpenRef.current) return;
|
|
19255
|
+
if (document.querySelector('[data-ohw-more-menu][data-state="open"]')) return;
|
|
18785
19256
|
setActive(null);
|
|
19257
|
+
setItemEditOn(false);
|
|
18786
19258
|
setError(null);
|
|
18787
19259
|
};
|
|
18788
19260
|
document.addEventListener("keydown", onKeyDown);
|
|
@@ -18816,137 +19288,133 @@ function AiMediaStripOverlay({
|
|
|
18816
19288
|
tree: nextTree,
|
|
18817
19289
|
label: entry.label,
|
|
18818
19290
|
media: extraMedia ? { ...entry.media, ...extraMedia } : entry.media,
|
|
18819
|
-
...entry.brand ? { brand: entry.brand } : {}
|
|
19291
|
+
...entry.brand ? { brand: entry.brand } : {},
|
|
19292
|
+
// The user is already looking at the strip they just edited — recentering the viewport
|
|
19293
|
+
// on every edit reads as the section jumping around.
|
|
19294
|
+
skipScrollIntoView: true
|
|
18820
19295
|
});
|
|
18821
19296
|
return true;
|
|
18822
19297
|
},
|
|
18823
19298
|
[findEntry, postToParent2, applyTreeLocalRef]
|
|
18824
19299
|
);
|
|
18825
19300
|
const activeEntry = active ? findEntry(active.sectionId) : null;
|
|
18826
|
-
const hoverHandleRect = useLiveItemRect(!active && hover ? hover : null);
|
|
18827
19301
|
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) => {
|
|
19302
|
+
const activeStripRect = useLiveItemRect(active, true);
|
|
19303
|
+
const hoverRect = useLiveItemRect(hover && !sameRef(hover, active) ? hover : null);
|
|
19304
|
+
const activeItems = activeEntry ? mediaStripItems(activeEntry.tree) : [];
|
|
19305
|
+
const activeItem = active ? activeItems[active.index] : void 0;
|
|
19306
|
+
const activeHref = activeItem?.href ?? "";
|
|
19307
|
+
const activeTarget = activeItem?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
|
|
19308
|
+
return /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
19309
|
+
hoverRect && /* @__PURE__ */ jsx21(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
|
|
19310
|
+
activeItemRect && activeStripRect && active && activeEntry && /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
19311
|
+
/* @__PURE__ */ jsx21(ItemInteractionLayer, { rect: activeItemRect, state: "active-top" }),
|
|
19312
|
+
/* @__PURE__ */ jsx21(StripToolbarSlot, { stripRect: activeStripRect, children: /* @__PURE__ */ jsx21(
|
|
19313
|
+
MediaStripToolbar,
|
|
19314
|
+
{
|
|
19315
|
+
entry: activeEntry,
|
|
19316
|
+
index: active.index,
|
|
19317
|
+
pending,
|
|
19318
|
+
error,
|
|
19319
|
+
itemEditOn,
|
|
19320
|
+
onToggleItemEdit: () => setItemEditOn((on) => !on),
|
|
19321
|
+
onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
|
|
19322
|
+
onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
|
|
19323
|
+
onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
|
|
19324
|
+
onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
|
|
19325
|
+
onResize: (delta) => {
|
|
19326
|
+
const slots = findMediaStripSlots(activeEntry.tree);
|
|
19327
|
+
const variant = slots?.variant === "reel" ? "reel" : "logos";
|
|
19328
|
+
const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
|
|
19329
|
+
void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
|
|
19330
|
+
},
|
|
19331
|
+
onOpenLink: () => setLinkOpen(true),
|
|
19332
|
+
onAddItem: () => {
|
|
19333
|
+
void requestAssetPick(postToParent2).then((picked) => {
|
|
19334
|
+
if (!picked) return;
|
|
19335
|
+
const item = { assetId: picked.assetId, alt: "Logo" };
|
|
18888
19336
|
void runMutation(
|
|
18889
19337
|
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
|
-
});
|
|
18904
|
-
});
|
|
18905
|
-
},
|
|
18906
|
-
onChangeImage: () => {
|
|
18907
|
-
void requestAssetPick(postToParent2).then((picked) => {
|
|
18908
|
-
if (!picked) return;
|
|
18909
|
-
void runMutation(
|
|
18910
|
-
active.sectionId,
|
|
18911
|
-
(tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
|
|
18912
|
-
{ [picked.assetId]: picked.url }
|
|
18913
|
-
);
|
|
19338
|
+
(tree) => addMediaStripItem(tree, item, active.index),
|
|
19339
|
+
{ [picked.assetId]: picked.url }
|
|
19340
|
+
).then((applied) => {
|
|
19341
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
18914
19342
|
});
|
|
18915
|
-
}
|
|
18916
|
-
|
|
18917
|
-
|
|
18918
|
-
|
|
18919
|
-
|
|
18920
|
-
|
|
18921
|
-
|
|
18922
|
-
|
|
18923
|
-
|
|
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
|
-
}
|
|
19343
|
+
});
|
|
19344
|
+
},
|
|
19345
|
+
onChangeImage: () => {
|
|
19346
|
+
void requestAssetPick(postToParent2).then((picked) => {
|
|
19347
|
+
if (!picked) return;
|
|
19348
|
+
void runMutation(
|
|
19349
|
+
active.sectionId,
|
|
19350
|
+
(tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
|
|
19351
|
+
{ [picked.assetId]: picked.url }
|
|
18935
19352
|
);
|
|
18936
|
-
}
|
|
19353
|
+
});
|
|
19354
|
+
},
|
|
19355
|
+
onRemoveItem: () => {
|
|
19356
|
+
void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
|
|
19357
|
+
(applied) => {
|
|
19358
|
+
if (applied) setActive(null);
|
|
19359
|
+
}
|
|
19360
|
+
);
|
|
19361
|
+
},
|
|
19362
|
+
onMoveLeft: () => {
|
|
19363
|
+
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
|
|
19364
|
+
(applied) => {
|
|
19365
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
|
|
19366
|
+
}
|
|
19367
|
+
);
|
|
19368
|
+
},
|
|
19369
|
+
onMoveRight: () => {
|
|
19370
|
+
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
|
|
19371
|
+
(applied) => {
|
|
19372
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
19373
|
+
}
|
|
19374
|
+
);
|
|
19375
|
+
}
|
|
19376
|
+
}
|
|
19377
|
+
) }),
|
|
19378
|
+
/* @__PURE__ */ jsx21(
|
|
19379
|
+
"div",
|
|
19380
|
+
{
|
|
19381
|
+
"data-ohw-bridge": "",
|
|
19382
|
+
"data-ohw-item-interaction": "",
|
|
19383
|
+
"aria-hidden": true,
|
|
19384
|
+
className: "pointer-events-none fixed rounded-[4px] px-[7px] py-[3px] font-sans text-[11px] font-medium leading-none text-primary-foreground whitespace-nowrap",
|
|
19385
|
+
style: {
|
|
19386
|
+
top: activeItemRect.top + activeItemRect.height + 10,
|
|
19387
|
+
left: activeItemRect.left - 5,
|
|
19388
|
+
background: PRIMARY3,
|
|
19389
|
+
zIndex: 2147483644
|
|
19390
|
+
},
|
|
19391
|
+
children: "Media item"
|
|
19392
|
+
}
|
|
19393
|
+
),
|
|
19394
|
+
linkOpen && /* @__PURE__ */ jsx21(
|
|
19395
|
+
LinkModal,
|
|
19396
|
+
{
|
|
19397
|
+
href: activeHref,
|
|
19398
|
+
linkTarget: activeTarget,
|
|
19399
|
+
onClose: () => setLinkOpen(false),
|
|
19400
|
+
onSave: (href, linkTarget) => {
|
|
19401
|
+
void runMutation(
|
|
19402
|
+
active.sectionId,
|
|
19403
|
+
(tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
|
|
19404
|
+
);
|
|
18937
19405
|
}
|
|
18938
|
-
|
|
18939
|
-
|
|
18940
|
-
)
|
|
19406
|
+
}
|
|
19407
|
+
)
|
|
19408
|
+
] })
|
|
18941
19409
|
] });
|
|
18942
19410
|
}
|
|
18943
19411
|
|
|
18944
19412
|
// 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
|
|
19413
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useLayoutEffect as useLayoutEffect5, useRef as useRef6, useState as useState9 } from "react";
|
|
19414
|
+
import { Check as Check3, ChevronDown as ChevronDown4, Minus as Minus2, Plus as Plus3, Star as Star2 } from "lucide-react";
|
|
19415
|
+
import { Fragment as Fragment8, jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
18948
19416
|
var PRIMARY4 = "var(--ohw-primary, #0885FE)";
|
|
18949
|
-
var
|
|
19417
|
+
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
19418
|
function findPricingCardElement(sectionId, index) {
|
|
18951
19419
|
const sectionEl = findByInstanceId(sectionId);
|
|
18952
19420
|
if (!sectionEl) return null;
|
|
@@ -18958,7 +19426,7 @@ function findPricingCardElement(sectionId, index) {
|
|
|
18958
19426
|
}
|
|
18959
19427
|
function cardRefFromTarget(target) {
|
|
18960
19428
|
if (!(target instanceof Element)) return null;
|
|
18961
|
-
if (target.closest(
|
|
19429
|
+
if (target.closest(CHROME_SELECTOR2)) return null;
|
|
18962
19430
|
const cardEl = target.closest("[data-ohw-pricing-card]");
|
|
18963
19431
|
if (!cardEl) return null;
|
|
18964
19432
|
const sectionEl = cardEl.closest("[data-ohw-section]");
|
|
@@ -18968,21 +19436,21 @@ function cardRefFromTarget(target) {
|
|
|
18968
19436
|
if (!sectionId || Number.isNaN(index)) return null;
|
|
18969
19437
|
return { sectionId, index };
|
|
18970
19438
|
}
|
|
18971
|
-
function
|
|
19439
|
+
function sameRef2(a, b) {
|
|
18972
19440
|
return a?.sectionId === b?.sectionId && a?.index === b?.index;
|
|
18973
19441
|
}
|
|
18974
|
-
function
|
|
19442
|
+
function rectOf2(el) {
|
|
18975
19443
|
if (!el) return null;
|
|
18976
19444
|
const r2 = el.getBoundingClientRect();
|
|
18977
19445
|
if (r2.width <= 0 || r2.height <= 0) return null;
|
|
18978
19446
|
return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
|
|
18979
19447
|
}
|
|
18980
19448
|
function readRect3(ref) {
|
|
18981
|
-
return
|
|
19449
|
+
return rectOf2(ref && findPricingCardElement(ref.sectionId, ref.index));
|
|
18982
19450
|
}
|
|
18983
19451
|
function readGridRect(ref) {
|
|
18984
19452
|
const card = ref && findPricingCardElement(ref.sectionId, ref.index);
|
|
18985
|
-
return
|
|
19453
|
+
return rectOf2(card?.closest("[data-ohw-pricing-collection]") ?? card);
|
|
18986
19454
|
}
|
|
18987
19455
|
function useLiveCardRect(ref, grid = false) {
|
|
18988
19456
|
const [rect, setRect] = useState9(null);
|
|
@@ -19012,19 +19480,19 @@ function useLiveCardRect(ref, grid = false) {
|
|
|
19012
19480
|
}
|
|
19013
19481
|
var TOOLBAR_GRID_GAP = 52;
|
|
19014
19482
|
var TOOLBAR_GRID_GAP_MOBILE = 42;
|
|
19015
|
-
var
|
|
19483
|
+
var TOOLBAR_EDGE_MARGIN3 = 4;
|
|
19016
19484
|
function GridToolbarSlot({ gridRect, children }) {
|
|
19017
19485
|
const slotRef = useRef6(null);
|
|
19018
19486
|
const [shift, setShift] = useState9(0);
|
|
19019
19487
|
const centerX = gridRect.left + gridRect.width / 2;
|
|
19020
|
-
|
|
19488
|
+
useLayoutEffect5(() => {
|
|
19021
19489
|
const slot = slotRef.current;
|
|
19022
19490
|
if (!slot) return;
|
|
19023
19491
|
const clamp = () => {
|
|
19024
19492
|
const w = slot.offsetWidth;
|
|
19025
19493
|
if (w <= 0) return;
|
|
19026
19494
|
const half = w / 2;
|
|
19027
|
-
const clamped = Math.max(
|
|
19495
|
+
const clamped = Math.max(TOOLBAR_EDGE_MARGIN3 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN3 - half));
|
|
19028
19496
|
setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
|
|
19029
19497
|
};
|
|
19030
19498
|
clamp();
|
|
@@ -19033,7 +19501,7 @@ function GridToolbarSlot({ gridRect, children }) {
|
|
|
19033
19501
|
return () => ro.disconnect();
|
|
19034
19502
|
}, [centerX, children]);
|
|
19035
19503
|
const mobile = window.innerWidth <= 480;
|
|
19036
|
-
return /* @__PURE__ */
|
|
19504
|
+
return /* @__PURE__ */ jsx22(
|
|
19037
19505
|
"div",
|
|
19038
19506
|
{
|
|
19039
19507
|
ref: slotRef,
|
|
@@ -19068,7 +19536,7 @@ function requestValidateTree2(postToParent2, tree) {
|
|
|
19068
19536
|
});
|
|
19069
19537
|
}
|
|
19070
19538
|
function StyleSwatch({ style }) {
|
|
19071
|
-
return /* @__PURE__ */
|
|
19539
|
+
return /* @__PURE__ */ jsx22(
|
|
19072
19540
|
"span",
|
|
19073
19541
|
{
|
|
19074
19542
|
"aria-hidden": true,
|
|
@@ -19082,35 +19550,35 @@ function StyleSwatch({ style }) {
|
|
|
19082
19550
|
);
|
|
19083
19551
|
}
|
|
19084
19552
|
function ButtonGlyph() {
|
|
19085
|
-
return /* @__PURE__ */
|
|
19086
|
-
/* @__PURE__ */
|
|
19087
|
-
/* @__PURE__ */
|
|
19553
|
+
return /* @__PURE__ */ jsxs13("svg", { width: "18", height: "12", viewBox: "0 0 18 12", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
|
|
19554
|
+
/* @__PURE__ */ jsx22("rect", { x: "0.75", y: "0.75", width: "16.5", height: "10.5", rx: "3", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
19555
|
+
/* @__PURE__ */ jsx22("path", { d: "M5.5 6H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
19088
19556
|
] });
|
|
19089
19557
|
}
|
|
19090
19558
|
function FeatureGlyph({ mode }) {
|
|
19091
|
-
return /* @__PURE__ */
|
|
19092
|
-
/* @__PURE__ */
|
|
19093
|
-
/* @__PURE__ */
|
|
19094
|
-
/* @__PURE__ */
|
|
19095
|
-
/* @__PURE__ */
|
|
19096
|
-
/* @__PURE__ */
|
|
19097
|
-
mode === "add" && /* @__PURE__ */
|
|
19559
|
+
return /* @__PURE__ */ jsxs13("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
|
|
19560
|
+
/* @__PURE__ */ jsx22("circle", { cx: "8", cy: "8", r: "7.25", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
19561
|
+
/* @__PURE__ */ jsx22("path", { d: "M5 8.2L7.2 10.3L11 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
19562
|
+
/* @__PURE__ */ jsx22("circle", { cx: "13.5", cy: "13.5", r: "4.25", fill: "var(--ohw-background, #ffffff)", stroke: "var(--ohw-background, #ffffff)", strokeWidth: "1" }),
|
|
19563
|
+
/* @__PURE__ */ jsx22("circle", { cx: "13.5", cy: "13.5", r: "3.75", fill: "var(--ohw-background, #ffffff)", stroke: PRIMARY4, strokeWidth: "1" }),
|
|
19564
|
+
/* @__PURE__ */ jsx22("path", { d: "M11.5 13.5H15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" }),
|
|
19565
|
+
mode === "add" && /* @__PURE__ */ jsx22("path", { d: "M13.5 11.5V15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" })
|
|
19098
19566
|
] });
|
|
19099
19567
|
}
|
|
19100
|
-
function
|
|
19568
|
+
function ToolbarAction2({
|
|
19101
19569
|
label,
|
|
19102
19570
|
onClick,
|
|
19103
19571
|
disabled = false,
|
|
19104
19572
|
children
|
|
19105
19573
|
}) {
|
|
19106
|
-
const button = /* @__PURE__ */
|
|
19107
|
-
return /* @__PURE__ */
|
|
19108
|
-
/* @__PURE__ */
|
|
19109
|
-
/* @__PURE__ */
|
|
19574
|
+
const button = /* @__PURE__ */ jsx22(CustomToolbarButton, { type: "button", "aria-label": label, disabled, onClick, className: "size-8", children });
|
|
19575
|
+
return /* @__PURE__ */ jsxs13(Tooltip, { children: [
|
|
19576
|
+
/* @__PURE__ */ jsx22(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx22("span", { className: "inline-flex", children: button }) : button }),
|
|
19577
|
+
/* @__PURE__ */ jsx22(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
|
|
19110
19578
|
] });
|
|
19111
19579
|
}
|
|
19112
|
-
function
|
|
19113
|
-
return /* @__PURE__ */
|
|
19580
|
+
function ToolbarSeparator2() {
|
|
19581
|
+
return /* @__PURE__ */ jsx22("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
|
|
19114
19582
|
}
|
|
19115
19583
|
function CardStyleMenu({
|
|
19116
19584
|
value,
|
|
@@ -19118,7 +19586,7 @@ function CardStyleMenu({
|
|
|
19118
19586
|
disabled = false
|
|
19119
19587
|
}) {
|
|
19120
19588
|
const current = PRICING_CARD_STYLES.find((s) => s.value === value) ?? PRICING_CARD_STYLES[0];
|
|
19121
|
-
const trigger = /* @__PURE__ */
|
|
19589
|
+
const trigger = /* @__PURE__ */ jsxs13(
|
|
19122
19590
|
"button",
|
|
19123
19591
|
{
|
|
19124
19592
|
type: "button",
|
|
@@ -19129,28 +19597,28 @@ function CardStyleMenu({
|
|
|
19129
19597
|
disabled && "cursor-not-allowed opacity-40 hover:bg-transparent"
|
|
19130
19598
|
),
|
|
19131
19599
|
children: [
|
|
19132
|
-
/* @__PURE__ */
|
|
19133
|
-
/* @__PURE__ */
|
|
19134
|
-
/* @__PURE__ */
|
|
19600
|
+
/* @__PURE__ */ jsx22(StyleSwatch, { style: current.value }),
|
|
19601
|
+
/* @__PURE__ */ jsx22("span", { className: "flex-1 text-left", children: current.label }),
|
|
19602
|
+
/* @__PURE__ */ jsx22(ChevronDown4, { size: 16, style: { pointerEvents: "none" } })
|
|
19135
19603
|
]
|
|
19136
19604
|
}
|
|
19137
19605
|
);
|
|
19138
19606
|
if (disabled) {
|
|
19139
|
-
return /* @__PURE__ */
|
|
19140
|
-
/* @__PURE__ */
|
|
19141
|
-
/* @__PURE__ */
|
|
19142
|
-
/* @__PURE__ */
|
|
19143
|
-
/* @__PURE__ */
|
|
19607
|
+
return /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
19608
|
+
/* @__PURE__ */ jsx22("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
|
|
19609
|
+
/* @__PURE__ */ jsxs13(Tooltip, { children: [
|
|
19610
|
+
/* @__PURE__ */ jsx22(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx22("span", { className: "inline-flex", children: trigger }) }),
|
|
19611
|
+
/* @__PURE__ */ jsx22(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
|
|
19144
19612
|
] })
|
|
19145
19613
|
] });
|
|
19146
19614
|
}
|
|
19147
|
-
return /* @__PURE__ */
|
|
19148
|
-
/* @__PURE__ */
|
|
19149
|
-
/* @__PURE__ */
|
|
19150
|
-
/* @__PURE__ */
|
|
19151
|
-
/* @__PURE__ */
|
|
19615
|
+
return /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
19616
|
+
/* @__PURE__ */ jsx22("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
|
|
19617
|
+
/* @__PURE__ */ jsxs13(DropdownMenu, { modal: false, children: [
|
|
19618
|
+
/* @__PURE__ */ jsx22(DropdownMenuTrigger, { asChild: true, children: trigger }),
|
|
19619
|
+
/* @__PURE__ */ jsx22(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
|
|
19152
19620
|
const selected = style.value === value;
|
|
19153
|
-
return /* @__PURE__ */
|
|
19621
|
+
return /* @__PURE__ */ jsxs13(
|
|
19154
19622
|
DropdownMenuItem,
|
|
19155
19623
|
{
|
|
19156
19624
|
role: "menuitemradio",
|
|
@@ -19158,9 +19626,9 @@ function CardStyleMenu({
|
|
|
19158
19626
|
onSelect: () => onChange(style.value),
|
|
19159
19627
|
className: cn("grid grid-cols-[18px_1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
|
|
19160
19628
|
children: [
|
|
19161
|
-
/* @__PURE__ */
|
|
19162
|
-
/* @__PURE__ */
|
|
19163
|
-
selected && /* @__PURE__ */
|
|
19629
|
+
/* @__PURE__ */ jsx22(StyleSwatch, { style: style.value }),
|
|
19630
|
+
/* @__PURE__ */ jsx22("span", { children: style.label }),
|
|
19631
|
+
selected && /* @__PURE__ */ jsx22(Check3, { size: 16, className: "text-bridge-primary" })
|
|
19164
19632
|
]
|
|
19165
19633
|
},
|
|
19166
19634
|
style.value
|
|
@@ -19190,7 +19658,7 @@ function PricingCardToolbar({
|
|
|
19190
19658
|
const style = pricingCardStyle(entry.tree, index);
|
|
19191
19659
|
const featuredTag = pricingCardFeaturedTag(entry.tree, index);
|
|
19192
19660
|
const mobile = window.innerWidth <= 480;
|
|
19193
|
-
return /* @__PURE__ */
|
|
19661
|
+
return /* @__PURE__ */ jsx22(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs13(
|
|
19194
19662
|
"div",
|
|
19195
19663
|
{
|
|
19196
19664
|
"data-ohw-bridge": "",
|
|
@@ -19202,7 +19670,7 @@ function PricingCardToolbar({
|
|
|
19202
19670
|
),
|
|
19203
19671
|
style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
|
|
19204
19672
|
children: [
|
|
19205
|
-
/* @__PURE__ */
|
|
19673
|
+
/* @__PURE__ */ jsxs13(
|
|
19206
19674
|
"div",
|
|
19207
19675
|
{
|
|
19208
19676
|
className: cn(
|
|
@@ -19211,8 +19679,8 @@ function PricingCardToolbar({
|
|
|
19211
19679
|
mobile ? "flex-wrap justify-center" : "flex-nowrap"
|
|
19212
19680
|
),
|
|
19213
19681
|
children: [
|
|
19214
|
-
/* @__PURE__ */
|
|
19215
|
-
/* @__PURE__ */
|
|
19682
|
+
/* @__PURE__ */ jsxs13(Tooltip, { children: [
|
|
19683
|
+
/* @__PURE__ */ jsx22(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx22(
|
|
19216
19684
|
CustomToolbarButton,
|
|
19217
19685
|
{
|
|
19218
19686
|
type: "button",
|
|
@@ -19220,7 +19688,7 @@ function PricingCardToolbar({
|
|
|
19220
19688
|
"aria-pressed": featuredTag,
|
|
19221
19689
|
onClick: () => onSetFeaturedTag(!featuredTag),
|
|
19222
19690
|
className: "group size-8",
|
|
19223
|
-
children: /* @__PURE__ */
|
|
19691
|
+
children: /* @__PURE__ */ jsx22(
|
|
19224
19692
|
Star2,
|
|
19225
19693
|
{
|
|
19226
19694
|
size: 16,
|
|
@@ -19235,25 +19703,25 @@ function PricingCardToolbar({
|
|
|
19235
19703
|
)
|
|
19236
19704
|
}
|
|
19237
19705
|
) }),
|
|
19238
|
-
/* @__PURE__ */
|
|
19706
|
+
/* @__PURE__ */ jsx22(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
|
|
19239
19707
|
] }),
|
|
19240
|
-
/* @__PURE__ */
|
|
19241
|
-
/* @__PURE__ */
|
|
19242
|
-
/* @__PURE__ */
|
|
19243
|
-
/* @__PURE__ */
|
|
19244
|
-
/* @__PURE__ */
|
|
19245
|
-
/* @__PURE__ */
|
|
19246
|
-
/* @__PURE__ */
|
|
19708
|
+
/* @__PURE__ */ jsx22(ToolbarSeparator2, {}),
|
|
19709
|
+
/* @__PURE__ */ jsx22(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
|
|
19710
|
+
/* @__PURE__ */ jsx22(ToolbarSeparator2, {}),
|
|
19711
|
+
/* @__PURE__ */ jsx22(ToolbarAction2, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ jsx22(ButtonGlyph, {}) }),
|
|
19712
|
+
/* @__PURE__ */ jsx22(ToolbarAction2, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ jsxs13("span", { className: "relative inline-flex", children: [
|
|
19713
|
+
/* @__PURE__ */ jsx22(ButtonGlyph, {}),
|
|
19714
|
+
/* @__PURE__ */ jsx22(Minus2, { size: 10, strokeWidth: 2.5, className: "absolute -right-1.5 -top-1.5 rounded-full bg-background text-bridge-primary" })
|
|
19247
19715
|
] }) }),
|
|
19248
|
-
/* @__PURE__ */
|
|
19249
|
-
/* @__PURE__ */
|
|
19250
|
-
/* @__PURE__ */
|
|
19251
|
-
/* @__PURE__ */
|
|
19252
|
-
/* @__PURE__ */
|
|
19716
|
+
/* @__PURE__ */ jsx22(ToolbarAction2, { label: "Add feature", onClick: onAddFeature, disabled: featureCount >= 10, children: /* @__PURE__ */ jsx22(FeatureGlyph, { mode: "add" }) }),
|
|
19717
|
+
/* @__PURE__ */ jsx22(ToolbarAction2, { label: "Remove feature", onClick: onRemoveFeature, disabled: featureCount <= 1, children: /* @__PURE__ */ jsx22(FeatureGlyph, { mode: "remove" }) }),
|
|
19718
|
+
/* @__PURE__ */ jsx22(ToolbarSeparator2, {}),
|
|
19719
|
+
/* @__PURE__ */ jsx22(ToolbarAction2, { label: "Add tier", onClick: onAddTier, disabled: collectionCount >= 4, children: /* @__PURE__ */ jsx22(Plus3, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19720
|
+
/* @__PURE__ */ jsx22(ToolbarAction2, { label: "Remove tier", onClick: onRemoveTier, disabled: collectionCount <= 1, children: /* @__PURE__ */ jsx22(Minus2, { size: 16, style: { pointerEvents: "none" } }) })
|
|
19253
19721
|
]
|
|
19254
19722
|
}
|
|
19255
19723
|
),
|
|
19256
|
-
error && /* @__PURE__ */
|
|
19724
|
+
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
19725
|
]
|
|
19258
19726
|
}
|
|
19259
19727
|
) });
|
|
@@ -19287,7 +19755,7 @@ function AiPricingCardOverlay({
|
|
|
19287
19755
|
const overEditable = Boolean(t?.closest?.("[data-ohw-editable], [data-ohw-role], a, button"));
|
|
19288
19756
|
setHover((prev) => {
|
|
19289
19757
|
const next = ref && !overEditable ? ref : null;
|
|
19290
|
-
return
|
|
19758
|
+
return sameRef2(prev, next) ? prev : next;
|
|
19291
19759
|
});
|
|
19292
19760
|
};
|
|
19293
19761
|
const onLeave = () => setHover(null);
|
|
@@ -19302,10 +19770,10 @@ function AiPricingCardOverlay({
|
|
|
19302
19770
|
const onClick = (e) => {
|
|
19303
19771
|
const t = e.target;
|
|
19304
19772
|
if (!(t instanceof Element)) return;
|
|
19305
|
-
if (t.closest(
|
|
19773
|
+
if (t.closest(CHROME_SELECTOR2)) return;
|
|
19306
19774
|
const ref = cardRefFromTarget(t);
|
|
19307
|
-
setActive((prev) =>
|
|
19308
|
-
if (!ref || !
|
|
19775
|
+
setActive((prev) => sameRef2(prev, ref) ? prev : ref);
|
|
19776
|
+
if (!ref || !sameRef2(activeRef.current, ref)) setError(null);
|
|
19309
19777
|
};
|
|
19310
19778
|
document.addEventListener("click", onClick, true);
|
|
19311
19779
|
return () => document.removeEventListener("click", onClick, true);
|
|
@@ -19370,12 +19838,12 @@ function AiPricingCardOverlay({
|
|
|
19370
19838
|
const activeEntry = active ? findEntry(active.sectionId) : null;
|
|
19371
19839
|
const activeCardRect = useLiveCardRect(active);
|
|
19372
19840
|
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__ */
|
|
19841
|
+
const hoverRect = useLiveCardRect(hover && !sameRef2(hover, active) ? hover : null);
|
|
19842
|
+
return /* @__PURE__ */ jsxs13(Fragment8, { children: [
|
|
19843
|
+
hoverRect && /* @__PURE__ */ jsx22(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
|
|
19844
|
+
activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ jsxs13(Fragment8, { children: [
|
|
19845
|
+
/* @__PURE__ */ jsx22(ItemInteractionLayer, { rect: activeCardRect, state: "active-top" }),
|
|
19846
|
+
/* @__PURE__ */ jsx22(GridToolbarSlot, { gridRect: activeGridRect, children: /* @__PURE__ */ jsx22(
|
|
19379
19847
|
PricingCardToolbar,
|
|
19380
19848
|
{
|
|
19381
19849
|
entry: activeEntry,
|
|
@@ -19403,7 +19871,7 @@ function AiPricingCardOverlay({
|
|
|
19403
19871
|
onRemoveFeature: () => runMutation(active.sectionId, (tree) => removePricingCardFeature(tree, active.index))
|
|
19404
19872
|
}
|
|
19405
19873
|
) }),
|
|
19406
|
-
/* @__PURE__ */
|
|
19874
|
+
/* @__PURE__ */ jsx22(
|
|
19407
19875
|
"div",
|
|
19408
19876
|
{
|
|
19409
19877
|
"data-ohw-bridge": "",
|
|
@@ -19496,10 +19964,10 @@ function extractYouTubeId(input) {
|
|
|
19496
19964
|
}
|
|
19497
19965
|
|
|
19498
19966
|
// src/ui/ai-section/AiVideoOverlay.tsx
|
|
19499
|
-
import { Fragment as Fragment9, jsx as
|
|
19967
|
+
import { Fragment as Fragment9, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
19500
19968
|
var PRIMARY5 = "#0885FE";
|
|
19501
|
-
var
|
|
19502
|
-
var
|
|
19969
|
+
var OHW_BLUE = `var(--ohw-primary, ${PRIMARY5})`;
|
|
19970
|
+
var OHW_BLUE_DARK = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY5}) 60%, #000000)`;
|
|
19503
19971
|
function findVideoBlockElement(sectionId, path) {
|
|
19504
19972
|
const sectionEl = findByInstanceId(sectionId);
|
|
19505
19973
|
if (!sectionEl) return null;
|
|
@@ -19559,12 +20027,12 @@ function requestValidateTree3(postToParent2, tree) {
|
|
|
19559
20027
|
postToParent2({ type: "ow:ai-validate-tree-request", id, tree });
|
|
19560
20028
|
});
|
|
19561
20029
|
}
|
|
19562
|
-
function
|
|
20030
|
+
function Pill({
|
|
19563
20031
|
label,
|
|
19564
20032
|
onClick,
|
|
19565
20033
|
disabled
|
|
19566
20034
|
}) {
|
|
19567
|
-
return /* @__PURE__ */
|
|
20035
|
+
return /* @__PURE__ */ jsx23(
|
|
19568
20036
|
"button",
|
|
19569
20037
|
{
|
|
19570
20038
|
type: "button",
|
|
@@ -19580,7 +20048,7 @@ function Pill2({
|
|
|
19580
20048
|
border: "none",
|
|
19581
20049
|
cursor: disabled ? "default" : "pointer",
|
|
19582
20050
|
background: "#ffffff",
|
|
19583
|
-
color:
|
|
20051
|
+
color: OHW_BLUE_DARK,
|
|
19584
20052
|
opacity: disabled ? 0.4 : 1,
|
|
19585
20053
|
fontSize: 12,
|
|
19586
20054
|
lineHeight: "16px",
|
|
@@ -19623,8 +20091,8 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
19623
20091
|
onCommit(id);
|
|
19624
20092
|
}
|
|
19625
20093
|
};
|
|
19626
|
-
return /* @__PURE__ */
|
|
19627
|
-
/* @__PURE__ */
|
|
20094
|
+
return /* @__PURE__ */ jsxs14("div", { style: { display: "flex", flexDirection: "column", gap: 4, width: "100%", maxWidth: 280 }, children: [
|
|
20095
|
+
/* @__PURE__ */ jsxs14(
|
|
19628
20096
|
"div",
|
|
19629
20097
|
{
|
|
19630
20098
|
style: {
|
|
@@ -19640,12 +20108,12 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
19640
20108
|
boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
|
|
19641
20109
|
},
|
|
19642
20110
|
children: [
|
|
19643
|
-
/* @__PURE__ */
|
|
20111
|
+
/* @__PURE__ */ jsx23(
|
|
19644
20112
|
"span",
|
|
19645
20113
|
{
|
|
19646
20114
|
style: {
|
|
19647
20115
|
flex: "0 0 auto",
|
|
19648
|
-
color:
|
|
20116
|
+
color: OHW_BLUE_DARK,
|
|
19649
20117
|
fontSize: 10,
|
|
19650
20118
|
lineHeight: "16px",
|
|
19651
20119
|
fontWeight: 700,
|
|
@@ -19655,7 +20123,7 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
19655
20123
|
children: "Video"
|
|
19656
20124
|
}
|
|
19657
20125
|
),
|
|
19658
|
-
/* @__PURE__ */
|
|
20126
|
+
/* @__PURE__ */ jsx23(
|
|
19659
20127
|
"input",
|
|
19660
20128
|
{
|
|
19661
20129
|
type: "text",
|
|
@@ -19692,7 +20160,7 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
19692
20160
|
]
|
|
19693
20161
|
}
|
|
19694
20162
|
),
|
|
19695
|
-
invalid && /* @__PURE__ */
|
|
20163
|
+
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
20164
|
] });
|
|
19697
20165
|
}
|
|
19698
20166
|
function VideoToolbar({
|
|
@@ -19702,7 +20170,7 @@ function VideoToolbar({
|
|
|
19702
20170
|
onSetVideoId,
|
|
19703
20171
|
onRemove
|
|
19704
20172
|
}) {
|
|
19705
|
-
return /* @__PURE__ */
|
|
20173
|
+
return /* @__PURE__ */ jsxs14(
|
|
19706
20174
|
"div",
|
|
19707
20175
|
{
|
|
19708
20176
|
"data-ohw-bridge": "",
|
|
@@ -19714,7 +20182,7 @@ function VideoToolbar({
|
|
|
19714
20182
|
gap: 6,
|
|
19715
20183
|
alignItems: "center",
|
|
19716
20184
|
width: 280,
|
|
19717
|
-
background:
|
|
20185
|
+
background: OHW_BLUE,
|
|
19718
20186
|
padding: 8,
|
|
19719
20187
|
borderRadius: 12,
|
|
19720
20188
|
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
@@ -19722,9 +20190,9 @@ function VideoToolbar({
|
|
|
19722
20190
|
opacity: pending ? 0.6 : 1
|
|
19723
20191
|
},
|
|
19724
20192
|
children: [
|
|
19725
|
-
/* @__PURE__ */
|
|
19726
|
-
/* @__PURE__ */
|
|
19727
|
-
error && /* @__PURE__ */
|
|
20193
|
+
/* @__PURE__ */ jsx23(VideoUrlInput, { value: videoId, onCommit: onSetVideoId }),
|
|
20194
|
+
/* @__PURE__ */ jsx23(Pill, { label: "Remove video", onClick: onRemove, disabled: !videoId }),
|
|
20195
|
+
error && /* @__PURE__ */ jsx23("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
|
|
19728
20196
|
]
|
|
19729
20197
|
}
|
|
19730
20198
|
);
|
|
@@ -19844,8 +20312,8 @@ function AiVideoOverlay({
|
|
|
19844
20312
|
const activeBlockRect = useLiveBlockRect(active);
|
|
19845
20313
|
const TOOLBAR_APPROX_H = 90;
|
|
19846
20314
|
const toolbarState = activeBlockRect && activeBlockRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
|
|
19847
|
-
return /* @__PURE__ */
|
|
19848
|
-
hoverHandleRect && hover && /* @__PURE__ */
|
|
20315
|
+
return /* @__PURE__ */ jsxs14(Fragment9, { children: [
|
|
20316
|
+
hoverHandleRect && hover && /* @__PURE__ */ jsx23(
|
|
19849
20317
|
"button",
|
|
19850
20318
|
{
|
|
19851
20319
|
type: "button",
|
|
@@ -19873,15 +20341,15 @@ function AiVideoOverlay({
|
|
|
19873
20341
|
fontSize: 14,
|
|
19874
20342
|
fontWeight: 700
|
|
19875
20343
|
},
|
|
19876
|
-
children: /* @__PURE__ */
|
|
20344
|
+
children: /* @__PURE__ */ jsx23(Star3, { size: 14, style: { pointerEvents: "none" } })
|
|
19877
20345
|
}
|
|
19878
20346
|
),
|
|
19879
|
-
activeBlockRect && active && activeEntry && /* @__PURE__ */
|
|
20347
|
+
activeBlockRect && active && activeEntry && /* @__PURE__ */ jsx23(
|
|
19880
20348
|
ItemInteractionLayer,
|
|
19881
20349
|
{
|
|
19882
20350
|
rect: activeBlockRect,
|
|
19883
20351
|
state: toolbarState,
|
|
19884
|
-
toolbar: /* @__PURE__ */
|
|
20352
|
+
toolbar: /* @__PURE__ */ jsx23(
|
|
19885
20353
|
VideoToolbar,
|
|
19886
20354
|
{
|
|
19887
20355
|
videoId: videoIdAt(activeEntry.tree, active.path),
|
|
@@ -19956,10 +20424,10 @@ function setCarouselAutoplay(tree, on) {
|
|
|
19956
20424
|
}
|
|
19957
20425
|
|
|
19958
20426
|
// src/ui/ai-section/AiFadeCarouselOverlay.tsx
|
|
19959
|
-
import { Fragment as Fragment10, jsx as
|
|
20427
|
+
import { Fragment as Fragment10, jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
19960
20428
|
var PRIMARY6 = "#0885FE";
|
|
19961
|
-
var
|
|
19962
|
-
var
|
|
20429
|
+
var OHW_BLUE2 = `var(--ohw-primary, ${PRIMARY6})`;
|
|
20430
|
+
var OHW_BLUE_DARK2 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY6}) 60%, #000000)`;
|
|
19963
20431
|
function findCarouselItemElement(sectionId, index) {
|
|
19964
20432
|
const sectionEl = findByInstanceId(sectionId);
|
|
19965
20433
|
if (!sectionEl) return null;
|
|
@@ -20038,8 +20506,8 @@ function requestAssetPick2(postToParent2) {
|
|
|
20038
20506
|
postToParent2({ type: "ow:asset-pick", id });
|
|
20039
20507
|
});
|
|
20040
20508
|
}
|
|
20041
|
-
function
|
|
20042
|
-
return /* @__PURE__ */
|
|
20509
|
+
function Pill2({ label, onClick, disabled }) {
|
|
20510
|
+
return /* @__PURE__ */ jsx24(
|
|
20043
20511
|
"button",
|
|
20044
20512
|
{
|
|
20045
20513
|
type: "button",
|
|
@@ -20055,7 +20523,7 @@ function Pill3({ label, onClick, disabled }) {
|
|
|
20055
20523
|
border: "none",
|
|
20056
20524
|
cursor: disabled ? "default" : "pointer",
|
|
20057
20525
|
background: "#ffffff",
|
|
20058
|
-
color:
|
|
20526
|
+
color: OHW_BLUE_DARK2,
|
|
20059
20527
|
opacity: disabled ? 0.4 : 1,
|
|
20060
20528
|
fontSize: 12,
|
|
20061
20529
|
lineHeight: "16px",
|
|
@@ -20073,7 +20541,7 @@ function TogglePill({
|
|
|
20073
20541
|
onToggle,
|
|
20074
20542
|
disabled
|
|
20075
20543
|
}) {
|
|
20076
|
-
return /* @__PURE__ */
|
|
20544
|
+
return /* @__PURE__ */ jsxs15(
|
|
20077
20545
|
"button",
|
|
20078
20546
|
{
|
|
20079
20547
|
type: "button",
|
|
@@ -20092,7 +20560,7 @@ function TogglePill({
|
|
|
20092
20560
|
border: "none",
|
|
20093
20561
|
cursor: disabled ? "default" : "pointer",
|
|
20094
20562
|
background: "#ffffff",
|
|
20095
|
-
color:
|
|
20563
|
+
color: OHW_BLUE_DARK2,
|
|
20096
20564
|
opacity: disabled ? 0.4 : 1,
|
|
20097
20565
|
fontSize: 12,
|
|
20098
20566
|
lineHeight: "16px",
|
|
@@ -20102,7 +20570,7 @@ function TogglePill({
|
|
|
20102
20570
|
},
|
|
20103
20571
|
children: [
|
|
20104
20572
|
label,
|
|
20105
|
-
/* @__PURE__ */
|
|
20573
|
+
/* @__PURE__ */ jsx24(
|
|
20106
20574
|
"span",
|
|
20107
20575
|
{
|
|
20108
20576
|
"aria-hidden": true,
|
|
@@ -20115,10 +20583,10 @@ function TogglePill({
|
|
|
20115
20583
|
// Off is a grey track, not a washed-out blue: the pill's own white background already
|
|
20116
20584
|
// carries the brand colour in the text, and a pale blue track next to it read as
|
|
20117
20585
|
// "disabled control" rather than "switch that is off".
|
|
20118
|
-
background: on ?
|
|
20586
|
+
background: on ? OHW_BLUE_DARK2 : "#CBD5E1",
|
|
20119
20587
|
transition: "background 120ms ease"
|
|
20120
20588
|
},
|
|
20121
|
-
children: /* @__PURE__ */
|
|
20589
|
+
children: /* @__PURE__ */ jsx24(
|
|
20122
20590
|
"span",
|
|
20123
20591
|
{
|
|
20124
20592
|
style: {
|
|
@@ -20147,7 +20615,7 @@ function CarouselSlideToolbar({
|
|
|
20147
20615
|
onChangeImage,
|
|
20148
20616
|
onToggleAutoplay
|
|
20149
20617
|
}) {
|
|
20150
|
-
return /* @__PURE__ */
|
|
20618
|
+
return /* @__PURE__ */ jsxs15(
|
|
20151
20619
|
"div",
|
|
20152
20620
|
{
|
|
20153
20621
|
"data-ohw-bridge": "",
|
|
@@ -20158,7 +20626,7 @@ function CarouselSlideToolbar({
|
|
|
20158
20626
|
flexDirection: "column",
|
|
20159
20627
|
gap: 6,
|
|
20160
20628
|
alignItems: "center",
|
|
20161
|
-
background:
|
|
20629
|
+
background: OHW_BLUE2,
|
|
20162
20630
|
padding: 8,
|
|
20163
20631
|
borderRadius: 12,
|
|
20164
20632
|
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
@@ -20170,11 +20638,11 @@ function CarouselSlideToolbar({
|
|
|
20170
20638
|
pointerEvents: pending ? "none" : "auto"
|
|
20171
20639
|
},
|
|
20172
20640
|
children: [
|
|
20173
|
-
/* @__PURE__ */
|
|
20174
|
-
/* @__PURE__ */
|
|
20175
|
-
/* @__PURE__ */
|
|
20641
|
+
/* @__PURE__ */ jsxs15("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
|
|
20642
|
+
/* @__PURE__ */ jsx24(Pill2, { label: "Change Image", onClick: onChangeImage }),
|
|
20643
|
+
/* @__PURE__ */ jsx24(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
|
|
20176
20644
|
] }),
|
|
20177
|
-
error && /* @__PURE__ */
|
|
20645
|
+
error && /* @__PURE__ */ jsx24("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
|
|
20178
20646
|
]
|
|
20179
20647
|
}
|
|
20180
20648
|
);
|
|
@@ -20314,8 +20782,8 @@ function AiFadeCarouselOverlay({
|
|
|
20314
20782
|
const activeItemRect = useLiveItemRect2(active);
|
|
20315
20783
|
const TOOLBAR_APPROX_H = 90;
|
|
20316
20784
|
const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
|
|
20317
|
-
return /* @__PURE__ */
|
|
20318
|
-
hoverHandleRect && hover && /* @__PURE__ */
|
|
20785
|
+
return /* @__PURE__ */ jsxs15(Fragment10, { children: [
|
|
20786
|
+
hoverHandleRect && hover && /* @__PURE__ */ jsx24(
|
|
20319
20787
|
"button",
|
|
20320
20788
|
{
|
|
20321
20789
|
type: "button",
|
|
@@ -20344,10 +20812,10 @@ function AiFadeCarouselOverlay({
|
|
|
20344
20812
|
fontSize: 14,
|
|
20345
20813
|
fontWeight: 700
|
|
20346
20814
|
},
|
|
20347
|
-
children: /* @__PURE__ */
|
|
20815
|
+
children: /* @__PURE__ */ jsx24(Star4, { size: 14, style: { pointerEvents: "none" } })
|
|
20348
20816
|
}
|
|
20349
20817
|
),
|
|
20350
|
-
swapping && /* @__PURE__ */
|
|
20818
|
+
swapping && /* @__PURE__ */ jsx24(
|
|
20351
20819
|
"div",
|
|
20352
20820
|
{
|
|
20353
20821
|
ref: skeletonRef,
|
|
@@ -20365,15 +20833,15 @@ function AiFadeCarouselOverlay({
|
|
|
20365
20833
|
zIndex: 2147483646,
|
|
20366
20834
|
pointerEvents: "none"
|
|
20367
20835
|
},
|
|
20368
|
-
children: /* @__PURE__ */
|
|
20836
|
+
children: /* @__PURE__ */ jsx24("style", { children: MEDIA_SKELETON_CSS })
|
|
20369
20837
|
}
|
|
20370
20838
|
),
|
|
20371
|
-
activeItemRect && active && activeEntry && /* @__PURE__ */
|
|
20839
|
+
activeItemRect && active && activeEntry && /* @__PURE__ */ jsx24(
|
|
20372
20840
|
ItemInteractionLayer,
|
|
20373
20841
|
{
|
|
20374
20842
|
rect: activeItemRect,
|
|
20375
20843
|
state: toolbarState,
|
|
20376
|
-
toolbar: /* @__PURE__ */
|
|
20844
|
+
toolbar: /* @__PURE__ */ jsx24(
|
|
20377
20845
|
CarouselSlideToolbar,
|
|
20378
20846
|
{
|
|
20379
20847
|
pending,
|
|
@@ -20441,190 +20909,55 @@ function isPointOverBridgeChrome(x, y) {
|
|
|
20441
20909
|
}
|
|
20442
20910
|
return false;
|
|
20443
20911
|
}
|
|
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
|
-
};
|
|
20912
|
+
var BUTTON_LIKE_SELECTOR = `button, [role="button"], ${CTA_BUTTON_SELECTOR}`;
|
|
20913
|
+
function isButtonLikeElement(el) {
|
|
20914
|
+
return el.matches(BUTTON_LIKE_SELECTOR);
|
|
20915
|
+
}
|
|
20916
|
+
function findClosestButtonLike(target) {
|
|
20917
|
+
return target.closest(BUTTON_LIKE_SELECTOR);
|
|
20918
|
+
}
|
|
20919
|
+
function findButtonAtPoint(x, y, media) {
|
|
20920
|
+
const hits = Array.from(
|
|
20921
|
+
document.querySelectorAll(BUTTON_LIKE_SELECTOR)
|
|
20922
|
+
).filter(
|
|
20923
|
+
(el) => containsPoint(el, x, y) && !(media && el.contains(media)) && // Bridge-injected chrome (e.g. MediaOverlay's own "Replace image" button) is never a
|
|
20924
|
+
// site button. Without this, once the media overlay renders its button lands right
|
|
20925
|
+
// under the cursor, gets detected as "a button on the media", and dismisses the very
|
|
20926
|
+
// overlay it belongs to — which removes the button, so the next hit-test finds nothing
|
|
20927
|
+
// and the overlay reappears. Flip-flops every tick: the "Replace image" button flashes.
|
|
20928
|
+
!el.closest("[data-ohw-bridge]") && // A carousel's own prev/next/dot controls (OHH-796) are `<button>`s in the template's
|
|
20929
|
+
// markup, so the bbox sweep that makes real CTAs win over a full-bleed hero image
|
|
20930
|
+
// (OHH-798) claimed them too and drew the editable-item hover frame around a control
|
|
20931
|
+
// that isn't content. They move the slideshow; there is nothing there to edit.
|
|
20932
|
+
!el.closest("[data-ohw-carousel-control]")
|
|
20933
|
+
);
|
|
20934
|
+
if (hits.length === 0) return null;
|
|
20935
|
+
return hits.reduce((best, el) => best.contains(el) ? el : best);
|
|
20936
|
+
}
|
|
20937
|
+
function findNavbarCtaAtPoint(x, y) {
|
|
20938
|
+
const hits = Array.from(
|
|
20939
|
+
document.querySelectorAll('[data-ohw-role="navbar-button"]')
|
|
20940
|
+
).filter((el) => containsPoint(el, x, y) && !el.closest("[data-ohw-bridge]"));
|
|
20941
|
+
if (hits.length === 0) return null;
|
|
20942
|
+
return hits.reduce((best, el) => best.contains(el) ? el : best);
|
|
20943
|
+
}
|
|
20944
|
+
|
|
20945
|
+
// src/lib/session-search.ts
|
|
20946
|
+
var STORAGE_KEY = "ohw-preserved-search";
|
|
20947
|
+
function readPreservedSearch() {
|
|
20948
|
+
if (typeof window === "undefined") return "";
|
|
20949
|
+
const fromUrl = window.location.search;
|
|
20950
|
+
if (fromUrl && fromUrl !== "?") {
|
|
20951
|
+
sessionStorage.setItem(STORAGE_KEY, fromUrl);
|
|
20952
|
+
return fromUrl;
|
|
20622
20953
|
}
|
|
20623
|
-
return
|
|
20954
|
+
return sessionStorage.getItem(STORAGE_KEY) ?? "";
|
|
20624
20955
|
}
|
|
20625
|
-
function
|
|
20626
|
-
const
|
|
20627
|
-
|
|
20956
|
+
function isEditSessionActive() {
|
|
20957
|
+
const search = readPreservedSearch();
|
|
20958
|
+
if (!search || search === "?") return false;
|
|
20959
|
+
const q = search.startsWith("?") ? search.slice(1) : search;
|
|
20960
|
+
return new URLSearchParams(q).get("mode") === "edit";
|
|
20628
20961
|
}
|
|
20629
20962
|
|
|
20630
20963
|
// src/lib/prefetch-sections.ts
|
|
@@ -20726,118 +21059,11 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
|
|
|
20726
21059
|
// src/ui/link-modal/LinkPopover.tsx
|
|
20727
21060
|
import { useEffect as useEffect13 } from "react";
|
|
20728
21061
|
|
|
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
21062
|
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
20837
21063
|
import { Info, X as X4 } from "lucide-react";
|
|
20838
21064
|
|
|
20839
21065
|
// src/ui/link-modal/DestinationBreadcrumb.tsx
|
|
20840
|
-
import { ArrowRight as
|
|
21066
|
+
import { ArrowRight as ArrowRight3, File, GalleryVertical } from "lucide-react";
|
|
20841
21067
|
import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
20842
21068
|
function DestinationBreadcrumb({
|
|
20843
21069
|
pageTitle,
|
|
@@ -20851,7 +21077,7 @@ function DestinationBreadcrumb({
|
|
|
20851
21077
|
/* @__PURE__ */ jsx25("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
|
|
20852
21078
|
] }),
|
|
20853
21079
|
/* @__PURE__ */ jsx25(
|
|
20854
|
-
|
|
21080
|
+
ArrowRight3,
|
|
20855
21081
|
{
|
|
20856
21082
|
size: 16,
|
|
20857
21083
|
className: "shrink-0 text-muted-foreground",
|
|
@@ -20963,7 +21189,7 @@ function Label({ className, ...props }) {
|
|
|
20963
21189
|
}
|
|
20964
21190
|
|
|
20965
21191
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
20966
|
-
import { ChevronDown as
|
|
21192
|
+
import { ChevronDown as ChevronDown5, File as File2, X as X3 } from "lucide-react";
|
|
20967
21193
|
import { jsx as jsx29, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
20968
21194
|
function FieldChevron({
|
|
20969
21195
|
onClick
|
|
@@ -20976,7 +21202,7 @@ function FieldChevron({
|
|
|
20976
21202
|
onClick,
|
|
20977
21203
|
"aria-label": "Open page list",
|
|
20978
21204
|
tabIndex: -1,
|
|
20979
|
-
children: /* @__PURE__ */ jsx29(
|
|
21205
|
+
children: /* @__PURE__ */ jsx29(ChevronDown5, { size: 16 })
|
|
20980
21206
|
}
|
|
20981
21207
|
);
|
|
20982
21208
|
}
|
|
@@ -21206,7 +21432,7 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
21206
21432
|
// src/ui/link-modal/SectionPickerOverlay.tsx
|
|
21207
21433
|
import { useCallback as useCallback7, useEffect as useEffect11, useMemo as useMemo2, useRef as useRef10, useState as useState13 } from "react";
|
|
21208
21434
|
import { createPortal as createPortal2 } from "react-dom";
|
|
21209
|
-
import { ArrowLeft as
|
|
21435
|
+
import { ArrowLeft as ArrowLeft3, Check as Check4 } from "lucide-react";
|
|
21210
21436
|
import { usePathname, useRouter as useRouter2 } from "next/navigation";
|
|
21211
21437
|
|
|
21212
21438
|
// src/lib/parent-scroll.ts
|
|
@@ -21483,7 +21709,7 @@ function SectionPickerOverlay({
|
|
|
21483
21709
|
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
21710
|
onClick: onBack,
|
|
21485
21711
|
children: [
|
|
21486
|
-
/* @__PURE__ */ jsx31(
|
|
21712
|
+
/* @__PURE__ */ jsx31(ArrowLeft3, { className: "size-4 shrink-0", "aria-hidden": true }),
|
|
21487
21713
|
"Back"
|
|
21488
21714
|
]
|
|
21489
21715
|
}
|
|
@@ -21552,7 +21778,7 @@ function SectionPickerOverlay({
|
|
|
21552
21778
|
className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
|
|
21553
21779
|
style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
|
|
21554
21780
|
"aria-hidden": true,
|
|
21555
|
-
children: /* @__PURE__ */ jsx31(
|
|
21781
|
+
children: /* @__PURE__ */ jsx31(Check4, { className: "size-5" })
|
|
21556
21782
|
}
|
|
21557
21783
|
) : null
|
|
21558
21784
|
]
|
|
@@ -21936,6 +22162,7 @@ function shouldUseDevFixtures() {
|
|
|
21936
22162
|
function getLogoElement(el) {
|
|
21937
22163
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
21938
22164
|
if (marked) return marked;
|
|
22165
|
+
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
21939
22166
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
21940
22167
|
if (!root) return null;
|
|
21941
22168
|
const anchor = el.closest("a");
|
|
@@ -22005,7 +22232,7 @@ function addFooterColumnWithPersist({
|
|
|
22005
22232
|
import {
|
|
22006
22233
|
useCallback as useCallback9,
|
|
22007
22234
|
useEffect as useEffect14,
|
|
22008
|
-
useLayoutEffect as
|
|
22235
|
+
useLayoutEffect as useLayoutEffect6,
|
|
22009
22236
|
useRef as useRef11,
|
|
22010
22237
|
useState as useState15
|
|
22011
22238
|
} from "react";
|
|
@@ -22102,7 +22329,7 @@ function FloatingPanel({
|
|
|
22102
22329
|
return () => window.removeEventListener("message", onParentScroll);
|
|
22103
22330
|
}, [open]);
|
|
22104
22331
|
const positionRef = useRef11(position);
|
|
22105
|
-
|
|
22332
|
+
useLayoutEffect6(() => {
|
|
22106
22333
|
if (!open) {
|
|
22107
22334
|
positionRef.current = position;
|
|
22108
22335
|
return;
|
|
@@ -22112,7 +22339,7 @@ function FloatingPanel({
|
|
|
22112
22339
|
}
|
|
22113
22340
|
positionRef.current = position;
|
|
22114
22341
|
}, [open, position, liveScroll, parentScroll]);
|
|
22115
|
-
|
|
22342
|
+
useLayoutEffect6(() => {
|
|
22116
22343
|
if (!open || !panelRef.current) return;
|
|
22117
22344
|
const el = panelRef.current;
|
|
22118
22345
|
const header = el.querySelector("[data-ohw-floating-panel-header]");
|
|
@@ -22321,7 +22548,7 @@ function SocialsDisplayPanel({ display, onChange, className }) {
|
|
|
22321
22548
|
}
|
|
22322
22549
|
|
|
22323
22550
|
// src/ui/button-style-panel.tsx
|
|
22324
|
-
import { Check as
|
|
22551
|
+
import { Check as Check5 } from "lucide-react";
|
|
22325
22552
|
import { jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
22326
22553
|
var SIZE_LABEL = { s: "S", m: "M", l: "L" };
|
|
22327
22554
|
function ButtonStylePanel({
|
|
@@ -22392,7 +22619,7 @@ function ButtonStylePanel({
|
|
|
22392
22619
|
{
|
|
22393
22620
|
className: "absolute right-0.5 top-0.5 flex size-5 items-center justify-center rounded-full bg-primary text-primary-foreground",
|
|
22394
22621
|
"aria-hidden": true,
|
|
22395
|
-
children: /* @__PURE__ */ jsx35(
|
|
22622
|
+
children: /* @__PURE__ */ jsx35(Check5, { className: "size-3", strokeWidth: 3 })
|
|
22396
22623
|
}
|
|
22397
22624
|
) : null
|
|
22398
22625
|
]
|
|
@@ -23417,7 +23644,7 @@ function useSectionDrag({
|
|
|
23417
23644
|
}
|
|
23418
23645
|
|
|
23419
23646
|
// src/ui/footer-container-chrome.tsx
|
|
23420
|
-
import { Plus as
|
|
23647
|
+
import { Plus as Plus4 } from "lucide-react";
|
|
23421
23648
|
import { jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
23422
23649
|
function FooterContainerChrome({
|
|
23423
23650
|
rect,
|
|
@@ -23458,7 +23685,7 @@ function FooterContainerChrome({
|
|
|
23458
23685
|
if (addDisabled) return;
|
|
23459
23686
|
onAdd();
|
|
23460
23687
|
},
|
|
23461
|
-
children: /* @__PURE__ */ jsx36(
|
|
23688
|
+
children: /* @__PURE__ */ jsx36(Plus4, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
23462
23689
|
}
|
|
23463
23690
|
) }),
|
|
23464
23691
|
/* @__PURE__ */ jsx36(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
|
|
@@ -23637,7 +23864,7 @@ function deleteSelectedNavFooterItem(deps) {
|
|
|
23637
23864
|
}
|
|
23638
23865
|
|
|
23639
23866
|
// src/ui/navbar-container-chrome.tsx
|
|
23640
|
-
import { Plus as
|
|
23867
|
+
import { Plus as Plus5 } from "lucide-react";
|
|
23641
23868
|
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
23642
23869
|
function NavbarContainerChrome({
|
|
23643
23870
|
rect,
|
|
@@ -23673,7 +23900,7 @@ function NavbarContainerChrome({
|
|
|
23673
23900
|
e.stopPropagation();
|
|
23674
23901
|
onAdd();
|
|
23675
23902
|
},
|
|
23676
|
-
children: /* @__PURE__ */ jsx37(
|
|
23903
|
+
children: /* @__PURE__ */ jsx37(Plus5, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
23677
23904
|
}
|
|
23678
23905
|
)
|
|
23679
23906
|
}
|
|
@@ -23745,7 +23972,7 @@ function Badge({ className, variant, ...props }) {
|
|
|
23745
23972
|
}
|
|
23746
23973
|
|
|
23747
23974
|
// src/OhhwellsBridge.tsx
|
|
23748
|
-
import { Brush as Brush2, Link as Link2, Plus as
|
|
23975
|
+
import { Brush as Brush2, Link as Link2, Plus as Plus6, Settings } from "lucide-react";
|
|
23749
23976
|
import { Fragment as Fragment13, jsx as jsx40, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
23750
23977
|
var PRIMARY7 = "#0885FE";
|
|
23751
23978
|
var IMAGE_FADE_MS = 300;
|
|
@@ -24522,7 +24749,7 @@ function getNavigationSelectionParent(el) {
|
|
|
24522
24749
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
24523
24750
|
return resolveFooterLinksContainerFrom(el);
|
|
24524
24751
|
}
|
|
24525
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
24752
|
+
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
24753
|
return getNavigationRoot(el);
|
|
24527
24754
|
}
|
|
24528
24755
|
return null;
|
|
@@ -24744,7 +24971,6 @@ var ICONS = {
|
|
|
24744
24971
|
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
24972
|
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
24973
|
};
|
|
24747
|
-
var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
|
|
24748
24974
|
var SELECTION_CHROME_GAP2 = 4;
|
|
24749
24975
|
var TOOLBAR_STROKE_GAP2 = 4;
|
|
24750
24976
|
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
@@ -24842,7 +25068,7 @@ function applyVisibleViewport(el, parentScroll) {
|
|
|
24842
25068
|
el.style.top = `${top}px`;
|
|
24843
25069
|
el.style.height = `${height}px`;
|
|
24844
25070
|
}
|
|
24845
|
-
var
|
|
25071
|
+
var TOOLBAR_EDGE_MARGIN4 = 4;
|
|
24846
25072
|
function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
24847
25073
|
const isAbove = transform.includes("translateY(-100%)");
|
|
24848
25074
|
let visualTop = isAbove ? top - approxH : top;
|
|
@@ -24869,8 +25095,8 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
|
24869
25095
|
function clampToolbarLeft(centerX, toolbarWidth) {
|
|
24870
25096
|
const half = toolbarWidth / 2;
|
|
24871
25097
|
return Math.max(
|
|
24872
|
-
|
|
24873
|
-
Math.min(centerX, window.innerWidth -
|
|
25098
|
+
TOOLBAR_EDGE_MARGIN4 + half,
|
|
25099
|
+
Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN4 - half)
|
|
24874
25100
|
);
|
|
24875
25101
|
}
|
|
24876
25102
|
function calcToolbarPos(rect, parentScroll, toolbarW = 306) {
|
|
@@ -25271,7 +25497,7 @@ function OhhwellsBridge() {
|
|
|
25271
25497
|
}, []);
|
|
25272
25498
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
25273
25499
|
const [subdomain, setSubdomain] = useState18(() => resolveSubdomain(subdomainFromQuery));
|
|
25274
|
-
|
|
25500
|
+
useLayoutEffect7(() => {
|
|
25275
25501
|
const next = resolveSubdomain(subdomainFromQuery);
|
|
25276
25502
|
if (next !== subdomain) setSubdomain(next);
|
|
25277
25503
|
if (next) return;
|
|
@@ -25301,6 +25527,34 @@ function OhhwellsBridge() {
|
|
|
25301
25527
|
const [fetchState, setFetchState] = useState18("idle");
|
|
25302
25528
|
const [showBranding, setShowBranding] = useState18(false);
|
|
25303
25529
|
const autoSaveTimers = useRef14(/* @__PURE__ */ new Map());
|
|
25530
|
+
useEffect17(() => {
|
|
25531
|
+
stampBridgeVersionOnDocument();
|
|
25532
|
+
}, []);
|
|
25533
|
+
useEffect17(() => {
|
|
25534
|
+
if (isEditMode) return;
|
|
25535
|
+
return armLoaderHangBeacon(subdomain, fetchState);
|
|
25536
|
+
}, [isEditMode, subdomain, fetchState]);
|
|
25537
|
+
useEffect17(() => {
|
|
25538
|
+
if (isEditMode || !subdomain) return;
|
|
25539
|
+
const onError = (event) => {
|
|
25540
|
+
reportOutageBeacon({
|
|
25541
|
+
subdomain,
|
|
25542
|
+
reason: "page_error",
|
|
25543
|
+
detail: event.message || "window error"
|
|
25544
|
+
});
|
|
25545
|
+
};
|
|
25546
|
+
const onRejection = (event) => {
|
|
25547
|
+
const reason = event.reason;
|
|
25548
|
+
const detail = reason instanceof Error ? reason.message : typeof reason === "string" ? reason : "unhandledrejection";
|
|
25549
|
+
reportOutageBeacon({ subdomain, reason: "page_error", detail });
|
|
25550
|
+
};
|
|
25551
|
+
window.addEventListener("error", onError);
|
|
25552
|
+
window.addEventListener("unhandledrejection", onRejection);
|
|
25553
|
+
return () => {
|
|
25554
|
+
window.removeEventListener("error", onError);
|
|
25555
|
+
window.removeEventListener("unhandledrejection", onRejection);
|
|
25556
|
+
};
|
|
25557
|
+
}, [isEditMode, subdomain]);
|
|
25304
25558
|
const activeElRef = useRef14(null);
|
|
25305
25559
|
const pointerHeldRef = useRef14(false);
|
|
25306
25560
|
const selectedElRef = useRef14(null);
|
|
@@ -25722,21 +25976,6 @@ function OhhwellsBridge() {
|
|
|
25722
25976
|
const [isItemDragging, setIsItemDragging] = useState18(false);
|
|
25723
25977
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = useState18(false);
|
|
25724
25978
|
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
25979
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState18(null);
|
|
25741
25980
|
const [footerHeadingVisible, setFooterHeadingVisible] = useState18(null);
|
|
25742
25981
|
const footerDragRef = useRef14(null);
|
|
@@ -25762,7 +26001,23 @@ function OhhwellsBridge() {
|
|
|
25762
26001
|
const stylesRef = useRef14("");
|
|
25763
26002
|
const appliedDrawerRef = useRef14(null);
|
|
25764
26003
|
const pendingDeleteUndoRef = useRef14(null);
|
|
26004
|
+
const [floatingPanel, setFloatingPanel] = useState18(null);
|
|
26005
|
+
const floatingPanelOpenRef = useRef14(false);
|
|
26006
|
+
const floatingPanelRef = useRef14(null);
|
|
26007
|
+
floatingPanelRef.current = floatingPanel;
|
|
26008
|
+
const setFloatingPanelRef = useRef14(setFloatingPanel);
|
|
26009
|
+
const [floatingPanelPos, setFloatingPanelPos] = useState18(null);
|
|
26010
|
+
const buttonCollectionDragRef = useRef14(null);
|
|
26011
|
+
const buttonDropInsertIndexRef = useRef14(null);
|
|
26012
|
+
const [buttonDropSlots, setButtonDropSlots] = useState18([]);
|
|
26013
|
+
const [activeButtonDropIndex, setActiveButtonDropIndex] = useState18(null);
|
|
26014
|
+
const buttonPointerDragRef = useRef14(null);
|
|
26015
|
+
const [buttonStyleTick, setButtonStyleTick] = useState18(0);
|
|
26016
|
+
const [logoSizeDraft, setLogoSizeDraft] = useState18(null);
|
|
26017
|
+
const [editorViewport, setEditorViewport] = useState18("desktop");
|
|
26018
|
+
const [parentScrollSnap, setParentScrollSnap] = useState18(null);
|
|
25765
26019
|
const [sitePages, setSitePages] = useState18([]);
|
|
26020
|
+
const collectionItemsRef = useRef14(/* @__PURE__ */ new Map());
|
|
25766
26021
|
const [sectionsByPath, setSectionsByPath] = useState18({});
|
|
25767
26022
|
const sectionsPrefetchGenRef = useRef14(0);
|
|
25768
26023
|
const setLinkPopoverRef = useRef14(setLinkPopover);
|
|
@@ -25770,7 +26025,18 @@ function OhhwellsBridge() {
|
|
|
25770
26025
|
const linkPopoverOpenRef = useRef14(false);
|
|
25771
26026
|
const linkPopoverGraceUntilRef = useRef14(0);
|
|
25772
26027
|
setLinkPopoverRef.current = setLinkPopover;
|
|
26028
|
+
setFloatingPanelRef.current = setFloatingPanel;
|
|
25773
26029
|
linkPopoverSessionRef.current = linkPopover;
|
|
26030
|
+
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
26031
|
+
useEffect17(() => {
|
|
26032
|
+
const syncViewport = () => {
|
|
26033
|
+
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
26034
|
+
setEditorViewport((prev) => prev === next ? prev : next);
|
|
26035
|
+
};
|
|
26036
|
+
syncViewport();
|
|
26037
|
+
window.addEventListener("resize", syncViewport);
|
|
26038
|
+
return () => window.removeEventListener("resize", syncViewport);
|
|
26039
|
+
}, []);
|
|
25774
26040
|
useEffect17(() => {
|
|
25775
26041
|
setSectionOrderPersistHandler((entries) => {
|
|
25776
26042
|
const currentPath = window.location.pathname;
|
|
@@ -25906,10 +26172,12 @@ function OhhwellsBridge() {
|
|
|
25906
26172
|
const onSitePages = (e) => {
|
|
25907
26173
|
if (e.data?.type !== "ow:site-pages" || !Array.isArray(e.data.pages)) return;
|
|
25908
26174
|
if (useFixtures) return;
|
|
25909
|
-
const
|
|
26175
|
+
const incoming = e.data.pages;
|
|
26176
|
+
const mapped = incoming.map((p) => ({
|
|
25910
26177
|
path: p.path,
|
|
25911
26178
|
title: p.title
|
|
25912
26179
|
}));
|
|
26180
|
+
collectionItemsRef.current = indexCollectionItems(incoming);
|
|
25913
26181
|
setSitePages(mapped);
|
|
25914
26182
|
runSectionsPrefetchRef.current(mapped);
|
|
25915
26183
|
};
|
|
@@ -27438,7 +27706,7 @@ function OhhwellsBridge() {
|
|
|
27438
27706
|
isFooterFrameSelection,
|
|
27439
27707
|
postToParent2
|
|
27440
27708
|
]);
|
|
27441
|
-
|
|
27709
|
+
useLayoutEffect7(() => {
|
|
27442
27710
|
if (!subdomain || isEditMode) {
|
|
27443
27711
|
setFetchState("done");
|
|
27444
27712
|
return;
|
|
@@ -27465,6 +27733,7 @@ function OhhwellsBridge() {
|
|
|
27465
27733
|
applyAiFooterFromContent(content);
|
|
27466
27734
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
27467
27735
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
27736
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
27468
27737
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
27469
27738
|
}
|
|
27470
27739
|
applyBrandChrome(content);
|
|
@@ -27475,12 +27744,12 @@ function OhhwellsBridge() {
|
|
|
27475
27744
|
if (key === "__ohw_sections") continue;
|
|
27476
27745
|
if (key === AI_SECTIONS_KEY) continue;
|
|
27477
27746
|
if (key === AI_FOOTER_KEY) continue;
|
|
27747
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
27748
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27478
27749
|
if (key === BRAND_KIT_KEY) continue;
|
|
27479
27750
|
if (key === STYLE_STORE_KEY) continue;
|
|
27480
27751
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
27481
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
27482
27752
|
if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
|
|
27483
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27484
27753
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
27485
27754
|
continue;
|
|
27486
27755
|
}
|
|
@@ -27557,7 +27826,17 @@ function OhhwellsBridge() {
|
|
|
27557
27826
|
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
27558
27827
|
const initialPath = pathname;
|
|
27559
27828
|
fetchedContentPaths.add(`${subdomain}::${initialPath}`);
|
|
27560
|
-
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) =>
|
|
27829
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => {
|
|
27830
|
+
if (!r2.ok) {
|
|
27831
|
+
reportOutageBeacon({
|
|
27832
|
+
subdomain,
|
|
27833
|
+
reason: "content_fetch_failed",
|
|
27834
|
+
detail: `HTTP ${r2.status}`
|
|
27835
|
+
});
|
|
27836
|
+
return null;
|
|
27837
|
+
}
|
|
27838
|
+
return r2.json();
|
|
27839
|
+
}).then((data) => {
|
|
27561
27840
|
if (cancelled) return;
|
|
27562
27841
|
const content = data?.content ?? {};
|
|
27563
27842
|
const branding = Boolean(data?.showBranding);
|
|
@@ -27566,7 +27845,12 @@ function OhhwellsBridge() {
|
|
|
27566
27845
|
recordOverriddenPaths(subdomain, data?.overriddenPaths);
|
|
27567
27846
|
setShowBranding(branding);
|
|
27568
27847
|
return applyContent(content);
|
|
27569
|
-
}).catch(() => {
|
|
27848
|
+
}).catch((err) => {
|
|
27849
|
+
reportOutageBeacon({
|
|
27850
|
+
subdomain,
|
|
27851
|
+
reason: "content_fetch_failed",
|
|
27852
|
+
detail: err instanceof Error ? err.message : "fetch failed"
|
|
27853
|
+
});
|
|
27570
27854
|
}).finally(() => {
|
|
27571
27855
|
if (!cancelled) setFetchState("done");
|
|
27572
27856
|
});
|
|
@@ -27696,17 +27980,18 @@ function OhhwellsBridge() {
|
|
|
27696
27980
|
}
|
|
27697
27981
|
applyAiFooterFromContent(content);
|
|
27698
27982
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
27983
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
27699
27984
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
27700
27985
|
}
|
|
27701
27986
|
for (const [key, val] of Object.entries(content)) {
|
|
27702
27987
|
if (key === "__ohw_sections") continue;
|
|
27703
27988
|
if (key === AI_SECTIONS_KEY) continue;
|
|
27704
27989
|
if (key === AI_FOOTER_KEY) continue;
|
|
27990
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
27991
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27705
27992
|
if (key === BRAND_KIT_KEY) continue;
|
|
27706
27993
|
if (key === STYLE_STORE_KEY) continue;
|
|
27707
27994
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
27708
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
27709
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27710
27995
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
27711
27996
|
continue;
|
|
27712
27997
|
}
|
|
@@ -27789,7 +28074,7 @@ function OhhwellsBridge() {
|
|
|
27789
28074
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
27790
28075
|
};
|
|
27791
28076
|
}, [subdomain, isEditMode, pathname]);
|
|
27792
|
-
|
|
28077
|
+
useLayoutEffect7(() => {
|
|
27793
28078
|
const el = document.getElementById("ohw-loader");
|
|
27794
28079
|
if (!el) return;
|
|
27795
28080
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
@@ -27973,26 +28258,11 @@ function OhhwellsBridge() {
|
|
|
27973
28258
|
const t2 = setTimeout(measure, 500);
|
|
27974
28259
|
const ro = new ResizeObserver(schedule);
|
|
27975
28260
|
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
28261
|
return () => {
|
|
27990
28262
|
clearTimeout(t1);
|
|
27991
28263
|
clearTimeout(t2);
|
|
27992
28264
|
if (raf != null) cancelAnimationFrame(raf);
|
|
27993
28265
|
ro.disconnect();
|
|
27994
|
-
clearResizeTimers();
|
|
27995
|
-
window.removeEventListener("resize", handleResize);
|
|
27996
28266
|
};
|
|
27997
28267
|
}, [pathname, isEditMode, postToParent2]);
|
|
27998
28268
|
useEffect17(() => {
|
|
@@ -28289,6 +28559,13 @@ function OhhwellsBridge() {
|
|
|
28289
28559
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
28290
28560
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
28291
28561
|
if (isInsideLinkEditor(target)) return;
|
|
28562
|
+
if (isInsideFloatingPanel(target)) return;
|
|
28563
|
+
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
28564
|
+
if (target.closest(
|
|
28565
|
+
'[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
|
|
28566
|
+
)) {
|
|
28567
|
+
return;
|
|
28568
|
+
}
|
|
28292
28569
|
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
28293
28570
|
clearMediaSelectionRef.current();
|
|
28294
28571
|
}
|
|
@@ -28312,11 +28589,15 @@ function OhhwellsBridge() {
|
|
|
28312
28589
|
return;
|
|
28313
28590
|
}
|
|
28314
28591
|
}
|
|
28315
|
-
|
|
28316
|
-
if (
|
|
28317
|
-
|
|
28318
|
-
|
|
28319
|
-
|
|
28592
|
+
const collectionItem = matchCollectionItemClick(target, collectionItemsRef.current);
|
|
28593
|
+
if (collectionItem) {
|
|
28594
|
+
e.preventDefault();
|
|
28595
|
+
e.stopPropagation();
|
|
28596
|
+
postToParentRef.current({
|
|
28597
|
+
type: "ow:collection-item-selected",
|
|
28598
|
+
path: collectionItem.path,
|
|
28599
|
+
collection: collectionItem.collection
|
|
28600
|
+
});
|
|
28320
28601
|
return;
|
|
28321
28602
|
}
|
|
28322
28603
|
{
|
|
@@ -28472,9 +28753,13 @@ function OhhwellsBridge() {
|
|
|
28472
28753
|
if (isIconEditable(editable) && !getSocialItem(editable)) {
|
|
28473
28754
|
e.preventDefault();
|
|
28474
28755
|
e.stopPropagation();
|
|
28475
|
-
selectIconElementRef.current(editable);
|
|
28476
28756
|
const aiIcon = editable.hasAttribute("data-ai-icon");
|
|
28477
28757
|
const featureIcon = aiIcon && /\.features\.\d+\.icon$/.test(editable.dataset.ohwKey ?? "");
|
|
28758
|
+
if (aiIcon) {
|
|
28759
|
+
aiSectionApiRef.current?.selectFromElement(editable);
|
|
28760
|
+
} else {
|
|
28761
|
+
selectIconElementRef.current(editable);
|
|
28762
|
+
}
|
|
28478
28763
|
postToParentRef.current({
|
|
28479
28764
|
type: "ow:icon-pick",
|
|
28480
28765
|
key: editable.dataset.ohwKey ?? "",
|
|
@@ -28702,6 +28987,9 @@ function OhhwellsBridge() {
|
|
|
28702
28987
|
setHoveredItemRect(null);
|
|
28703
28988
|
hoveredNavContainerRef.current = null;
|
|
28704
28989
|
setHoveredNavContainerRect(null);
|
|
28990
|
+
siblingHintElRef.current = null;
|
|
28991
|
+
setSiblingHintRect(null);
|
|
28992
|
+
setSiblingHintRects([]);
|
|
28705
28993
|
return;
|
|
28706
28994
|
}
|
|
28707
28995
|
{
|
|
@@ -28822,7 +29110,6 @@ function OhhwellsBridge() {
|
|
|
28822
29110
|
hoveredNavContainerRef.current = null;
|
|
28823
29111
|
setHoveredNavContainerRect(null);
|
|
28824
29112
|
hoveredItemElRef.current = editable;
|
|
28825
|
-
setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
|
|
28826
29113
|
}
|
|
28827
29114
|
}
|
|
28828
29115
|
}
|
|
@@ -29532,7 +29819,11 @@ function OhhwellsBridge() {
|
|
|
29532
29819
|
};
|
|
29533
29820
|
const handleMouseMove = (e) => {
|
|
29534
29821
|
const { clientX, clientY } = e;
|
|
29535
|
-
if (pointOwnedByFloatingPanel(clientX, clientY))
|
|
29822
|
+
if (pointOwnedByFloatingPanel(clientX, clientY)) {
|
|
29823
|
+
dismissImageHover();
|
|
29824
|
+
clearImageHover();
|
|
29825
|
+
return;
|
|
29826
|
+
}
|
|
29536
29827
|
if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
|
|
29537
29828
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
29538
29829
|
formHoverElRef.current = null;
|
|
@@ -29561,7 +29852,12 @@ function OhhwellsBridge() {
|
|
|
29561
29852
|
setHoveredItemRect(null);
|
|
29562
29853
|
hoveredNavContainerRef.current = null;
|
|
29563
29854
|
setHoveredNavContainerRect(null);
|
|
29855
|
+
siblingHintElRef.current = null;
|
|
29856
|
+
setSiblingHintRect(null);
|
|
29857
|
+
setSiblingHintRects([]);
|
|
29564
29858
|
dismissImageHover();
|
|
29859
|
+
clearImageHover();
|
|
29860
|
+
setSectionGap(null);
|
|
29565
29861
|
return;
|
|
29566
29862
|
}
|
|
29567
29863
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
@@ -29573,7 +29869,11 @@ function OhhwellsBridge() {
|
|
|
29573
29869
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
29574
29870
|
const { clientX, clientY } = e.data;
|
|
29575
29871
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
29576
|
-
if (pointOwnedByFloatingPanel(clientX, clientY))
|
|
29872
|
+
if (pointOwnedByFloatingPanel(clientX, clientY)) {
|
|
29873
|
+
dismissImageHover();
|
|
29874
|
+
clearImageHover();
|
|
29875
|
+
return;
|
|
29876
|
+
}
|
|
29577
29877
|
if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
|
|
29578
29878
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
29579
29879
|
probeSectionGapAt(clientX, clientY);
|
|
@@ -29953,6 +30253,7 @@ function OhhwellsBridge() {
|
|
|
29953
30253
|
applyAiFooterFromContent(content);
|
|
29954
30254
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
29955
30255
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
30256
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
29956
30257
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
29957
30258
|
}
|
|
29958
30259
|
applyBrandChrome(content);
|
|
@@ -29967,12 +30268,12 @@ function OhhwellsBridge() {
|
|
|
29967
30268
|
}
|
|
29968
30269
|
if (key === AI_SECTIONS_KEY) continue;
|
|
29969
30270
|
if (key === AI_FOOTER_KEY) continue;
|
|
30271
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
30272
|
+
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
29970
30273
|
if (key === BRAND_KIT_KEY) continue;
|
|
29971
30274
|
if (key === STYLE_STORE_KEY) continue;
|
|
29972
30275
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
29973
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
29974
30276
|
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
30277
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
29977
30278
|
continue;
|
|
29978
30279
|
}
|
|
@@ -30608,12 +30909,24 @@ function OhhwellsBridge() {
|
|
|
30608
30909
|
closeLinkPopoverRef.current();
|
|
30609
30910
|
return;
|
|
30610
30911
|
}
|
|
30912
|
+
if (floatingPanelOpenRef.current) {
|
|
30913
|
+
setFloatingPanelRef.current(null);
|
|
30914
|
+
deselectRef.current();
|
|
30915
|
+
deactivateRef.current();
|
|
30916
|
+
return;
|
|
30917
|
+
}
|
|
30611
30918
|
deselectRef.current();
|
|
30612
30919
|
deactivateRef.current();
|
|
30613
30920
|
clearMediaSelectionRef.current();
|
|
30614
30921
|
clearIconSelectionRef.current();
|
|
30615
30922
|
};
|
|
30616
30923
|
window.addEventListener("message", handleDeactivate);
|
|
30924
|
+
const handleSelectNav = (e) => {
|
|
30925
|
+
if (e.data?.type !== "ow:select-nav") return;
|
|
30926
|
+
const navContainer = findSelectableNavContainer();
|
|
30927
|
+
if (navContainer) selectFrameRef.current(navContainer);
|
|
30928
|
+
};
|
|
30929
|
+
window.addEventListener("message", handleSelectNav);
|
|
30617
30930
|
const handleToastAction = (e) => {
|
|
30618
30931
|
if (e.data?.type !== "ow:toast-action") return;
|
|
30619
30932
|
const actionId = typeof e.data.actionId === "string" ? e.data.actionId : null;
|
|
@@ -31430,10 +31743,11 @@ function OhhwellsBridge() {
|
|
|
31430
31743
|
window.removeEventListener("message", handleDeleteSection);
|
|
31431
31744
|
window.removeEventListener("message", handleDuplicateSection);
|
|
31432
31745
|
window.removeEventListener("message", handleDeactivate);
|
|
31433
|
-
|
|
31746
|
+
window.removeEventListener("message", handleSelectNav);
|
|
31434
31747
|
window.removeEventListener("message", handleToastAction);
|
|
31435
31748
|
window.removeEventListener("message", handleFormCount);
|
|
31436
31749
|
window.removeEventListener("message", handleUiEscape);
|
|
31750
|
+
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
31437
31751
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
31438
31752
|
autoSaveTimers.current.clear();
|
|
31439
31753
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
@@ -31727,7 +32041,7 @@ function OhhwellsBridge() {
|
|
|
31727
32041
|
postToParent2({
|
|
31728
32042
|
type: "ow:ready",
|
|
31729
32043
|
version: "1",
|
|
31730
|
-
bridgeVersion: "0.1.
|
|
32044
|
+
bridgeVersion: "0.1.153-next.415",
|
|
31731
32045
|
path: pathname,
|
|
31732
32046
|
nodes: collectEditableNodes(editContentRef.current),
|
|
31733
32047
|
sections
|
|
@@ -32462,7 +32776,7 @@ function OhhwellsBridge() {
|
|
|
32462
32776
|
className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
|
|
32463
32777
|
onClick: () => setFieldTypePickerOpen((open) => !open),
|
|
32464
32778
|
"data-ohw-add-field": "",
|
|
32465
|
-
children: /* @__PURE__ */ jsx40(
|
|
32779
|
+
children: /* @__PURE__ */ jsx40(Plus6, { size: 15, "aria-hidden": true })
|
|
32466
32780
|
}
|
|
32467
32781
|
),
|
|
32468
32782
|
/* @__PURE__ */ jsx40("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
@@ -32952,6 +33266,7 @@ export {
|
|
|
32952
33266
|
foldAlignIntoTrees,
|
|
32953
33267
|
getEditModeInitialState,
|
|
32954
33268
|
hasMountedContentNodes,
|
|
33269
|
+
indexCollectionItems,
|
|
32955
33270
|
insertFooterHours,
|
|
32956
33271
|
isEditSessionActive,
|
|
32957
33272
|
isPlainLeftClick,
|
|
@@ -32959,6 +33274,7 @@ export {
|
|
|
32959
33274
|
isRenderableTree,
|
|
32960
33275
|
isStickySearchParam,
|
|
32961
33276
|
isValidUrl,
|
|
33277
|
+
matchCollectionItemClick,
|
|
32962
33278
|
nextViableSlide,
|
|
32963
33279
|
parseAiFooterState,
|
|
32964
33280
|
parseAiSectionsState,
|