@ohhwells/bridge 0.1.160-next.429 → 0.1.161
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.cjs +747 -1092
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +770 -1131
- package/dist/index.js.map +1 -1
- package/dist/pages.cjs +1 -9
- package/dist/pages.cjs.map +1 -1
- package/dist/pages.d.cts +0 -2
- package/dist/pages.d.ts +0 -2
- package/dist/pages.js +1 -9
- package/dist/pages.js.map +1 -1
- package/dist/styles.css +0 -116
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1208,21 +1208,21 @@ function chromeFrom(sample) {
|
|
|
1208
1208
|
};
|
|
1209
1209
|
}
|
|
1210
1210
|
function filledPrimary(seed) {
|
|
1211
|
-
const
|
|
1212
|
-
const luminance = relativeLuminance(
|
|
1211
|
+
const paint = parseColor(paintColor(seed)) ?? { r: 15, g: 15, b: 15, a: 1 };
|
|
1212
|
+
const luminance = relativeLuminance(paint);
|
|
1213
1213
|
return {
|
|
1214
|
-
background: toCss({ ...
|
|
1214
|
+
background: toCss({ ...paint, a: 1 }),
|
|
1215
1215
|
color: luminance > 0.55 ? "rgb(15, 15, 15)" : "rgb(255, 255, 255)",
|
|
1216
1216
|
borderColor: TRANSPARENT,
|
|
1217
1217
|
borderWidth: "0px"
|
|
1218
1218
|
};
|
|
1219
1219
|
}
|
|
1220
1220
|
function generatedSecondary(primary) {
|
|
1221
|
-
const
|
|
1221
|
+
const paint = accentColor(primary);
|
|
1222
1222
|
return {
|
|
1223
1223
|
background: TRANSPARENT,
|
|
1224
|
-
color:
|
|
1225
|
-
borderColor:
|
|
1224
|
+
color: paint,
|
|
1225
|
+
borderColor: paint,
|
|
1226
1226
|
borderWidth: "1px"
|
|
1227
1227
|
};
|
|
1228
1228
|
}
|
|
@@ -1235,9 +1235,9 @@ function generatedGhost(primary) {
|
|
|
1235
1235
|
};
|
|
1236
1236
|
}
|
|
1237
1237
|
function normalizeOutlineChrome(outline, primary) {
|
|
1238
|
-
const
|
|
1238
|
+
const paint = accentColor(primary);
|
|
1239
1239
|
const text = parseColor(outline.color);
|
|
1240
|
-
const paintRgb = parseColor(
|
|
1240
|
+
const paintRgb = parseColor(paint);
|
|
1241
1241
|
const primaryLabel = parseColor(primary.color);
|
|
1242
1242
|
const matchesOnPrimary = Boolean(text && primaryLabel) && colorKey(outline.color) === colorKey(primary.color);
|
|
1243
1243
|
const textTooLight = text ? relativeLuminance(text) > 0.7 : false;
|
|
@@ -1246,8 +1246,8 @@ function normalizeOutlineChrome(outline, primary) {
|
|
|
1246
1246
|
const hasBorder = parseFloat(outline.borderWidth) > 0;
|
|
1247
1247
|
return {
|
|
1248
1248
|
...outline,
|
|
1249
|
-
color:
|
|
1250
|
-
borderColor: hasBorder ?
|
|
1249
|
+
color: paint,
|
|
1250
|
+
borderColor: hasBorder ? paint : outline.borderColor
|
|
1251
1251
|
};
|
|
1252
1252
|
}
|
|
1253
1253
|
function generateButtonVariants(samples) {
|
|
@@ -6763,21 +6763,6 @@ function pricingCardFeatureCount(tree, index) {
|
|
|
6763
6763
|
const target = findPricingCollection(tree)?.children?.[index];
|
|
6764
6764
|
return target ? pricingFeatureList(target).length : 0;
|
|
6765
6765
|
}
|
|
6766
|
-
function prevailingFeatureIcon(features) {
|
|
6767
|
-
const counts = /* @__PURE__ */ new Map();
|
|
6768
|
-
for (const row of features) {
|
|
6769
|
-
const key = `${row.icon ?? ""}|${row.iconColor ?? ""}`;
|
|
6770
|
-
const entry = counts.get(key) ?? { count: 0, ...row.icon ? { icon: row.icon } : {}, ...row.iconColor ? { iconColor: row.iconColor } : {} };
|
|
6771
|
-
entry.count += 1;
|
|
6772
|
-
counts.set(key, entry);
|
|
6773
|
-
}
|
|
6774
|
-
let best = null;
|
|
6775
|
-
for (const entry of counts.values()) {
|
|
6776
|
-
if (!best || entry.count > best.count) best = entry;
|
|
6777
|
-
}
|
|
6778
|
-
if (!best) return {};
|
|
6779
|
-
return { ...best.icon ? { icon: best.icon } : {}, ...best.iconColor ? { iconColor: best.iconColor } : {} };
|
|
6780
|
-
}
|
|
6781
6766
|
function addPricingCardFeature(tree, index, text) {
|
|
6782
6767
|
return withPricingCollection(tree, (collection) => {
|
|
6783
6768
|
const children = collection.children;
|
|
@@ -6786,7 +6771,7 @@ function addPricingCardFeature(tree, index, text) {
|
|
|
6786
6771
|
const features = pricingFeatureList(target);
|
|
6787
6772
|
if (features.length >= PRICING_FEATURES_MAX) return false;
|
|
6788
6773
|
target.slots = target.slots ?? {};
|
|
6789
|
-
target.slots.features = [...features, { text
|
|
6774
|
+
target.slots.features = [...features, { text }];
|
|
6790
6775
|
return true;
|
|
6791
6776
|
});
|
|
6792
6777
|
}
|
|
@@ -7430,120 +7415,6 @@ function findSelectableNavContainer(doc = document) {
|
|
|
7430
7415
|
);
|
|
7431
7416
|
}
|
|
7432
7417
|
|
|
7433
|
-
// src/lib/youtube.ts
|
|
7434
|
-
var YOUTUBE_ID_PATTERN = /^[A-Za-z0-9_-]{11}$/;
|
|
7435
|
-
function extractYouTubeId(input) {
|
|
7436
|
-
const trimmed = input.trim();
|
|
7437
|
-
if (!trimmed) return null;
|
|
7438
|
-
if (YOUTUBE_ID_PATTERN.test(trimmed)) return trimmed;
|
|
7439
|
-
let url;
|
|
7440
|
-
try {
|
|
7441
|
-
url = new URL(trimmed);
|
|
7442
|
-
} catch {
|
|
7443
|
-
return null;
|
|
7444
|
-
}
|
|
7445
|
-
const host = url.hostname.replace(/^www\./, "");
|
|
7446
|
-
if (host !== "youtube.com" && host !== "m.youtube.com" && host !== "youtu.be" && host !== "youtube-nocookie.com") {
|
|
7447
|
-
return null;
|
|
7448
|
-
}
|
|
7449
|
-
let candidate = null;
|
|
7450
|
-
if (host === "youtu.be") {
|
|
7451
|
-
candidate = url.pathname.slice(1).split("/")[0] ?? null;
|
|
7452
|
-
} else if (url.pathname === "/watch") {
|
|
7453
|
-
candidate = url.searchParams.get("v");
|
|
7454
|
-
} else {
|
|
7455
|
-
const match = url.pathname.match(/^\/(?:embed|shorts)\/([^/]+)/);
|
|
7456
|
-
candidate = match ? match[1] : null;
|
|
7457
|
-
}
|
|
7458
|
-
return candidate && YOUTUBE_ID_PATTERN.test(candidate) ? candidate : null;
|
|
7459
|
-
}
|
|
7460
|
-
|
|
7461
|
-
// src/lib/section-embed.ts
|
|
7462
|
-
var SECTION_EMBED_SUFFIX = "__ohw_embed";
|
|
7463
|
-
function readStoredEmbed(value) {
|
|
7464
|
-
if (value.startsWith("start\n")) {
|
|
7465
|
-
return { raw: value.slice("start\n".length), at: "start" };
|
|
7466
|
-
}
|
|
7467
|
-
return { raw: value, at: "end" };
|
|
7468
|
-
}
|
|
7469
|
-
function embedFrameSrc(value) {
|
|
7470
|
-
const videoId = extractYouTubeId(value);
|
|
7471
|
-
if (videoId) {
|
|
7472
|
-
return { src: `https://www.youtube-nocookie.com/embed/${videoId}?rel=0`, title: "YouTube video" };
|
|
7473
|
-
}
|
|
7474
|
-
let url;
|
|
7475
|
-
try {
|
|
7476
|
-
url = new URL(value);
|
|
7477
|
-
} catch {
|
|
7478
|
-
return null;
|
|
7479
|
-
}
|
|
7480
|
-
const host = url.hostname.replace(/^www\./, "").toLowerCase();
|
|
7481
|
-
if (host === "google.com" && url.pathname.startsWith("/maps") || host === "maps.google.com") {
|
|
7482
|
-
const query = url.searchParams.get("q") || url.searchParams.get("query") || "";
|
|
7483
|
-
const src = query ? `https://maps.google.com/maps?q=${encodeURIComponent(query)}&output=embed` : `https://maps.google.com/maps?output=embed`;
|
|
7484
|
-
return { src, title: "Map" };
|
|
7485
|
-
}
|
|
7486
|
-
if (host === "maps.app.goo.gl") {
|
|
7487
|
-
return { src: value, title: "Map" };
|
|
7488
|
-
}
|
|
7489
|
-
if (host === "calendly.com" || host.endsWith(".calendly.com") || host === "calendar.google.com") {
|
|
7490
|
-
return { src: value, title: "Calendar" };
|
|
7491
|
-
}
|
|
7492
|
-
if (host === "docs.google.com" && url.pathname.includes("/forms/")) {
|
|
7493
|
-
return { src: value.replace(/\/edit(?:\?.*)?$/i, "/viewform"), title: "Form" };
|
|
7494
|
-
}
|
|
7495
|
-
if (host === "forms.gle") {
|
|
7496
|
-
return { src: value, title: "Form" };
|
|
7497
|
-
}
|
|
7498
|
-
return null;
|
|
7499
|
-
}
|
|
7500
|
-
function place(section, box, at) {
|
|
7501
|
-
if (at === "start") {
|
|
7502
|
-
section.insertBefore(box, section.firstChild);
|
|
7503
|
-
return;
|
|
7504
|
-
}
|
|
7505
|
-
section.appendChild(box);
|
|
7506
|
-
}
|
|
7507
|
-
function paint(section, key, src, title, at) {
|
|
7508
|
-
const existing = section.querySelector(`[data-ohw-section-embed="${CSS.escape(key)}"]`);
|
|
7509
|
-
const frame = existing?.querySelector("iframe");
|
|
7510
|
-
if (existing && frame) {
|
|
7511
|
-
if (frame.getAttribute("src") !== src) frame.setAttribute("src", src);
|
|
7512
|
-
frame.title = title;
|
|
7513
|
-
place(section, existing, at);
|
|
7514
|
-
return;
|
|
7515
|
-
}
|
|
7516
|
-
existing?.remove();
|
|
7517
|
-
const box = document.createElement("div");
|
|
7518
|
-
box.setAttribute("data-ohw-section-embed", key);
|
|
7519
|
-
box.style.cssText = at === "start" ? "width:100%;max-width:960px;margin:0 auto 32px;padding:32px 24px 0;box-sizing:border-box;" : "width:100%;max-width:960px;margin:32px auto 0;padding:0 24px 32px;box-sizing:border-box;";
|
|
7520
|
-
const frameWrap = document.createElement("div");
|
|
7521
|
-
frameWrap.style.cssText = "position:relative;width:100%;aspect-ratio:16/9;min-height:250px;border-radius:12px;overflow:hidden;background:#0f172a;";
|
|
7522
|
-
const iframe = document.createElement("iframe");
|
|
7523
|
-
iframe.src = src;
|
|
7524
|
-
iframe.title = title;
|
|
7525
|
-
iframe.style.cssText = "position:absolute;inset:0;width:100%;height:100%;border:0;";
|
|
7526
|
-
iframe.allow = "accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture";
|
|
7527
|
-
iframe.setAttribute("allowfullscreen", "");
|
|
7528
|
-
frameWrap.appendChild(iframe);
|
|
7529
|
-
box.appendChild(frameWrap);
|
|
7530
|
-
place(section, box, at);
|
|
7531
|
-
}
|
|
7532
|
-
function applySectionEmbeds(content) {
|
|
7533
|
-
for (const [key, val] of Object.entries(content)) {
|
|
7534
|
-
if (!key.endsWith(SECTION_EMBED_SUFFIX)) continue;
|
|
7535
|
-
const sectionId = key.slice(0, -SECTION_EMBED_SUFFIX.length);
|
|
7536
|
-
const section = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
|
|
7537
|
-
const stored = typeof val === "string" ? readStoredEmbed(val) : null;
|
|
7538
|
-
const frame = stored ? embedFrameSrc(stored.raw) : null;
|
|
7539
|
-
if (!section || !stored || !frame) {
|
|
7540
|
-
section?.querySelector(`[data-ohw-section-embed="${CSS.escape(key)}"]`)?.remove();
|
|
7541
|
-
continue;
|
|
7542
|
-
}
|
|
7543
|
-
paint(section, key, frame.src, frame.title, stored.at);
|
|
7544
|
-
}
|
|
7545
|
-
}
|
|
7546
|
-
|
|
7547
7418
|
// src/ui/ai-tree/aiSectionsManager.tsx
|
|
7548
7419
|
var import_react_dom = require("react-dom");
|
|
7549
7420
|
var import_client = require("react-dom/client");
|
|
@@ -8117,7 +7988,7 @@ var AI_MOBILE_CSS = [
|
|
|
8117
7988
|
// page's first section. Top only (bottom needs no nav clearance); ~96px approximates the
|
|
8118
7989
|
// template nav's own height (measured ~94px) — there's no shared `--ohw-header-h` var to read
|
|
8119
7990
|
// an exact figure from (no live measurement exists), so this is a safe approximation, not a
|
|
8120
|
-
// pixel-exact fit. Horizontal spacing already comes from `data-ai-
|
|
7991
|
+
// pixel-exact fit. Horizontal spacing already comes from `data-ai-container`.
|
|
8121
7992
|
'[data-ai-overlay-clearance] [data-ai-overlap-layer="overlay"]{padding-top:96px}',
|
|
8122
7993
|
// A full-bleed carousel's height is pure arithmetic: it spans the whole window, so 16/9 turns
|
|
8123
7994
|
// window width straight into height. Measured at 16/9 it came out ~90% of the viewport at EVERY
|
|
@@ -8133,10 +8004,8 @@ var AI_MOBILE_CSS = [
|
|
|
8133
8004
|
"[data-ai-section]{overflow-x:hidden}",
|
|
8134
8005
|
// `:not([data-ai-full-bleed])`: this `!important` gutter beat the inline `padding: 0` that a
|
|
8135
8006
|
// full-bleed section's container sets, so a carousel/media hero that is edge-to-edge on desktop
|
|
8136
|
-
// still got a 20px band of section background down both sides on a phone.
|
|
8137
|
-
|
|
8138
|
-
"[data-ai-section-inner]:not([data-ai-full-bleed]){padding:0 20px !important}",
|
|
8139
|
-
"[data-ai-container]{padding:0 20px !important}",
|
|
8007
|
+
// still got a 20px band of section background down both sides on a phone.
|
|
8008
|
+
"[data-ai-container]:not([data-ai-full-bleed]){padding:0 20px !important}",
|
|
8140
8009
|
"[data-ai-row]{display:flex !important;flex-direction:column !important;align-items:stretch !important}",
|
|
8141
8010
|
"[data-ai-cell]{width:100%;min-width:0}",
|
|
8142
8011
|
// The rule above turns every row into a COLUMN flex container on phones, which silently breaks
|
|
@@ -8341,31 +8210,6 @@ function pricingCardEmphasis(featured, ctx, hasBg) {
|
|
|
8341
8210
|
function textAttrs(ctx, path) {
|
|
8342
8211
|
return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
|
|
8343
8212
|
}
|
|
8344
|
-
var AI_RESPONSIVE_CSS = [
|
|
8345
|
-
"@media (max-width: 960px) {",
|
|
8346
|
-
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
|
|
8347
|
-
' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
|
|
8348
|
-
"}",
|
|
8349
|
-
"@media (max-width: 640px) {",
|
|
8350
|
-
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
|
|
8351
|
-
" [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
|
|
8352
|
-
// Group containers flatten to a column on phones; span placements come along for free.
|
|
8353
|
-
// `:not([data-ai-group="overlap"])` for the same reason as the twin pair in AI_MOBILE_CSS — see
|
|
8354
|
-
// the comment there. This sheet's copy is the narrower selector, so without the exemption it
|
|
8355
|
-
// flattens an `overlap` hero below 640px even though the other rule stands down: measured a 390px
|
|
8356
|
-
// viewport with the heading/CTA in flow *under* the image, 219px of section background where the
|
|
8357
|
-
// layered text used to be.
|
|
8358
|
-
' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) { display: flex !important; flex-direction: column !important; }',
|
|
8359
|
-
' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) > * { grid-column: auto !important; }',
|
|
8360
|
-
// `:not([data-ai-full-bleed])` for the same reason as the twin rule in AI_MOBILE_CSS: this one
|
|
8361
|
-
// is narrower (0,2,0 vs 0,1,0) and also `!important`, so without the guard it wins outright and
|
|
8362
|
-
// a full-bleed hero gets its 20px side band back below 640px only — the one width where the
|
|
8363
|
-
// other rule had already been taught to stand down.
|
|
8364
|
-
" [data-ai-responsive] [data-ai-section-inner]:not([data-ai-full-bleed]) { padding-left: 20px !important; padding-right: 20px !important; }",
|
|
8365
|
-
" [data-ai-responsive] { overflow-x: hidden; }",
|
|
8366
|
-
" [data-ai-responsive] img { max-width: 100%; }",
|
|
8367
|
-
"}"
|
|
8368
|
-
].join("\n");
|
|
8369
8213
|
var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
8370
8214
|
function MediaBox({
|
|
8371
8215
|
refValue,
|
|
@@ -8420,7 +8264,7 @@ function MediaBox({
|
|
|
8420
8264
|
position: fill ? "absolute" : void 0,
|
|
8421
8265
|
inset: fill ? 0 : void 0,
|
|
8422
8266
|
width: fill ? "100%" : fixedSize ? "auto" : "100%",
|
|
8423
|
-
height: fill ? "100%" :
|
|
8267
|
+
height: fill ? "100%" : void 0,
|
|
8424
8268
|
aspectRatio: fill ? void 0 : aspectRatio,
|
|
8425
8269
|
minHeight: fill || fixedSize ? void 0 : height ?? (aspectRatio ? void 0 : 180),
|
|
8426
8270
|
borderRadius: radius,
|
|
@@ -9916,7 +9760,7 @@ function CollectionBlock({ node, ctx, path }) {
|
|
|
9916
9760
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
9917
9761
|
"div",
|
|
9918
9762
|
{
|
|
9919
|
-
"data-ai-grid":
|
|
9763
|
+
"data-ai-grid": "",
|
|
9920
9764
|
"data-ohw-pricing-collection": isPricing ? "" : void 0,
|
|
9921
9765
|
style: {
|
|
9922
9766
|
display: "grid",
|
|
@@ -10218,7 +10062,7 @@ function renderNode(node, ctx, path, ambientAlign) {
|
|
|
10218
10062
|
},
|
|
10219
10063
|
children: [
|
|
10220
10064
|
i > 0 && ctx.heroOverlapFullBleed ? (
|
|
10221
|
-
// The section's `data-ai-
|
|
10065
|
+
// The section's `data-ai-container` gave up its max-width/gutter so the base
|
|
10222
10066
|
// layer (this group's i===0 sibling) can span edge-to-edge — reintroduced here,
|
|
10223
10067
|
// scoped to just the overlay text, so a heading/copy/CTA stack doesn't stretch
|
|
10224
10068
|
// the full section width instead of reading at the usual content width.
|
|
@@ -10637,7 +10481,6 @@ function AiTreeRenderer({
|
|
|
10637
10481
|
...fillHeight ? { "data-ai-fill-height": "" } : {},
|
|
10638
10482
|
...needsOverlayClearance ? { "data-ai-overlay-clearance": "" } : {},
|
|
10639
10483
|
...bgAttrs,
|
|
10640
|
-
"data-ai-responsive": "",
|
|
10641
10484
|
style: {
|
|
10642
10485
|
position: "relative",
|
|
10643
10486
|
padding: `${padCss} 0`,
|
|
@@ -10651,13 +10494,12 @@ function AiTreeRenderer({
|
|
|
10651
10494
|
...fillHeight ? { display: "grid" } : {}
|
|
10652
10495
|
},
|
|
10653
10496
|
children: [
|
|
10654
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
|
|
10655
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
|
|
10656
10497
|
isOverlay && backgroundUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
|
|
10498
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
|
|
10657
10499
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
10658
10500
|
"div",
|
|
10659
10501
|
{
|
|
10660
|
-
"data-ai-
|
|
10502
|
+
"data-ai-container": "",
|
|
10661
10503
|
...fullBleedMedia ? { "data-ai-full-bleed": "" } : {},
|
|
10662
10504
|
style: {
|
|
10663
10505
|
position: "relative",
|
|
@@ -10674,7 +10516,7 @@ function AiTreeRenderer({
|
|
|
10674
10516
|
children: tree.rows.map((row, r2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
10675
10517
|
"div",
|
|
10676
10518
|
{
|
|
10677
|
-
"data-ai-
|
|
10519
|
+
"data-ai-row": "",
|
|
10678
10520
|
style: {
|
|
10679
10521
|
display: "grid",
|
|
10680
10522
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
@@ -11336,10 +11178,9 @@ function applyAiSectionsToDom(state, options) {
|
|
|
11336
11178
|
if (existing && existing.serialized === serialized && existing.container.isConnected) {
|
|
11337
11179
|
continue;
|
|
11338
11180
|
}
|
|
11181
|
+
const isNewMount = !existing || !existing.container.isConnected;
|
|
11339
11182
|
let container = existing?.container;
|
|
11340
|
-
let isNewMount = false;
|
|
11341
11183
|
if (!container || !container.isConnected) {
|
|
11342
|
-
isNewMount = true;
|
|
11343
11184
|
existing?.root.unmount();
|
|
11344
11185
|
container?.remove();
|
|
11345
11186
|
container = document.createElement("div");
|
|
@@ -11677,34 +11518,6 @@ function minSpanForFooterBlock(type) {
|
|
|
11677
11518
|
return 3;
|
|
11678
11519
|
}
|
|
11679
11520
|
}
|
|
11680
|
-
function readLiveSocialItems() {
|
|
11681
|
-
const root = getFooterRoot();
|
|
11682
|
-
const row = root?.querySelector("[data-ohw-socials-row]");
|
|
11683
|
-
if (!row) return [];
|
|
11684
|
-
const items = [];
|
|
11685
|
-
for (const anchor of Array.from(row.querySelectorAll("a[href]"))) {
|
|
11686
|
-
const href = anchor.getAttribute("href")?.trim() ?? "";
|
|
11687
|
-
const aria = anchor.getAttribute("aria-label")?.trim().toLowerCase() ?? "";
|
|
11688
|
-
const platform = FOOTER_SOCIAL_PLATFORMS.find((name) => aria === name) ?? FOOTER_SOCIAL_PLATFORMS.find((name) => href.toLowerCase().includes(name));
|
|
11689
|
-
if (!platform || !/^https?:\/\//i.test(href)) continue;
|
|
11690
|
-
items.push({ platform, href });
|
|
11691
|
-
}
|
|
11692
|
-
return items;
|
|
11693
|
-
}
|
|
11694
|
-
function syncSocialRowsFromDom(tree) {
|
|
11695
|
-
const root = getFooterRoot();
|
|
11696
|
-
if (!root) return;
|
|
11697
|
-
const row = root.querySelector("[data-ohw-socials-row]");
|
|
11698
|
-
const live = readLiveSocialItems();
|
|
11699
|
-
if (row && live.length === 0) return;
|
|
11700
|
-
for (const col of tree.columns) {
|
|
11701
|
-
col.blocks = col.blocks.flatMap((block) => {
|
|
11702
|
-
if (block.type !== "social-row") return [block];
|
|
11703
|
-
if (!row) return [];
|
|
11704
|
-
return [{ ...block, items: live.map((item) => ({ platform: item.platform, href: item.href })) }];
|
|
11705
|
-
});
|
|
11706
|
-
}
|
|
11707
|
-
}
|
|
11708
11521
|
function collectBrandBlocks(tree) {
|
|
11709
11522
|
const brand = [];
|
|
11710
11523
|
for (const col of tree.columns) {
|
|
@@ -11950,7 +11763,6 @@ function textOf2(el) {
|
|
|
11950
11763
|
}
|
|
11951
11764
|
function syncFooterTreeLinksFromDom(tree) {
|
|
11952
11765
|
const next = cloneTree(tree);
|
|
11953
|
-
syncSocialRowsFromDom(next);
|
|
11954
11766
|
const domCols = listFooterColumns().map((col) => {
|
|
11955
11767
|
const heading = getFooterColumnHeadingEl(col);
|
|
11956
11768
|
const title = heading ? textOf2(heading) : void 0;
|
|
@@ -17655,7 +17467,7 @@ function apiBase() {
|
|
|
17655
17467
|
function bridgeVersion() {
|
|
17656
17468
|
try {
|
|
17657
17469
|
if (true) {
|
|
17658
|
-
return "0.1.
|
|
17470
|
+
return "0.1.161";
|
|
17659
17471
|
}
|
|
17660
17472
|
} catch {
|
|
17661
17473
|
}
|
|
@@ -17669,7 +17481,7 @@ function stampBridgeVersionOnDocument() {
|
|
|
17669
17481
|
return;
|
|
17670
17482
|
}
|
|
17671
17483
|
try {
|
|
17672
|
-
const v = true ? "0.1.
|
|
17484
|
+
const v = true ? "0.1.161" : "";
|
|
17673
17485
|
if (v) {
|
|
17674
17486
|
document.documentElement.setAttribute("data-ohw-bridge-version", v);
|
|
17675
17487
|
window.__OHW_BRIDGE_VERSION__ = v;
|
|
@@ -18347,7 +18159,6 @@ function MediaOverlay({
|
|
|
18347
18159
|
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
18348
18160
|
);
|
|
18349
18161
|
}, [isVideo]);
|
|
18350
|
-
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
18351
18162
|
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
18352
18163
|
const box = {
|
|
18353
18164
|
position: "fixed",
|
|
@@ -18446,10 +18257,11 @@ function MediaOverlay({
|
|
|
18446
18257
|
className: "flex items-center justify-center cursor-pointer",
|
|
18447
18258
|
style: {
|
|
18448
18259
|
...box,
|
|
18449
|
-
//
|
|
18450
|
-
//
|
|
18451
|
-
//
|
|
18452
|
-
|
|
18260
|
+
// When text overlays this media, let clicks fall THROUGH to the text underneath. In the
|
|
18261
|
+
// parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
|
|
18262
|
+
// in-document, pointer-events does it natively. The button below opts back in, so
|
|
18263
|
+
// Replace still works.
|
|
18264
|
+
pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
|
|
18453
18265
|
// Selected: a firm component ring with no wash, so the image reads as chosen rather
|
|
18454
18266
|
// than hovered. Hover keeps the existing tinted preview.
|
|
18455
18267
|
boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
@@ -18476,17 +18288,17 @@ function MediaOverlay({
|
|
|
18476
18288
|
},
|
|
18477
18289
|
children: [
|
|
18478
18290
|
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
18479
|
-
|
|
18291
|
+
isVideo ? "Replace video" : "Replace image"
|
|
18480
18292
|
]
|
|
18481
18293
|
}
|
|
18482
18294
|
),
|
|
18483
|
-
|
|
18295
|
+
replaceMode === "none" || cueOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
18484
18296
|
Button,
|
|
18485
18297
|
{
|
|
18486
18298
|
"data-ohw-media-overlay": "",
|
|
18487
18299
|
variant: "outline",
|
|
18488
18300
|
size: "sm",
|
|
18489
|
-
"aria-label":
|
|
18301
|
+
"aria-label": isVideo ? "Replace video" : "Replace image",
|
|
18490
18302
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
18491
18303
|
style: {
|
|
18492
18304
|
...OVERLAY_BUTTON_STYLE,
|
|
@@ -18509,7 +18321,7 @@ function MediaOverlay({
|
|
|
18509
18321
|
},
|
|
18510
18322
|
children: [
|
|
18511
18323
|
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
18512
|
-
replaceMode === "full" ?
|
|
18324
|
+
replaceMode === "full" ? isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image" : null
|
|
18513
18325
|
]
|
|
18514
18326
|
}
|
|
18515
18327
|
)
|
|
@@ -19103,7 +18915,7 @@ function AiSectionOverlay({
|
|
|
19103
18915
|
|
|
19104
18916
|
// src/ui/ai-section/AiMediaStripOverlay.tsx
|
|
19105
18917
|
var import_react12 = require("react");
|
|
19106
|
-
var
|
|
18918
|
+
var import_lucide_react8 = require("lucide-react");
|
|
19107
18919
|
|
|
19108
18920
|
// src/lib/ai-media-strip-tree.ts
|
|
19109
18921
|
var MEDIA_STRIP_ITEM_MIN = 1;
|
|
@@ -19217,6 +19029,14 @@ function setMediaStripItemAsset(tree, index, assetId) {
|
|
|
19217
19029
|
return true;
|
|
19218
19030
|
});
|
|
19219
19031
|
}
|
|
19032
|
+
function setMediaStripItemAlt(tree, index, alt) {
|
|
19033
|
+
return withMediaStrip(tree, (block) => {
|
|
19034
|
+
const items = block.items;
|
|
19035
|
+
if (index < 0 || index >= items.length) return false;
|
|
19036
|
+
items[index] = { ...items[index], alt };
|
|
19037
|
+
return true;
|
|
19038
|
+
});
|
|
19039
|
+
}
|
|
19220
19040
|
function setMediaStripItemLink(tree, index, link) {
|
|
19221
19041
|
return withMediaStrip(tree, (block) => {
|
|
19222
19042
|
const items = block.items;
|
|
@@ -19234,117 +19054,11 @@ function setMediaStripItemLink(tree, index, link) {
|
|
|
19234
19054
|
});
|
|
19235
19055
|
}
|
|
19236
19056
|
|
|
19237
|
-
// src/ui/dialog.tsx
|
|
19238
|
-
var React9 = __toESM(require("react"), 1);
|
|
19239
|
-
var import_radix_ui6 = require("radix-ui");
|
|
19240
|
-
var import_lucide_react8 = require("lucide-react");
|
|
19241
|
-
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
19242
|
-
function Dialog2({
|
|
19243
|
-
...props
|
|
19244
|
-
}) {
|
|
19245
|
-
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_radix_ui6.Dialog.Root, { "data-slot": "dialog", ...props });
|
|
19246
|
-
}
|
|
19247
|
-
function DialogPortal({
|
|
19248
|
-
...props
|
|
19249
|
-
}) {
|
|
19250
|
-
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_radix_ui6.Dialog.Portal, { ...props });
|
|
19251
|
-
}
|
|
19252
|
-
function DialogOverlay({
|
|
19253
|
-
className,
|
|
19254
|
-
...props
|
|
19255
|
-
}) {
|
|
19256
|
-
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19257
|
-
import_radix_ui6.Dialog.Overlay,
|
|
19258
|
-
{
|
|
19259
|
-
"data-slot": "dialog-overlay",
|
|
19260
|
-
"data-ohw-link-modal-root": "",
|
|
19261
|
-
className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
|
|
19262
|
-
...props
|
|
19263
|
-
}
|
|
19264
|
-
);
|
|
19265
|
-
}
|
|
19266
|
-
var DialogContent = React9.forwardRef(
|
|
19267
|
-
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
19268
|
-
const positionMode = container ? "absolute" : "fixed";
|
|
19269
|
-
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(DialogPortal, { container: container ?? void 0, children: [
|
|
19270
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
19271
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
19272
|
-
import_radix_ui6.Dialog.Content,
|
|
19273
|
-
{
|
|
19274
|
-
ref,
|
|
19275
|
-
"data-slot": "dialog-content",
|
|
19276
|
-
className: cn(
|
|
19277
|
-
positionMode,
|
|
19278
|
-
"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",
|
|
19279
|
-
"rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
|
|
19280
|
-
container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
|
|
19281
|
-
className
|
|
19282
|
-
),
|
|
19283
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
19284
|
-
...props,
|
|
19285
|
-
children: [
|
|
19286
|
-
children,
|
|
19287
|
-
showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19288
|
-
import_radix_ui6.Dialog.Close,
|
|
19289
|
-
{
|
|
19290
|
-
type: "button",
|
|
19291
|
-
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
19292
|
-
"aria-label": "Close",
|
|
19293
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react8.X, { size: 16, "aria-hidden": true })
|
|
19294
|
-
}
|
|
19295
|
-
) : null
|
|
19296
|
-
]
|
|
19297
|
-
}
|
|
19298
|
-
)
|
|
19299
|
-
] });
|
|
19300
|
-
}
|
|
19301
|
-
);
|
|
19302
|
-
DialogContent.displayName = import_radix_ui6.Dialog.Content.displayName;
|
|
19303
|
-
function DialogHeader({
|
|
19304
|
-
className,
|
|
19305
|
-
...props
|
|
19306
|
-
}) {
|
|
19307
|
-
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
19308
|
-
}
|
|
19309
|
-
function DialogFooter({
|
|
19310
|
-
className,
|
|
19311
|
-
...props
|
|
19312
|
-
}) {
|
|
19313
|
-
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19314
|
-
"div",
|
|
19315
|
-
{
|
|
19316
|
-
className: cn("flex items-center justify-end gap-2", className),
|
|
19317
|
-
...props
|
|
19318
|
-
}
|
|
19319
|
-
);
|
|
19320
|
-
}
|
|
19321
|
-
var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19322
|
-
import_radix_ui6.Dialog.Title,
|
|
19323
|
-
{
|
|
19324
|
-
ref,
|
|
19325
|
-
className: cn(
|
|
19326
|
-
"text-lg font-semibold leading-none tracking-tight text-card-foreground",
|
|
19327
|
-
className
|
|
19328
|
-
),
|
|
19329
|
-
...props
|
|
19330
|
-
}
|
|
19331
|
-
));
|
|
19332
|
-
DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
|
|
19333
|
-
var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19334
|
-
import_radix_ui6.Dialog.Description,
|
|
19335
|
-
{
|
|
19336
|
-
ref,
|
|
19337
|
-
className: cn("text-sm text-muted-foreground", className),
|
|
19338
|
-
...props
|
|
19339
|
-
}
|
|
19340
|
-
));
|
|
19341
|
-
DialogDescription.displayName = import_radix_ui6.Dialog.Description.displayName;
|
|
19342
|
-
var DialogClose = import_radix_ui6.Dialog.Close;
|
|
19343
|
-
|
|
19344
19057
|
// src/ui/ai-section/AiMediaStripOverlay.tsx
|
|
19345
|
-
var
|
|
19346
|
-
var PRIMARY3 = "
|
|
19347
|
-
var
|
|
19058
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
19059
|
+
var PRIMARY3 = "#0885FE";
|
|
19060
|
+
var OHW_BLUE = `var(--ohw-primary, ${PRIMARY3})`;
|
|
19061
|
+
var OHW_BLUE_DARK = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY3}) 60%, #000000)`;
|
|
19348
19062
|
function findMediaStripItemElement(sectionId, index) {
|
|
19349
19063
|
const sectionEl = findByInstanceId(sectionId);
|
|
19350
19064
|
if (!sectionEl) return null;
|
|
@@ -19354,35 +19068,14 @@ function findMediaStripItemElement(sectionId, index) {
|
|
|
19354
19068
|
}
|
|
19355
19069
|
return null;
|
|
19356
19070
|
}
|
|
19357
|
-
function
|
|
19358
|
-
|
|
19359
|
-
if (target.closest(CHROME_SELECTOR)) return null;
|
|
19360
|
-
const itemEl = target.closest("[data-ohw-media-strip-item]");
|
|
19361
|
-
if (!itemEl) return null;
|
|
19362
|
-
const sectionEl = itemEl.closest("[data-ohw-section]");
|
|
19363
|
-
const unit = sectionEl ? movableUnit(sectionEl) : null;
|
|
19364
|
-
const sectionId = unit ? instanceIdOf(unit) || null : null;
|
|
19365
|
-
const index = Number(itemEl.dataset.ohwMediaStripIndex);
|
|
19366
|
-
if (!sectionId || Number.isNaN(index)) return null;
|
|
19367
|
-
return { sectionId, index };
|
|
19368
|
-
}
|
|
19369
|
-
function sameRef(a, b) {
|
|
19370
|
-
return a?.sectionId === b?.sectionId && a?.index === b?.index;
|
|
19371
|
-
}
|
|
19372
|
-
function rectOf(el) {
|
|
19071
|
+
function readRect2(ref) {
|
|
19072
|
+
const el = ref && findMediaStripItemElement(ref.sectionId, ref.index);
|
|
19373
19073
|
if (!el) return null;
|
|
19374
19074
|
const r2 = el.getBoundingClientRect();
|
|
19375
19075
|
if (r2.width <= 0 || r2.height <= 0) return null;
|
|
19376
19076
|
return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
|
|
19377
19077
|
}
|
|
19378
|
-
function
|
|
19379
|
-
return rectOf(ref && findMediaStripItemElement(ref.sectionId, ref.index));
|
|
19380
|
-
}
|
|
19381
|
-
function readStripRect(ref) {
|
|
19382
|
-
const item = ref && findMediaStripItemElement(ref.sectionId, ref.index);
|
|
19383
|
-
return rectOf(item?.closest("[data-ohw-media-strip]") ?? item);
|
|
19384
|
-
}
|
|
19385
|
-
function useLiveItemRect(ref, strip = false) {
|
|
19078
|
+
function useLiveItemRect(ref) {
|
|
19386
19079
|
const [rect, setRect] = (0, import_react12.useState)(null);
|
|
19387
19080
|
(0, import_react12.useEffect)(() => {
|
|
19388
19081
|
if (!ref) {
|
|
@@ -19390,7 +19083,7 @@ function useLiveItemRect(ref, strip = false) {
|
|
|
19390
19083
|
return;
|
|
19391
19084
|
}
|
|
19392
19085
|
const update = () => {
|
|
19393
|
-
const next =
|
|
19086
|
+
const next = readRect2(ref);
|
|
19394
19087
|
setRect(
|
|
19395
19088
|
(prev) => prev && next && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
|
|
19396
19089
|
);
|
|
@@ -19405,49 +19098,9 @@ function useLiveItemRect(ref, strip = false) {
|
|
|
19405
19098
|
window.removeEventListener("resize", update);
|
|
19406
19099
|
clearInterval(interval);
|
|
19407
19100
|
};
|
|
19408
|
-
}, [ref?.sectionId, ref?.index
|
|
19101
|
+
}, [ref?.sectionId, ref?.index]);
|
|
19409
19102
|
return rect;
|
|
19410
19103
|
}
|
|
19411
|
-
var TOOLBAR_STRIP_GAP = 52;
|
|
19412
|
-
var TOOLBAR_STRIP_GAP_MOBILE = 42;
|
|
19413
|
-
var TOOLBAR_EDGE_MARGIN2 = 4;
|
|
19414
|
-
function StripToolbarSlot({ stripRect, children }) {
|
|
19415
|
-
const slotRef = (0, import_react12.useRef)(null);
|
|
19416
|
-
const [shift, setShift] = (0, import_react12.useState)(0);
|
|
19417
|
-
const centerX = stripRect.left + stripRect.width / 2;
|
|
19418
|
-
(0, import_react12.useLayoutEffect)(() => {
|
|
19419
|
-
const slot = slotRef.current;
|
|
19420
|
-
if (!slot) return;
|
|
19421
|
-
const clamp = () => {
|
|
19422
|
-
const w = slot.offsetWidth;
|
|
19423
|
-
if (w <= 0) return;
|
|
19424
|
-
const half = w / 2;
|
|
19425
|
-
const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
|
|
19426
|
-
setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
|
|
19427
|
-
};
|
|
19428
|
-
clamp();
|
|
19429
|
-
const ro = new ResizeObserver(clamp);
|
|
19430
|
-
ro.observe(slot);
|
|
19431
|
-
return () => ro.disconnect();
|
|
19432
|
-
}, [centerX, children]);
|
|
19433
|
-
const mobile = window.innerWidth <= 480;
|
|
19434
|
-
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19435
|
-
"div",
|
|
19436
|
-
{
|
|
19437
|
-
ref: slotRef,
|
|
19438
|
-
"data-ohw-bridge": "",
|
|
19439
|
-
"data-ohw-item-interaction": "",
|
|
19440
|
-
className: "pointer-events-auto fixed",
|
|
19441
|
-
style: {
|
|
19442
|
-
top: stripRect.top - (mobile ? TOOLBAR_STRIP_GAP_MOBILE : TOOLBAR_STRIP_GAP),
|
|
19443
|
-
left: centerX + shift,
|
|
19444
|
-
transform: "translate(-50%, -100%)",
|
|
19445
|
-
zIndex: 2147483645
|
|
19446
|
-
},
|
|
19447
|
-
children
|
|
19448
|
-
}
|
|
19449
|
-
);
|
|
19450
|
-
}
|
|
19451
19104
|
function requestValidateTree(postToParent2, tree) {
|
|
19452
19105
|
return new Promise((resolve) => {
|
|
19453
19106
|
const id = `ai-validate-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -19484,72 +19137,116 @@ function requestAssetPick(postToParent2) {
|
|
|
19484
19137
|
postToParent2({ type: "ow:asset-pick", id });
|
|
19485
19138
|
});
|
|
19486
19139
|
}
|
|
19487
|
-
function
|
|
19140
|
+
function Pill({
|
|
19488
19141
|
label,
|
|
19489
19142
|
onClick,
|
|
19490
|
-
disabled
|
|
19491
|
-
active
|
|
19492
|
-
children
|
|
19493
|
-
}) {
|
|
19494
|
-
const button = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, active, onClick, className: "size-8", children });
|
|
19495
|
-
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
|
|
19496
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "inline-flex", children: button }) : button }),
|
|
19497
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
|
|
19498
|
-
] });
|
|
19499
|
-
}
|
|
19500
|
-
function ToolbarSeparator() {
|
|
19501
|
-
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
|
|
19502
|
-
}
|
|
19503
|
-
function OptionMenu({
|
|
19504
|
-
label,
|
|
19505
|
-
value,
|
|
19506
|
-
options,
|
|
19507
|
-
onChange
|
|
19143
|
+
disabled,
|
|
19144
|
+
active
|
|
19508
19145
|
}) {
|
|
19509
|
-
|
|
19510
|
-
|
|
19511
|
-
|
|
19512
|
-
|
|
19513
|
-
|
|
19514
|
-
|
|
19515
|
-
|
|
19516
|
-
|
|
19517
|
-
|
|
19518
|
-
|
|
19519
|
-
|
|
19520
|
-
|
|
19521
|
-
|
|
19522
|
-
|
|
19523
|
-
|
|
19524
|
-
|
|
19525
|
-
|
|
19526
|
-
|
|
19527
|
-
|
|
19528
|
-
|
|
19146
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19147
|
+
"button",
|
|
19148
|
+
{
|
|
19149
|
+
type: "button",
|
|
19150
|
+
onClick,
|
|
19151
|
+
disabled,
|
|
19152
|
+
style: {
|
|
19153
|
+
height: 28,
|
|
19154
|
+
padding: "0 10px",
|
|
19155
|
+
display: "inline-flex",
|
|
19156
|
+
alignItems: "center",
|
|
19157
|
+
gap: 4,
|
|
19158
|
+
borderRadius: 999,
|
|
19159
|
+
border: "none",
|
|
19160
|
+
cursor: disabled ? "default" : "pointer",
|
|
19161
|
+
background: active ? OHW_BLUE_DARK : "#ffffff",
|
|
19162
|
+
color: active ? "#ffffff" : OHW_BLUE_DARK,
|
|
19163
|
+
opacity: disabled ? 0.4 : 1,
|
|
19164
|
+
fontSize: 12,
|
|
19165
|
+
lineHeight: "16px",
|
|
19166
|
+
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
19167
|
+
whiteSpace: "nowrap",
|
|
19168
|
+
flex: "0 0 auto"
|
|
19169
|
+
},
|
|
19170
|
+
children: label
|
|
19171
|
+
}
|
|
19172
|
+
);
|
|
19173
|
+
}
|
|
19174
|
+
function AltInput({ value, onCommit }) {
|
|
19175
|
+
const [draft, setDraft] = (0, import_react12.useState)(value);
|
|
19176
|
+
(0, import_react12.useEffect)(() => setDraft(value), [value]);
|
|
19177
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
19178
|
+
"div",
|
|
19179
|
+
{
|
|
19180
|
+
style: {
|
|
19181
|
+
display: "flex",
|
|
19182
|
+
alignItems: "center",
|
|
19183
|
+
gap: 6,
|
|
19184
|
+
height: 28,
|
|
19185
|
+
padding: "0 12px",
|
|
19186
|
+
borderRadius: 999,
|
|
19187
|
+
background: "#ffffff",
|
|
19188
|
+
width: "100%",
|
|
19189
|
+
maxWidth: 260,
|
|
19190
|
+
boxSizing: "border-box"
|
|
19191
|
+
},
|
|
19192
|
+
children: [
|
|
19193
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19194
|
+
"span",
|
|
19529
19195
|
{
|
|
19530
|
-
|
|
19531
|
-
|
|
19532
|
-
|
|
19533
|
-
|
|
19534
|
-
|
|
19535
|
-
|
|
19536
|
-
|
|
19537
|
-
|
|
19538
|
-
|
|
19539
|
-
|
|
19540
|
-
)
|
|
19541
|
-
|
|
19542
|
-
|
|
19543
|
-
|
|
19196
|
+
style: {
|
|
19197
|
+
flex: "0 0 auto",
|
|
19198
|
+
color: OHW_BLUE_DARK,
|
|
19199
|
+
fontSize: 10,
|
|
19200
|
+
fontWeight: 700,
|
|
19201
|
+
textTransform: "uppercase",
|
|
19202
|
+
letterSpacing: 0.4
|
|
19203
|
+
},
|
|
19204
|
+
children: "Alt"
|
|
19205
|
+
}
|
|
19206
|
+
),
|
|
19207
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19208
|
+
"input",
|
|
19209
|
+
{
|
|
19210
|
+
type: "text",
|
|
19211
|
+
value: draft,
|
|
19212
|
+
onChange: (e) => setDraft(e.target.value),
|
|
19213
|
+
onBlur: () => {
|
|
19214
|
+
if (draft !== value) onCommit(draft);
|
|
19215
|
+
},
|
|
19216
|
+
onKeyDown: (e) => {
|
|
19217
|
+
if (e.key === "Enter") e.currentTarget.blur();
|
|
19218
|
+
if (e.key === "Escape") {
|
|
19219
|
+
setDraft(value);
|
|
19220
|
+
e.currentTarget.blur();
|
|
19221
|
+
}
|
|
19222
|
+
},
|
|
19223
|
+
placeholder: "Describe this image",
|
|
19224
|
+
"aria-label": "Image alt text",
|
|
19225
|
+
style: {
|
|
19226
|
+
flex: 1,
|
|
19227
|
+
minWidth: 0,
|
|
19228
|
+
border: "none",
|
|
19229
|
+
outline: "none",
|
|
19230
|
+
background: "transparent",
|
|
19231
|
+
fontSize: 12,
|
|
19232
|
+
lineHeight: "16px",
|
|
19233
|
+
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
19234
|
+
color: "#1f2937"
|
|
19235
|
+
}
|
|
19236
|
+
}
|
|
19237
|
+
)
|
|
19238
|
+
]
|
|
19239
|
+
}
|
|
19240
|
+
);
|
|
19544
19241
|
}
|
|
19545
19242
|
var VARIANTS = [
|
|
19546
19243
|
{ value: "logos", label: "Logos" },
|
|
19547
19244
|
{ value: "reel", label: "Reel" }
|
|
19548
19245
|
];
|
|
19549
19246
|
var ALIGNS = [
|
|
19550
|
-
{ value: "left", label: "
|
|
19551
|
-
{ value: "center", label: "
|
|
19552
|
-
{ value: "right", label: "
|
|
19247
|
+
{ value: "left", label: "Left" },
|
|
19248
|
+
{ value: "center", label: "Center" },
|
|
19249
|
+
{ value: "right", label: "Right" }
|
|
19553
19250
|
];
|
|
19554
19251
|
var HOVERS = [
|
|
19555
19252
|
{ value: "none", label: "None" },
|
|
@@ -19557,104 +19254,104 @@ var HOVERS = [
|
|
|
19557
19254
|
{ value: "zoom", label: "Zoom" },
|
|
19558
19255
|
{ value: "fade", label: "Fade" }
|
|
19559
19256
|
];
|
|
19257
|
+
var TREATMENTS = [
|
|
19258
|
+
{ value: "color", label: "Color" },
|
|
19259
|
+
{ value: "grayscale", label: "Grayscale" }
|
|
19260
|
+
];
|
|
19560
19261
|
var HTTP_URL_RE = /^https?:\/\/\S+$/i;
|
|
19561
|
-
function
|
|
19562
|
-
|
|
19563
|
-
linkTarget,
|
|
19564
|
-
onClose,
|
|
19565
|
-
onSave
|
|
19566
|
-
}) {
|
|
19567
|
-
const [draft, setDraft] = (0, import_react12.useState)(href);
|
|
19568
|
-
const [newTab, setNewTab] = (0, import_react12.useState)(linkTarget !== "same-tab");
|
|
19262
|
+
function LinkInput({ value, onCommit }) {
|
|
19263
|
+
const [draft, setDraft] = (0, import_react12.useState)(value);
|
|
19569
19264
|
const [invalid, setInvalid] = (0, import_react12.useState)(false);
|
|
19570
|
-
|
|
19265
|
+
(0, import_react12.useEffect)(() => {
|
|
19266
|
+
setDraft(value);
|
|
19267
|
+
setInvalid(false);
|
|
19268
|
+
}, [value]);
|
|
19269
|
+
const commit = () => {
|
|
19571
19270
|
const next = draft.trim();
|
|
19572
|
-
if (next
|
|
19573
|
-
|
|
19574
|
-
|
|
19575
|
-
|
|
19576
|
-
onSave(next, newTab ? "new-tab" : "same-tab");
|
|
19577
|
-
onClose();
|
|
19271
|
+
if (next === value) return setInvalid(false);
|
|
19272
|
+
if (next && !HTTP_URL_RE.test(next)) return setInvalid(true);
|
|
19273
|
+
setInvalid(false);
|
|
19274
|
+
onCommit(next);
|
|
19578
19275
|
};
|
|
19579
|
-
return /* @__PURE__ */ (0,
|
|
19580
|
-
|
|
19581
|
-
|
|
19582
|
-
|
|
19583
|
-
"
|
|
19584
|
-
|
|
19585
|
-
|
|
19586
|
-
|
|
19587
|
-
|
|
19588
|
-
|
|
19589
|
-
|
|
19590
|
-
|
|
19591
|
-
|
|
19592
|
-
|
|
19593
|
-
|
|
19594
|
-
|
|
19595
|
-
|
|
19596
|
-
|
|
19597
|
-
"
|
|
19598
|
-
|
|
19599
|
-
|
|
19600
|
-
|
|
19601
|
-
|
|
19602
|
-
|
|
19603
|
-
|
|
19604
|
-
|
|
19605
|
-
|
|
19606
|
-
|
|
19607
|
-
|
|
19608
|
-
|
|
19609
|
-
|
|
19610
|
-
|
|
19611
|
-
|
|
19612
|
-
|
|
19613
|
-
|
|
19614
|
-
|
|
19615
|
-
|
|
19616
|
-
|
|
19617
|
-
|
|
19618
|
-
|
|
19619
|
-
|
|
19620
|
-
|
|
19621
|
-
|
|
19622
|
-
|
|
19623
|
-
|
|
19624
|
-
|
|
19625
|
-
|
|
19626
|
-
|
|
19627
|
-
|
|
19628
|
-
|
|
19629
|
-
|
|
19630
|
-
|
|
19631
|
-
|
|
19632
|
-
|
|
19633
|
-
|
|
19634
|
-
|
|
19635
|
-
|
|
19636
|
-
|
|
19637
|
-
|
|
19638
|
-
|
|
19639
|
-
|
|
19640
|
-
|
|
19641
|
-
|
|
19642
|
-
|
|
19643
|
-
|
|
19276
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
19277
|
+
"div",
|
|
19278
|
+
{
|
|
19279
|
+
style: {
|
|
19280
|
+
display: "flex",
|
|
19281
|
+
alignItems: "center",
|
|
19282
|
+
gap: 6,
|
|
19283
|
+
height: 28,
|
|
19284
|
+
padding: "0 12px",
|
|
19285
|
+
borderRadius: 999,
|
|
19286
|
+
background: "#ffffff",
|
|
19287
|
+
width: "100%",
|
|
19288
|
+
maxWidth: 260,
|
|
19289
|
+
boxSizing: "border-box",
|
|
19290
|
+
boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
|
|
19291
|
+
},
|
|
19292
|
+
children: [
|
|
19293
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19294
|
+
"span",
|
|
19295
|
+
{
|
|
19296
|
+
style: {
|
|
19297
|
+
flex: "0 0 auto",
|
|
19298
|
+
color: OHW_BLUE_DARK,
|
|
19299
|
+
fontSize: 10,
|
|
19300
|
+
fontWeight: 700,
|
|
19301
|
+
textTransform: "uppercase",
|
|
19302
|
+
letterSpacing: 0.4
|
|
19303
|
+
},
|
|
19304
|
+
children: "Link"
|
|
19305
|
+
}
|
|
19306
|
+
),
|
|
19307
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19308
|
+
"input",
|
|
19309
|
+
{
|
|
19310
|
+
type: "text",
|
|
19311
|
+
inputMode: "url",
|
|
19312
|
+
value: draft,
|
|
19313
|
+
onChange: (e) => setDraft(e.target.value),
|
|
19314
|
+
onBlur: commit,
|
|
19315
|
+
onKeyDown: (e) => {
|
|
19316
|
+
if (e.key === "Enter") e.currentTarget.blur();
|
|
19317
|
+
if (e.key === "Escape") {
|
|
19318
|
+
setDraft(value);
|
|
19319
|
+
setInvalid(false);
|
|
19320
|
+
e.currentTarget.blur();
|
|
19321
|
+
}
|
|
19322
|
+
},
|
|
19323
|
+
placeholder: "https://example.com",
|
|
19324
|
+
"aria-label": "Image link URL",
|
|
19325
|
+
"aria-invalid": invalid,
|
|
19326
|
+
style: {
|
|
19327
|
+
flex: 1,
|
|
19328
|
+
minWidth: 0,
|
|
19329
|
+
border: "none",
|
|
19330
|
+
outline: "none",
|
|
19331
|
+
background: "transparent",
|
|
19332
|
+
fontSize: 12,
|
|
19333
|
+
lineHeight: "16px",
|
|
19334
|
+
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
19335
|
+
color: "#1f2937"
|
|
19336
|
+
}
|
|
19337
|
+
}
|
|
19338
|
+
)
|
|
19339
|
+
]
|
|
19340
|
+
}
|
|
19341
|
+
);
|
|
19644
19342
|
}
|
|
19645
19343
|
function MediaStripToolbar({
|
|
19646
19344
|
entry,
|
|
19647
19345
|
index,
|
|
19648
19346
|
pending,
|
|
19649
19347
|
error,
|
|
19650
|
-
itemEditOn,
|
|
19651
|
-
onToggleItemEdit,
|
|
19652
19348
|
onSetVariant,
|
|
19653
19349
|
onSetAlign,
|
|
19654
19350
|
onSetHover,
|
|
19655
19351
|
onSetTreatment,
|
|
19656
19352
|
onResize,
|
|
19657
|
-
|
|
19353
|
+
onSetAlt,
|
|
19354
|
+
onSetLink,
|
|
19658
19355
|
onAddItem,
|
|
19659
19356
|
onRemoveItem,
|
|
19660
19357
|
onChangeImage,
|
|
@@ -19663,102 +19360,81 @@ function MediaStripToolbar({
|
|
|
19663
19360
|
}) {
|
|
19664
19361
|
const items = mediaStripItems(entry.tree);
|
|
19665
19362
|
const itemCount = items.length;
|
|
19363
|
+
const currentAlt = items[index]?.alt ?? "";
|
|
19364
|
+
const currentHref = items[index]?.href ?? "";
|
|
19365
|
+
const currentTarget = items[index]?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
|
|
19666
19366
|
const slots = findMediaStripSlots(entry.tree);
|
|
19667
19367
|
const variant = slots?.variant === "reel" ? "reel" : "logos";
|
|
19668
19368
|
const align = slots?.align === "left" || slots?.align === "right" ? slots.align : "center";
|
|
19669
19369
|
const hover = slots?.hover === "none" || slots?.hover === "lift" || slots?.hover === "zoom" || slots?.hover === "fade" ? slots.hover : "lift";
|
|
19670
19370
|
const treatment = slots?.treatment === "color" || slots?.treatment === "grayscale" ? slots.treatment : variant === "logos" ? "grayscale" : "color";
|
|
19671
19371
|
const sizeValue = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
|
|
19672
|
-
const
|
|
19673
|
-
const
|
|
19674
|
-
|
|
19372
|
+
const isMobile = window.innerWidth <= 480;
|
|
19373
|
+
const rowStyle = isMobile ? {
|
|
19374
|
+
display: "flex",
|
|
19375
|
+
gap: 6,
|
|
19376
|
+
flexWrap: "nowrap",
|
|
19377
|
+
justifyContent: "center",
|
|
19378
|
+
overflowX: "auto",
|
|
19379
|
+
WebkitOverflowScrolling: "touch",
|
|
19380
|
+
width: "100%",
|
|
19381
|
+
scrollbarWidth: "none"
|
|
19382
|
+
} : { display: "flex", gap: 6, flexWrap: "nowrap", justifyContent: "center" };
|
|
19383
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
19675
19384
|
"div",
|
|
19676
19385
|
{
|
|
19677
19386
|
"data-ohw-bridge": "",
|
|
19678
19387
|
"data-ohw-toolbar": "",
|
|
19679
19388
|
onMouseDown: (e) => e.stopPropagation(),
|
|
19680
|
-
|
|
19681
|
-
|
|
19389
|
+
style: {
|
|
19390
|
+
display: "flex",
|
|
19391
|
+
flexDirection: "column",
|
|
19392
|
+
gap: 6,
|
|
19393
|
+
alignItems: "center",
|
|
19394
|
+
background: OHW_BLUE,
|
|
19395
|
+
padding: 8,
|
|
19396
|
+
borderRadius: 12,
|
|
19397
|
+
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
19398
|
+
pointerEvents: pending ? "none" : "auto",
|
|
19399
|
+
opacity: pending ? 0.6 : 1,
|
|
19400
|
+
maxWidth: isMobile ? "calc(100vw - 24px)" : "none"
|
|
19401
|
+
},
|
|
19682
19402
|
children: [
|
|
19683
|
-
/* @__PURE__ */ (0,
|
|
19684
|
-
|
|
19685
|
-
{
|
|
19686
|
-
|
|
19687
|
-
|
|
19688
|
-
|
|
19689
|
-
|
|
19690
|
-
|
|
19691
|
-
|
|
19692
|
-
|
|
19693
|
-
|
|
19694
|
-
|
|
19695
|
-
|
|
19696
|
-
|
|
19697
|
-
|
|
19698
|
-
|
|
19699
|
-
|
|
19700
|
-
|
|
19701
|
-
|
|
19702
|
-
|
|
19703
|
-
|
|
19704
|
-
|
|
19705
|
-
|
|
19706
|
-
|
|
19707
|
-
|
|
19708
|
-
|
|
19709
|
-
|
|
19710
|
-
|
|
19711
|
-
|
|
19712
|
-
|
|
19713
|
-
|
|
19714
|
-
|
|
19715
|
-
) }),
|
|
19716
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: itemEditOn ? "Done editing this image" : "Edit this image" })
|
|
19717
|
-
] }),
|
|
19718
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19719
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: gatedLabel("Change image"), onClick: onChangeImage, disabled: !itemEditOn, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Image, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19720
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: gatedLabel("Link"), onClick: onOpenLink, disabled: !itemEditOn, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Link, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19721
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: gatedLabel("Move left"), onClick: onMoveLeft, disabled: !itemEditOn || index <= 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ArrowLeft, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19722
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19723
|
-
ToolbarAction,
|
|
19724
|
-
{
|
|
19725
|
-
label: gatedLabel("Move right"),
|
|
19726
|
-
onClick: onMoveRight,
|
|
19727
|
-
disabled: !itemEditOn || index >= itemCount - 1,
|
|
19728
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ArrowRight, { size: 16, style: { pointerEvents: "none" } })
|
|
19729
|
-
}
|
|
19730
|
-
),
|
|
19731
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: gatedLabel("Remove image"), onClick: onRemoveItem, disabled: !itemEditOn || itemCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ImageMinus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19732
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19733
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(OptionMenu, { label: "Layout", value: variant, options: VARIANTS, onChange: onSetVariant }),
|
|
19734
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(OptionMenu, { label: "Hover", value: hover, options: HOVERS, onChange: onSetHover }),
|
|
19735
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19736
|
-
ToolbarAction,
|
|
19737
|
-
{
|
|
19738
|
-
label: treatment === "grayscale" ? "Show in color" : "Show grayscale",
|
|
19739
|
-
active: treatment === "grayscale",
|
|
19740
|
-
onClick: () => onSetTreatment(treatment === "grayscale" ? "color" : "grayscale"),
|
|
19741
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Palette, { size: 16, style: { pointerEvents: "none" } })
|
|
19742
|
-
}
|
|
19743
|
-
),
|
|
19744
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19745
|
-
ALIGNS.map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label, active: align === value, onClick: () => onSetAlign(value), children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Icon, { size: 16, style: { pointerEvents: "none" } }) }, value)),
|
|
19746
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19747
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Smaller", onClick: () => onResize(-8), children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Minus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19748
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "min-w-[40px] text-center text-xs tabular-nums text-muted-foreground", children: [
|
|
19749
|
-
sizeValue,
|
|
19750
|
-
"px"
|
|
19751
|
-
] }),
|
|
19752
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Larger", onClick: () => onResize(8), children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Plus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19753
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19754
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Add image", onClick: onAddItem, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ImagePlus, { size: 16, style: { pointerEvents: "none" } }) })
|
|
19755
|
-
]
|
|
19756
|
-
}
|
|
19757
|
-
),
|
|
19758
|
-
error && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
|
|
19403
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: rowStyle, children: [
|
|
19404
|
+
VARIANTS.map((v) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: v.label, active: variant === v.value, onClick: () => onSetVariant(v.value) }, v.value)),
|
|
19405
|
+
ALIGNS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: a.label, active: align === a.value, onClick: () => onSetAlign(a.value) }, a.value))
|
|
19406
|
+
] }),
|
|
19407
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: rowStyle, children: [
|
|
19408
|
+
HOVERS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: h.label, active: hover === h.value, onClick: () => onSetHover(h.value) }, h.value)),
|
|
19409
|
+
TREATMENTS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: t.label, active: treatment === t.value, onClick: () => onSetTreatment(t.value) }, t.value))
|
|
19410
|
+
] }),
|
|
19411
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
|
|
19412
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "\u2212", onClick: () => onResize(-8) }),
|
|
19413
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: { color: "#ffffff", fontSize: 12, minWidth: 34, textAlign: "center" }, children: [
|
|
19414
|
+
sizeValue,
|
|
19415
|
+
"px"
|
|
19416
|
+
] }),
|
|
19417
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "+", onClick: () => onResize(8) })
|
|
19418
|
+
] }),
|
|
19419
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { display: "flex", justifyContent: "center", width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(AltInput, { value: currentAlt, onCommit: onSetAlt }) }),
|
|
19420
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { display: "flex", justifyContent: "center", width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(LinkInput, { value: currentHref, onCommit: (href) => onSetLink(href, currentTarget) }) }),
|
|
19421
|
+
currentHref && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: rowStyle, children: [
|
|
19422
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "New tab", active: currentTarget === "new-tab", onClick: () => onSetLink(currentHref, "new-tab") }),
|
|
19423
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "Same tab", active: currentTarget === "same-tab", onClick: () => onSetLink(currentHref, "same-tab") })
|
|
19424
|
+
] }),
|
|
19425
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: rowStyle, children: [
|
|
19426
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "Change Image", onClick: onChangeImage }),
|
|
19427
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "+ Item", onClick: onAddItem }),
|
|
19428
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "\u2212 Item", onClick: onRemoveItem, disabled: itemCount <= 1 })
|
|
19429
|
+
] }),
|
|
19430
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: rowStyle, children: [
|
|
19431
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "\u2190 Move", onClick: onMoveLeft, disabled: index <= 0 }),
|
|
19432
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "\u2192 Move", onClick: onMoveRight, disabled: index >= itemCount - 1 })
|
|
19433
|
+
] }),
|
|
19434
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
|
|
19759
19435
|
]
|
|
19760
19436
|
}
|
|
19761
|
-
)
|
|
19437
|
+
);
|
|
19762
19438
|
}
|
|
19763
19439
|
function findMediaStripSlots(tree) {
|
|
19764
19440
|
const stack = tree.rows.flatMap((row) => row.blocks);
|
|
@@ -19777,23 +19453,31 @@ function AiMediaStripOverlay({
|
|
|
19777
19453
|
}) {
|
|
19778
19454
|
const [hover, setHover] = (0, import_react12.useState)(null);
|
|
19779
19455
|
const [active, setActive] = (0, import_react12.useState)(null);
|
|
19780
|
-
const [itemEditOn, setItemEditOn] = (0, import_react12.useState)(false);
|
|
19781
|
-
const [linkOpen, setLinkOpen] = (0, import_react12.useState)(false);
|
|
19782
19456
|
const [pending, setPending] = (0, import_react12.useState)(false);
|
|
19783
19457
|
const [error, setError] = (0, import_react12.useState)(null);
|
|
19784
19458
|
const activeRef = (0, import_react12.useRef)(null);
|
|
19785
19459
|
activeRef.current = active;
|
|
19786
|
-
const linkOpenRef = (0, import_react12.useRef)(false);
|
|
19787
|
-
linkOpenRef.current = linkOpen;
|
|
19788
19460
|
(0, import_react12.useEffect)(() => {
|
|
19789
19461
|
const onMove = (e) => {
|
|
19790
|
-
const ref = itemRefFromTarget(e.target);
|
|
19791
19462
|
const t = e.target;
|
|
19792
|
-
|
|
19793
|
-
|
|
19794
|
-
|
|
19795
|
-
|
|
19796
|
-
|
|
19463
|
+
if (!(t instanceof HTMLElement)) return;
|
|
19464
|
+
if (t.closest("[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-link-modal-root], [data-ohw-section-picker], [data-ohw-ai-review]")) {
|
|
19465
|
+
return;
|
|
19466
|
+
}
|
|
19467
|
+
const itemEl = t.closest("[data-ohw-media-strip-item]");
|
|
19468
|
+
if (!itemEl) {
|
|
19469
|
+
setHover(null);
|
|
19470
|
+
return;
|
|
19471
|
+
}
|
|
19472
|
+
const sectionEl = itemEl.closest("[data-ohw-section]");
|
|
19473
|
+
const unit = sectionEl ? movableUnit(sectionEl) : null;
|
|
19474
|
+
const sectionId = unit ? instanceIdOf(unit) || null : null;
|
|
19475
|
+
const index = Number(itemEl.dataset.ohwMediaStripIndex);
|
|
19476
|
+
if (!sectionId || Number.isNaN(index)) {
|
|
19477
|
+
setHover(null);
|
|
19478
|
+
return;
|
|
19479
|
+
}
|
|
19480
|
+
setHover({ sectionId, index });
|
|
19797
19481
|
};
|
|
19798
19482
|
const onLeave = () => setHover(null);
|
|
19799
19483
|
document.addEventListener("mousemove", onMove, { passive: true });
|
|
@@ -19805,25 +19489,23 @@ function AiMediaStripOverlay({
|
|
|
19805
19489
|
}, []);
|
|
19806
19490
|
(0, import_react12.useEffect)(() => {
|
|
19807
19491
|
const onClick = (e) => {
|
|
19492
|
+
const current = activeRef.current;
|
|
19493
|
+
if (!current) return;
|
|
19808
19494
|
const t = e.target;
|
|
19809
|
-
if (!(t instanceof
|
|
19810
|
-
if (t.closest(
|
|
19811
|
-
const
|
|
19812
|
-
if (
|
|
19813
|
-
|
|
19814
|
-
setItemEditOn(false);
|
|
19495
|
+
if (!(t instanceof HTMLElement)) return;
|
|
19496
|
+
if (t.closest("[data-ohw-item-interaction]")) return;
|
|
19497
|
+
const itemEl = findMediaStripItemElement(current.sectionId, current.index);
|
|
19498
|
+
if (itemEl && itemEl.contains(t)) return;
|
|
19499
|
+
setActive(null);
|
|
19815
19500
|
setError(null);
|
|
19816
|
-
setActive(ref);
|
|
19817
19501
|
};
|
|
19818
19502
|
document.addEventListener("click", onClick, true);
|
|
19819
19503
|
return () => document.removeEventListener("click", onClick, true);
|
|
19820
|
-
}, [
|
|
19504
|
+
}, []);
|
|
19821
19505
|
(0, import_react12.useEffect)(() => {
|
|
19822
19506
|
const onBlur = () => {
|
|
19823
19507
|
if (!activeRef.current) return;
|
|
19824
19508
|
setActive(null);
|
|
19825
|
-
setItemEditOn(false);
|
|
19826
|
-
setLinkOpen(false);
|
|
19827
19509
|
setError(null);
|
|
19828
19510
|
};
|
|
19829
19511
|
window.addEventListener("blur", onBlur);
|
|
@@ -19833,10 +19515,7 @@ function AiMediaStripOverlay({
|
|
|
19833
19515
|
const onKeyDown = (e) => {
|
|
19834
19516
|
if (e.key !== "Escape") return;
|
|
19835
19517
|
if (!activeRef.current) return;
|
|
19836
|
-
if (linkOpenRef.current) return;
|
|
19837
|
-
if (document.querySelector('[data-ohw-more-menu][data-state="open"]')) return;
|
|
19838
19518
|
setActive(null);
|
|
19839
|
-
setItemEditOn(false);
|
|
19840
19519
|
setError(null);
|
|
19841
19520
|
};
|
|
19842
19521
|
document.addEventListener("keydown", onKeyDown);
|
|
@@ -19870,133 +19549,137 @@ function AiMediaStripOverlay({
|
|
|
19870
19549
|
tree: nextTree,
|
|
19871
19550
|
label: entry.label,
|
|
19872
19551
|
media: extraMedia ? { ...entry.media, ...extraMedia } : entry.media,
|
|
19873
|
-
...entry.brand ? { brand: entry.brand } : {}
|
|
19874
|
-
// The user is already looking at the strip they just edited — recentering the viewport
|
|
19875
|
-
// on every edit reads as the section jumping around.
|
|
19876
|
-
skipScrollIntoView: true
|
|
19552
|
+
...entry.brand ? { brand: entry.brand } : {}
|
|
19877
19553
|
});
|
|
19878
19554
|
return true;
|
|
19879
19555
|
},
|
|
19880
19556
|
[findEntry, postToParent2, applyTreeLocalRef]
|
|
19881
19557
|
);
|
|
19882
19558
|
const activeEntry = active ? findEntry(active.sectionId) : null;
|
|
19559
|
+
const hoverHandleRect = useLiveItemRect(!active && hover ? hover : null);
|
|
19883
19560
|
const activeItemRect = useLiveItemRect(active);
|
|
19884
|
-
const
|
|
19885
|
-
const
|
|
19886
|
-
|
|
19887
|
-
|
|
19888
|
-
|
|
19889
|
-
|
|
19890
|
-
|
|
19891
|
-
|
|
19892
|
-
|
|
19893
|
-
|
|
19894
|
-
|
|
19895
|
-
|
|
19896
|
-
|
|
19897
|
-
|
|
19898
|
-
|
|
19899
|
-
|
|
19900
|
-
|
|
19901
|
-
|
|
19902
|
-
|
|
19903
|
-
|
|
19904
|
-
|
|
19905
|
-
|
|
19906
|
-
|
|
19907
|
-
|
|
19908
|
-
|
|
19909
|
-
|
|
19910
|
-
|
|
19911
|
-
|
|
19912
|
-
|
|
19913
|
-
|
|
19914
|
-
|
|
19915
|
-
|
|
19916
|
-
|
|
19917
|
-
|
|
19561
|
+
const TOOLBAR_APPROX_H = 170;
|
|
19562
|
+
const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
|
|
19563
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
19564
|
+
hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19565
|
+
"button",
|
|
19566
|
+
{
|
|
19567
|
+
type: "button",
|
|
19568
|
+
"data-ohw-toolbar": "",
|
|
19569
|
+
onClick: () => {
|
|
19570
|
+
clearInteractionChromeRef.current();
|
|
19571
|
+
setActive(hover);
|
|
19572
|
+
},
|
|
19573
|
+
"aria-label": "Configure media item",
|
|
19574
|
+
style: {
|
|
19575
|
+
position: "fixed",
|
|
19576
|
+
top: hoverHandleRect.top + 8,
|
|
19577
|
+
left: hoverHandleRect.left + hoverHandleRect.width - 36,
|
|
19578
|
+
width: 28,
|
|
19579
|
+
height: 28,
|
|
19580
|
+
borderRadius: 8,
|
|
19581
|
+
border: `1.5px dashed ${PRIMARY3}`,
|
|
19582
|
+
background: "#ffffff",
|
|
19583
|
+
color: PRIMARY3,
|
|
19584
|
+
display: "flex",
|
|
19585
|
+
alignItems: "center",
|
|
19586
|
+
justifyContent: "center",
|
|
19587
|
+
cursor: "pointer",
|
|
19588
|
+
zIndex: 2147483643,
|
|
19589
|
+
fontSize: 14,
|
|
19590
|
+
fontWeight: 700
|
|
19591
|
+
},
|
|
19592
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react8.Star, { size: 14, style: { pointerEvents: "none" } })
|
|
19593
|
+
}
|
|
19594
|
+
),
|
|
19595
|
+
activeItemRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19596
|
+
ItemInteractionLayer,
|
|
19597
|
+
{
|
|
19598
|
+
rect: activeItemRect,
|
|
19599
|
+
state: toolbarState,
|
|
19600
|
+
toolbar: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19601
|
+
MediaStripToolbar,
|
|
19602
|
+
{
|
|
19603
|
+
entry: activeEntry,
|
|
19604
|
+
index: active.index,
|
|
19605
|
+
pending,
|
|
19606
|
+
error,
|
|
19607
|
+
onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
|
|
19608
|
+
onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
|
|
19609
|
+
onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
|
|
19610
|
+
onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
|
|
19611
|
+
onResize: (delta) => {
|
|
19612
|
+
const slots = findMediaStripSlots(activeEntry.tree);
|
|
19613
|
+
const variant = slots?.variant === "reel" ? "reel" : "logos";
|
|
19614
|
+
const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
|
|
19615
|
+
void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
|
|
19616
|
+
},
|
|
19617
|
+
onSetAlt: (alt) => {
|
|
19618
|
+
void runMutation(active.sectionId, (tree) => setMediaStripItemAlt(tree, active.index, alt));
|
|
19619
|
+
},
|
|
19620
|
+
onSetLink: (href, linkTarget) => {
|
|
19918
19621
|
void runMutation(
|
|
19919
19622
|
active.sectionId,
|
|
19920
|
-
(tree) =>
|
|
19921
|
-
|
|
19922
|
-
|
|
19923
|
-
|
|
19623
|
+
(tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
|
|
19624
|
+
);
|
|
19625
|
+
},
|
|
19626
|
+
onAddItem: () => {
|
|
19627
|
+
void requestAssetPick(postToParent2).then((picked) => {
|
|
19628
|
+
if (!picked) return;
|
|
19629
|
+
const item = { assetId: picked.assetId, alt: "Logo" };
|
|
19630
|
+
void runMutation(
|
|
19631
|
+
active.sectionId,
|
|
19632
|
+
(tree) => addMediaStripItem(tree, item, active.index),
|
|
19633
|
+
{ [picked.assetId]: picked.url }
|
|
19634
|
+
).then((applied) => {
|
|
19635
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
19636
|
+
});
|
|
19924
19637
|
});
|
|
19925
|
-
}
|
|
19926
|
-
|
|
19927
|
-
|
|
19928
|
-
|
|
19929
|
-
|
|
19930
|
-
|
|
19931
|
-
|
|
19932
|
-
|
|
19933
|
-
|
|
19638
|
+
},
|
|
19639
|
+
onChangeImage: () => {
|
|
19640
|
+
void requestAssetPick(postToParent2).then((picked) => {
|
|
19641
|
+
if (!picked) return;
|
|
19642
|
+
void runMutation(
|
|
19643
|
+
active.sectionId,
|
|
19644
|
+
(tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
|
|
19645
|
+
{ [picked.assetId]: picked.url }
|
|
19646
|
+
);
|
|
19647
|
+
});
|
|
19648
|
+
},
|
|
19649
|
+
onRemoveItem: () => {
|
|
19650
|
+
void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
|
|
19651
|
+
(applied) => {
|
|
19652
|
+
if (applied) setActive(null);
|
|
19653
|
+
}
|
|
19934
19654
|
);
|
|
19935
|
-
}
|
|
19936
|
-
|
|
19937
|
-
|
|
19938
|
-
|
|
19939
|
-
|
|
19940
|
-
|
|
19941
|
-
|
|
19942
|
-
|
|
19943
|
-
|
|
19944
|
-
|
|
19945
|
-
|
|
19946
|
-
|
|
19947
|
-
|
|
19948
|
-
|
|
19949
|
-
|
|
19950
|
-
},
|
|
19951
|
-
onMoveRight: () => {
|
|
19952
|
-
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
|
|
19953
|
-
(applied) => {
|
|
19954
|
-
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
19955
|
-
}
|
|
19956
|
-
);
|
|
19957
|
-
}
|
|
19958
|
-
}
|
|
19959
|
-
) }),
|
|
19960
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19961
|
-
"div",
|
|
19962
|
-
{
|
|
19963
|
-
"data-ohw-bridge": "",
|
|
19964
|
-
"data-ohw-item-interaction": "",
|
|
19965
|
-
"aria-hidden": true,
|
|
19966
|
-
className: "pointer-events-none fixed rounded-[4px] px-[7px] py-[3px] font-sans text-[11px] font-medium leading-none text-primary-foreground whitespace-nowrap",
|
|
19967
|
-
style: {
|
|
19968
|
-
top: activeItemRect.top + activeItemRect.height + 10,
|
|
19969
|
-
left: activeItemRect.left - 5,
|
|
19970
|
-
background: PRIMARY3,
|
|
19971
|
-
zIndex: 2147483644
|
|
19972
|
-
},
|
|
19973
|
-
children: "Media item"
|
|
19974
|
-
}
|
|
19975
|
-
),
|
|
19976
|
-
linkOpen && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19977
|
-
LinkModal,
|
|
19978
|
-
{
|
|
19979
|
-
href: activeHref,
|
|
19980
|
-
linkTarget: activeTarget,
|
|
19981
|
-
onClose: () => setLinkOpen(false),
|
|
19982
|
-
onSave: (href, linkTarget) => {
|
|
19983
|
-
void runMutation(
|
|
19984
|
-
active.sectionId,
|
|
19985
|
-
(tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
|
|
19986
|
-
);
|
|
19655
|
+
},
|
|
19656
|
+
onMoveLeft: () => {
|
|
19657
|
+
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
|
|
19658
|
+
(applied) => {
|
|
19659
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
|
|
19660
|
+
}
|
|
19661
|
+
);
|
|
19662
|
+
},
|
|
19663
|
+
onMoveRight: () => {
|
|
19664
|
+
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
|
|
19665
|
+
(applied) => {
|
|
19666
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
19667
|
+
}
|
|
19668
|
+
);
|
|
19669
|
+
}
|
|
19987
19670
|
}
|
|
19988
|
-
|
|
19989
|
-
|
|
19990
|
-
|
|
19671
|
+
)
|
|
19672
|
+
}
|
|
19673
|
+
)
|
|
19991
19674
|
] });
|
|
19992
19675
|
}
|
|
19993
19676
|
|
|
19994
19677
|
// src/ui/ai-section/AiPricingCardOverlay.tsx
|
|
19995
19678
|
var import_react13 = require("react");
|
|
19996
|
-
var
|
|
19997
|
-
var
|
|
19679
|
+
var import_lucide_react9 = require("lucide-react");
|
|
19680
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
19998
19681
|
var PRIMARY4 = "var(--ohw-primary, #0885FE)";
|
|
19999
|
-
var
|
|
19682
|
+
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]";
|
|
20000
19683
|
function findPricingCardElement(sectionId, index) {
|
|
20001
19684
|
const sectionEl = findByInstanceId(sectionId);
|
|
20002
19685
|
if (!sectionEl) return null;
|
|
@@ -20008,7 +19691,7 @@ function findPricingCardElement(sectionId, index) {
|
|
|
20008
19691
|
}
|
|
20009
19692
|
function cardRefFromTarget(target) {
|
|
20010
19693
|
if (!(target instanceof Element)) return null;
|
|
20011
|
-
if (target.closest(
|
|
19694
|
+
if (target.closest(CHROME_SELECTOR)) return null;
|
|
20012
19695
|
const cardEl = target.closest("[data-ohw-pricing-card]");
|
|
20013
19696
|
if (!cardEl) return null;
|
|
20014
19697
|
const sectionEl = cardEl.closest("[data-ohw-section]");
|
|
@@ -20018,21 +19701,21 @@ function cardRefFromTarget(target) {
|
|
|
20018
19701
|
if (!sectionId || Number.isNaN(index)) return null;
|
|
20019
19702
|
return { sectionId, index };
|
|
20020
19703
|
}
|
|
20021
|
-
function
|
|
19704
|
+
function sameRef(a, b) {
|
|
20022
19705
|
return a?.sectionId === b?.sectionId && a?.index === b?.index;
|
|
20023
19706
|
}
|
|
20024
|
-
function
|
|
19707
|
+
function rectOf(el) {
|
|
20025
19708
|
if (!el) return null;
|
|
20026
19709
|
const r2 = el.getBoundingClientRect();
|
|
20027
19710
|
if (r2.width <= 0 || r2.height <= 0) return null;
|
|
20028
19711
|
return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
|
|
20029
19712
|
}
|
|
20030
19713
|
function readRect3(ref) {
|
|
20031
|
-
return
|
|
19714
|
+
return rectOf(ref && findPricingCardElement(ref.sectionId, ref.index));
|
|
20032
19715
|
}
|
|
20033
19716
|
function readGridRect(ref) {
|
|
20034
19717
|
const card = ref && findPricingCardElement(ref.sectionId, ref.index);
|
|
20035
|
-
return
|
|
19718
|
+
return rectOf(card?.closest("[data-ohw-pricing-collection]") ?? card);
|
|
20036
19719
|
}
|
|
20037
19720
|
function useLiveCardRect(ref, grid = false) {
|
|
20038
19721
|
const [rect, setRect] = (0, import_react13.useState)(null);
|
|
@@ -20062,7 +19745,7 @@ function useLiveCardRect(ref, grid = false) {
|
|
|
20062
19745
|
}
|
|
20063
19746
|
var TOOLBAR_GRID_GAP = 52;
|
|
20064
19747
|
var TOOLBAR_GRID_GAP_MOBILE = 42;
|
|
20065
|
-
var
|
|
19748
|
+
var TOOLBAR_EDGE_MARGIN2 = 4;
|
|
20066
19749
|
function GridToolbarSlot({ gridRect, children }) {
|
|
20067
19750
|
const slotRef = (0, import_react13.useRef)(null);
|
|
20068
19751
|
const [shift, setShift] = (0, import_react13.useState)(0);
|
|
@@ -20074,7 +19757,7 @@ function GridToolbarSlot({ gridRect, children }) {
|
|
|
20074
19757
|
const w = slot.offsetWidth;
|
|
20075
19758
|
if (w <= 0) return;
|
|
20076
19759
|
const half = w / 2;
|
|
20077
|
-
const clamped = Math.max(
|
|
19760
|
+
const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
|
|
20078
19761
|
setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
|
|
20079
19762
|
};
|
|
20080
19763
|
clamp();
|
|
@@ -20083,7 +19766,7 @@ function GridToolbarSlot({ gridRect, children }) {
|
|
|
20083
19766
|
return () => ro.disconnect();
|
|
20084
19767
|
}, [centerX, children]);
|
|
20085
19768
|
const mobile = window.innerWidth <= 480;
|
|
20086
|
-
return /* @__PURE__ */ (0,
|
|
19769
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
20087
19770
|
"div",
|
|
20088
19771
|
{
|
|
20089
19772
|
ref: slotRef,
|
|
@@ -20118,7 +19801,7 @@ function requestValidateTree2(postToParent2, tree) {
|
|
|
20118
19801
|
});
|
|
20119
19802
|
}
|
|
20120
19803
|
function StyleSwatch({ style }) {
|
|
20121
|
-
return /* @__PURE__ */ (0,
|
|
19804
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
20122
19805
|
"span",
|
|
20123
19806
|
{
|
|
20124
19807
|
"aria-hidden": true,
|
|
@@ -20132,35 +19815,35 @@ function StyleSwatch({ style }) {
|
|
|
20132
19815
|
);
|
|
20133
19816
|
}
|
|
20134
19817
|
function ButtonGlyph() {
|
|
20135
|
-
return /* @__PURE__ */ (0,
|
|
20136
|
-
/* @__PURE__ */ (0,
|
|
20137
|
-
/* @__PURE__ */ (0,
|
|
19818
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("svg", { width: "18", height: "12", viewBox: "0 0 18 12", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
|
|
19819
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("rect", { x: "0.75", y: "0.75", width: "16.5", height: "10.5", rx: "3", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
19820
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M5.5 6H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
20138
19821
|
] });
|
|
20139
19822
|
}
|
|
20140
19823
|
function FeatureGlyph({ mode }) {
|
|
20141
|
-
return /* @__PURE__ */ (0,
|
|
20142
|
-
/* @__PURE__ */ (0,
|
|
20143
|
-
/* @__PURE__ */ (0,
|
|
20144
|
-
/* @__PURE__ */ (0,
|
|
20145
|
-
/* @__PURE__ */ (0,
|
|
20146
|
-
/* @__PURE__ */ (0,
|
|
20147
|
-
mode === "add" && /* @__PURE__ */ (0,
|
|
19824
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
|
|
19825
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("circle", { cx: "8", cy: "8", r: "7.25", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
19826
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M5 8.2L7.2 10.3L11 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
19827
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("circle", { cx: "13.5", cy: "13.5", r: "4.25", fill: "var(--ohw-background, #ffffff)", stroke: "var(--ohw-background, #ffffff)", strokeWidth: "1" }),
|
|
19828
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("circle", { cx: "13.5", cy: "13.5", r: "3.75", fill: "var(--ohw-background, #ffffff)", stroke: PRIMARY4, strokeWidth: "1" }),
|
|
19829
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M11.5 13.5H15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" }),
|
|
19830
|
+
mode === "add" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M13.5 11.5V15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" })
|
|
20148
19831
|
] });
|
|
20149
19832
|
}
|
|
20150
|
-
function
|
|
19833
|
+
function ToolbarAction({
|
|
20151
19834
|
label,
|
|
20152
19835
|
onClick,
|
|
20153
19836
|
disabled = false,
|
|
20154
19837
|
children
|
|
20155
19838
|
}) {
|
|
20156
|
-
const button = /* @__PURE__ */ (0,
|
|
20157
|
-
return /* @__PURE__ */ (0,
|
|
20158
|
-
/* @__PURE__ */ (0,
|
|
20159
|
-
/* @__PURE__ */ (0,
|
|
19839
|
+
const button = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, onClick, className: "size-8", children });
|
|
19840
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
|
|
19841
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "inline-flex", children: button }) : button }),
|
|
19842
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
|
|
20160
19843
|
] });
|
|
20161
19844
|
}
|
|
20162
|
-
function
|
|
20163
|
-
return /* @__PURE__ */ (0,
|
|
19845
|
+
function ToolbarSeparator() {
|
|
19846
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
|
|
20164
19847
|
}
|
|
20165
19848
|
function CardStyleMenu({
|
|
20166
19849
|
value,
|
|
@@ -20168,7 +19851,7 @@ function CardStyleMenu({
|
|
|
20168
19851
|
disabled = false
|
|
20169
19852
|
}) {
|
|
20170
19853
|
const current = PRICING_CARD_STYLES.find((s) => s.value === value) ?? PRICING_CARD_STYLES[0];
|
|
20171
|
-
const trigger = /* @__PURE__ */ (0,
|
|
19854
|
+
const trigger = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
20172
19855
|
"button",
|
|
20173
19856
|
{
|
|
20174
19857
|
type: "button",
|
|
@@ -20179,28 +19862,28 @@ function CardStyleMenu({
|
|
|
20179
19862
|
disabled && "cursor-not-allowed opacity-40 hover:bg-transparent"
|
|
20180
19863
|
),
|
|
20181
19864
|
children: [
|
|
20182
|
-
/* @__PURE__ */ (0,
|
|
20183
|
-
/* @__PURE__ */ (0,
|
|
20184
|
-
/* @__PURE__ */ (0,
|
|
19865
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StyleSwatch, { style: current.value }),
|
|
19866
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "flex-1 text-left", children: current.label }),
|
|
19867
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ChevronDown, { size: 16, style: { pointerEvents: "none" } })
|
|
20185
19868
|
]
|
|
20186
19869
|
}
|
|
20187
19870
|
);
|
|
20188
19871
|
if (disabled) {
|
|
20189
|
-
return /* @__PURE__ */ (0,
|
|
20190
|
-
/* @__PURE__ */ (0,
|
|
20191
|
-
/* @__PURE__ */ (0,
|
|
20192
|
-
/* @__PURE__ */ (0,
|
|
20193
|
-
/* @__PURE__ */ (0,
|
|
19872
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
19873
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
|
|
19874
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
|
|
19875
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "inline-flex", children: trigger }) }),
|
|
19876
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
|
|
20194
19877
|
] })
|
|
20195
19878
|
] });
|
|
20196
19879
|
}
|
|
20197
|
-
return /* @__PURE__ */ (0,
|
|
20198
|
-
/* @__PURE__ */ (0,
|
|
20199
|
-
/* @__PURE__ */ (0,
|
|
20200
|
-
/* @__PURE__ */ (0,
|
|
20201
|
-
/* @__PURE__ */ (0,
|
|
19880
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
19881
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
|
|
19882
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(DropdownMenu, { modal: false, children: [
|
|
19883
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuTrigger, { asChild: true, children: trigger }),
|
|
19884
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
|
|
20202
19885
|
const selected = style.value === value;
|
|
20203
|
-
return /* @__PURE__ */ (0,
|
|
19886
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
20204
19887
|
DropdownMenuItem,
|
|
20205
19888
|
{
|
|
20206
19889
|
role: "menuitemradio",
|
|
@@ -20208,9 +19891,9 @@ function CardStyleMenu({
|
|
|
20208
19891
|
onSelect: () => onChange(style.value),
|
|
20209
19892
|
className: cn("grid grid-cols-[18px_1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
|
|
20210
19893
|
children: [
|
|
20211
|
-
/* @__PURE__ */ (0,
|
|
20212
|
-
/* @__PURE__ */ (0,
|
|
20213
|
-
selected && /* @__PURE__ */ (0,
|
|
19894
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StyleSwatch, { style: style.value }),
|
|
19895
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: style.label }),
|
|
19896
|
+
selected && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Check, { size: 16, className: "text-bridge-primary" })
|
|
20214
19897
|
]
|
|
20215
19898
|
},
|
|
20216
19899
|
style.value
|
|
@@ -20240,7 +19923,7 @@ function PricingCardToolbar({
|
|
|
20240
19923
|
const style = pricingCardStyle(entry.tree, index);
|
|
20241
19924
|
const featuredTag = pricingCardFeaturedTag(entry.tree, index);
|
|
20242
19925
|
const mobile = window.innerWidth <= 480;
|
|
20243
|
-
return /* @__PURE__ */ (0,
|
|
19926
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
20244
19927
|
"div",
|
|
20245
19928
|
{
|
|
20246
19929
|
"data-ohw-bridge": "",
|
|
@@ -20252,7 +19935,7 @@ function PricingCardToolbar({
|
|
|
20252
19935
|
),
|
|
20253
19936
|
style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
|
|
20254
19937
|
children: [
|
|
20255
|
-
/* @__PURE__ */ (0,
|
|
19938
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
20256
19939
|
"div",
|
|
20257
19940
|
{
|
|
20258
19941
|
className: cn(
|
|
@@ -20261,8 +19944,8 @@ function PricingCardToolbar({
|
|
|
20261
19944
|
mobile ? "flex-wrap justify-center" : "flex-nowrap"
|
|
20262
19945
|
),
|
|
20263
19946
|
children: [
|
|
20264
|
-
/* @__PURE__ */ (0,
|
|
20265
|
-
/* @__PURE__ */ (0,
|
|
19947
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
|
|
19948
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
20266
19949
|
CustomToolbarButton,
|
|
20267
19950
|
{
|
|
20268
19951
|
type: "button",
|
|
@@ -20270,8 +19953,8 @@ function PricingCardToolbar({
|
|
|
20270
19953
|
"aria-pressed": featuredTag,
|
|
20271
19954
|
onClick: () => onSetFeaturedTag(!featuredTag),
|
|
20272
19955
|
className: "group size-8",
|
|
20273
|
-
children: /* @__PURE__ */ (0,
|
|
20274
|
-
|
|
19956
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19957
|
+
import_lucide_react9.Star,
|
|
20275
19958
|
{
|
|
20276
19959
|
size: 16,
|
|
20277
19960
|
fill: "currentColor",
|
|
@@ -20285,25 +19968,25 @@ function PricingCardToolbar({
|
|
|
20285
19968
|
)
|
|
20286
19969
|
}
|
|
20287
19970
|
) }),
|
|
20288
|
-
/* @__PURE__ */ (0,
|
|
19971
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
|
|
20289
19972
|
] }),
|
|
20290
|
-
/* @__PURE__ */ (0,
|
|
20291
|
-
/* @__PURE__ */ (0,
|
|
20292
|
-
/* @__PURE__ */ (0,
|
|
20293
|
-
/* @__PURE__ */ (0,
|
|
20294
|
-
/* @__PURE__ */ (0,
|
|
20295
|
-
/* @__PURE__ */ (0,
|
|
20296
|
-
/* @__PURE__ */ (0,
|
|
19973
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19974
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
|
|
19975
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19976
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ButtonGlyph, {}) }),
|
|
19977
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "relative inline-flex", children: [
|
|
19978
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ButtonGlyph, {}),
|
|
19979
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Minus, { size: 10, strokeWidth: 2.5, className: "absolute -right-1.5 -top-1.5 rounded-full bg-background text-bridge-primary" })
|
|
20297
19980
|
] }) }),
|
|
20298
|
-
/* @__PURE__ */ (0,
|
|
20299
|
-
/* @__PURE__ */ (0,
|
|
20300
|
-
/* @__PURE__ */ (0,
|
|
20301
|
-
/* @__PURE__ */ (0,
|
|
20302
|
-
/* @__PURE__ */ (0,
|
|
19981
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Add feature", onClick: onAddFeature, disabled: featureCount >= 10, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(FeatureGlyph, { mode: "add" }) }),
|
|
19982
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Remove feature", onClick: onRemoveFeature, disabled: featureCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(FeatureGlyph, { mode: "remove" }) }),
|
|
19983
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19984
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Add tier", onClick: onAddTier, disabled: collectionCount >= 4, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Plus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19985
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Remove tier", onClick: onRemoveTier, disabled: collectionCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Minus, { size: 16, style: { pointerEvents: "none" } }) })
|
|
20303
19986
|
]
|
|
20304
19987
|
}
|
|
20305
19988
|
),
|
|
20306
|
-
error && /* @__PURE__ */ (0,
|
|
19989
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
|
|
20307
19990
|
]
|
|
20308
19991
|
}
|
|
20309
19992
|
) });
|
|
@@ -20337,7 +20020,7 @@ function AiPricingCardOverlay({
|
|
|
20337
20020
|
const overEditable = Boolean(t?.closest?.("[data-ohw-editable], [data-ohw-role], a, button"));
|
|
20338
20021
|
setHover((prev) => {
|
|
20339
20022
|
const next = ref && !overEditable ? ref : null;
|
|
20340
|
-
return
|
|
20023
|
+
return sameRef(prev, next) ? prev : next;
|
|
20341
20024
|
});
|
|
20342
20025
|
};
|
|
20343
20026
|
const onLeave = () => setHover(null);
|
|
@@ -20352,10 +20035,10 @@ function AiPricingCardOverlay({
|
|
|
20352
20035
|
const onClick = (e) => {
|
|
20353
20036
|
const t = e.target;
|
|
20354
20037
|
if (!(t instanceof Element)) return;
|
|
20355
|
-
if (t.closest(
|
|
20038
|
+
if (t.closest(CHROME_SELECTOR)) return;
|
|
20356
20039
|
const ref = cardRefFromTarget(t);
|
|
20357
|
-
setActive((prev) =>
|
|
20358
|
-
if (!ref || !
|
|
20040
|
+
setActive((prev) => sameRef(prev, ref) ? prev : ref);
|
|
20041
|
+
if (!ref || !sameRef(activeRef.current, ref)) setError(null);
|
|
20359
20042
|
};
|
|
20360
20043
|
document.addEventListener("click", onClick, true);
|
|
20361
20044
|
return () => document.removeEventListener("click", onClick, true);
|
|
@@ -20420,12 +20103,12 @@ function AiPricingCardOverlay({
|
|
|
20420
20103
|
const activeEntry = active ? findEntry(active.sectionId) : null;
|
|
20421
20104
|
const activeCardRect = useLiveCardRect(active);
|
|
20422
20105
|
const activeGridRect = useLiveCardRect(active, true);
|
|
20423
|
-
const hoverRect = useLiveCardRect(hover && !
|
|
20424
|
-
return /* @__PURE__ */ (0,
|
|
20425
|
-
hoverRect && /* @__PURE__ */ (0,
|
|
20426
|
-
activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ (0,
|
|
20427
|
-
/* @__PURE__ */ (0,
|
|
20428
|
-
/* @__PURE__ */ (0,
|
|
20106
|
+
const hoverRect = useLiveCardRect(hover && !sameRef(hover, active) ? hover : null);
|
|
20107
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
20108
|
+
hoverRect && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
|
|
20109
|
+
activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
20110
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: activeCardRect, state: "active-top" }),
|
|
20111
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(GridToolbarSlot, { gridRect: activeGridRect, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
20429
20112
|
PricingCardToolbar,
|
|
20430
20113
|
{
|
|
20431
20114
|
entry: activeEntry,
|
|
@@ -20453,7 +20136,7 @@ function AiPricingCardOverlay({
|
|
|
20453
20136
|
onRemoveFeature: () => runMutation(active.sectionId, (tree) => removePricingCardFeature(tree, active.index))
|
|
20454
20137
|
}
|
|
20455
20138
|
) }),
|
|
20456
|
-
/* @__PURE__ */ (0,
|
|
20139
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
20457
20140
|
"div",
|
|
20458
20141
|
{
|
|
20459
20142
|
"data-ohw-bridge": "",
|
|
@@ -20475,7 +20158,7 @@ function AiPricingCardOverlay({
|
|
|
20475
20158
|
|
|
20476
20159
|
// src/ui/ai-section/AiVideoOverlay.tsx
|
|
20477
20160
|
var import_react14 = require("react");
|
|
20478
|
-
var
|
|
20161
|
+
var import_lucide_react10 = require("lucide-react");
|
|
20479
20162
|
|
|
20480
20163
|
// src/lib/ai-video-tree.ts
|
|
20481
20164
|
function resolveVideoBlock(tree, path) {
|
|
@@ -20517,11 +20200,39 @@ function clearVideo(tree, path) {
|
|
|
20517
20200
|
});
|
|
20518
20201
|
}
|
|
20519
20202
|
|
|
20203
|
+
// src/lib/youtube.ts
|
|
20204
|
+
var YOUTUBE_ID_PATTERN = /^[A-Za-z0-9_-]{11}$/;
|
|
20205
|
+
function extractYouTubeId(input) {
|
|
20206
|
+
const trimmed = input.trim();
|
|
20207
|
+
if (!trimmed) return null;
|
|
20208
|
+
if (YOUTUBE_ID_PATTERN.test(trimmed)) return trimmed;
|
|
20209
|
+
let url;
|
|
20210
|
+
try {
|
|
20211
|
+
url = new URL(trimmed);
|
|
20212
|
+
} catch {
|
|
20213
|
+
return null;
|
|
20214
|
+
}
|
|
20215
|
+
const host = url.hostname.replace(/^www\./, "");
|
|
20216
|
+
if (host !== "youtube.com" && host !== "m.youtube.com" && host !== "youtu.be" && host !== "youtube-nocookie.com") {
|
|
20217
|
+
return null;
|
|
20218
|
+
}
|
|
20219
|
+
let candidate = null;
|
|
20220
|
+
if (host === "youtu.be") {
|
|
20221
|
+
candidate = url.pathname.slice(1).split("/")[0] ?? null;
|
|
20222
|
+
} else if (url.pathname === "/watch") {
|
|
20223
|
+
candidate = url.searchParams.get("v");
|
|
20224
|
+
} else {
|
|
20225
|
+
const match = url.pathname.match(/^\/(?:embed|shorts)\/([^/]+)/);
|
|
20226
|
+
candidate = match ? match[1] : null;
|
|
20227
|
+
}
|
|
20228
|
+
return candidate && YOUTUBE_ID_PATTERN.test(candidate) ? candidate : null;
|
|
20229
|
+
}
|
|
20230
|
+
|
|
20520
20231
|
// src/ui/ai-section/AiVideoOverlay.tsx
|
|
20521
|
-
var
|
|
20232
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
20522
20233
|
var PRIMARY5 = "#0885FE";
|
|
20523
|
-
var
|
|
20524
|
-
var
|
|
20234
|
+
var OHW_BLUE2 = `var(--ohw-primary, ${PRIMARY5})`;
|
|
20235
|
+
var OHW_BLUE_DARK2 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY5}) 60%, #000000)`;
|
|
20525
20236
|
function findVideoBlockElement(sectionId, path) {
|
|
20526
20237
|
const sectionEl = findByInstanceId(sectionId);
|
|
20527
20238
|
if (!sectionEl) return null;
|
|
@@ -20581,12 +20292,12 @@ function requestValidateTree3(postToParent2, tree) {
|
|
|
20581
20292
|
postToParent2({ type: "ow:ai-validate-tree-request", id, tree });
|
|
20582
20293
|
});
|
|
20583
20294
|
}
|
|
20584
|
-
function
|
|
20295
|
+
function Pill2({
|
|
20585
20296
|
label,
|
|
20586
20297
|
onClick,
|
|
20587
20298
|
disabled
|
|
20588
20299
|
}) {
|
|
20589
|
-
return /* @__PURE__ */ (0,
|
|
20300
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
20590
20301
|
"button",
|
|
20591
20302
|
{
|
|
20592
20303
|
type: "button",
|
|
@@ -20602,7 +20313,7 @@ function Pill({
|
|
|
20602
20313
|
border: "none",
|
|
20603
20314
|
cursor: disabled ? "default" : "pointer",
|
|
20604
20315
|
background: "#ffffff",
|
|
20605
|
-
color:
|
|
20316
|
+
color: OHW_BLUE_DARK2,
|
|
20606
20317
|
opacity: disabled ? 0.4 : 1,
|
|
20607
20318
|
fontSize: 12,
|
|
20608
20319
|
lineHeight: "16px",
|
|
@@ -20624,7 +20335,7 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
20624
20335
|
setDraft(value ? watchUrl(value) : "");
|
|
20625
20336
|
setInvalid(false);
|
|
20626
20337
|
}, [value]);
|
|
20627
|
-
const
|
|
20338
|
+
const commit = () => {
|
|
20628
20339
|
const next = draft.trim();
|
|
20629
20340
|
if (!next) {
|
|
20630
20341
|
setInvalid(false);
|
|
@@ -20645,8 +20356,8 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
20645
20356
|
onCommit(id);
|
|
20646
20357
|
}
|
|
20647
20358
|
};
|
|
20648
|
-
return /* @__PURE__ */ (0,
|
|
20649
|
-
/* @__PURE__ */ (0,
|
|
20359
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 4, width: "100%", maxWidth: 280 }, children: [
|
|
20360
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
20650
20361
|
"div",
|
|
20651
20362
|
{
|
|
20652
20363
|
style: {
|
|
@@ -20662,12 +20373,12 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
20662
20373
|
boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
|
|
20663
20374
|
},
|
|
20664
20375
|
children: [
|
|
20665
|
-
/* @__PURE__ */ (0,
|
|
20376
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
20666
20377
|
"span",
|
|
20667
20378
|
{
|
|
20668
20379
|
style: {
|
|
20669
20380
|
flex: "0 0 auto",
|
|
20670
|
-
color:
|
|
20381
|
+
color: OHW_BLUE_DARK2,
|
|
20671
20382
|
fontSize: 10,
|
|
20672
20383
|
lineHeight: "16px",
|
|
20673
20384
|
fontWeight: 700,
|
|
@@ -20677,14 +20388,14 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
20677
20388
|
children: "Video"
|
|
20678
20389
|
}
|
|
20679
20390
|
),
|
|
20680
|
-
/* @__PURE__ */ (0,
|
|
20391
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
20681
20392
|
"input",
|
|
20682
20393
|
{
|
|
20683
20394
|
type: "text",
|
|
20684
20395
|
inputMode: "url",
|
|
20685
20396
|
value: draft,
|
|
20686
20397
|
onChange: (e) => handleChange(e.target.value),
|
|
20687
|
-
onBlur:
|
|
20398
|
+
onBlur: commit,
|
|
20688
20399
|
onKeyDown: (e) => {
|
|
20689
20400
|
if (e.key === "Enter") e.currentTarget.blur();
|
|
20690
20401
|
if (e.key === "Escape") {
|
|
@@ -20714,7 +20425,7 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
20714
20425
|
]
|
|
20715
20426
|
}
|
|
20716
20427
|
),
|
|
20717
|
-
invalid && /* @__PURE__ */ (0,
|
|
20428
|
+
invalid && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, textAlign: "center" }, children: "That doesn't look like a YouTube link \u2014 try pasting the video URL again." })
|
|
20718
20429
|
] });
|
|
20719
20430
|
}
|
|
20720
20431
|
function VideoToolbar({
|
|
@@ -20724,7 +20435,7 @@ function VideoToolbar({
|
|
|
20724
20435
|
onSetVideoId,
|
|
20725
20436
|
onRemove
|
|
20726
20437
|
}) {
|
|
20727
|
-
return /* @__PURE__ */ (0,
|
|
20438
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
20728
20439
|
"div",
|
|
20729
20440
|
{
|
|
20730
20441
|
"data-ohw-bridge": "",
|
|
@@ -20736,7 +20447,7 @@ function VideoToolbar({
|
|
|
20736
20447
|
gap: 6,
|
|
20737
20448
|
alignItems: "center",
|
|
20738
20449
|
width: 280,
|
|
20739
|
-
background:
|
|
20450
|
+
background: OHW_BLUE2,
|
|
20740
20451
|
padding: 8,
|
|
20741
20452
|
borderRadius: 12,
|
|
20742
20453
|
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
@@ -20744,9 +20455,9 @@ function VideoToolbar({
|
|
|
20744
20455
|
opacity: pending ? 0.6 : 1
|
|
20745
20456
|
},
|
|
20746
20457
|
children: [
|
|
20747
|
-
/* @__PURE__ */ (0,
|
|
20748
|
-
/* @__PURE__ */ (0,
|
|
20749
|
-
error && /* @__PURE__ */ (0,
|
|
20458
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VideoUrlInput, { value: videoId, onCommit: onSetVideoId }),
|
|
20459
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Pill2, { label: "Remove video", onClick: onRemove, disabled: !videoId }),
|
|
20460
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
|
|
20750
20461
|
]
|
|
20751
20462
|
}
|
|
20752
20463
|
);
|
|
@@ -20866,8 +20577,8 @@ function AiVideoOverlay({
|
|
|
20866
20577
|
const activeBlockRect = useLiveBlockRect(active);
|
|
20867
20578
|
const TOOLBAR_APPROX_H = 90;
|
|
20868
20579
|
const toolbarState = activeBlockRect && activeBlockRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
|
|
20869
|
-
return /* @__PURE__ */ (0,
|
|
20870
|
-
hoverHandleRect && hover && /* @__PURE__ */ (0,
|
|
20580
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
20581
|
+
hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
20871
20582
|
"button",
|
|
20872
20583
|
{
|
|
20873
20584
|
type: "button",
|
|
@@ -20895,15 +20606,15 @@ function AiVideoOverlay({
|
|
|
20895
20606
|
fontSize: 14,
|
|
20896
20607
|
fontWeight: 700
|
|
20897
20608
|
},
|
|
20898
|
-
children: /* @__PURE__ */ (0,
|
|
20609
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.Star, { size: 14, style: { pointerEvents: "none" } })
|
|
20899
20610
|
}
|
|
20900
20611
|
),
|
|
20901
|
-
activeBlockRect && active && activeEntry && /* @__PURE__ */ (0,
|
|
20612
|
+
activeBlockRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
20902
20613
|
ItemInteractionLayer,
|
|
20903
20614
|
{
|
|
20904
20615
|
rect: activeBlockRect,
|
|
20905
20616
|
state: toolbarState,
|
|
20906
|
-
toolbar: /* @__PURE__ */ (0,
|
|
20617
|
+
toolbar: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
20907
20618
|
VideoToolbar,
|
|
20908
20619
|
{
|
|
20909
20620
|
videoId: videoIdAt(activeEntry.tree, active.path),
|
|
@@ -20927,7 +20638,7 @@ function AiVideoOverlay({
|
|
|
20927
20638
|
|
|
20928
20639
|
// src/ui/ai-section/AiFadeCarouselOverlay.tsx
|
|
20929
20640
|
var import_react15 = require("react");
|
|
20930
|
-
var
|
|
20641
|
+
var import_lucide_react11 = require("lucide-react");
|
|
20931
20642
|
|
|
20932
20643
|
// src/lib/ai-carousel-tree.ts
|
|
20933
20644
|
function isCarouselBlock(node) {
|
|
@@ -20978,10 +20689,10 @@ function setCarouselAutoplay(tree, on) {
|
|
|
20978
20689
|
}
|
|
20979
20690
|
|
|
20980
20691
|
// src/ui/ai-section/AiFadeCarouselOverlay.tsx
|
|
20981
|
-
var
|
|
20692
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
20982
20693
|
var PRIMARY6 = "#0885FE";
|
|
20983
|
-
var
|
|
20984
|
-
var
|
|
20694
|
+
var OHW_BLUE3 = `var(--ohw-primary, ${PRIMARY6})`;
|
|
20695
|
+
var OHW_BLUE_DARK3 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY6}) 60%, #000000)`;
|
|
20985
20696
|
function findCarouselItemElement(sectionId, index) {
|
|
20986
20697
|
const sectionEl = findByInstanceId(sectionId);
|
|
20987
20698
|
if (!sectionEl) return null;
|
|
@@ -21060,8 +20771,8 @@ function requestAssetPick2(postToParent2) {
|
|
|
21060
20771
|
postToParent2({ type: "ow:asset-pick", id });
|
|
21061
20772
|
});
|
|
21062
20773
|
}
|
|
21063
|
-
function
|
|
21064
|
-
return /* @__PURE__ */ (0,
|
|
20774
|
+
function Pill3({ label, onClick, disabled }) {
|
|
20775
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
21065
20776
|
"button",
|
|
21066
20777
|
{
|
|
21067
20778
|
type: "button",
|
|
@@ -21077,7 +20788,7 @@ function Pill2({ label, onClick, disabled }) {
|
|
|
21077
20788
|
border: "none",
|
|
21078
20789
|
cursor: disabled ? "default" : "pointer",
|
|
21079
20790
|
background: "#ffffff",
|
|
21080
|
-
color:
|
|
20791
|
+
color: OHW_BLUE_DARK3,
|
|
21081
20792
|
opacity: disabled ? 0.4 : 1,
|
|
21082
20793
|
fontSize: 12,
|
|
21083
20794
|
lineHeight: "16px",
|
|
@@ -21095,7 +20806,7 @@ function TogglePill({
|
|
|
21095
20806
|
onToggle,
|
|
21096
20807
|
disabled
|
|
21097
20808
|
}) {
|
|
21098
|
-
return /* @__PURE__ */ (0,
|
|
20809
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
21099
20810
|
"button",
|
|
21100
20811
|
{
|
|
21101
20812
|
type: "button",
|
|
@@ -21114,7 +20825,7 @@ function TogglePill({
|
|
|
21114
20825
|
border: "none",
|
|
21115
20826
|
cursor: disabled ? "default" : "pointer",
|
|
21116
20827
|
background: "#ffffff",
|
|
21117
|
-
color:
|
|
20828
|
+
color: OHW_BLUE_DARK3,
|
|
21118
20829
|
opacity: disabled ? 0.4 : 1,
|
|
21119
20830
|
fontSize: 12,
|
|
21120
20831
|
lineHeight: "16px",
|
|
@@ -21124,7 +20835,7 @@ function TogglePill({
|
|
|
21124
20835
|
},
|
|
21125
20836
|
children: [
|
|
21126
20837
|
label,
|
|
21127
|
-
/* @__PURE__ */ (0,
|
|
20838
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
21128
20839
|
"span",
|
|
21129
20840
|
{
|
|
21130
20841
|
"aria-hidden": true,
|
|
@@ -21137,10 +20848,10 @@ function TogglePill({
|
|
|
21137
20848
|
// Off is a grey track, not a washed-out blue: the pill's own white background already
|
|
21138
20849
|
// carries the brand colour in the text, and a pale blue track next to it read as
|
|
21139
20850
|
// "disabled control" rather than "switch that is off".
|
|
21140
|
-
background: on ?
|
|
20851
|
+
background: on ? OHW_BLUE_DARK3 : "#CBD5E1",
|
|
21141
20852
|
transition: "background 120ms ease"
|
|
21142
20853
|
},
|
|
21143
|
-
children: /* @__PURE__ */ (0,
|
|
20854
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
21144
20855
|
"span",
|
|
21145
20856
|
{
|
|
21146
20857
|
style: {
|
|
@@ -21169,7 +20880,7 @@ function CarouselSlideToolbar({
|
|
|
21169
20880
|
onChangeImage,
|
|
21170
20881
|
onToggleAutoplay
|
|
21171
20882
|
}) {
|
|
21172
|
-
return /* @__PURE__ */ (0,
|
|
20883
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
21173
20884
|
"div",
|
|
21174
20885
|
{
|
|
21175
20886
|
"data-ohw-bridge": "",
|
|
@@ -21180,7 +20891,7 @@ function CarouselSlideToolbar({
|
|
|
21180
20891
|
flexDirection: "column",
|
|
21181
20892
|
gap: 6,
|
|
21182
20893
|
alignItems: "center",
|
|
21183
|
-
background:
|
|
20894
|
+
background: OHW_BLUE3,
|
|
21184
20895
|
padding: 8,
|
|
21185
20896
|
borderRadius: 12,
|
|
21186
20897
|
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
@@ -21192,11 +20903,11 @@ function CarouselSlideToolbar({
|
|
|
21192
20903
|
pointerEvents: pending ? "none" : "auto"
|
|
21193
20904
|
},
|
|
21194
20905
|
children: [
|
|
21195
|
-
/* @__PURE__ */ (0,
|
|
21196
|
-
/* @__PURE__ */ (0,
|
|
21197
|
-
/* @__PURE__ */ (0,
|
|
20906
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
|
|
20907
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Pill3, { label: "Change Image", onClick: onChangeImage }),
|
|
20908
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
|
|
21198
20909
|
] }),
|
|
21199
|
-
error && /* @__PURE__ */ (0,
|
|
20910
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
|
|
21200
20911
|
]
|
|
21201
20912
|
}
|
|
21202
20913
|
);
|
|
@@ -21336,8 +21047,8 @@ function AiFadeCarouselOverlay({
|
|
|
21336
21047
|
const activeItemRect = useLiveItemRect2(active);
|
|
21337
21048
|
const TOOLBAR_APPROX_H = 90;
|
|
21338
21049
|
const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
|
|
21339
|
-
return /* @__PURE__ */ (0,
|
|
21340
|
-
hoverHandleRect && hover && /* @__PURE__ */ (0,
|
|
21050
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
21051
|
+
hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
21341
21052
|
"button",
|
|
21342
21053
|
{
|
|
21343
21054
|
type: "button",
|
|
@@ -21366,10 +21077,10 @@ function AiFadeCarouselOverlay({
|
|
|
21366
21077
|
fontSize: 14,
|
|
21367
21078
|
fontWeight: 700
|
|
21368
21079
|
},
|
|
21369
|
-
children: /* @__PURE__ */ (0,
|
|
21080
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.Star, { size: 14, style: { pointerEvents: "none" } })
|
|
21370
21081
|
}
|
|
21371
21082
|
),
|
|
21372
|
-
swapping && /* @__PURE__ */ (0,
|
|
21083
|
+
swapping && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
21373
21084
|
"div",
|
|
21374
21085
|
{
|
|
21375
21086
|
ref: skeletonRef,
|
|
@@ -21387,15 +21098,15 @@ function AiFadeCarouselOverlay({
|
|
|
21387
21098
|
zIndex: 2147483646,
|
|
21388
21099
|
pointerEvents: "none"
|
|
21389
21100
|
},
|
|
21390
|
-
children: /* @__PURE__ */ (0,
|
|
21101
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("style", { children: MEDIA_SKELETON_CSS })
|
|
21391
21102
|
}
|
|
21392
21103
|
),
|
|
21393
|
-
activeItemRect && active && activeEntry && /* @__PURE__ */ (0,
|
|
21104
|
+
activeItemRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
21394
21105
|
ItemInteractionLayer,
|
|
21395
21106
|
{
|
|
21396
21107
|
rect: activeItemRect,
|
|
21397
21108
|
state: toolbarState,
|
|
21398
|
-
toolbar: /* @__PURE__ */ (0,
|
|
21109
|
+
toolbar: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
21399
21110
|
CarouselSlideToolbar,
|
|
21400
21111
|
{
|
|
21401
21112
|
pending,
|
|
@@ -21586,6 +21297,113 @@ function mergePrefetchedSections(prev, fetched, livePath, liveSections) {
|
|
|
21586
21297
|
// src/ui/link-modal/LinkPopover.tsx
|
|
21587
21298
|
var import_react19 = require("react");
|
|
21588
21299
|
|
|
21300
|
+
// src/ui/dialog.tsx
|
|
21301
|
+
var React9 = __toESM(require("react"), 1);
|
|
21302
|
+
var import_radix_ui6 = require("radix-ui");
|
|
21303
|
+
var import_lucide_react12 = require("lucide-react");
|
|
21304
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
21305
|
+
function Dialog2({
|
|
21306
|
+
...props
|
|
21307
|
+
}) {
|
|
21308
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_radix_ui6.Dialog.Root, { "data-slot": "dialog", ...props });
|
|
21309
|
+
}
|
|
21310
|
+
function DialogPortal({
|
|
21311
|
+
...props
|
|
21312
|
+
}) {
|
|
21313
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_radix_ui6.Dialog.Portal, { ...props });
|
|
21314
|
+
}
|
|
21315
|
+
function DialogOverlay({
|
|
21316
|
+
className,
|
|
21317
|
+
...props
|
|
21318
|
+
}) {
|
|
21319
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
21320
|
+
import_radix_ui6.Dialog.Overlay,
|
|
21321
|
+
{
|
|
21322
|
+
"data-slot": "dialog-overlay",
|
|
21323
|
+
"data-ohw-link-modal-root": "",
|
|
21324
|
+
className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
|
|
21325
|
+
...props
|
|
21326
|
+
}
|
|
21327
|
+
);
|
|
21328
|
+
}
|
|
21329
|
+
var DialogContent = React9.forwardRef(
|
|
21330
|
+
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
21331
|
+
const positionMode = container ? "absolute" : "fixed";
|
|
21332
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DialogPortal, { container: container ?? void 0, children: [
|
|
21333
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
21334
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
21335
|
+
import_radix_ui6.Dialog.Content,
|
|
21336
|
+
{
|
|
21337
|
+
ref,
|
|
21338
|
+
"data-slot": "dialog-content",
|
|
21339
|
+
className: cn(
|
|
21340
|
+
positionMode,
|
|
21341
|
+
"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",
|
|
21342
|
+
"rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
|
|
21343
|
+
container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
|
|
21344
|
+
className
|
|
21345
|
+
),
|
|
21346
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
21347
|
+
...props,
|
|
21348
|
+
children: [
|
|
21349
|
+
children,
|
|
21350
|
+
showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
21351
|
+
import_radix_ui6.Dialog.Close,
|
|
21352
|
+
{
|
|
21353
|
+
type: "button",
|
|
21354
|
+
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
21355
|
+
"aria-label": "Close",
|
|
21356
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.X, { size: 16, "aria-hidden": true })
|
|
21357
|
+
}
|
|
21358
|
+
) : null
|
|
21359
|
+
]
|
|
21360
|
+
}
|
|
21361
|
+
)
|
|
21362
|
+
] });
|
|
21363
|
+
}
|
|
21364
|
+
);
|
|
21365
|
+
DialogContent.displayName = import_radix_ui6.Dialog.Content.displayName;
|
|
21366
|
+
function DialogHeader({
|
|
21367
|
+
className,
|
|
21368
|
+
...props
|
|
21369
|
+
}) {
|
|
21370
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
21371
|
+
}
|
|
21372
|
+
function DialogFooter({
|
|
21373
|
+
className,
|
|
21374
|
+
...props
|
|
21375
|
+
}) {
|
|
21376
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
21377
|
+
"div",
|
|
21378
|
+
{
|
|
21379
|
+
className: cn("flex items-center justify-end gap-2", className),
|
|
21380
|
+
...props
|
|
21381
|
+
}
|
|
21382
|
+
);
|
|
21383
|
+
}
|
|
21384
|
+
var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
21385
|
+
import_radix_ui6.Dialog.Title,
|
|
21386
|
+
{
|
|
21387
|
+
ref,
|
|
21388
|
+
className: cn(
|
|
21389
|
+
"text-lg font-semibold leading-none tracking-tight text-card-foreground",
|
|
21390
|
+
className
|
|
21391
|
+
),
|
|
21392
|
+
...props
|
|
21393
|
+
}
|
|
21394
|
+
));
|
|
21395
|
+
DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
|
|
21396
|
+
var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
21397
|
+
import_radix_ui6.Dialog.Description,
|
|
21398
|
+
{
|
|
21399
|
+
ref,
|
|
21400
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
21401
|
+
...props
|
|
21402
|
+
}
|
|
21403
|
+
));
|
|
21404
|
+
DialogDescription.displayName = import_radix_ui6.Dialog.Description.displayName;
|
|
21405
|
+
var DialogClose = import_radix_ui6.Dialog.Close;
|
|
21406
|
+
|
|
21589
21407
|
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
21590
21408
|
var import_lucide_react16 = require("lucide-react");
|
|
21591
21409
|
|
|
@@ -22689,7 +22507,6 @@ function shouldUseDevFixtures() {
|
|
|
22689
22507
|
function getLogoElement(el) {
|
|
22690
22508
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
22691
22509
|
if (marked) return marked;
|
|
22692
|
-
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
22693
22510
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
22694
22511
|
if (!root) return null;
|
|
22695
22512
|
const anchor = el.closest("a");
|
|
@@ -24384,102 +24201,6 @@ function deleteSelectedNavFooterItem(deps) {
|
|
|
24384
24201
|
return false;
|
|
24385
24202
|
}
|
|
24386
24203
|
|
|
24387
|
-
// src/lib/nav-page-sync.ts
|
|
24388
|
-
function labelKeyFor(hrefKey) {
|
|
24389
|
-
return hrefKey.replace(/-href$/, "-label");
|
|
24390
|
-
}
|
|
24391
|
-
function isPageLinkKey(key) {
|
|
24392
|
-
return isNavbarHrefKey(key) || isFooterHrefKey(key);
|
|
24393
|
-
}
|
|
24394
|
-
function currentHref(key, anchor, content) {
|
|
24395
|
-
const stored = content[key];
|
|
24396
|
-
if (typeof stored === "string" && stored.length > 0) return stored;
|
|
24397
|
-
return anchor.getAttribute("href") ?? "";
|
|
24398
|
-
}
|
|
24399
|
-
function normalizePath2(value) {
|
|
24400
|
-
if (value.length > 1 && value.endsWith("/")) return value.slice(0, -1);
|
|
24401
|
-
return value;
|
|
24402
|
-
}
|
|
24403
|
-
function pointsAt(href, path) {
|
|
24404
|
-
const normalized = normalizePath2(href);
|
|
24405
|
-
const target = normalizePath2(path);
|
|
24406
|
-
if (normalized === target) return true;
|
|
24407
|
-
return (normalized.startsWith(`${target}#`) || normalized.startsWith(`${target}?`)) && target !== "/";
|
|
24408
|
-
}
|
|
24409
|
-
function retargetHref(href, oldPath, newPath) {
|
|
24410
|
-
const normalized = normalizePath2(href);
|
|
24411
|
-
const target = normalizePath2(oldPath);
|
|
24412
|
-
if (normalized === target) return newPath;
|
|
24413
|
-
return `${newPath}${normalized.slice(target.length)}`;
|
|
24414
|
-
}
|
|
24415
|
-
function setLabelText(key, text) {
|
|
24416
|
-
document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`).forEach((el) => {
|
|
24417
|
-
el.textContent = text;
|
|
24418
|
-
});
|
|
24419
|
-
}
|
|
24420
|
-
function commit(delta, deps) {
|
|
24421
|
-
if (Object.keys(delta).length === 0) return;
|
|
24422
|
-
deps.setEditContent({ ...deps.getEditContent(), ...delta });
|
|
24423
|
-
deps.postToParent({
|
|
24424
|
-
type: "ow:change",
|
|
24425
|
-
nodes: Object.entries(delta).map(([key, text]) => ({ key, text }))
|
|
24426
|
-
});
|
|
24427
|
-
}
|
|
24428
|
-
function navLinksTo(path, content) {
|
|
24429
|
-
return Array.from(document.querySelectorAll("[data-ohw-href-key]")).filter((anchor) => {
|
|
24430
|
-
const key = anchor.getAttribute("data-ohw-href-key");
|
|
24431
|
-
return isNavbarHrefKey(key) && pointsAt(currentHref(key, anchor, content), path);
|
|
24432
|
-
}).map((anchor) => anchor.getAttribute("data-ohw-href-key"));
|
|
24433
|
-
}
|
|
24434
|
-
function addNavLinkForPage(page, deps) {
|
|
24435
|
-
const content = deps.getEditContent();
|
|
24436
|
-
if (navLinksTo(page.path, content).length > 0) return false;
|
|
24437
|
-
const roots = listNavbarRootItems();
|
|
24438
|
-
const afterAnchor = roots[roots.length - 1] ?? null;
|
|
24439
|
-
let inserted;
|
|
24440
|
-
try {
|
|
24441
|
-
inserted = insertNavbarItem(page.path, page.title, afterAnchor);
|
|
24442
|
-
} catch {
|
|
24443
|
-
return false;
|
|
24444
|
-
}
|
|
24445
|
-
const { hrefKey, labelKey, index } = inserted;
|
|
24446
|
-
deps.applyLinkByKey(hrefKey, page.path);
|
|
24447
|
-
setLabelText(labelKey, page.title);
|
|
24448
|
-
commit(
|
|
24449
|
-
{
|
|
24450
|
-
[hrefKey]: page.path,
|
|
24451
|
-
[labelKey]: page.title,
|
|
24452
|
-
[NAV_COUNT_KEY]: String(index + 1),
|
|
24453
|
-
[NAV_ORDER_KEY]: getNavbarOrderJson()
|
|
24454
|
-
},
|
|
24455
|
-
deps
|
|
24456
|
-
);
|
|
24457
|
-
return true;
|
|
24458
|
-
}
|
|
24459
|
-
function retargetPageLinks(change, deps) {
|
|
24460
|
-
const { oldPath, newPath, oldTitle, newTitle } = change;
|
|
24461
|
-
if (!oldPath || !newPath || normalizePath2(oldPath) === normalizePath2(newPath)) return 0;
|
|
24462
|
-
const content = deps.getEditContent();
|
|
24463
|
-
const delta = {};
|
|
24464
|
-
for (const anchor of Array.from(document.querySelectorAll("[data-ohw-href-key]"))) {
|
|
24465
|
-
const hrefKey = anchor.getAttribute("data-ohw-href-key");
|
|
24466
|
-
if (!isPageLinkKey(hrefKey)) continue;
|
|
24467
|
-
const href = currentHref(hrefKey, anchor, content);
|
|
24468
|
-
if (!pointsAt(href, oldPath)) continue;
|
|
24469
|
-
const nextHref = retargetHref(href, oldPath, newPath);
|
|
24470
|
-
deps.applyLinkByKey(hrefKey, nextHref);
|
|
24471
|
-
delta[hrefKey] = nextHref;
|
|
24472
|
-
if (!oldTitle || !newTitle) continue;
|
|
24473
|
-
const labelKey = labelKeyFor(hrefKey);
|
|
24474
|
-
const label = content[labelKey] ?? anchor.querySelector('[data-ohw-editable="text"]')?.textContent ?? "";
|
|
24475
|
-
if (label.trim() !== oldTitle) continue;
|
|
24476
|
-
setLabelText(labelKey, newTitle);
|
|
24477
|
-
delta[labelKey] = newTitle;
|
|
24478
|
-
}
|
|
24479
|
-
commit(delta, deps);
|
|
24480
|
-
return Object.keys(delta).filter((key) => key.endsWith("-href")).length;
|
|
24481
|
-
}
|
|
24482
|
-
|
|
24483
24204
|
// src/ui/navbar-container-chrome.tsx
|
|
24484
24205
|
var import_lucide_react21 = require("lucide-react");
|
|
24485
24206
|
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
@@ -25367,7 +25088,7 @@ function getNavigationSelectionParent(el) {
|
|
|
25367
25088
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
25368
25089
|
return resolveFooterLinksContainerFrom(el);
|
|
25369
25090
|
}
|
|
25370
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") ||
|
|
25091
|
+
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
25371
25092
|
return getNavigationRoot(el);
|
|
25372
25093
|
}
|
|
25373
25094
|
return null;
|
|
@@ -25589,6 +25310,7 @@ var ICONS = {
|
|
|
25589
25310
|
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"/>',
|
|
25590
25311
|
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"/>'
|
|
25591
25312
|
};
|
|
25313
|
+
var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
|
|
25592
25314
|
var SELECTION_CHROME_GAP2 = 4;
|
|
25593
25315
|
var TOOLBAR_STROKE_GAP2 = 4;
|
|
25594
25316
|
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
@@ -25686,7 +25408,7 @@ function applyVisibleViewport(el, parentScroll) {
|
|
|
25686
25408
|
el.style.top = `${top}px`;
|
|
25687
25409
|
el.style.height = `${height}px`;
|
|
25688
25410
|
}
|
|
25689
|
-
var
|
|
25411
|
+
var TOOLBAR_EDGE_MARGIN3 = 4;
|
|
25690
25412
|
function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
25691
25413
|
const isAbove = transform.includes("translateY(-100%)");
|
|
25692
25414
|
let visualTop = isAbove ? top - approxH : top;
|
|
@@ -25713,8 +25435,8 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
|
25713
25435
|
function clampToolbarLeft(centerX, toolbarWidth) {
|
|
25714
25436
|
const half = toolbarWidth / 2;
|
|
25715
25437
|
return Math.max(
|
|
25716
|
-
|
|
25717
|
-
Math.min(centerX, window.innerWidth -
|
|
25438
|
+
TOOLBAR_EDGE_MARGIN3 + half,
|
|
25439
|
+
Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN3 - half)
|
|
25718
25440
|
);
|
|
25719
25441
|
}
|
|
25720
25442
|
function calcToolbarPos(rect, parentScroll, toolbarW = 306) {
|
|
@@ -26596,6 +26318,21 @@ function OhhwellsBridge() {
|
|
|
26596
26318
|
const [isItemDragging, setIsItemDragging] = (0, import_react23.useState)(false);
|
|
26597
26319
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react23.useState)(false);
|
|
26598
26320
|
isFooterFrameSelectionRef.current = isFooterFrameSelection;
|
|
26321
|
+
const [floatingPanel, setFloatingPanel] = (0, import_react23.useState)(null);
|
|
26322
|
+
const floatingPanelOpenRef = (0, import_react23.useRef)(false);
|
|
26323
|
+
floatingPanelOpenRef.current = floatingPanel !== null;
|
|
26324
|
+
const floatingPanelRef = (0, import_react23.useRef)(null);
|
|
26325
|
+
floatingPanelRef.current = floatingPanel;
|
|
26326
|
+
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react23.useState)(null);
|
|
26327
|
+
const buttonCollectionDragRef = (0, import_react23.useRef)(null);
|
|
26328
|
+
const buttonDropInsertIndexRef = (0, import_react23.useRef)(null);
|
|
26329
|
+
const [buttonDropSlots, setButtonDropSlots] = (0, import_react23.useState)([]);
|
|
26330
|
+
const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react23.useState)(null);
|
|
26331
|
+
const buttonPointerDragRef = (0, import_react23.useRef)(null);
|
|
26332
|
+
const [buttonStyleTick, setButtonStyleTick] = (0, import_react23.useState)(0);
|
|
26333
|
+
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react23.useState)(null);
|
|
26334
|
+
const [editorViewport, setEditorViewport] = (0, import_react23.useState)("desktop");
|
|
26335
|
+
const [parentScrollSnap, setParentScrollSnap] = (0, import_react23.useState)(null);
|
|
26599
26336
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react23.useState)(null);
|
|
26600
26337
|
const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react23.useState)(null);
|
|
26601
26338
|
const footerDragRef = (0, import_react23.useRef)(null);
|
|
@@ -26621,21 +26358,6 @@ function OhhwellsBridge() {
|
|
|
26621
26358
|
const stylesRef = (0, import_react23.useRef)("");
|
|
26622
26359
|
const appliedDrawerRef = (0, import_react23.useRef)(null);
|
|
26623
26360
|
const pendingDeleteUndoRef = (0, import_react23.useRef)(null);
|
|
26624
|
-
const [floatingPanel, setFloatingPanel] = (0, import_react23.useState)(null);
|
|
26625
|
-
const floatingPanelOpenRef = (0, import_react23.useRef)(false);
|
|
26626
|
-
const floatingPanelRef = (0, import_react23.useRef)(null);
|
|
26627
|
-
floatingPanelRef.current = floatingPanel;
|
|
26628
|
-
const setFloatingPanelRef = (0, import_react23.useRef)(setFloatingPanel);
|
|
26629
|
-
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react23.useState)(null);
|
|
26630
|
-
const buttonCollectionDragRef = (0, import_react23.useRef)(null);
|
|
26631
|
-
const buttonDropInsertIndexRef = (0, import_react23.useRef)(null);
|
|
26632
|
-
const [buttonDropSlots, setButtonDropSlots] = (0, import_react23.useState)([]);
|
|
26633
|
-
const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react23.useState)(null);
|
|
26634
|
-
const buttonPointerDragRef = (0, import_react23.useRef)(null);
|
|
26635
|
-
const [buttonStyleTick, setButtonStyleTick] = (0, import_react23.useState)(0);
|
|
26636
|
-
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react23.useState)(null);
|
|
26637
|
-
const [editorViewport, setEditorViewport] = (0, import_react23.useState)("desktop");
|
|
26638
|
-
const [parentScrollSnap, setParentScrollSnap] = (0, import_react23.useState)(null);
|
|
26639
26361
|
const [sitePages, setSitePages] = (0, import_react23.useState)([]);
|
|
26640
26362
|
const collectionItemsRef = (0, import_react23.useRef)(/* @__PURE__ */ new Map());
|
|
26641
26363
|
const [sectionsByPath, setSectionsByPath] = (0, import_react23.useState)({});
|
|
@@ -26645,18 +26367,7 @@ function OhhwellsBridge() {
|
|
|
26645
26367
|
const linkPopoverOpenRef = (0, import_react23.useRef)(false);
|
|
26646
26368
|
const linkPopoverGraceUntilRef = (0, import_react23.useRef)(0);
|
|
26647
26369
|
setLinkPopoverRef.current = setLinkPopover;
|
|
26648
|
-
setFloatingPanelRef.current = setFloatingPanel;
|
|
26649
26370
|
linkPopoverSessionRef.current = linkPopover;
|
|
26650
|
-
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
26651
|
-
(0, import_react23.useEffect)(() => {
|
|
26652
|
-
const syncViewport = () => {
|
|
26653
|
-
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
26654
|
-
setEditorViewport((prev) => prev === next ? prev : next);
|
|
26655
|
-
};
|
|
26656
|
-
syncViewport();
|
|
26657
|
-
window.addEventListener("resize", syncViewport);
|
|
26658
|
-
return () => window.removeEventListener("resize", syncViewport);
|
|
26659
|
-
}, []);
|
|
26660
26371
|
(0, import_react23.useEffect)(() => {
|
|
26661
26372
|
setSectionOrderPersistHandler((entries) => {
|
|
26662
26373
|
const currentPath = window.location.pathname;
|
|
@@ -26805,43 +26516,6 @@ function OhhwellsBridge() {
|
|
|
26805
26516
|
if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
|
|
26806
26517
|
return () => window.removeEventListener("message", onSitePages);
|
|
26807
26518
|
}, [isEditMode, postToParent2]);
|
|
26808
|
-
(0, import_react23.useEffect)(() => {
|
|
26809
|
-
if (!isEditMode) return;
|
|
26810
|
-
const deps = {
|
|
26811
|
-
getEditContent: () => editContentRef.current,
|
|
26812
|
-
setEditContent: (next) => {
|
|
26813
|
-
editContentRef.current = next;
|
|
26814
|
-
},
|
|
26815
|
-
applyLinkByKey,
|
|
26816
|
-
postToParent: postToParent2
|
|
26817
|
-
};
|
|
26818
|
-
const onPageMessage = (e) => {
|
|
26819
|
-
if (e.data?.type === "ow:page-created") {
|
|
26820
|
-
const { path, title } = e.data;
|
|
26821
|
-
if (typeof path !== "string" || !path) return;
|
|
26822
|
-
if (addNavLinkForPage({ path, title: typeof title === "string" && title ? title : path }, deps)) {
|
|
26823
|
-
enforceLinkHrefs();
|
|
26824
|
-
}
|
|
26825
|
-
return;
|
|
26826
|
-
}
|
|
26827
|
-
if (e.data?.type === "ow:page-renamed") {
|
|
26828
|
-
const { oldPath, newPath, oldTitle, newTitle } = e.data;
|
|
26829
|
-
if (typeof oldPath !== "string" || typeof newPath !== "string") return;
|
|
26830
|
-
const moved = retargetPageLinks(
|
|
26831
|
-
{
|
|
26832
|
-
oldPath,
|
|
26833
|
-
newPath,
|
|
26834
|
-
oldTitle: typeof oldTitle === "string" ? oldTitle : void 0,
|
|
26835
|
-
newTitle: typeof newTitle === "string" ? newTitle : void 0
|
|
26836
|
-
},
|
|
26837
|
-
deps
|
|
26838
|
-
);
|
|
26839
|
-
if (moved > 0) enforceLinkHrefs();
|
|
26840
|
-
}
|
|
26841
|
-
};
|
|
26842
|
-
window.addEventListener("message", onPageMessage);
|
|
26843
|
-
return () => window.removeEventListener("message", onPageMessage);
|
|
26844
|
-
}, [isEditMode, postToParent2]);
|
|
26845
26519
|
(0, import_react23.useEffect)(() => {
|
|
26846
26520
|
if (!isEditMode || shouldUseDevFixtures()) return;
|
|
26847
26521
|
void loadAllSectionsManifest().then((manifest) => {
|
|
@@ -28390,7 +28064,6 @@ function OhhwellsBridge() {
|
|
|
28390
28064
|
applyAiFooterFromContent(content);
|
|
28391
28065
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
28392
28066
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
28393
|
-
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
28394
28067
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
28395
28068
|
}
|
|
28396
28069
|
applyBrandChrome(content);
|
|
@@ -28401,16 +28074,15 @@ function OhhwellsBridge() {
|
|
|
28401
28074
|
if (key === "__ohw_sections") continue;
|
|
28402
28075
|
if (key === AI_SECTIONS_KEY) continue;
|
|
28403
28076
|
if (key === AI_FOOTER_KEY) continue;
|
|
28404
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
28405
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
28406
28077
|
if (key === BRAND_KIT_KEY) continue;
|
|
28407
28078
|
if (key === STYLE_STORE_KEY) continue;
|
|
28408
28079
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
28080
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
28409
28081
|
if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
|
|
28082
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
28410
28083
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
28411
28084
|
continue;
|
|
28412
28085
|
}
|
|
28413
|
-
if (key.endsWith(SECTION_EMBED_SUFFIX)) continue;
|
|
28414
28086
|
if (applyVideoSettingNode(key, val)) continue;
|
|
28415
28087
|
if (applyCarouselNode(key, val)) continue;
|
|
28416
28088
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -28450,7 +28122,6 @@ function OhhwellsBridge() {
|
|
|
28450
28122
|
});
|
|
28451
28123
|
applyLinkByKey(key, val);
|
|
28452
28124
|
}
|
|
28453
|
-
applySectionEmbeds(content);
|
|
28454
28125
|
applyLogoFromContent(content);
|
|
28455
28126
|
applyLogoSizes(content);
|
|
28456
28127
|
reconcileNavbarItemsFromContent(content);
|
|
@@ -28639,22 +28310,20 @@ function OhhwellsBridge() {
|
|
|
28639
28310
|
}
|
|
28640
28311
|
applyAiFooterFromContent(content);
|
|
28641
28312
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
28642
|
-
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
28643
28313
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
28644
28314
|
}
|
|
28645
28315
|
for (const [key, val] of Object.entries(content)) {
|
|
28646
28316
|
if (key === "__ohw_sections") continue;
|
|
28647
28317
|
if (key === AI_SECTIONS_KEY) continue;
|
|
28648
28318
|
if (key === AI_FOOTER_KEY) continue;
|
|
28649
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
28650
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
28651
28319
|
if (key === BRAND_KIT_KEY) continue;
|
|
28652
28320
|
if (key === STYLE_STORE_KEY) continue;
|
|
28653
28321
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
28322
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
28323
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
28654
28324
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
28655
28325
|
continue;
|
|
28656
28326
|
}
|
|
28657
|
-
if (key.endsWith(SECTION_EMBED_SUFFIX)) continue;
|
|
28658
28327
|
if (applyVideoSettingNode(key, val)) continue;
|
|
28659
28328
|
if (applyCarouselNode(key, val)) continue;
|
|
28660
28329
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -28679,7 +28348,6 @@ function OhhwellsBridge() {
|
|
|
28679
28348
|
});
|
|
28680
28349
|
applyLinkByKey(key, val);
|
|
28681
28350
|
}
|
|
28682
|
-
applySectionEmbeds(content);
|
|
28683
28351
|
applyLogoFromContent(content);
|
|
28684
28352
|
reconcileNavbarItemsFromContent(content);
|
|
28685
28353
|
reconcileFooterOrderFromContent(content);
|
|
@@ -28919,11 +28587,26 @@ function OhhwellsBridge() {
|
|
|
28919
28587
|
const t2 = setTimeout(measure, 500);
|
|
28920
28588
|
const ro = new ResizeObserver(schedule);
|
|
28921
28589
|
ro.observe(document.body);
|
|
28590
|
+
let lastWidth = window.innerWidth;
|
|
28591
|
+
let resizeTimers = [];
|
|
28592
|
+
const clearResizeTimers = () => {
|
|
28593
|
+
resizeTimers.forEach(clearTimeout);
|
|
28594
|
+
resizeTimers = [];
|
|
28595
|
+
};
|
|
28596
|
+
const handleResize = () => {
|
|
28597
|
+
if (window.innerWidth === lastWidth) return;
|
|
28598
|
+
lastWidth = window.innerWidth;
|
|
28599
|
+
clearResizeTimers();
|
|
28600
|
+
resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
|
|
28601
|
+
};
|
|
28602
|
+
window.addEventListener("resize", handleResize);
|
|
28922
28603
|
return () => {
|
|
28923
28604
|
clearTimeout(t1);
|
|
28924
28605
|
clearTimeout(t2);
|
|
28925
28606
|
if (raf != null) cancelAnimationFrame(raf);
|
|
28926
28607
|
ro.disconnect();
|
|
28608
|
+
clearResizeTimers();
|
|
28609
|
+
window.removeEventListener("resize", handleResize);
|
|
28927
28610
|
};
|
|
28928
28611
|
}, [pathname, isEditMode, postToParent2]);
|
|
28929
28612
|
(0, import_react23.useEffect)(() => {
|
|
@@ -29220,13 +28903,6 @@ function OhhwellsBridge() {
|
|
|
29220
28903
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
29221
28904
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
29222
28905
|
if (isInsideLinkEditor(target)) return;
|
|
29223
|
-
if (isInsideFloatingPanel(target)) return;
|
|
29224
|
-
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
29225
|
-
if (target.closest(
|
|
29226
|
-
'[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
|
|
29227
|
-
)) {
|
|
29228
|
-
return;
|
|
29229
|
-
}
|
|
29230
28906
|
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
29231
28907
|
clearMediaSelectionRef.current();
|
|
29232
28908
|
}
|
|
@@ -29250,6 +28926,8 @@ function OhhwellsBridge() {
|
|
|
29250
28926
|
return;
|
|
29251
28927
|
}
|
|
29252
28928
|
}
|
|
28929
|
+
if (isInsideFloatingPanel(target)) return;
|
|
28930
|
+
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
29253
28931
|
const collectionItem = matchCollectionItemClick(target, collectionItemsRef.current);
|
|
29254
28932
|
if (collectionItem) {
|
|
29255
28933
|
e.preventDefault();
|
|
@@ -29261,6 +28939,11 @@ function OhhwellsBridge() {
|
|
|
29261
28939
|
});
|
|
29262
28940
|
return;
|
|
29263
28941
|
}
|
|
28942
|
+
if (target.closest(
|
|
28943
|
+
'[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
|
|
28944
|
+
)) {
|
|
28945
|
+
return;
|
|
28946
|
+
}
|
|
29264
28947
|
{
|
|
29265
28948
|
const formEl = getFormElement(target);
|
|
29266
28949
|
const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
|
|
@@ -29414,13 +29097,9 @@ function OhhwellsBridge() {
|
|
|
29414
29097
|
if (isIconEditable(editable) && !getSocialItem(editable)) {
|
|
29415
29098
|
e.preventDefault();
|
|
29416
29099
|
e.stopPropagation();
|
|
29100
|
+
selectIconElementRef.current(editable);
|
|
29417
29101
|
const aiIcon = editable.hasAttribute("data-ai-icon");
|
|
29418
29102
|
const featureIcon = aiIcon && /\.features\.\d+\.icon$/.test(editable.dataset.ohwKey ?? "");
|
|
29419
|
-
if (aiIcon) {
|
|
29420
|
-
aiSectionApiRef.current?.selectFromElement(editable);
|
|
29421
|
-
} else {
|
|
29422
|
-
selectIconElementRef.current(editable);
|
|
29423
|
-
}
|
|
29424
29103
|
postToParentRef.current({
|
|
29425
29104
|
type: "ow:icon-pick",
|
|
29426
29105
|
key: editable.dataset.ohwKey ?? "",
|
|
@@ -29648,9 +29327,6 @@ function OhhwellsBridge() {
|
|
|
29648
29327
|
setHoveredItemRect(null);
|
|
29649
29328
|
hoveredNavContainerRef.current = null;
|
|
29650
29329
|
setHoveredNavContainerRect(null);
|
|
29651
|
-
siblingHintElRef.current = null;
|
|
29652
|
-
setSiblingHintRect(null);
|
|
29653
|
-
setSiblingHintRects([]);
|
|
29654
29330
|
return;
|
|
29655
29331
|
}
|
|
29656
29332
|
{
|
|
@@ -29771,6 +29447,7 @@ function OhhwellsBridge() {
|
|
|
29771
29447
|
hoveredNavContainerRef.current = null;
|
|
29772
29448
|
setHoveredNavContainerRect(null);
|
|
29773
29449
|
hoveredItemElRef.current = editable;
|
|
29450
|
+
setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
|
|
29774
29451
|
}
|
|
29775
29452
|
}
|
|
29776
29453
|
}
|
|
@@ -30480,11 +30157,7 @@ function OhhwellsBridge() {
|
|
|
30480
30157
|
};
|
|
30481
30158
|
const handleMouseMove = (e) => {
|
|
30482
30159
|
const { clientX, clientY } = e;
|
|
30483
|
-
if (pointOwnedByFloatingPanel(clientX, clientY))
|
|
30484
|
-
dismissImageHover();
|
|
30485
|
-
clearImageHover();
|
|
30486
|
-
return;
|
|
30487
|
-
}
|
|
30160
|
+
if (pointOwnedByFloatingPanel(clientX, clientY)) return;
|
|
30488
30161
|
if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
|
|
30489
30162
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
30490
30163
|
formHoverElRef.current = null;
|
|
@@ -30513,12 +30186,7 @@ function OhhwellsBridge() {
|
|
|
30513
30186
|
setHoveredItemRect(null);
|
|
30514
30187
|
hoveredNavContainerRef.current = null;
|
|
30515
30188
|
setHoveredNavContainerRect(null);
|
|
30516
|
-
siblingHintElRef.current = null;
|
|
30517
|
-
setSiblingHintRect(null);
|
|
30518
|
-
setSiblingHintRects([]);
|
|
30519
30189
|
dismissImageHover();
|
|
30520
|
-
clearImageHover();
|
|
30521
|
-
setSectionGap(null);
|
|
30522
30190
|
return;
|
|
30523
30191
|
}
|
|
30524
30192
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
@@ -30530,11 +30198,7 @@ function OhhwellsBridge() {
|
|
|
30530
30198
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
30531
30199
|
const { clientX, clientY } = e.data;
|
|
30532
30200
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
30533
|
-
if (pointOwnedByFloatingPanel(clientX, clientY))
|
|
30534
|
-
dismissImageHover();
|
|
30535
|
-
clearImageHover();
|
|
30536
|
-
return;
|
|
30537
|
-
}
|
|
30201
|
+
if (pointOwnedByFloatingPanel(clientX, clientY)) return;
|
|
30538
30202
|
if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
|
|
30539
30203
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
30540
30204
|
probeSectionGapAt(clientX, clientY);
|
|
@@ -30914,7 +30578,6 @@ function OhhwellsBridge() {
|
|
|
30914
30578
|
applyAiFooterFromContent(content);
|
|
30915
30579
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
30916
30580
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
30917
|
-
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
30918
30581
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
30919
30582
|
}
|
|
30920
30583
|
applyBrandChrome(content);
|
|
@@ -30929,16 +30592,15 @@ function OhhwellsBridge() {
|
|
|
30929
30592
|
}
|
|
30930
30593
|
if (key === AI_SECTIONS_KEY) continue;
|
|
30931
30594
|
if (key === AI_FOOTER_KEY) continue;
|
|
30932
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
30933
|
-
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
30934
30595
|
if (key === BRAND_KIT_KEY) continue;
|
|
30935
30596
|
if (key === STYLE_STORE_KEY) continue;
|
|
30936
30597
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
30598
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
30937
30599
|
if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
|
|
30600
|
+
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
30938
30601
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
30939
30602
|
continue;
|
|
30940
30603
|
}
|
|
30941
|
-
if (key.endsWith(SECTION_EMBED_SUFFIX)) continue;
|
|
30942
30604
|
if (applyVideoSettingNode(key, val)) continue;
|
|
30943
30605
|
if (applyCarouselNode(key, val)) continue;
|
|
30944
30606
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -30964,7 +30626,6 @@ function OhhwellsBridge() {
|
|
|
30964
30626
|
});
|
|
30965
30627
|
applyLinkByKey(key, val);
|
|
30966
30628
|
}
|
|
30967
|
-
applySectionEmbeds(content);
|
|
30968
30629
|
applyLogoFromContent(content);
|
|
30969
30630
|
applyLogoSizes(content);
|
|
30970
30631
|
document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
|
|
@@ -31572,12 +31233,6 @@ function OhhwellsBridge() {
|
|
|
31572
31233
|
closeLinkPopoverRef.current();
|
|
31573
31234
|
return;
|
|
31574
31235
|
}
|
|
31575
|
-
if (floatingPanelOpenRef.current) {
|
|
31576
|
-
setFloatingPanelRef.current(null);
|
|
31577
|
-
deselectRef.current();
|
|
31578
|
-
deactivateRef.current();
|
|
31579
|
-
return;
|
|
31580
|
-
}
|
|
31581
31236
|
deselectRef.current();
|
|
31582
31237
|
deactivateRef.current();
|
|
31583
31238
|
clearMediaSelectionRef.current();
|
|
@@ -32413,10 +32068,10 @@ function OhhwellsBridge() {
|
|
|
32413
32068
|
window.removeEventListener("message", handleDuplicateSection);
|
|
32414
32069
|
window.removeEventListener("message", handleDeactivate);
|
|
32415
32070
|
window.removeEventListener("message", handleSelectNav);
|
|
32071
|
+
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
32416
32072
|
window.removeEventListener("message", handleToastAction);
|
|
32417
32073
|
window.removeEventListener("message", handleFormCount);
|
|
32418
32074
|
window.removeEventListener("message", handleUiEscape);
|
|
32419
|
-
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
32420
32075
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
32421
32076
|
autoSaveTimers.current.clear();
|
|
32422
32077
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
@@ -32710,7 +32365,7 @@ function OhhwellsBridge() {
|
|
|
32710
32365
|
postToParent2({
|
|
32711
32366
|
type: "ow:ready",
|
|
32712
32367
|
version: "1",
|
|
32713
|
-
bridgeVersion: "0.1.
|
|
32368
|
+
bridgeVersion: "0.1.161",
|
|
32714
32369
|
path: pathname,
|
|
32715
32370
|
nodes: collectEditableNodes(editContentRef.current),
|
|
32716
32371
|
sections
|