@ohhwells/bridge 0.1.159 → 0.1.160-next.428
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 +1116 -754
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1157 -779
- package/dist/index.js.map +1 -1
- package/dist/pages.cjs +9 -1
- package/dist/pages.cjs.map +1 -1
- package/dist/pages.d.cts +2 -0
- package/dist/pages.d.ts +2 -0
- package/dist/pages.js +9 -1
- package/dist/pages.js.map +1 -1
- package/dist/styles.css +116 -0
- 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 paint2 = parseColor(paintColor(seed)) ?? { r: 15, g: 15, b: 15, a: 1 };
|
|
1212
|
+
const luminance = relativeLuminance(paint2);
|
|
1213
1213
|
return {
|
|
1214
|
-
background: toCss({ ...
|
|
1214
|
+
background: toCss({ ...paint2, 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 paint2 = accentColor(primary);
|
|
1222
1222
|
return {
|
|
1223
1223
|
background: TRANSPARENT,
|
|
1224
|
-
color:
|
|
1225
|
-
borderColor:
|
|
1224
|
+
color: paint2,
|
|
1225
|
+
borderColor: paint2,
|
|
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 paint2 = accentColor(primary);
|
|
1239
1239
|
const text = parseColor(outline.color);
|
|
1240
|
-
const paintRgb = parseColor(
|
|
1240
|
+
const paintRgb = parseColor(paint2);
|
|
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: paint2,
|
|
1250
|
+
borderColor: hasBorder ? paint2 : outline.borderColor
|
|
1251
1251
|
};
|
|
1252
1252
|
}
|
|
1253
1253
|
function generateButtonVariants(samples) {
|
|
@@ -6763,6 +6763,21 @@ 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
|
+
}
|
|
6766
6781
|
function addPricingCardFeature(tree, index, text) {
|
|
6767
6782
|
return withPricingCollection(tree, (collection) => {
|
|
6768
6783
|
const children = collection.children;
|
|
@@ -6771,7 +6786,7 @@ function addPricingCardFeature(tree, index, text) {
|
|
|
6771
6786
|
const features = pricingFeatureList(target);
|
|
6772
6787
|
if (features.length >= PRICING_FEATURES_MAX) return false;
|
|
6773
6788
|
target.slots = target.slots ?? {};
|
|
6774
|
-
target.slots.features = [...features, { text }];
|
|
6789
|
+
target.slots.features = [...features, { text, ...prevailingFeatureIcon(features) }];
|
|
6775
6790
|
return true;
|
|
6776
6791
|
});
|
|
6777
6792
|
}
|
|
@@ -7383,6 +7398,23 @@ function applyCustomCodeToHead(content) {
|
|
|
7383
7398
|
if (beforeNodes.length > 0) document.head.append(...beforeNodes);
|
|
7384
7399
|
}
|
|
7385
7400
|
|
|
7401
|
+
// src/lib/node-font-size.ts
|
|
7402
|
+
var TEXT_NODE_TYPES = /* @__PURE__ */ new Set(["text", "text/rich", "plain", "link"]);
|
|
7403
|
+
function escapeKey(key) {
|
|
7404
|
+
return typeof CSS !== "undefined" && typeof CSS.escape === "function" ? CSS.escape(key) : key.replace(/["\\]/g, "\\$&");
|
|
7405
|
+
}
|
|
7406
|
+
function measureNodeFontSize(key, type, root) {
|
|
7407
|
+
if (!TEXT_NODE_TYPES.has(type)) return void 0;
|
|
7408
|
+
const el = root.querySelector(`[data-ohw-editable][data-ohw-key="${escapeKey(key)}"]`);
|
|
7409
|
+
if (!el) return void 0;
|
|
7410
|
+
const size = Number.parseFloat(window.getComputedStyle(el).fontSize);
|
|
7411
|
+
return Number.isFinite(size) && size > 0 ? Math.round(size) : void 0;
|
|
7412
|
+
}
|
|
7413
|
+
function withNodeFontSize(node, root) {
|
|
7414
|
+
const fontSize = measureNodeFontSize(node.key, node.type, root);
|
|
7415
|
+
return fontSize === void 0 ? node : { ...node, fontSize };
|
|
7416
|
+
}
|
|
7417
|
+
|
|
7386
7418
|
// src/lib/selectNavContainer.ts
|
|
7387
7419
|
function isOnScreen(el) {
|
|
7388
7420
|
const rect = el.getBoundingClientRect();
|
|
@@ -7398,6 +7430,120 @@ function findSelectableNavContainer(doc = document) {
|
|
|
7398
7430
|
);
|
|
7399
7431
|
}
|
|
7400
7432
|
|
|
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
|
+
|
|
7401
7547
|
// src/ui/ai-tree/aiSectionsManager.tsx
|
|
7402
7548
|
var import_react_dom = require("react-dom");
|
|
7403
7549
|
var import_client = require("react-dom/client");
|
|
@@ -7971,7 +8117,7 @@ var AI_MOBILE_CSS = [
|
|
|
7971
8117
|
// page's first section. Top only (bottom needs no nav clearance); ~96px approximates the
|
|
7972
8118
|
// template nav's own height (measured ~94px) — there's no shared `--ohw-header-h` var to read
|
|
7973
8119
|
// an exact figure from (no live measurement exists), so this is a safe approximation, not a
|
|
7974
|
-
// pixel-exact fit. Horizontal spacing already comes from `data-ai-
|
|
8120
|
+
// pixel-exact fit. Horizontal spacing already comes from `data-ai-section-inner`.
|
|
7975
8121
|
'[data-ai-overlay-clearance] [data-ai-overlap-layer="overlay"]{padding-top:96px}',
|
|
7976
8122
|
// A full-bleed carousel's height is pure arithmetic: it spans the whole window, so 16/9 turns
|
|
7977
8123
|
// window width straight into height. Measured at 16/9 it came out ~90% of the viewport at EVERY
|
|
@@ -7987,8 +8133,10 @@ var AI_MOBILE_CSS = [
|
|
|
7987
8133
|
"[data-ai-section]{overflow-x:hidden}",
|
|
7988
8134
|
// `:not([data-ai-full-bleed])`: this `!important` gutter beat the inline `padding: 0` that a
|
|
7989
8135
|
// full-bleed section's container sets, so a carousel/media hero that is edge-to-edge on desktop
|
|
7990
|
-
// still got a 20px band of section background down both sides on a phone.
|
|
7991
|
-
|
|
8136
|
+
// still got a 20px band of section background down both sides on a phone. The footer's own
|
|
8137
|
+
// container keeps the unguarded rule below — `data-ai-full-bleed` can never appear on it.
|
|
8138
|
+
"[data-ai-section-inner]:not([data-ai-full-bleed]){padding:0 20px !important}",
|
|
8139
|
+
"[data-ai-container]{padding:0 20px !important}",
|
|
7992
8140
|
"[data-ai-row]{display:flex !important;flex-direction:column !important;align-items:stretch !important}",
|
|
7993
8141
|
"[data-ai-cell]{width:100%;min-width:0}",
|
|
7994
8142
|
// The rule above turns every row into a COLUMN flex container on phones, which silently breaks
|
|
@@ -8193,6 +8341,31 @@ function pricingCardEmphasis(featured, ctx, hasBg) {
|
|
|
8193
8341
|
function textAttrs(ctx, path) {
|
|
8194
8342
|
return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
|
|
8195
8343
|
}
|
|
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");
|
|
8196
8369
|
var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
8197
8370
|
function MediaBox({
|
|
8198
8371
|
refValue,
|
|
@@ -8247,7 +8420,7 @@ function MediaBox({
|
|
|
8247
8420
|
position: fill ? "absolute" : void 0,
|
|
8248
8421
|
inset: fill ? 0 : void 0,
|
|
8249
8422
|
width: fill ? "100%" : fixedSize ? "auto" : "100%",
|
|
8250
|
-
height: fill ? "100%" : void 0,
|
|
8423
|
+
height: fill ? "100%" : fixedSize ? height : void 0,
|
|
8251
8424
|
aspectRatio: fill ? void 0 : aspectRatio,
|
|
8252
8425
|
minHeight: fill || fixedSize ? void 0 : height ?? (aspectRatio ? void 0 : 180),
|
|
8253
8426
|
borderRadius: radius,
|
|
@@ -9743,7 +9916,7 @@ function CollectionBlock({ node, ctx, path }) {
|
|
|
9743
9916
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
9744
9917
|
"div",
|
|
9745
9918
|
{
|
|
9746
|
-
"data-ai-grid":
|
|
9919
|
+
"data-ai-grid": String(itemsPerRow),
|
|
9747
9920
|
"data-ohw-pricing-collection": isPricing ? "" : void 0,
|
|
9748
9921
|
style: {
|
|
9749
9922
|
display: "grid",
|
|
@@ -10045,7 +10218,7 @@ function renderNode(node, ctx, path, ambientAlign) {
|
|
|
10045
10218
|
},
|
|
10046
10219
|
children: [
|
|
10047
10220
|
i > 0 && ctx.heroOverlapFullBleed ? (
|
|
10048
|
-
// The section's `data-ai-
|
|
10221
|
+
// The section's `data-ai-section-inner` gave up its max-width/gutter so the base
|
|
10049
10222
|
// layer (this group's i===0 sibling) can span edge-to-edge — reintroduced here,
|
|
10050
10223
|
// scoped to just the overlay text, so a heading/copy/CTA stack doesn't stretch
|
|
10051
10224
|
// the full section width instead of reading at the usual content width.
|
|
@@ -10464,6 +10637,7 @@ function AiTreeRenderer({
|
|
|
10464
10637
|
...fillHeight ? { "data-ai-fill-height": "" } : {},
|
|
10465
10638
|
...needsOverlayClearance ? { "data-ai-overlay-clearance": "" } : {},
|
|
10466
10639
|
...bgAttrs,
|
|
10640
|
+
"data-ai-responsive": "",
|
|
10467
10641
|
style: {
|
|
10468
10642
|
position: "relative",
|
|
10469
10643
|
padding: `${padCss} 0`,
|
|
@@ -10477,12 +10651,13 @@ function AiTreeRenderer({
|
|
|
10477
10651
|
...fillHeight ? { display: "grid" } : {}
|
|
10478
10652
|
},
|
|
10479
10653
|
children: [
|
|
10480
|
-
|
|
10654
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
|
|
10481
10655
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
|
|
10656
|
+
isOverlay && backgroundUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
|
|
10482
10657
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
10483
10658
|
"div",
|
|
10484
10659
|
{
|
|
10485
|
-
"data-ai-
|
|
10660
|
+
"data-ai-section-inner": "",
|
|
10486
10661
|
...fullBleedMedia ? { "data-ai-full-bleed": "" } : {},
|
|
10487
10662
|
style: {
|
|
10488
10663
|
position: "relative",
|
|
@@ -10499,7 +10674,7 @@ function AiTreeRenderer({
|
|
|
10499
10674
|
children: tree.rows.map((row, r2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
10500
10675
|
"div",
|
|
10501
10676
|
{
|
|
10502
|
-
"data-ai-
|
|
10677
|
+
"data-ai-columns": "",
|
|
10503
10678
|
style: {
|
|
10504
10679
|
display: "grid",
|
|
10505
10680
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
@@ -11161,9 +11336,10 @@ function applyAiSectionsToDom(state, options) {
|
|
|
11161
11336
|
if (existing && existing.serialized === serialized && existing.container.isConnected) {
|
|
11162
11337
|
continue;
|
|
11163
11338
|
}
|
|
11164
|
-
const isNewMount = !existing || !existing.container.isConnected;
|
|
11165
11339
|
let container = existing?.container;
|
|
11340
|
+
let isNewMount = false;
|
|
11166
11341
|
if (!container || !container.isConnected) {
|
|
11342
|
+
isNewMount = true;
|
|
11167
11343
|
existing?.root.unmount();
|
|
11168
11344
|
container?.remove();
|
|
11169
11345
|
container = document.createElement("div");
|
|
@@ -11501,6 +11677,34 @@ function minSpanForFooterBlock(type) {
|
|
|
11501
11677
|
return 3;
|
|
11502
11678
|
}
|
|
11503
11679
|
}
|
|
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
|
+
}
|
|
11504
11708
|
function collectBrandBlocks(tree) {
|
|
11505
11709
|
const brand = [];
|
|
11506
11710
|
for (const col of tree.columns) {
|
|
@@ -11746,6 +11950,7 @@ function textOf2(el) {
|
|
|
11746
11950
|
}
|
|
11747
11951
|
function syncFooterTreeLinksFromDom(tree) {
|
|
11748
11952
|
const next = cloneTree(tree);
|
|
11953
|
+
syncSocialRowsFromDom(next);
|
|
11749
11954
|
const domCols = listFooterColumns().map((col) => {
|
|
11750
11955
|
const heading = getFooterColumnHeadingEl(col);
|
|
11751
11956
|
const title = heading ? textOf2(heading) : void 0;
|
|
@@ -17322,7 +17527,7 @@ function apiBase() {
|
|
|
17322
17527
|
function bridgeVersion() {
|
|
17323
17528
|
try {
|
|
17324
17529
|
if (true) {
|
|
17325
|
-
return "0.1.
|
|
17530
|
+
return "0.1.160-next.428";
|
|
17326
17531
|
}
|
|
17327
17532
|
} catch {
|
|
17328
17533
|
}
|
|
@@ -17336,7 +17541,7 @@ function stampBridgeVersionOnDocument() {
|
|
|
17336
17541
|
return;
|
|
17337
17542
|
}
|
|
17338
17543
|
try {
|
|
17339
|
-
const v = true ? "0.1.
|
|
17544
|
+
const v = true ? "0.1.160-next.428" : "";
|
|
17340
17545
|
if (v) {
|
|
17341
17546
|
document.documentElement.setAttribute("data-ohw-bridge-version", v);
|
|
17342
17547
|
window.__OHW_BRIDGE_VERSION__ = v;
|
|
@@ -18014,6 +18219,7 @@ function MediaOverlay({
|
|
|
18014
18219
|
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
18015
18220
|
);
|
|
18016
18221
|
}, [isVideo]);
|
|
18222
|
+
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
18017
18223
|
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
18018
18224
|
const box = {
|
|
18019
18225
|
position: "fixed",
|
|
@@ -18112,11 +18318,10 @@ function MediaOverlay({
|
|
|
18112
18318
|
className: "flex items-center justify-center cursor-pointer",
|
|
18113
18319
|
style: {
|
|
18114
18320
|
...box,
|
|
18115
|
-
//
|
|
18116
|
-
//
|
|
18117
|
-
//
|
|
18118
|
-
|
|
18119
|
-
pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
|
|
18321
|
+
// Visual only. `pointer-events: auto` on this full-bleed rect covered the navbar
|
|
18322
|
+
// (hero bg includes the absolute TopNav) and swallowed CTA press-drag. Text overlay
|
|
18323
|
+
// and cueOnly also need clicks to fall through — Replace / video controls opt back in.
|
|
18324
|
+
pointerEvents: "none",
|
|
18120
18325
|
// Selected: a firm component ring with no wash, so the image reads as chosen rather
|
|
18121
18326
|
// than hovered. Hover keeps the existing tinted preview.
|
|
18122
18327
|
boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
@@ -18143,17 +18348,17 @@ function MediaOverlay({
|
|
|
18143
18348
|
},
|
|
18144
18349
|
children: [
|
|
18145
18350
|
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 }),
|
|
18146
|
-
|
|
18351
|
+
replaceLabel
|
|
18147
18352
|
]
|
|
18148
18353
|
}
|
|
18149
18354
|
),
|
|
18150
|
-
replaceMode
|
|
18355
|
+
showChrome && replaceMode !== "none" && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
18151
18356
|
Button,
|
|
18152
18357
|
{
|
|
18153
18358
|
"data-ohw-media-overlay": "",
|
|
18154
18359
|
variant: "outline",
|
|
18155
18360
|
size: "sm",
|
|
18156
|
-
"aria-label":
|
|
18361
|
+
"aria-label": replaceLabel,
|
|
18157
18362
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
18158
18363
|
style: {
|
|
18159
18364
|
...OVERLAY_BUTTON_STYLE,
|
|
@@ -18176,7 +18381,7 @@ function MediaOverlay({
|
|
|
18176
18381
|
},
|
|
18177
18382
|
children: [
|
|
18178
18383
|
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 }),
|
|
18179
|
-
replaceMode === "full" ?
|
|
18384
|
+
replaceMode === "full" ? replaceLabel : null
|
|
18180
18385
|
]
|
|
18181
18386
|
}
|
|
18182
18387
|
)
|
|
@@ -18770,7 +18975,7 @@ function AiSectionOverlay({
|
|
|
18770
18975
|
|
|
18771
18976
|
// src/ui/ai-section/AiMediaStripOverlay.tsx
|
|
18772
18977
|
var import_react10 = require("react");
|
|
18773
|
-
var
|
|
18978
|
+
var import_lucide_react9 = require("lucide-react");
|
|
18774
18979
|
|
|
18775
18980
|
// src/lib/ai-media-strip-tree.ts
|
|
18776
18981
|
var MEDIA_STRIP_ITEM_MIN = 1;
|
|
@@ -18884,14 +19089,6 @@ function setMediaStripItemAsset(tree, index, assetId) {
|
|
|
18884
19089
|
return true;
|
|
18885
19090
|
});
|
|
18886
19091
|
}
|
|
18887
|
-
function setMediaStripItemAlt(tree, index, alt) {
|
|
18888
|
-
return withMediaStrip(tree, (block) => {
|
|
18889
|
-
const items = block.items;
|
|
18890
|
-
if (index < 0 || index >= items.length) return false;
|
|
18891
|
-
items[index] = { ...items[index], alt };
|
|
18892
|
-
return true;
|
|
18893
|
-
});
|
|
18894
|
-
}
|
|
18895
19092
|
function setMediaStripItemLink(tree, index, link) {
|
|
18896
19093
|
return withMediaStrip(tree, (block) => {
|
|
18897
19094
|
const items = block.items;
|
|
@@ -18909,11 +19106,117 @@ function setMediaStripItemLink(tree, index, link) {
|
|
|
18909
19106
|
});
|
|
18910
19107
|
}
|
|
18911
19108
|
|
|
18912
|
-
// src/ui/
|
|
19109
|
+
// src/ui/dialog.tsx
|
|
19110
|
+
var React9 = __toESM(require("react"), 1);
|
|
19111
|
+
var import_radix_ui6 = require("radix-ui");
|
|
19112
|
+
var import_lucide_react8 = require("lucide-react");
|
|
18913
19113
|
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
18914
|
-
|
|
18915
|
-
|
|
18916
|
-
|
|
19114
|
+
function Dialog2({
|
|
19115
|
+
...props
|
|
19116
|
+
}) {
|
|
19117
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_radix_ui6.Dialog.Root, { "data-slot": "dialog", ...props });
|
|
19118
|
+
}
|
|
19119
|
+
function DialogPortal({
|
|
19120
|
+
...props
|
|
19121
|
+
}) {
|
|
19122
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_radix_ui6.Dialog.Portal, { ...props });
|
|
19123
|
+
}
|
|
19124
|
+
function DialogOverlay({
|
|
19125
|
+
className,
|
|
19126
|
+
...props
|
|
19127
|
+
}) {
|
|
19128
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19129
|
+
import_radix_ui6.Dialog.Overlay,
|
|
19130
|
+
{
|
|
19131
|
+
"data-slot": "dialog-overlay",
|
|
19132
|
+
"data-ohw-link-modal-root": "",
|
|
19133
|
+
className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
|
|
19134
|
+
...props
|
|
19135
|
+
}
|
|
19136
|
+
);
|
|
19137
|
+
}
|
|
19138
|
+
var DialogContent = React9.forwardRef(
|
|
19139
|
+
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
19140
|
+
const positionMode = container ? "absolute" : "fixed";
|
|
19141
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(DialogPortal, { container: container ?? void 0, children: [
|
|
19142
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
19143
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
19144
|
+
import_radix_ui6.Dialog.Content,
|
|
19145
|
+
{
|
|
19146
|
+
ref,
|
|
19147
|
+
"data-slot": "dialog-content",
|
|
19148
|
+
className: cn(
|
|
19149
|
+
positionMode,
|
|
19150
|
+
"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",
|
|
19151
|
+
"rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
|
|
19152
|
+
container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
|
|
19153
|
+
className
|
|
19154
|
+
),
|
|
19155
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
19156
|
+
...props,
|
|
19157
|
+
children: [
|
|
19158
|
+
children,
|
|
19159
|
+
showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19160
|
+
import_radix_ui6.Dialog.Close,
|
|
19161
|
+
{
|
|
19162
|
+
type: "button",
|
|
19163
|
+
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
19164
|
+
"aria-label": "Close",
|
|
19165
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react8.X, { size: 16, "aria-hidden": true })
|
|
19166
|
+
}
|
|
19167
|
+
) : null
|
|
19168
|
+
]
|
|
19169
|
+
}
|
|
19170
|
+
)
|
|
19171
|
+
] });
|
|
19172
|
+
}
|
|
19173
|
+
);
|
|
19174
|
+
DialogContent.displayName = import_radix_ui6.Dialog.Content.displayName;
|
|
19175
|
+
function DialogHeader({
|
|
19176
|
+
className,
|
|
19177
|
+
...props
|
|
19178
|
+
}) {
|
|
19179
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
19180
|
+
}
|
|
19181
|
+
function DialogFooter({
|
|
19182
|
+
className,
|
|
19183
|
+
...props
|
|
19184
|
+
}) {
|
|
19185
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19186
|
+
"div",
|
|
19187
|
+
{
|
|
19188
|
+
className: cn("flex items-center justify-end gap-2", className),
|
|
19189
|
+
...props
|
|
19190
|
+
}
|
|
19191
|
+
);
|
|
19192
|
+
}
|
|
19193
|
+
var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19194
|
+
import_radix_ui6.Dialog.Title,
|
|
19195
|
+
{
|
|
19196
|
+
ref,
|
|
19197
|
+
className: cn(
|
|
19198
|
+
"text-lg font-semibold leading-none tracking-tight text-card-foreground",
|
|
19199
|
+
className
|
|
19200
|
+
),
|
|
19201
|
+
...props
|
|
19202
|
+
}
|
|
19203
|
+
));
|
|
19204
|
+
DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
|
|
19205
|
+
var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19206
|
+
import_radix_ui6.Dialog.Description,
|
|
19207
|
+
{
|
|
19208
|
+
ref,
|
|
19209
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
19210
|
+
...props
|
|
19211
|
+
}
|
|
19212
|
+
));
|
|
19213
|
+
DialogDescription.displayName = import_radix_ui6.Dialog.Description.displayName;
|
|
19214
|
+
var DialogClose = import_radix_ui6.Dialog.Close;
|
|
19215
|
+
|
|
19216
|
+
// src/ui/ai-section/AiMediaStripOverlay.tsx
|
|
19217
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
19218
|
+
var PRIMARY3 = "var(--ohw-primary, #0885FE)";
|
|
19219
|
+
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]";
|
|
18917
19220
|
function findMediaStripItemElement(sectionId, index) {
|
|
18918
19221
|
const sectionEl = findByInstanceId(sectionId);
|
|
18919
19222
|
if (!sectionEl) return null;
|
|
@@ -18923,14 +19226,35 @@ function findMediaStripItemElement(sectionId, index) {
|
|
|
18923
19226
|
}
|
|
18924
19227
|
return null;
|
|
18925
19228
|
}
|
|
18926
|
-
function
|
|
18927
|
-
|
|
19229
|
+
function itemRefFromTarget(target) {
|
|
19230
|
+
if (!(target instanceof Element)) return null;
|
|
19231
|
+
if (target.closest(CHROME_SELECTOR)) return null;
|
|
19232
|
+
const itemEl = target.closest("[data-ohw-media-strip-item]");
|
|
19233
|
+
if (!itemEl) return null;
|
|
19234
|
+
const sectionEl = itemEl.closest("[data-ohw-section]");
|
|
19235
|
+
const unit = sectionEl ? movableUnit(sectionEl) : null;
|
|
19236
|
+
const sectionId = unit ? instanceIdOf(unit) || null : null;
|
|
19237
|
+
const index = Number(itemEl.dataset.ohwMediaStripIndex);
|
|
19238
|
+
if (!sectionId || Number.isNaN(index)) return null;
|
|
19239
|
+
return { sectionId, index };
|
|
19240
|
+
}
|
|
19241
|
+
function sameRef(a, b) {
|
|
19242
|
+
return a?.sectionId === b?.sectionId && a?.index === b?.index;
|
|
19243
|
+
}
|
|
19244
|
+
function rectOf(el) {
|
|
18928
19245
|
if (!el) return null;
|
|
18929
19246
|
const r2 = el.getBoundingClientRect();
|
|
18930
19247
|
if (r2.width <= 0 || r2.height <= 0) return null;
|
|
18931
19248
|
return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
|
|
18932
19249
|
}
|
|
18933
|
-
function
|
|
19250
|
+
function readRect2(ref) {
|
|
19251
|
+
return rectOf(ref && findMediaStripItemElement(ref.sectionId, ref.index));
|
|
19252
|
+
}
|
|
19253
|
+
function readStripRect(ref) {
|
|
19254
|
+
const item = ref && findMediaStripItemElement(ref.sectionId, ref.index);
|
|
19255
|
+
return rectOf(item?.closest("[data-ohw-media-strip]") ?? item);
|
|
19256
|
+
}
|
|
19257
|
+
function useLiveItemRect(ref, strip = false) {
|
|
18934
19258
|
const [rect, setRect] = (0, import_react10.useState)(null);
|
|
18935
19259
|
(0, import_react10.useEffect)(() => {
|
|
18936
19260
|
if (!ref) {
|
|
@@ -18938,7 +19262,7 @@ function useLiveItemRect(ref) {
|
|
|
18938
19262
|
return;
|
|
18939
19263
|
}
|
|
18940
19264
|
const update = () => {
|
|
18941
|
-
const next = readRect2(ref);
|
|
19265
|
+
const next = strip ? readStripRect(ref) : readRect2(ref);
|
|
18942
19266
|
setRect(
|
|
18943
19267
|
(prev) => prev && next && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
|
|
18944
19268
|
);
|
|
@@ -18953,9 +19277,49 @@ function useLiveItemRect(ref) {
|
|
|
18953
19277
|
window.removeEventListener("resize", update);
|
|
18954
19278
|
clearInterval(interval);
|
|
18955
19279
|
};
|
|
18956
|
-
}, [ref?.sectionId, ref?.index]);
|
|
19280
|
+
}, [ref?.sectionId, ref?.index, strip]);
|
|
18957
19281
|
return rect;
|
|
18958
19282
|
}
|
|
19283
|
+
var TOOLBAR_STRIP_GAP = 52;
|
|
19284
|
+
var TOOLBAR_STRIP_GAP_MOBILE = 42;
|
|
19285
|
+
var TOOLBAR_EDGE_MARGIN2 = 4;
|
|
19286
|
+
function StripToolbarSlot({ stripRect, children }) {
|
|
19287
|
+
const slotRef = (0, import_react10.useRef)(null);
|
|
19288
|
+
const [shift, setShift] = (0, import_react10.useState)(0);
|
|
19289
|
+
const centerX = stripRect.left + stripRect.width / 2;
|
|
19290
|
+
(0, import_react10.useLayoutEffect)(() => {
|
|
19291
|
+
const slot = slotRef.current;
|
|
19292
|
+
if (!slot) return;
|
|
19293
|
+
const clamp = () => {
|
|
19294
|
+
const w = slot.offsetWidth;
|
|
19295
|
+
if (w <= 0) return;
|
|
19296
|
+
const half = w / 2;
|
|
19297
|
+
const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
|
|
19298
|
+
setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
|
|
19299
|
+
};
|
|
19300
|
+
clamp();
|
|
19301
|
+
const ro = new ResizeObserver(clamp);
|
|
19302
|
+
ro.observe(slot);
|
|
19303
|
+
return () => ro.disconnect();
|
|
19304
|
+
}, [centerX, children]);
|
|
19305
|
+
const mobile = window.innerWidth <= 480;
|
|
19306
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19307
|
+
"div",
|
|
19308
|
+
{
|
|
19309
|
+
ref: slotRef,
|
|
19310
|
+
"data-ohw-bridge": "",
|
|
19311
|
+
"data-ohw-item-interaction": "",
|
|
19312
|
+
className: "pointer-events-auto fixed",
|
|
19313
|
+
style: {
|
|
19314
|
+
top: stripRect.top - (mobile ? TOOLBAR_STRIP_GAP_MOBILE : TOOLBAR_STRIP_GAP),
|
|
19315
|
+
left: centerX + shift,
|
|
19316
|
+
transform: "translate(-50%, -100%)",
|
|
19317
|
+
zIndex: 2147483645
|
|
19318
|
+
},
|
|
19319
|
+
children
|
|
19320
|
+
}
|
|
19321
|
+
);
|
|
19322
|
+
}
|
|
18959
19323
|
function requestValidateTree(postToParent2, tree) {
|
|
18960
19324
|
return new Promise((resolve) => {
|
|
18961
19325
|
const id = `ai-validate-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -18992,116 +19356,72 @@ function requestAssetPick(postToParent2) {
|
|
|
18992
19356
|
postToParent2({ type: "ow:asset-pick", id });
|
|
18993
19357
|
});
|
|
18994
19358
|
}
|
|
18995
|
-
function
|
|
19359
|
+
function ToolbarAction({
|
|
18996
19360
|
label,
|
|
18997
19361
|
onClick,
|
|
18998
|
-
disabled,
|
|
18999
|
-
active
|
|
19362
|
+
disabled = false,
|
|
19363
|
+
active = false,
|
|
19364
|
+
children
|
|
19000
19365
|
}) {
|
|
19001
|
-
|
|
19002
|
-
|
|
19003
|
-
{
|
|
19004
|
-
|
|
19005
|
-
|
|
19006
|
-
disabled,
|
|
19007
|
-
style: {
|
|
19008
|
-
height: 28,
|
|
19009
|
-
padding: "0 10px",
|
|
19010
|
-
display: "inline-flex",
|
|
19011
|
-
alignItems: "center",
|
|
19012
|
-
gap: 4,
|
|
19013
|
-
borderRadius: 999,
|
|
19014
|
-
border: "none",
|
|
19015
|
-
cursor: disabled ? "default" : "pointer",
|
|
19016
|
-
background: active ? OHW_BLUE_DARK : "#ffffff",
|
|
19017
|
-
color: active ? "#ffffff" : OHW_BLUE_DARK,
|
|
19018
|
-
opacity: disabled ? 0.4 : 1,
|
|
19019
|
-
fontSize: 12,
|
|
19020
|
-
lineHeight: "16px",
|
|
19021
|
-
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
19022
|
-
whiteSpace: "nowrap",
|
|
19023
|
-
flex: "0 0 auto"
|
|
19024
|
-
},
|
|
19025
|
-
children: label
|
|
19026
|
-
}
|
|
19027
|
-
);
|
|
19366
|
+
const button = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, active, onClick, className: "size-8", children });
|
|
19367
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
|
|
19368
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "inline-flex", children: button }) : button }),
|
|
19369
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
|
|
19370
|
+
] });
|
|
19028
19371
|
}
|
|
19029
|
-
function
|
|
19030
|
-
|
|
19031
|
-
|
|
19032
|
-
|
|
19033
|
-
|
|
19034
|
-
|
|
19035
|
-
|
|
19036
|
-
|
|
19037
|
-
|
|
19038
|
-
|
|
19039
|
-
|
|
19040
|
-
|
|
19041
|
-
|
|
19042
|
-
|
|
19043
|
-
|
|
19044
|
-
|
|
19045
|
-
|
|
19046
|
-
|
|
19047
|
-
|
|
19048
|
-
|
|
19049
|
-
|
|
19050
|
-
|
|
19051
|
-
|
|
19052
|
-
|
|
19053
|
-
|
|
19054
|
-
|
|
19055
|
-
|
|
19056
|
-
|
|
19057
|
-
|
|
19058
|
-
},
|
|
19059
|
-
children: "Alt"
|
|
19060
|
-
}
|
|
19061
|
-
),
|
|
19062
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19063
|
-
"input",
|
|
19372
|
+
function ToolbarSeparator() {
|
|
19373
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
|
|
19374
|
+
}
|
|
19375
|
+
function OptionMenu({
|
|
19376
|
+
label,
|
|
19377
|
+
value,
|
|
19378
|
+
options,
|
|
19379
|
+
onChange
|
|
19380
|
+
}) {
|
|
19381
|
+
const current = options.find((o) => o.value === value) ?? options[0];
|
|
19382
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
19383
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-xs text-muted-foreground", children: label }),
|
|
19384
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(DropdownMenu, { modal: false, children: [
|
|
19385
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
19386
|
+
"button",
|
|
19387
|
+
{
|
|
19388
|
+
type: "button",
|
|
19389
|
+
"aria-label": label,
|
|
19390
|
+
className: "inline-flex h-8 min-w-[76px] items-center gap-[7px] rounded-[6px] bg-transparent px-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted data-[state=open]:bg-muted",
|
|
19391
|
+
children: [
|
|
19392
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "flex-1 text-left", children: current.label }),
|
|
19393
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ChevronDown, { size: 16, style: { pointerEvents: "none" } })
|
|
19394
|
+
]
|
|
19395
|
+
}
|
|
19396
|
+
) }),
|
|
19397
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[132px] min-w-[132px] p-1", children: options.map((option) => {
|
|
19398
|
+
const selected = option.value === value;
|
|
19399
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
19400
|
+
DropdownMenuItem,
|
|
19064
19401
|
{
|
|
19065
|
-
|
|
19066
|
-
|
|
19067
|
-
|
|
19068
|
-
|
|
19069
|
-
|
|
19070
|
-
|
|
19071
|
-
|
|
19072
|
-
|
|
19073
|
-
|
|
19074
|
-
|
|
19075
|
-
|
|
19076
|
-
|
|
19077
|
-
|
|
19078
|
-
|
|
19079
|
-
"aria-label": "Image alt text",
|
|
19080
|
-
style: {
|
|
19081
|
-
flex: 1,
|
|
19082
|
-
minWidth: 0,
|
|
19083
|
-
border: "none",
|
|
19084
|
-
outline: "none",
|
|
19085
|
-
background: "transparent",
|
|
19086
|
-
fontSize: 12,
|
|
19087
|
-
lineHeight: "16px",
|
|
19088
|
-
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
19089
|
-
color: "#1f2937"
|
|
19090
|
-
}
|
|
19091
|
-
}
|
|
19092
|
-
)
|
|
19093
|
-
]
|
|
19094
|
-
}
|
|
19095
|
-
);
|
|
19402
|
+
role: "menuitemradio",
|
|
19403
|
+
"aria-checked": selected,
|
|
19404
|
+
onSelect: () => onChange(option.value),
|
|
19405
|
+
className: cn("grid grid-cols-[1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
|
|
19406
|
+
children: [
|
|
19407
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: option.label }),
|
|
19408
|
+
selected && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Check, { size: 16, className: "text-bridge-primary" })
|
|
19409
|
+
]
|
|
19410
|
+
},
|
|
19411
|
+
option.value
|
|
19412
|
+
);
|
|
19413
|
+
}) })
|
|
19414
|
+
] })
|
|
19415
|
+
] });
|
|
19096
19416
|
}
|
|
19097
19417
|
var VARIANTS = [
|
|
19098
19418
|
{ value: "logos", label: "Logos" },
|
|
19099
19419
|
{ value: "reel", label: "Reel" }
|
|
19100
19420
|
];
|
|
19101
19421
|
var ALIGNS = [
|
|
19102
|
-
{ value: "left", label: "
|
|
19103
|
-
{ value: "center", label: "
|
|
19104
|
-
{ value: "right", label: "
|
|
19422
|
+
{ value: "left", label: "Align left", Icon: import_lucide_react9.AlignLeft },
|
|
19423
|
+
{ value: "center", label: "Align center", Icon: import_lucide_react9.AlignCenter },
|
|
19424
|
+
{ value: "right", label: "Align right", Icon: import_lucide_react9.AlignRight }
|
|
19105
19425
|
];
|
|
19106
19426
|
var HOVERS = [
|
|
19107
19427
|
{ value: "none", label: "None" },
|
|
@@ -19109,104 +19429,104 @@ var HOVERS = [
|
|
|
19109
19429
|
{ value: "zoom", label: "Zoom" },
|
|
19110
19430
|
{ value: "fade", label: "Fade" }
|
|
19111
19431
|
];
|
|
19112
|
-
var TREATMENTS = [
|
|
19113
|
-
{ value: "color", label: "Color" },
|
|
19114
|
-
{ value: "grayscale", label: "Grayscale" }
|
|
19115
|
-
];
|
|
19116
19432
|
var HTTP_URL_RE = /^https?:\/\/\S+$/i;
|
|
19117
|
-
function
|
|
19118
|
-
|
|
19433
|
+
function LinkModal({
|
|
19434
|
+
href,
|
|
19435
|
+
linkTarget,
|
|
19436
|
+
onClose,
|
|
19437
|
+
onSave
|
|
19438
|
+
}) {
|
|
19439
|
+
const [draft, setDraft] = (0, import_react10.useState)(href);
|
|
19440
|
+
const [newTab, setNewTab] = (0, import_react10.useState)(linkTarget !== "same-tab");
|
|
19119
19441
|
const [invalid, setInvalid] = (0, import_react10.useState)(false);
|
|
19120
|
-
|
|
19121
|
-
setDraft(value);
|
|
19122
|
-
setInvalid(false);
|
|
19123
|
-
}, [value]);
|
|
19124
|
-
const commit = () => {
|
|
19442
|
+
const save = () => {
|
|
19125
19443
|
const next = draft.trim();
|
|
19126
|
-
if (next
|
|
19127
|
-
|
|
19128
|
-
|
|
19129
|
-
onCommit(next);
|
|
19130
|
-
};
|
|
19131
|
-
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
19132
|
-
"div",
|
|
19133
|
-
{
|
|
19134
|
-
style: {
|
|
19135
|
-
display: "flex",
|
|
19136
|
-
alignItems: "center",
|
|
19137
|
-
gap: 6,
|
|
19138
|
-
height: 28,
|
|
19139
|
-
padding: "0 12px",
|
|
19140
|
-
borderRadius: 999,
|
|
19141
|
-
background: "#ffffff",
|
|
19142
|
-
width: "100%",
|
|
19143
|
-
maxWidth: 260,
|
|
19144
|
-
boxSizing: "border-box",
|
|
19145
|
-
boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
|
|
19146
|
-
},
|
|
19147
|
-
children: [
|
|
19148
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19149
|
-
"span",
|
|
19150
|
-
{
|
|
19151
|
-
style: {
|
|
19152
|
-
flex: "0 0 auto",
|
|
19153
|
-
color: OHW_BLUE_DARK,
|
|
19154
|
-
fontSize: 10,
|
|
19155
|
-
fontWeight: 700,
|
|
19156
|
-
textTransform: "uppercase",
|
|
19157
|
-
letterSpacing: 0.4
|
|
19158
|
-
},
|
|
19159
|
-
children: "Link"
|
|
19160
|
-
}
|
|
19161
|
-
),
|
|
19162
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19163
|
-
"input",
|
|
19164
|
-
{
|
|
19165
|
-
type: "text",
|
|
19166
|
-
inputMode: "url",
|
|
19167
|
-
value: draft,
|
|
19168
|
-
onChange: (e) => setDraft(e.target.value),
|
|
19169
|
-
onBlur: commit,
|
|
19170
|
-
onKeyDown: (e) => {
|
|
19171
|
-
if (e.key === "Enter") e.currentTarget.blur();
|
|
19172
|
-
if (e.key === "Escape") {
|
|
19173
|
-
setDraft(value);
|
|
19174
|
-
setInvalid(false);
|
|
19175
|
-
e.currentTarget.blur();
|
|
19176
|
-
}
|
|
19177
|
-
},
|
|
19178
|
-
placeholder: "https://example.com",
|
|
19179
|
-
"aria-label": "Image link URL",
|
|
19180
|
-
"aria-invalid": invalid,
|
|
19181
|
-
style: {
|
|
19182
|
-
flex: 1,
|
|
19183
|
-
minWidth: 0,
|
|
19184
|
-
border: "none",
|
|
19185
|
-
outline: "none",
|
|
19186
|
-
background: "transparent",
|
|
19187
|
-
fontSize: 12,
|
|
19188
|
-
lineHeight: "16px",
|
|
19189
|
-
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
19190
|
-
color: "#1f2937"
|
|
19191
|
-
}
|
|
19192
|
-
}
|
|
19193
|
-
)
|
|
19194
|
-
]
|
|
19444
|
+
if (next && !HTTP_URL_RE.test(next)) {
|
|
19445
|
+
setInvalid(true);
|
|
19446
|
+
return;
|
|
19195
19447
|
}
|
|
19196
|
-
|
|
19448
|
+
onSave(next, newTab ? "new-tab" : "same-tab");
|
|
19449
|
+
onClose();
|
|
19450
|
+
};
|
|
19451
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Dialog2, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(DialogContent, { "data-ohw-link-modal-root": "", className: "max-w-[400px] gap-4 p-5", children: [
|
|
19452
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DialogTitle, { className: "text-base", children: "Image link" }) }),
|
|
19453
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-3", children: [
|
|
19454
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19455
|
+
"input",
|
|
19456
|
+
{
|
|
19457
|
+
autoFocus: true,
|
|
19458
|
+
type: "text",
|
|
19459
|
+
inputMode: "url",
|
|
19460
|
+
value: draft,
|
|
19461
|
+
onChange: (e) => {
|
|
19462
|
+
setDraft(e.target.value);
|
|
19463
|
+
setInvalid(false);
|
|
19464
|
+
},
|
|
19465
|
+
onKeyDown: (e) => {
|
|
19466
|
+
if (e.key === "Enter") save();
|
|
19467
|
+
},
|
|
19468
|
+
placeholder: "https://example.com",
|
|
19469
|
+
"aria-label": "Image link URL",
|
|
19470
|
+
"aria-invalid": invalid,
|
|
19471
|
+
className: cn(
|
|
19472
|
+
"h-9 w-full rounded-[6px] border border-border bg-background px-3 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/70 focus:border-bridge-primary",
|
|
19473
|
+
invalid && "border-destructive focus:border-destructive"
|
|
19474
|
+
)
|
|
19475
|
+
}
|
|
19476
|
+
),
|
|
19477
|
+
invalid && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-xs text-destructive", children: "Enter a full URL starting with http:// or https://" }),
|
|
19478
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex items-center gap-2 text-[13px] text-foreground", children: [
|
|
19479
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "checkbox", checked: newTab, onChange: (e) => setNewTab(e.target.checked) }),
|
|
19480
|
+
"Open in new tab"
|
|
19481
|
+
] })
|
|
19482
|
+
] }),
|
|
19483
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(DialogFooter, { children: [
|
|
19484
|
+
href && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19485
|
+
"button",
|
|
19486
|
+
{
|
|
19487
|
+
type: "button",
|
|
19488
|
+
onClick: () => {
|
|
19489
|
+
onSave("", "new-tab");
|
|
19490
|
+
onClose();
|
|
19491
|
+
},
|
|
19492
|
+
className: "mr-auto rounded-[6px] px-3 py-2 text-[13px] font-medium text-destructive transition-colors hover:bg-muted",
|
|
19493
|
+
children: "Remove link"
|
|
19494
|
+
}
|
|
19495
|
+
),
|
|
19496
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19497
|
+
"button",
|
|
19498
|
+
{
|
|
19499
|
+
type: "button",
|
|
19500
|
+
onClick: onClose,
|
|
19501
|
+
className: "rounded-[6px] px-3 py-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted",
|
|
19502
|
+
children: "Cancel"
|
|
19503
|
+
}
|
|
19504
|
+
),
|
|
19505
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19506
|
+
"button",
|
|
19507
|
+
{
|
|
19508
|
+
type: "button",
|
|
19509
|
+
onClick: save,
|
|
19510
|
+
className: "rounded-[6px] bg-bridge-primary px-3 py-2 text-[13px] font-medium text-primary-foreground transition-opacity hover:opacity-90",
|
|
19511
|
+
children: "Save"
|
|
19512
|
+
}
|
|
19513
|
+
)
|
|
19514
|
+
] })
|
|
19515
|
+
] }) });
|
|
19197
19516
|
}
|
|
19198
19517
|
function MediaStripToolbar({
|
|
19199
19518
|
entry,
|
|
19200
19519
|
index,
|
|
19201
19520
|
pending,
|
|
19202
19521
|
error,
|
|
19522
|
+
itemEditOn,
|
|
19523
|
+
onToggleItemEdit,
|
|
19203
19524
|
onSetVariant,
|
|
19204
19525
|
onSetAlign,
|
|
19205
19526
|
onSetHover,
|
|
19206
19527
|
onSetTreatment,
|
|
19207
19528
|
onResize,
|
|
19208
|
-
|
|
19209
|
-
onSetLink,
|
|
19529
|
+
onOpenLink,
|
|
19210
19530
|
onAddItem,
|
|
19211
19531
|
onRemoveItem,
|
|
19212
19532
|
onChangeImage,
|
|
@@ -19215,81 +19535,102 @@ function MediaStripToolbar({
|
|
|
19215
19535
|
}) {
|
|
19216
19536
|
const items = mediaStripItems(entry.tree);
|
|
19217
19537
|
const itemCount = items.length;
|
|
19218
|
-
const currentAlt = items[index]?.alt ?? "";
|
|
19219
|
-
const currentHref = items[index]?.href ?? "";
|
|
19220
|
-
const currentTarget = items[index]?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
|
|
19221
19538
|
const slots = findMediaStripSlots(entry.tree);
|
|
19222
19539
|
const variant = slots?.variant === "reel" ? "reel" : "logos";
|
|
19223
19540
|
const align = slots?.align === "left" || slots?.align === "right" ? slots.align : "center";
|
|
19224
19541
|
const hover = slots?.hover === "none" || slots?.hover === "lift" || slots?.hover === "zoom" || slots?.hover === "fade" ? slots.hover : "lift";
|
|
19225
19542
|
const treatment = slots?.treatment === "color" || slots?.treatment === "grayscale" ? slots.treatment : variant === "logos" ? "grayscale" : "color";
|
|
19226
19543
|
const sizeValue = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
|
|
19227
|
-
const
|
|
19228
|
-
const
|
|
19229
|
-
|
|
19230
|
-
gap: 6,
|
|
19231
|
-
flexWrap: "nowrap",
|
|
19232
|
-
justifyContent: "center",
|
|
19233
|
-
overflowX: "auto",
|
|
19234
|
-
WebkitOverflowScrolling: "touch",
|
|
19235
|
-
width: "100%",
|
|
19236
|
-
scrollbarWidth: "none"
|
|
19237
|
-
} : { display: "flex", gap: 6, flexWrap: "nowrap", justifyContent: "center" };
|
|
19238
|
-
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
19544
|
+
const mobile = window.innerWidth <= 480;
|
|
19545
|
+
const gatedLabel = (label) => itemEditOn ? label : "Turn on the star to edit this image";
|
|
19546
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
19239
19547
|
"div",
|
|
19240
19548
|
{
|
|
19241
19549
|
"data-ohw-bridge": "",
|
|
19242
19550
|
"data-ohw-toolbar": "",
|
|
19243
19551
|
onMouseDown: (e) => e.stopPropagation(),
|
|
19244
|
-
|
|
19245
|
-
|
|
19246
|
-
flexDirection: "column",
|
|
19247
|
-
gap: 6,
|
|
19248
|
-
alignItems: "center",
|
|
19249
|
-
background: OHW_BLUE,
|
|
19250
|
-
padding: 8,
|
|
19251
|
-
borderRadius: 12,
|
|
19252
|
-
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
19253
|
-
pointerEvents: pending ? "none" : "auto",
|
|
19254
|
-
opacity: pending ? 0.6 : 1,
|
|
19255
|
-
maxWidth: isMobile ? "calc(100vw - 24px)" : "none"
|
|
19256
|
-
},
|
|
19552
|
+
className: cn("flex flex-col items-center gap-1.5 font-sans", pending && "pointer-events-none opacity-60"),
|
|
19553
|
+
style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
|
|
19257
19554
|
children: [
|
|
19258
|
-
/* @__PURE__ */ (0,
|
|
19259
|
-
|
|
19260
|
-
|
|
19261
|
-
|
|
19262
|
-
|
|
19263
|
-
|
|
19264
|
-
|
|
19265
|
-
|
|
19266
|
-
|
|
19267
|
-
|
|
19268
|
-
|
|
19269
|
-
|
|
19270
|
-
|
|
19271
|
-
|
|
19272
|
-
|
|
19273
|
-
|
|
19274
|
-
|
|
19275
|
-
|
|
19276
|
-
|
|
19277
|
-
|
|
19278
|
-
|
|
19279
|
-
|
|
19280
|
-
|
|
19281
|
-
|
|
19282
|
-
|
|
19283
|
-
|
|
19284
|
-
|
|
19285
|
-
|
|
19286
|
-
|
|
19287
|
-
|
|
19288
|
-
|
|
19289
|
-
|
|
19555
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
19556
|
+
"div",
|
|
19557
|
+
{
|
|
19558
|
+
className: cn(
|
|
19559
|
+
"flex items-center gap-1 rounded-[10px] border border-border bg-background p-1 whitespace-nowrap",
|
|
19560
|
+
"shadow-[0px_10px_15px_-3px_rgba(0,0,0,0.1),0px_4px_6px_-4px_rgba(0,0,0,0.1)]",
|
|
19561
|
+
mobile ? "flex-wrap justify-center" : "flex-nowrap"
|
|
19562
|
+
),
|
|
19563
|
+
children: [
|
|
19564
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
|
|
19565
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19566
|
+
CustomToolbarButton,
|
|
19567
|
+
{
|
|
19568
|
+
type: "button",
|
|
19569
|
+
"aria-label": itemEditOn ? "Done editing this image" : "Edit this image",
|
|
19570
|
+
"aria-pressed": itemEditOn,
|
|
19571
|
+
onClick: onToggleItemEdit,
|
|
19572
|
+
className: "group size-8",
|
|
19573
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19574
|
+
import_lucide_react9.Star,
|
|
19575
|
+
{
|
|
19576
|
+
size: 16,
|
|
19577
|
+
fill: "currentColor",
|
|
19578
|
+
strokeWidth: 0,
|
|
19579
|
+
className: cn(
|
|
19580
|
+
"transition-colors",
|
|
19581
|
+
itemEditOn ? "text-[#f59e0b] group-hover:text-[#d97706]" : "text-[#d6d3d1] group-hover:text-[#fbbf24]"
|
|
19582
|
+
),
|
|
19583
|
+
style: { pointerEvents: "none" }
|
|
19584
|
+
}
|
|
19585
|
+
)
|
|
19586
|
+
}
|
|
19587
|
+
) }),
|
|
19588
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: itemEditOn ? "Done editing this image" : "Edit this image" })
|
|
19589
|
+
] }),
|
|
19590
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19591
|
+
/* @__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" } }) }),
|
|
19592
|
+
/* @__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" } }) }),
|
|
19593
|
+
/* @__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" } }) }),
|
|
19594
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19595
|
+
ToolbarAction,
|
|
19596
|
+
{
|
|
19597
|
+
label: gatedLabel("Move right"),
|
|
19598
|
+
onClick: onMoveRight,
|
|
19599
|
+
disabled: !itemEditOn || index >= itemCount - 1,
|
|
19600
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ArrowRight, { size: 16, style: { pointerEvents: "none" } })
|
|
19601
|
+
}
|
|
19602
|
+
),
|
|
19603
|
+
/* @__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" } }) }),
|
|
19604
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19605
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(OptionMenu, { label: "Layout", value: variant, options: VARIANTS, onChange: onSetVariant }),
|
|
19606
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(OptionMenu, { label: "Hover", value: hover, options: HOVERS, onChange: onSetHover }),
|
|
19607
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19608
|
+
ToolbarAction,
|
|
19609
|
+
{
|
|
19610
|
+
label: treatment === "grayscale" ? "Show in color" : "Show grayscale",
|
|
19611
|
+
active: treatment === "grayscale",
|
|
19612
|
+
onClick: () => onSetTreatment(treatment === "grayscale" ? "color" : "grayscale"),
|
|
19613
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Palette, { size: 16, style: { pointerEvents: "none" } })
|
|
19614
|
+
}
|
|
19615
|
+
),
|
|
19616
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19617
|
+
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)),
|
|
19618
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19619
|
+
/* @__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" } }) }),
|
|
19620
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "min-w-[40px] text-center text-xs tabular-nums text-muted-foreground", children: [
|
|
19621
|
+
sizeValue,
|
|
19622
|
+
"px"
|
|
19623
|
+
] }),
|
|
19624
|
+
/* @__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" } }) }),
|
|
19625
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
|
|
19626
|
+
/* @__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" } }) })
|
|
19627
|
+
]
|
|
19628
|
+
}
|
|
19629
|
+
),
|
|
19630
|
+
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 })
|
|
19290
19631
|
]
|
|
19291
19632
|
}
|
|
19292
|
-
);
|
|
19633
|
+
) });
|
|
19293
19634
|
}
|
|
19294
19635
|
function findMediaStripSlots(tree) {
|
|
19295
19636
|
const stack = tree.rows.flatMap((row) => row.blocks);
|
|
@@ -19308,31 +19649,23 @@ function AiMediaStripOverlay({
|
|
|
19308
19649
|
}) {
|
|
19309
19650
|
const [hover, setHover] = (0, import_react10.useState)(null);
|
|
19310
19651
|
const [active, setActive] = (0, import_react10.useState)(null);
|
|
19652
|
+
const [itemEditOn, setItemEditOn] = (0, import_react10.useState)(false);
|
|
19653
|
+
const [linkOpen, setLinkOpen] = (0, import_react10.useState)(false);
|
|
19311
19654
|
const [pending, setPending] = (0, import_react10.useState)(false);
|
|
19312
19655
|
const [error, setError] = (0, import_react10.useState)(null);
|
|
19313
19656
|
const activeRef = (0, import_react10.useRef)(null);
|
|
19314
19657
|
activeRef.current = active;
|
|
19658
|
+
const linkOpenRef = (0, import_react10.useRef)(false);
|
|
19659
|
+
linkOpenRef.current = linkOpen;
|
|
19315
19660
|
(0, import_react10.useEffect)(() => {
|
|
19316
19661
|
const onMove = (e) => {
|
|
19662
|
+
const ref = itemRefFromTarget(e.target);
|
|
19317
19663
|
const t = e.target;
|
|
19318
|
-
|
|
19319
|
-
|
|
19320
|
-
|
|
19321
|
-
|
|
19322
|
-
|
|
19323
|
-
if (!itemEl) {
|
|
19324
|
-
setHover(null);
|
|
19325
|
-
return;
|
|
19326
|
-
}
|
|
19327
|
-
const sectionEl = itemEl.closest("[data-ohw-section]");
|
|
19328
|
-
const unit = sectionEl ? movableUnit(sectionEl) : null;
|
|
19329
|
-
const sectionId = unit ? instanceIdOf(unit) || null : null;
|
|
19330
|
-
const index = Number(itemEl.dataset.ohwMediaStripIndex);
|
|
19331
|
-
if (!sectionId || Number.isNaN(index)) {
|
|
19332
|
-
setHover(null);
|
|
19333
|
-
return;
|
|
19334
|
-
}
|
|
19335
|
-
setHover({ sectionId, index });
|
|
19664
|
+
const overEditable = Boolean(t?.closest?.("[data-ohw-editable]"));
|
|
19665
|
+
setHover((prev) => {
|
|
19666
|
+
const next = ref && !overEditable ? ref : null;
|
|
19667
|
+
return sameRef(prev, next) ? prev : next;
|
|
19668
|
+
});
|
|
19336
19669
|
};
|
|
19337
19670
|
const onLeave = () => setHover(null);
|
|
19338
19671
|
document.addEventListener("mousemove", onMove, { passive: true });
|
|
@@ -19344,23 +19677,25 @@ function AiMediaStripOverlay({
|
|
|
19344
19677
|
}, []);
|
|
19345
19678
|
(0, import_react10.useEffect)(() => {
|
|
19346
19679
|
const onClick = (e) => {
|
|
19347
|
-
const current = activeRef.current;
|
|
19348
|
-
if (!current) return;
|
|
19349
19680
|
const t = e.target;
|
|
19350
|
-
if (!(t instanceof
|
|
19351
|
-
if (t.closest(
|
|
19352
|
-
const
|
|
19353
|
-
if (
|
|
19354
|
-
|
|
19681
|
+
if (!(t instanceof Element)) return;
|
|
19682
|
+
if (t.closest(CHROME_SELECTOR)) return;
|
|
19683
|
+
const ref = itemRefFromTarget(t);
|
|
19684
|
+
if (sameRef(activeRef.current, ref)) return;
|
|
19685
|
+
if (ref) clearInteractionChromeRef.current();
|
|
19686
|
+
setItemEditOn(false);
|
|
19355
19687
|
setError(null);
|
|
19688
|
+
setActive(ref);
|
|
19356
19689
|
};
|
|
19357
19690
|
document.addEventListener("click", onClick, true);
|
|
19358
19691
|
return () => document.removeEventListener("click", onClick, true);
|
|
19359
|
-
}, []);
|
|
19692
|
+
}, [clearInteractionChromeRef]);
|
|
19360
19693
|
(0, import_react10.useEffect)(() => {
|
|
19361
19694
|
const onBlur = () => {
|
|
19362
19695
|
if (!activeRef.current) return;
|
|
19363
19696
|
setActive(null);
|
|
19697
|
+
setItemEditOn(false);
|
|
19698
|
+
setLinkOpen(false);
|
|
19364
19699
|
setError(null);
|
|
19365
19700
|
};
|
|
19366
19701
|
window.addEventListener("blur", onBlur);
|
|
@@ -19370,7 +19705,10 @@ function AiMediaStripOverlay({
|
|
|
19370
19705
|
const onKeyDown = (e) => {
|
|
19371
19706
|
if (e.key !== "Escape") return;
|
|
19372
19707
|
if (!activeRef.current) return;
|
|
19708
|
+
if (linkOpenRef.current) return;
|
|
19709
|
+
if (document.querySelector('[data-ohw-more-menu][data-state="open"]')) return;
|
|
19373
19710
|
setActive(null);
|
|
19711
|
+
setItemEditOn(false);
|
|
19374
19712
|
setError(null);
|
|
19375
19713
|
};
|
|
19376
19714
|
document.addEventListener("keydown", onKeyDown);
|
|
@@ -19404,137 +19742,133 @@ function AiMediaStripOverlay({
|
|
|
19404
19742
|
tree: nextTree,
|
|
19405
19743
|
label: entry.label,
|
|
19406
19744
|
media: extraMedia ? { ...entry.media, ...extraMedia } : entry.media,
|
|
19407
|
-
...entry.brand ? { brand: entry.brand } : {}
|
|
19745
|
+
...entry.brand ? { brand: entry.brand } : {},
|
|
19746
|
+
// The user is already looking at the strip they just edited — recentering the viewport
|
|
19747
|
+
// on every edit reads as the section jumping around.
|
|
19748
|
+
skipScrollIntoView: true
|
|
19408
19749
|
});
|
|
19409
19750
|
return true;
|
|
19410
19751
|
},
|
|
19411
19752
|
[findEntry, postToParent2, applyTreeLocalRef]
|
|
19412
19753
|
);
|
|
19413
19754
|
const activeEntry = active ? findEntry(active.sectionId) : null;
|
|
19414
|
-
const hoverHandleRect = useLiveItemRect(!active && hover ? hover : null);
|
|
19415
19755
|
const activeItemRect = useLiveItemRect(active);
|
|
19416
|
-
const
|
|
19417
|
-
const
|
|
19418
|
-
|
|
19419
|
-
|
|
19420
|
-
|
|
19421
|
-
|
|
19422
|
-
|
|
19423
|
-
|
|
19424
|
-
|
|
19425
|
-
|
|
19426
|
-
|
|
19427
|
-
|
|
19428
|
-
|
|
19429
|
-
|
|
19430
|
-
|
|
19431
|
-
|
|
19432
|
-
|
|
19433
|
-
|
|
19434
|
-
|
|
19435
|
-
|
|
19436
|
-
|
|
19437
|
-
|
|
19438
|
-
|
|
19439
|
-
|
|
19440
|
-
|
|
19441
|
-
|
|
19442
|
-
|
|
19443
|
-
|
|
19444
|
-
|
|
19445
|
-
|
|
19446
|
-
|
|
19447
|
-
|
|
19448
|
-
|
|
19449
|
-
|
|
19450
|
-
activeItemRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19451
|
-
ItemInteractionLayer,
|
|
19452
|
-
{
|
|
19453
|
-
rect: activeItemRect,
|
|
19454
|
-
state: toolbarState,
|
|
19455
|
-
toolbar: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19456
|
-
MediaStripToolbar,
|
|
19457
|
-
{
|
|
19458
|
-
entry: activeEntry,
|
|
19459
|
-
index: active.index,
|
|
19460
|
-
pending,
|
|
19461
|
-
error,
|
|
19462
|
-
onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
|
|
19463
|
-
onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
|
|
19464
|
-
onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
|
|
19465
|
-
onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
|
|
19466
|
-
onResize: (delta) => {
|
|
19467
|
-
const slots = findMediaStripSlots(activeEntry.tree);
|
|
19468
|
-
const variant = slots?.variant === "reel" ? "reel" : "logos";
|
|
19469
|
-
const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
|
|
19470
|
-
void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
|
|
19471
|
-
},
|
|
19472
|
-
onSetAlt: (alt) => {
|
|
19473
|
-
void runMutation(active.sectionId, (tree) => setMediaStripItemAlt(tree, active.index, alt));
|
|
19474
|
-
},
|
|
19475
|
-
onSetLink: (href, linkTarget) => {
|
|
19756
|
+
const activeStripRect = useLiveItemRect(active, true);
|
|
19757
|
+
const hoverRect = useLiveItemRect(hover && !sameRef(hover, active) ? hover : null);
|
|
19758
|
+
const activeItems = activeEntry ? mediaStripItems(activeEntry.tree) : [];
|
|
19759
|
+
const activeItem = active ? activeItems[active.index] : void 0;
|
|
19760
|
+
const activeHref = activeItem?.href ?? "";
|
|
19761
|
+
const activeTarget = activeItem?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
|
|
19762
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
19763
|
+
hoverRect && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
|
|
19764
|
+
activeItemRect && activeStripRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
19765
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: activeItemRect, state: "active-top" }),
|
|
19766
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StripToolbarSlot, { stripRect: activeStripRect, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19767
|
+
MediaStripToolbar,
|
|
19768
|
+
{
|
|
19769
|
+
entry: activeEntry,
|
|
19770
|
+
index: active.index,
|
|
19771
|
+
pending,
|
|
19772
|
+
error,
|
|
19773
|
+
itemEditOn,
|
|
19774
|
+
onToggleItemEdit: () => setItemEditOn((on) => !on),
|
|
19775
|
+
onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
|
|
19776
|
+
onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
|
|
19777
|
+
onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
|
|
19778
|
+
onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
|
|
19779
|
+
onResize: (delta) => {
|
|
19780
|
+
const slots = findMediaStripSlots(activeEntry.tree);
|
|
19781
|
+
const variant = slots?.variant === "reel" ? "reel" : "logos";
|
|
19782
|
+
const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
|
|
19783
|
+
void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
|
|
19784
|
+
},
|
|
19785
|
+
onOpenLink: () => setLinkOpen(true),
|
|
19786
|
+
onAddItem: () => {
|
|
19787
|
+
void requestAssetPick(postToParent2).then((picked) => {
|
|
19788
|
+
if (!picked) return;
|
|
19789
|
+
const item = { assetId: picked.assetId, alt: "Logo" };
|
|
19476
19790
|
void runMutation(
|
|
19477
19791
|
active.sectionId,
|
|
19478
|
-
(tree) =>
|
|
19479
|
-
|
|
19480
|
-
|
|
19481
|
-
|
|
19482
|
-
void requestAssetPick(postToParent2).then((picked) => {
|
|
19483
|
-
if (!picked) return;
|
|
19484
|
-
const item = { assetId: picked.assetId, alt: "Logo" };
|
|
19485
|
-
void runMutation(
|
|
19486
|
-
active.sectionId,
|
|
19487
|
-
(tree) => addMediaStripItem(tree, item, active.index),
|
|
19488
|
-
{ [picked.assetId]: picked.url }
|
|
19489
|
-
).then((applied) => {
|
|
19490
|
-
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
19491
|
-
});
|
|
19792
|
+
(tree) => addMediaStripItem(tree, item, active.index),
|
|
19793
|
+
{ [picked.assetId]: picked.url }
|
|
19794
|
+
).then((applied) => {
|
|
19795
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
19492
19796
|
});
|
|
19493
|
-
}
|
|
19494
|
-
|
|
19495
|
-
|
|
19496
|
-
|
|
19497
|
-
|
|
19498
|
-
|
|
19499
|
-
|
|
19500
|
-
|
|
19501
|
-
|
|
19502
|
-
});
|
|
19503
|
-
},
|
|
19504
|
-
onRemoveItem: () => {
|
|
19505
|
-
void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
|
|
19506
|
-
(applied) => {
|
|
19507
|
-
if (applied) setActive(null);
|
|
19508
|
-
}
|
|
19509
|
-
);
|
|
19510
|
-
},
|
|
19511
|
-
onMoveLeft: () => {
|
|
19512
|
-
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
|
|
19513
|
-
(applied) => {
|
|
19514
|
-
if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
|
|
19515
|
-
}
|
|
19516
|
-
);
|
|
19517
|
-
},
|
|
19518
|
-
onMoveRight: () => {
|
|
19519
|
-
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
|
|
19520
|
-
(applied) => {
|
|
19521
|
-
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
19522
|
-
}
|
|
19797
|
+
});
|
|
19798
|
+
},
|
|
19799
|
+
onChangeImage: () => {
|
|
19800
|
+
void requestAssetPick(postToParent2).then((picked) => {
|
|
19801
|
+
if (!picked) return;
|
|
19802
|
+
void runMutation(
|
|
19803
|
+
active.sectionId,
|
|
19804
|
+
(tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
|
|
19805
|
+
{ [picked.assetId]: picked.url }
|
|
19523
19806
|
);
|
|
19524
|
-
}
|
|
19807
|
+
});
|
|
19808
|
+
},
|
|
19809
|
+
onRemoveItem: () => {
|
|
19810
|
+
void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
|
|
19811
|
+
(applied) => {
|
|
19812
|
+
if (applied) setActive(null);
|
|
19813
|
+
}
|
|
19814
|
+
);
|
|
19815
|
+
},
|
|
19816
|
+
onMoveLeft: () => {
|
|
19817
|
+
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
|
|
19818
|
+
(applied) => {
|
|
19819
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
|
|
19820
|
+
}
|
|
19821
|
+
);
|
|
19822
|
+
},
|
|
19823
|
+
onMoveRight: () => {
|
|
19824
|
+
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
|
|
19825
|
+
(applied) => {
|
|
19826
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
19827
|
+
}
|
|
19828
|
+
);
|
|
19525
19829
|
}
|
|
19526
|
-
|
|
19527
|
-
}
|
|
19528
|
-
|
|
19830
|
+
}
|
|
19831
|
+
) }),
|
|
19832
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19833
|
+
"div",
|
|
19834
|
+
{
|
|
19835
|
+
"data-ohw-bridge": "",
|
|
19836
|
+
"data-ohw-item-interaction": "",
|
|
19837
|
+
"aria-hidden": true,
|
|
19838
|
+
className: "pointer-events-none fixed rounded-[4px] px-[7px] py-[3px] font-sans text-[11px] font-medium leading-none text-primary-foreground whitespace-nowrap",
|
|
19839
|
+
style: {
|
|
19840
|
+
top: activeItemRect.top + activeItemRect.height + 10,
|
|
19841
|
+
left: activeItemRect.left - 5,
|
|
19842
|
+
background: PRIMARY3,
|
|
19843
|
+
zIndex: 2147483644
|
|
19844
|
+
},
|
|
19845
|
+
children: "Media item"
|
|
19846
|
+
}
|
|
19847
|
+
),
|
|
19848
|
+
linkOpen && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19849
|
+
LinkModal,
|
|
19850
|
+
{
|
|
19851
|
+
href: activeHref,
|
|
19852
|
+
linkTarget: activeTarget,
|
|
19853
|
+
onClose: () => setLinkOpen(false),
|
|
19854
|
+
onSave: (href, linkTarget) => {
|
|
19855
|
+
void runMutation(
|
|
19856
|
+
active.sectionId,
|
|
19857
|
+
(tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
|
|
19858
|
+
);
|
|
19859
|
+
}
|
|
19860
|
+
}
|
|
19861
|
+
)
|
|
19862
|
+
] })
|
|
19529
19863
|
] });
|
|
19530
19864
|
}
|
|
19531
19865
|
|
|
19532
19866
|
// src/ui/ai-section/AiPricingCardOverlay.tsx
|
|
19533
19867
|
var import_react11 = require("react");
|
|
19534
|
-
var
|
|
19535
|
-
var
|
|
19868
|
+
var import_lucide_react10 = require("lucide-react");
|
|
19869
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
19536
19870
|
var PRIMARY4 = "var(--ohw-primary, #0885FE)";
|
|
19537
|
-
var
|
|
19871
|
+
var CHROME_SELECTOR2 = "[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-link-modal-root], [data-ohw-section-picker], [data-ohw-ai-review], [data-ohw-more-menu]";
|
|
19538
19872
|
function findPricingCardElement(sectionId, index) {
|
|
19539
19873
|
const sectionEl = findByInstanceId(sectionId);
|
|
19540
19874
|
if (!sectionEl) return null;
|
|
@@ -19546,7 +19880,7 @@ function findPricingCardElement(sectionId, index) {
|
|
|
19546
19880
|
}
|
|
19547
19881
|
function cardRefFromTarget(target) {
|
|
19548
19882
|
if (!(target instanceof Element)) return null;
|
|
19549
|
-
if (target.closest(
|
|
19883
|
+
if (target.closest(CHROME_SELECTOR2)) return null;
|
|
19550
19884
|
const cardEl = target.closest("[data-ohw-pricing-card]");
|
|
19551
19885
|
if (!cardEl) return null;
|
|
19552
19886
|
const sectionEl = cardEl.closest("[data-ohw-section]");
|
|
@@ -19556,21 +19890,21 @@ function cardRefFromTarget(target) {
|
|
|
19556
19890
|
if (!sectionId || Number.isNaN(index)) return null;
|
|
19557
19891
|
return { sectionId, index };
|
|
19558
19892
|
}
|
|
19559
|
-
function
|
|
19893
|
+
function sameRef2(a, b) {
|
|
19560
19894
|
return a?.sectionId === b?.sectionId && a?.index === b?.index;
|
|
19561
19895
|
}
|
|
19562
|
-
function
|
|
19896
|
+
function rectOf2(el) {
|
|
19563
19897
|
if (!el) return null;
|
|
19564
19898
|
const r2 = el.getBoundingClientRect();
|
|
19565
19899
|
if (r2.width <= 0 || r2.height <= 0) return null;
|
|
19566
19900
|
return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
|
|
19567
19901
|
}
|
|
19568
19902
|
function readRect3(ref) {
|
|
19569
|
-
return
|
|
19903
|
+
return rectOf2(ref && findPricingCardElement(ref.sectionId, ref.index));
|
|
19570
19904
|
}
|
|
19571
19905
|
function readGridRect(ref) {
|
|
19572
19906
|
const card = ref && findPricingCardElement(ref.sectionId, ref.index);
|
|
19573
|
-
return
|
|
19907
|
+
return rectOf2(card?.closest("[data-ohw-pricing-collection]") ?? card);
|
|
19574
19908
|
}
|
|
19575
19909
|
function useLiveCardRect(ref, grid = false) {
|
|
19576
19910
|
const [rect, setRect] = (0, import_react11.useState)(null);
|
|
@@ -19600,7 +19934,7 @@ function useLiveCardRect(ref, grid = false) {
|
|
|
19600
19934
|
}
|
|
19601
19935
|
var TOOLBAR_GRID_GAP = 52;
|
|
19602
19936
|
var TOOLBAR_GRID_GAP_MOBILE = 42;
|
|
19603
|
-
var
|
|
19937
|
+
var TOOLBAR_EDGE_MARGIN3 = 4;
|
|
19604
19938
|
function GridToolbarSlot({ gridRect, children }) {
|
|
19605
19939
|
const slotRef = (0, import_react11.useRef)(null);
|
|
19606
19940
|
const [shift, setShift] = (0, import_react11.useState)(0);
|
|
@@ -19612,7 +19946,7 @@ function GridToolbarSlot({ gridRect, children }) {
|
|
|
19612
19946
|
const w = slot.offsetWidth;
|
|
19613
19947
|
if (w <= 0) return;
|
|
19614
19948
|
const half = w / 2;
|
|
19615
|
-
const clamped = Math.max(
|
|
19949
|
+
const clamped = Math.max(TOOLBAR_EDGE_MARGIN3 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN3 - half));
|
|
19616
19950
|
setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
|
|
19617
19951
|
};
|
|
19618
19952
|
clamp();
|
|
@@ -19621,7 +19955,7 @@ function GridToolbarSlot({ gridRect, children }) {
|
|
|
19621
19955
|
return () => ro.disconnect();
|
|
19622
19956
|
}, [centerX, children]);
|
|
19623
19957
|
const mobile = window.innerWidth <= 480;
|
|
19624
|
-
return /* @__PURE__ */ (0,
|
|
19958
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19625
19959
|
"div",
|
|
19626
19960
|
{
|
|
19627
19961
|
ref: slotRef,
|
|
@@ -19656,7 +19990,7 @@ function requestValidateTree2(postToParent2, tree) {
|
|
|
19656
19990
|
});
|
|
19657
19991
|
}
|
|
19658
19992
|
function StyleSwatch({ style }) {
|
|
19659
|
-
return /* @__PURE__ */ (0,
|
|
19993
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19660
19994
|
"span",
|
|
19661
19995
|
{
|
|
19662
19996
|
"aria-hidden": true,
|
|
@@ -19670,35 +20004,35 @@ function StyleSwatch({ style }) {
|
|
|
19670
20004
|
);
|
|
19671
20005
|
}
|
|
19672
20006
|
function ButtonGlyph() {
|
|
19673
|
-
return /* @__PURE__ */ (0,
|
|
19674
|
-
/* @__PURE__ */ (0,
|
|
19675
|
-
/* @__PURE__ */ (0,
|
|
20007
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("svg", { width: "18", height: "12", viewBox: "0 0 18 12", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
|
|
20008
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("rect", { x: "0.75", y: "0.75", width: "16.5", height: "10.5", rx: "3", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
20009
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M5.5 6H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
19676
20010
|
] });
|
|
19677
20011
|
}
|
|
19678
20012
|
function FeatureGlyph({ mode }) {
|
|
19679
|
-
return /* @__PURE__ */ (0,
|
|
19680
|
-
/* @__PURE__ */ (0,
|
|
19681
|
-
/* @__PURE__ */ (0,
|
|
19682
|
-
/* @__PURE__ */ (0,
|
|
19683
|
-
/* @__PURE__ */ (0,
|
|
19684
|
-
/* @__PURE__ */ (0,
|
|
19685
|
-
mode === "add" && /* @__PURE__ */ (0,
|
|
20013
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
|
|
20014
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("circle", { cx: "8", cy: "8", r: "7.25", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
20015
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M5 8.2L7.2 10.3L11 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
20016
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("circle", { cx: "13.5", cy: "13.5", r: "4.25", fill: "var(--ohw-background, #ffffff)", stroke: "var(--ohw-background, #ffffff)", strokeWidth: "1" }),
|
|
20017
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("circle", { cx: "13.5", cy: "13.5", r: "3.75", fill: "var(--ohw-background, #ffffff)", stroke: PRIMARY4, strokeWidth: "1" }),
|
|
20018
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M11.5 13.5H15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" }),
|
|
20019
|
+
mode === "add" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M13.5 11.5V15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" })
|
|
19686
20020
|
] });
|
|
19687
20021
|
}
|
|
19688
|
-
function
|
|
20022
|
+
function ToolbarAction2({
|
|
19689
20023
|
label,
|
|
19690
20024
|
onClick,
|
|
19691
20025
|
disabled = false,
|
|
19692
20026
|
children
|
|
19693
20027
|
}) {
|
|
19694
|
-
const button = /* @__PURE__ */ (0,
|
|
19695
|
-
return /* @__PURE__ */ (0,
|
|
19696
|
-
/* @__PURE__ */ (0,
|
|
19697
|
-
/* @__PURE__ */ (0,
|
|
20028
|
+
const button = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, onClick, className: "size-8", children });
|
|
20029
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Tooltip, { children: [
|
|
20030
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "inline-flex", children: button }) : button }),
|
|
20031
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
|
|
19698
20032
|
] });
|
|
19699
20033
|
}
|
|
19700
|
-
function
|
|
19701
|
-
return /* @__PURE__ */ (0,
|
|
20034
|
+
function ToolbarSeparator2() {
|
|
20035
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
|
|
19702
20036
|
}
|
|
19703
20037
|
function CardStyleMenu({
|
|
19704
20038
|
value,
|
|
@@ -19706,7 +20040,7 @@ function CardStyleMenu({
|
|
|
19706
20040
|
disabled = false
|
|
19707
20041
|
}) {
|
|
19708
20042
|
const current = PRICING_CARD_STYLES.find((s) => s.value === value) ?? PRICING_CARD_STYLES[0];
|
|
19709
|
-
const trigger = /* @__PURE__ */ (0,
|
|
20043
|
+
const trigger = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
19710
20044
|
"button",
|
|
19711
20045
|
{
|
|
19712
20046
|
type: "button",
|
|
@@ -19717,28 +20051,28 @@ function CardStyleMenu({
|
|
|
19717
20051
|
disabled && "cursor-not-allowed opacity-40 hover:bg-transparent"
|
|
19718
20052
|
),
|
|
19719
20053
|
children: [
|
|
19720
|
-
/* @__PURE__ */ (0,
|
|
19721
|
-
/* @__PURE__ */ (0,
|
|
19722
|
-
/* @__PURE__ */ (0,
|
|
20054
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(StyleSwatch, { style: current.value }),
|
|
20055
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "flex-1 text-left", children: current.label }),
|
|
20056
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.ChevronDown, { size: 16, style: { pointerEvents: "none" } })
|
|
19723
20057
|
]
|
|
19724
20058
|
}
|
|
19725
20059
|
);
|
|
19726
20060
|
if (disabled) {
|
|
19727
|
-
return /* @__PURE__ */ (0,
|
|
19728
|
-
/* @__PURE__ */ (0,
|
|
19729
|
-
/* @__PURE__ */ (0,
|
|
19730
|
-
/* @__PURE__ */ (0,
|
|
19731
|
-
/* @__PURE__ */ (0,
|
|
20061
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
20062
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
|
|
20063
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Tooltip, { children: [
|
|
20064
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "inline-flex", children: trigger }) }),
|
|
20065
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
|
|
19732
20066
|
] })
|
|
19733
20067
|
] });
|
|
19734
20068
|
}
|
|
19735
|
-
return /* @__PURE__ */ (0,
|
|
19736
|
-
/* @__PURE__ */ (0,
|
|
19737
|
-
/* @__PURE__ */ (0,
|
|
19738
|
-
/* @__PURE__ */ (0,
|
|
19739
|
-
/* @__PURE__ */ (0,
|
|
20069
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
20070
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
|
|
20071
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DropdownMenu, { modal: false, children: [
|
|
20072
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DropdownMenuTrigger, { asChild: true, children: trigger }),
|
|
20073
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
|
|
19740
20074
|
const selected = style.value === value;
|
|
19741
|
-
return /* @__PURE__ */ (0,
|
|
20075
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
19742
20076
|
DropdownMenuItem,
|
|
19743
20077
|
{
|
|
19744
20078
|
role: "menuitemradio",
|
|
@@ -19746,9 +20080,9 @@ function CardStyleMenu({
|
|
|
19746
20080
|
onSelect: () => onChange(style.value),
|
|
19747
20081
|
className: cn("grid grid-cols-[18px_1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
|
|
19748
20082
|
children: [
|
|
19749
|
-
/* @__PURE__ */ (0,
|
|
19750
|
-
/* @__PURE__ */ (0,
|
|
19751
|
-
selected && /* @__PURE__ */ (0,
|
|
20083
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(StyleSwatch, { style: style.value }),
|
|
20084
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: style.label }),
|
|
20085
|
+
selected && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.Check, { size: 16, className: "text-bridge-primary" })
|
|
19752
20086
|
]
|
|
19753
20087
|
},
|
|
19754
20088
|
style.value
|
|
@@ -19778,7 +20112,7 @@ function PricingCardToolbar({
|
|
|
19778
20112
|
const style = pricingCardStyle(entry.tree, index);
|
|
19779
20113
|
const featuredTag = pricingCardFeaturedTag(entry.tree, index);
|
|
19780
20114
|
const mobile = window.innerWidth <= 480;
|
|
19781
|
-
return /* @__PURE__ */ (0,
|
|
20115
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
19782
20116
|
"div",
|
|
19783
20117
|
{
|
|
19784
20118
|
"data-ohw-bridge": "",
|
|
@@ -19790,7 +20124,7 @@ function PricingCardToolbar({
|
|
|
19790
20124
|
),
|
|
19791
20125
|
style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
|
|
19792
20126
|
children: [
|
|
19793
|
-
/* @__PURE__ */ (0,
|
|
20127
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
19794
20128
|
"div",
|
|
19795
20129
|
{
|
|
19796
20130
|
className: cn(
|
|
@@ -19799,8 +20133,8 @@ function PricingCardToolbar({
|
|
|
19799
20133
|
mobile ? "flex-wrap justify-center" : "flex-nowrap"
|
|
19800
20134
|
),
|
|
19801
20135
|
children: [
|
|
19802
|
-
/* @__PURE__ */ (0,
|
|
19803
|
-
/* @__PURE__ */ (0,
|
|
20136
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Tooltip, { children: [
|
|
20137
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19804
20138
|
CustomToolbarButton,
|
|
19805
20139
|
{
|
|
19806
20140
|
type: "button",
|
|
@@ -19808,8 +20142,8 @@ function PricingCardToolbar({
|
|
|
19808
20142
|
"aria-pressed": featuredTag,
|
|
19809
20143
|
onClick: () => onSetFeaturedTag(!featuredTag),
|
|
19810
20144
|
className: "group size-8",
|
|
19811
|
-
children: /* @__PURE__ */ (0,
|
|
19812
|
-
|
|
20145
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
20146
|
+
import_lucide_react10.Star,
|
|
19813
20147
|
{
|
|
19814
20148
|
size: 16,
|
|
19815
20149
|
fill: "currentColor",
|
|
@@ -19823,25 +20157,25 @@ function PricingCardToolbar({
|
|
|
19823
20157
|
)
|
|
19824
20158
|
}
|
|
19825
20159
|
) }),
|
|
19826
|
-
/* @__PURE__ */ (0,
|
|
20160
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
|
|
19827
20161
|
] }),
|
|
19828
|
-
/* @__PURE__ */ (0,
|
|
19829
|
-
/* @__PURE__ */ (0,
|
|
19830
|
-
/* @__PURE__ */ (0,
|
|
19831
|
-
/* @__PURE__ */ (0,
|
|
19832
|
-
/* @__PURE__ */ (0,
|
|
19833
|
-
/* @__PURE__ */ (0,
|
|
19834
|
-
/* @__PURE__ */ (0,
|
|
20162
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarSeparator2, {}),
|
|
20163
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
|
|
20164
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarSeparator2, {}),
|
|
20165
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ButtonGlyph, {}) }),
|
|
20166
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "relative inline-flex", children: [
|
|
20167
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ButtonGlyph, {}),
|
|
20168
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.Minus, { size: 10, strokeWidth: 2.5, className: "absolute -right-1.5 -top-1.5 rounded-full bg-background text-bridge-primary" })
|
|
19835
20169
|
] }) }),
|
|
19836
|
-
/* @__PURE__ */ (0,
|
|
19837
|
-
/* @__PURE__ */ (0,
|
|
19838
|
-
/* @__PURE__ */ (0,
|
|
19839
|
-
/* @__PURE__ */ (0,
|
|
19840
|
-
/* @__PURE__ */ (0,
|
|
20170
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Add feature", onClick: onAddFeature, disabled: featureCount >= 10, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(FeatureGlyph, { mode: "add" }) }),
|
|
20171
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Remove feature", onClick: onRemoveFeature, disabled: featureCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(FeatureGlyph, { mode: "remove" }) }),
|
|
20172
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarSeparator2, {}),
|
|
20173
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Add tier", onClick: onAddTier, disabled: collectionCount >= 4, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.Plus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
20174
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Remove tier", onClick: onRemoveTier, disabled: collectionCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.Minus, { size: 16, style: { pointerEvents: "none" } }) })
|
|
19841
20175
|
]
|
|
19842
20176
|
}
|
|
19843
20177
|
),
|
|
19844
|
-
error && /* @__PURE__ */ (0,
|
|
20178
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
|
|
19845
20179
|
]
|
|
19846
20180
|
}
|
|
19847
20181
|
) });
|
|
@@ -19875,7 +20209,7 @@ function AiPricingCardOverlay({
|
|
|
19875
20209
|
const overEditable = Boolean(t?.closest?.("[data-ohw-editable], [data-ohw-role], a, button"));
|
|
19876
20210
|
setHover((prev) => {
|
|
19877
20211
|
const next = ref && !overEditable ? ref : null;
|
|
19878
|
-
return
|
|
20212
|
+
return sameRef2(prev, next) ? prev : next;
|
|
19879
20213
|
});
|
|
19880
20214
|
};
|
|
19881
20215
|
const onLeave = () => setHover(null);
|
|
@@ -19890,10 +20224,10 @@ function AiPricingCardOverlay({
|
|
|
19890
20224
|
const onClick = (e) => {
|
|
19891
20225
|
const t = e.target;
|
|
19892
20226
|
if (!(t instanceof Element)) return;
|
|
19893
|
-
if (t.closest(
|
|
20227
|
+
if (t.closest(CHROME_SELECTOR2)) return;
|
|
19894
20228
|
const ref = cardRefFromTarget(t);
|
|
19895
|
-
setActive((prev) =>
|
|
19896
|
-
if (!ref || !
|
|
20229
|
+
setActive((prev) => sameRef2(prev, ref) ? prev : ref);
|
|
20230
|
+
if (!ref || !sameRef2(activeRef.current, ref)) setError(null);
|
|
19897
20231
|
};
|
|
19898
20232
|
document.addEventListener("click", onClick, true);
|
|
19899
20233
|
return () => document.removeEventListener("click", onClick, true);
|
|
@@ -19958,12 +20292,12 @@ function AiPricingCardOverlay({
|
|
|
19958
20292
|
const activeEntry = active ? findEntry(active.sectionId) : null;
|
|
19959
20293
|
const activeCardRect = useLiveCardRect(active);
|
|
19960
20294
|
const activeGridRect = useLiveCardRect(active, true);
|
|
19961
|
-
const hoverRect = useLiveCardRect(hover && !
|
|
19962
|
-
return /* @__PURE__ */ (0,
|
|
19963
|
-
hoverRect && /* @__PURE__ */ (0,
|
|
19964
|
-
activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ (0,
|
|
19965
|
-
/* @__PURE__ */ (0,
|
|
19966
|
-
/* @__PURE__ */ (0,
|
|
20295
|
+
const hoverRect = useLiveCardRect(hover && !sameRef2(hover, active) ? hover : null);
|
|
20296
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
20297
|
+
hoverRect && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
|
|
20298
|
+
activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
20299
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ItemInteractionLayer, { rect: activeCardRect, state: "active-top" }),
|
|
20300
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GridToolbarSlot, { gridRect: activeGridRect, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19967
20301
|
PricingCardToolbar,
|
|
19968
20302
|
{
|
|
19969
20303
|
entry: activeEntry,
|
|
@@ -19991,7 +20325,7 @@ function AiPricingCardOverlay({
|
|
|
19991
20325
|
onRemoveFeature: () => runMutation(active.sectionId, (tree) => removePricingCardFeature(tree, active.index))
|
|
19992
20326
|
}
|
|
19993
20327
|
) }),
|
|
19994
|
-
/* @__PURE__ */ (0,
|
|
20328
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19995
20329
|
"div",
|
|
19996
20330
|
{
|
|
19997
20331
|
"data-ohw-bridge": "",
|
|
@@ -20013,7 +20347,7 @@ function AiPricingCardOverlay({
|
|
|
20013
20347
|
|
|
20014
20348
|
// src/ui/ai-section/AiVideoOverlay.tsx
|
|
20015
20349
|
var import_react12 = require("react");
|
|
20016
|
-
var
|
|
20350
|
+
var import_lucide_react11 = require("lucide-react");
|
|
20017
20351
|
|
|
20018
20352
|
// src/lib/ai-video-tree.ts
|
|
20019
20353
|
function resolveVideoBlock(tree, path) {
|
|
@@ -20046,48 +20380,20 @@ function setVideoId(tree, path, videoId) {
|
|
|
20046
20380
|
return true;
|
|
20047
20381
|
});
|
|
20048
20382
|
}
|
|
20049
|
-
function clearVideo(tree, path) {
|
|
20050
|
-
return withVideo(tree, path, (block) => {
|
|
20051
|
-
const slots = { ...block.slots };
|
|
20052
|
-
delete slots.videoId;
|
|
20053
|
-
block.slots = slots;
|
|
20054
|
-
return true;
|
|
20055
|
-
});
|
|
20056
|
-
}
|
|
20057
|
-
|
|
20058
|
-
// src/lib/youtube.ts
|
|
20059
|
-
var YOUTUBE_ID_PATTERN = /^[A-Za-z0-9_-]{11}$/;
|
|
20060
|
-
function extractYouTubeId(input) {
|
|
20061
|
-
const trimmed = input.trim();
|
|
20062
|
-
if (!trimmed) return null;
|
|
20063
|
-
if (YOUTUBE_ID_PATTERN.test(trimmed)) return trimmed;
|
|
20064
|
-
let url;
|
|
20065
|
-
try {
|
|
20066
|
-
url = new URL(trimmed);
|
|
20067
|
-
} catch {
|
|
20068
|
-
return null;
|
|
20069
|
-
}
|
|
20070
|
-
const host = url.hostname.replace(/^www\./, "");
|
|
20071
|
-
if (host !== "youtube.com" && host !== "m.youtube.com" && host !== "youtu.be" && host !== "youtube-nocookie.com") {
|
|
20072
|
-
return null;
|
|
20073
|
-
}
|
|
20074
|
-
let candidate = null;
|
|
20075
|
-
if (host === "youtu.be") {
|
|
20076
|
-
candidate = url.pathname.slice(1).split("/")[0] ?? null;
|
|
20077
|
-
} else if (url.pathname === "/watch") {
|
|
20078
|
-
candidate = url.searchParams.get("v");
|
|
20079
|
-
} else {
|
|
20080
|
-
const match = url.pathname.match(/^\/(?:embed|shorts)\/([^/]+)/);
|
|
20081
|
-
candidate = match ? match[1] : null;
|
|
20082
|
-
}
|
|
20083
|
-
return candidate && YOUTUBE_ID_PATTERN.test(candidate) ? candidate : null;
|
|
20383
|
+
function clearVideo(tree, path) {
|
|
20384
|
+
return withVideo(tree, path, (block) => {
|
|
20385
|
+
const slots = { ...block.slots };
|
|
20386
|
+
delete slots.videoId;
|
|
20387
|
+
block.slots = slots;
|
|
20388
|
+
return true;
|
|
20389
|
+
});
|
|
20084
20390
|
}
|
|
20085
20391
|
|
|
20086
20392
|
// src/ui/ai-section/AiVideoOverlay.tsx
|
|
20087
|
-
var
|
|
20393
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
20088
20394
|
var PRIMARY5 = "#0885FE";
|
|
20089
|
-
var
|
|
20090
|
-
var
|
|
20395
|
+
var OHW_BLUE = `var(--ohw-primary, ${PRIMARY5})`;
|
|
20396
|
+
var OHW_BLUE_DARK = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY5}) 60%, #000000)`;
|
|
20091
20397
|
function findVideoBlockElement(sectionId, path) {
|
|
20092
20398
|
const sectionEl = findByInstanceId(sectionId);
|
|
20093
20399
|
if (!sectionEl) return null;
|
|
@@ -20147,12 +20453,12 @@ function requestValidateTree3(postToParent2, tree) {
|
|
|
20147
20453
|
postToParent2({ type: "ow:ai-validate-tree-request", id, tree });
|
|
20148
20454
|
});
|
|
20149
20455
|
}
|
|
20150
|
-
function
|
|
20456
|
+
function Pill({
|
|
20151
20457
|
label,
|
|
20152
20458
|
onClick,
|
|
20153
20459
|
disabled
|
|
20154
20460
|
}) {
|
|
20155
|
-
return /* @__PURE__ */ (0,
|
|
20461
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20156
20462
|
"button",
|
|
20157
20463
|
{
|
|
20158
20464
|
type: "button",
|
|
@@ -20168,7 +20474,7 @@ function Pill2({
|
|
|
20168
20474
|
border: "none",
|
|
20169
20475
|
cursor: disabled ? "default" : "pointer",
|
|
20170
20476
|
background: "#ffffff",
|
|
20171
|
-
color:
|
|
20477
|
+
color: OHW_BLUE_DARK,
|
|
20172
20478
|
opacity: disabled ? 0.4 : 1,
|
|
20173
20479
|
fontSize: 12,
|
|
20174
20480
|
lineHeight: "16px",
|
|
@@ -20190,7 +20496,7 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
20190
20496
|
setDraft(value ? watchUrl(value) : "");
|
|
20191
20497
|
setInvalid(false);
|
|
20192
20498
|
}, [value]);
|
|
20193
|
-
const
|
|
20499
|
+
const commit2 = () => {
|
|
20194
20500
|
const next = draft.trim();
|
|
20195
20501
|
if (!next) {
|
|
20196
20502
|
setInvalid(false);
|
|
@@ -20211,8 +20517,8 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
20211
20517
|
onCommit(id);
|
|
20212
20518
|
}
|
|
20213
20519
|
};
|
|
20214
|
-
return /* @__PURE__ */ (0,
|
|
20215
|
-
/* @__PURE__ */ (0,
|
|
20520
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 4, width: "100%", maxWidth: 280 }, children: [
|
|
20521
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
20216
20522
|
"div",
|
|
20217
20523
|
{
|
|
20218
20524
|
style: {
|
|
@@ -20228,12 +20534,12 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
20228
20534
|
boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
|
|
20229
20535
|
},
|
|
20230
20536
|
children: [
|
|
20231
|
-
/* @__PURE__ */ (0,
|
|
20537
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20232
20538
|
"span",
|
|
20233
20539
|
{
|
|
20234
20540
|
style: {
|
|
20235
20541
|
flex: "0 0 auto",
|
|
20236
|
-
color:
|
|
20542
|
+
color: OHW_BLUE_DARK,
|
|
20237
20543
|
fontSize: 10,
|
|
20238
20544
|
lineHeight: "16px",
|
|
20239
20545
|
fontWeight: 700,
|
|
@@ -20243,14 +20549,14 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
20243
20549
|
children: "Video"
|
|
20244
20550
|
}
|
|
20245
20551
|
),
|
|
20246
|
-
/* @__PURE__ */ (0,
|
|
20552
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20247
20553
|
"input",
|
|
20248
20554
|
{
|
|
20249
20555
|
type: "text",
|
|
20250
20556
|
inputMode: "url",
|
|
20251
20557
|
value: draft,
|
|
20252
20558
|
onChange: (e) => handleChange(e.target.value),
|
|
20253
|
-
onBlur:
|
|
20559
|
+
onBlur: commit2,
|
|
20254
20560
|
onKeyDown: (e) => {
|
|
20255
20561
|
if (e.key === "Enter") e.currentTarget.blur();
|
|
20256
20562
|
if (e.key === "Escape") {
|
|
@@ -20280,7 +20586,7 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
20280
20586
|
]
|
|
20281
20587
|
}
|
|
20282
20588
|
),
|
|
20283
|
-
invalid && /* @__PURE__ */ (0,
|
|
20589
|
+
invalid && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, textAlign: "center" }, children: "That doesn't look like a YouTube link \u2014 try pasting the video URL again." })
|
|
20284
20590
|
] });
|
|
20285
20591
|
}
|
|
20286
20592
|
function VideoToolbar({
|
|
@@ -20290,7 +20596,7 @@ function VideoToolbar({
|
|
|
20290
20596
|
onSetVideoId,
|
|
20291
20597
|
onRemove
|
|
20292
20598
|
}) {
|
|
20293
|
-
return /* @__PURE__ */ (0,
|
|
20599
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
20294
20600
|
"div",
|
|
20295
20601
|
{
|
|
20296
20602
|
"data-ohw-bridge": "",
|
|
@@ -20302,7 +20608,7 @@ function VideoToolbar({
|
|
|
20302
20608
|
gap: 6,
|
|
20303
20609
|
alignItems: "center",
|
|
20304
20610
|
width: 280,
|
|
20305
|
-
background:
|
|
20611
|
+
background: OHW_BLUE,
|
|
20306
20612
|
padding: 8,
|
|
20307
20613
|
borderRadius: 12,
|
|
20308
20614
|
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
@@ -20310,9 +20616,9 @@ function VideoToolbar({
|
|
|
20310
20616
|
opacity: pending ? 0.6 : 1
|
|
20311
20617
|
},
|
|
20312
20618
|
children: [
|
|
20313
|
-
/* @__PURE__ */ (0,
|
|
20314
|
-
/* @__PURE__ */ (0,
|
|
20315
|
-
error && /* @__PURE__ */ (0,
|
|
20619
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(VideoUrlInput, { value: videoId, onCommit: onSetVideoId }),
|
|
20620
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Pill, { label: "Remove video", onClick: onRemove, disabled: !videoId }),
|
|
20621
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
|
|
20316
20622
|
]
|
|
20317
20623
|
}
|
|
20318
20624
|
);
|
|
@@ -20432,8 +20738,8 @@ function AiVideoOverlay({
|
|
|
20432
20738
|
const activeBlockRect = useLiveBlockRect(active);
|
|
20433
20739
|
const TOOLBAR_APPROX_H = 90;
|
|
20434
20740
|
const toolbarState = activeBlockRect && activeBlockRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
|
|
20435
|
-
return /* @__PURE__ */ (0,
|
|
20436
|
-
hoverHandleRect && hover && /* @__PURE__ */ (0,
|
|
20741
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
20742
|
+
hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20437
20743
|
"button",
|
|
20438
20744
|
{
|
|
20439
20745
|
type: "button",
|
|
@@ -20461,15 +20767,15 @@ function AiVideoOverlay({
|
|
|
20461
20767
|
fontSize: 14,
|
|
20462
20768
|
fontWeight: 700
|
|
20463
20769
|
},
|
|
20464
|
-
children: /* @__PURE__ */ (0,
|
|
20770
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.Star, { size: 14, style: { pointerEvents: "none" } })
|
|
20465
20771
|
}
|
|
20466
20772
|
),
|
|
20467
|
-
activeBlockRect && active && activeEntry && /* @__PURE__ */ (0,
|
|
20773
|
+
activeBlockRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20468
20774
|
ItemInteractionLayer,
|
|
20469
20775
|
{
|
|
20470
20776
|
rect: activeBlockRect,
|
|
20471
20777
|
state: toolbarState,
|
|
20472
|
-
toolbar: /* @__PURE__ */ (0,
|
|
20778
|
+
toolbar: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20473
20779
|
VideoToolbar,
|
|
20474
20780
|
{
|
|
20475
20781
|
videoId: videoIdAt(activeEntry.tree, active.path),
|
|
@@ -20493,7 +20799,7 @@ function AiVideoOverlay({
|
|
|
20493
20799
|
|
|
20494
20800
|
// src/ui/ai-section/AiFadeCarouselOverlay.tsx
|
|
20495
20801
|
var import_react13 = require("react");
|
|
20496
|
-
var
|
|
20802
|
+
var import_lucide_react12 = require("lucide-react");
|
|
20497
20803
|
|
|
20498
20804
|
// src/lib/ai-carousel-tree.ts
|
|
20499
20805
|
function isCarouselBlock(node) {
|
|
@@ -20544,10 +20850,10 @@ function setCarouselAutoplay(tree, on) {
|
|
|
20544
20850
|
}
|
|
20545
20851
|
|
|
20546
20852
|
// src/ui/ai-section/AiFadeCarouselOverlay.tsx
|
|
20547
|
-
var
|
|
20853
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
20548
20854
|
var PRIMARY6 = "#0885FE";
|
|
20549
|
-
var
|
|
20550
|
-
var
|
|
20855
|
+
var OHW_BLUE2 = `var(--ohw-primary, ${PRIMARY6})`;
|
|
20856
|
+
var OHW_BLUE_DARK2 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY6}) 60%, #000000)`;
|
|
20551
20857
|
function findCarouselItemElement(sectionId, index) {
|
|
20552
20858
|
const sectionEl = findByInstanceId(sectionId);
|
|
20553
20859
|
if (!sectionEl) return null;
|
|
@@ -20626,8 +20932,8 @@ function requestAssetPick2(postToParent2) {
|
|
|
20626
20932
|
postToParent2({ type: "ow:asset-pick", id });
|
|
20627
20933
|
});
|
|
20628
20934
|
}
|
|
20629
|
-
function
|
|
20630
|
-
return /* @__PURE__ */ (0,
|
|
20935
|
+
function Pill2({ label, onClick, disabled }) {
|
|
20936
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
20631
20937
|
"button",
|
|
20632
20938
|
{
|
|
20633
20939
|
type: "button",
|
|
@@ -20643,7 +20949,7 @@ function Pill3({ label, onClick, disabled }) {
|
|
|
20643
20949
|
border: "none",
|
|
20644
20950
|
cursor: disabled ? "default" : "pointer",
|
|
20645
20951
|
background: "#ffffff",
|
|
20646
|
-
color:
|
|
20952
|
+
color: OHW_BLUE_DARK2,
|
|
20647
20953
|
opacity: disabled ? 0.4 : 1,
|
|
20648
20954
|
fontSize: 12,
|
|
20649
20955
|
lineHeight: "16px",
|
|
@@ -20661,7 +20967,7 @@ function TogglePill({
|
|
|
20661
20967
|
onToggle,
|
|
20662
20968
|
disabled
|
|
20663
20969
|
}) {
|
|
20664
|
-
return /* @__PURE__ */ (0,
|
|
20970
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
20665
20971
|
"button",
|
|
20666
20972
|
{
|
|
20667
20973
|
type: "button",
|
|
@@ -20680,7 +20986,7 @@ function TogglePill({
|
|
|
20680
20986
|
border: "none",
|
|
20681
20987
|
cursor: disabled ? "default" : "pointer",
|
|
20682
20988
|
background: "#ffffff",
|
|
20683
|
-
color:
|
|
20989
|
+
color: OHW_BLUE_DARK2,
|
|
20684
20990
|
opacity: disabled ? 0.4 : 1,
|
|
20685
20991
|
fontSize: 12,
|
|
20686
20992
|
lineHeight: "16px",
|
|
@@ -20690,7 +20996,7 @@ function TogglePill({
|
|
|
20690
20996
|
},
|
|
20691
20997
|
children: [
|
|
20692
20998
|
label,
|
|
20693
|
-
/* @__PURE__ */ (0,
|
|
20999
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
20694
21000
|
"span",
|
|
20695
21001
|
{
|
|
20696
21002
|
"aria-hidden": true,
|
|
@@ -20703,10 +21009,10 @@ function TogglePill({
|
|
|
20703
21009
|
// Off is a grey track, not a washed-out blue: the pill's own white background already
|
|
20704
21010
|
// carries the brand colour in the text, and a pale blue track next to it read as
|
|
20705
21011
|
// "disabled control" rather than "switch that is off".
|
|
20706
|
-
background: on ?
|
|
21012
|
+
background: on ? OHW_BLUE_DARK2 : "#CBD5E1",
|
|
20707
21013
|
transition: "background 120ms ease"
|
|
20708
21014
|
},
|
|
20709
|
-
children: /* @__PURE__ */ (0,
|
|
21015
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
20710
21016
|
"span",
|
|
20711
21017
|
{
|
|
20712
21018
|
style: {
|
|
@@ -20735,7 +21041,7 @@ function CarouselSlideToolbar({
|
|
|
20735
21041
|
onChangeImage,
|
|
20736
21042
|
onToggleAutoplay
|
|
20737
21043
|
}) {
|
|
20738
|
-
return /* @__PURE__ */ (0,
|
|
21044
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
20739
21045
|
"div",
|
|
20740
21046
|
{
|
|
20741
21047
|
"data-ohw-bridge": "",
|
|
@@ -20746,7 +21052,7 @@ function CarouselSlideToolbar({
|
|
|
20746
21052
|
flexDirection: "column",
|
|
20747
21053
|
gap: 6,
|
|
20748
21054
|
alignItems: "center",
|
|
20749
|
-
background:
|
|
21055
|
+
background: OHW_BLUE2,
|
|
20750
21056
|
padding: 8,
|
|
20751
21057
|
borderRadius: 12,
|
|
20752
21058
|
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
@@ -20758,11 +21064,11 @@ function CarouselSlideToolbar({
|
|
|
20758
21064
|
pointerEvents: pending ? "none" : "auto"
|
|
20759
21065
|
},
|
|
20760
21066
|
children: [
|
|
20761
|
-
/* @__PURE__ */ (0,
|
|
20762
|
-
/* @__PURE__ */ (0,
|
|
20763
|
-
/* @__PURE__ */ (0,
|
|
21067
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
|
|
21068
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Pill2, { label: "Change Image", onClick: onChangeImage }),
|
|
21069
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
|
|
20764
21070
|
] }),
|
|
20765
|
-
error && /* @__PURE__ */ (0,
|
|
21071
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
|
|
20766
21072
|
]
|
|
20767
21073
|
}
|
|
20768
21074
|
);
|
|
@@ -20902,8 +21208,8 @@ function AiFadeCarouselOverlay({
|
|
|
20902
21208
|
const activeItemRect = useLiveItemRect2(active);
|
|
20903
21209
|
const TOOLBAR_APPROX_H = 90;
|
|
20904
21210
|
const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
|
|
20905
|
-
return /* @__PURE__ */ (0,
|
|
20906
|
-
hoverHandleRect && hover && /* @__PURE__ */ (0,
|
|
21211
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
21212
|
+
hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
20907
21213
|
"button",
|
|
20908
21214
|
{
|
|
20909
21215
|
type: "button",
|
|
@@ -20932,10 +21238,10 @@ function AiFadeCarouselOverlay({
|
|
|
20932
21238
|
fontSize: 14,
|
|
20933
21239
|
fontWeight: 700
|
|
20934
21240
|
},
|
|
20935
|
-
children: /* @__PURE__ */ (0,
|
|
21241
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.Star, { size: 14, style: { pointerEvents: "none" } })
|
|
20936
21242
|
}
|
|
20937
21243
|
),
|
|
20938
|
-
swapping && /* @__PURE__ */ (0,
|
|
21244
|
+
swapping && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
20939
21245
|
"div",
|
|
20940
21246
|
{
|
|
20941
21247
|
ref: skeletonRef,
|
|
@@ -20953,15 +21259,15 @@ function AiFadeCarouselOverlay({
|
|
|
20953
21259
|
zIndex: 2147483646,
|
|
20954
21260
|
pointerEvents: "none"
|
|
20955
21261
|
},
|
|
20956
|
-
children: /* @__PURE__ */ (0,
|
|
21262
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("style", { children: MEDIA_SKELETON_CSS })
|
|
20957
21263
|
}
|
|
20958
21264
|
),
|
|
20959
|
-
activeItemRect && active && activeEntry && /* @__PURE__ */ (0,
|
|
21265
|
+
activeItemRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
20960
21266
|
ItemInteractionLayer,
|
|
20961
21267
|
{
|
|
20962
21268
|
rect: activeItemRect,
|
|
20963
21269
|
state: toolbarState,
|
|
20964
|
-
toolbar: /* @__PURE__ */ (0,
|
|
21270
|
+
toolbar: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
20965
21271
|
CarouselSlideToolbar,
|
|
20966
21272
|
{
|
|
20967
21273
|
pending,
|
|
@@ -21179,113 +21485,6 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
|
|
|
21179
21485
|
// src/ui/link-modal/LinkPopover.tsx
|
|
21180
21486
|
var import_react17 = require("react");
|
|
21181
21487
|
|
|
21182
|
-
// src/ui/dialog.tsx
|
|
21183
|
-
var React9 = __toESM(require("react"), 1);
|
|
21184
|
-
var import_radix_ui6 = require("radix-ui");
|
|
21185
|
-
var import_lucide_react12 = require("lucide-react");
|
|
21186
|
-
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
21187
|
-
function Dialog2({
|
|
21188
|
-
...props
|
|
21189
|
-
}) {
|
|
21190
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_radix_ui6.Dialog.Root, { "data-slot": "dialog", ...props });
|
|
21191
|
-
}
|
|
21192
|
-
function DialogPortal({
|
|
21193
|
-
...props
|
|
21194
|
-
}) {
|
|
21195
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_radix_ui6.Dialog.Portal, { ...props });
|
|
21196
|
-
}
|
|
21197
|
-
function DialogOverlay({
|
|
21198
|
-
className,
|
|
21199
|
-
...props
|
|
21200
|
-
}) {
|
|
21201
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
21202
|
-
import_radix_ui6.Dialog.Overlay,
|
|
21203
|
-
{
|
|
21204
|
-
"data-slot": "dialog-overlay",
|
|
21205
|
-
"data-ohw-link-modal-root": "",
|
|
21206
|
-
className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
|
|
21207
|
-
...props
|
|
21208
|
-
}
|
|
21209
|
-
);
|
|
21210
|
-
}
|
|
21211
|
-
var DialogContent = React9.forwardRef(
|
|
21212
|
-
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
21213
|
-
const positionMode = container ? "absolute" : "fixed";
|
|
21214
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DialogPortal, { container: container ?? void 0, children: [
|
|
21215
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
21216
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
21217
|
-
import_radix_ui6.Dialog.Content,
|
|
21218
|
-
{
|
|
21219
|
-
ref,
|
|
21220
|
-
"data-slot": "dialog-content",
|
|
21221
|
-
className: cn(
|
|
21222
|
-
positionMode,
|
|
21223
|
-
"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",
|
|
21224
|
-
"rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
|
|
21225
|
-
container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
|
|
21226
|
-
className
|
|
21227
|
-
),
|
|
21228
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
21229
|
-
...props,
|
|
21230
|
-
children: [
|
|
21231
|
-
children,
|
|
21232
|
-
showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
21233
|
-
import_radix_ui6.Dialog.Close,
|
|
21234
|
-
{
|
|
21235
|
-
type: "button",
|
|
21236
|
-
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
21237
|
-
"aria-label": "Close",
|
|
21238
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.X, { size: 16, "aria-hidden": true })
|
|
21239
|
-
}
|
|
21240
|
-
) : null
|
|
21241
|
-
]
|
|
21242
|
-
}
|
|
21243
|
-
)
|
|
21244
|
-
] });
|
|
21245
|
-
}
|
|
21246
|
-
);
|
|
21247
|
-
DialogContent.displayName = import_radix_ui6.Dialog.Content.displayName;
|
|
21248
|
-
function DialogHeader({
|
|
21249
|
-
className,
|
|
21250
|
-
...props
|
|
21251
|
-
}) {
|
|
21252
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
21253
|
-
}
|
|
21254
|
-
function DialogFooter({
|
|
21255
|
-
className,
|
|
21256
|
-
...props
|
|
21257
|
-
}) {
|
|
21258
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
21259
|
-
"div",
|
|
21260
|
-
{
|
|
21261
|
-
className: cn("flex items-center justify-end gap-2", className),
|
|
21262
|
-
...props
|
|
21263
|
-
}
|
|
21264
|
-
);
|
|
21265
|
-
}
|
|
21266
|
-
var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
21267
|
-
import_radix_ui6.Dialog.Title,
|
|
21268
|
-
{
|
|
21269
|
-
ref,
|
|
21270
|
-
className: cn(
|
|
21271
|
-
"text-lg font-semibold leading-none tracking-tight text-card-foreground",
|
|
21272
|
-
className
|
|
21273
|
-
),
|
|
21274
|
-
...props
|
|
21275
|
-
}
|
|
21276
|
-
));
|
|
21277
|
-
DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
|
|
21278
|
-
var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
21279
|
-
import_radix_ui6.Dialog.Description,
|
|
21280
|
-
{
|
|
21281
|
-
ref,
|
|
21282
|
-
className: cn("text-sm text-muted-foreground", className),
|
|
21283
|
-
...props
|
|
21284
|
-
}
|
|
21285
|
-
));
|
|
21286
|
-
DialogDescription.displayName = import_radix_ui6.Dialog.Description.displayName;
|
|
21287
|
-
var DialogClose = import_radix_ui6.Dialog.Close;
|
|
21288
|
-
|
|
21289
21488
|
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
21290
21489
|
var import_lucide_react16 = require("lucide-react");
|
|
21291
21490
|
|
|
@@ -22389,6 +22588,7 @@ function shouldUseDevFixtures() {
|
|
|
22389
22588
|
function getLogoElement(el) {
|
|
22390
22589
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
22391
22590
|
if (marked) return marked;
|
|
22591
|
+
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
22392
22592
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
22393
22593
|
if (!root) return null;
|
|
22394
22594
|
const anchor = el.closest("a");
|
|
@@ -24083,6 +24283,102 @@ function deleteSelectedNavFooterItem(deps) {
|
|
|
24083
24283
|
return false;
|
|
24084
24284
|
}
|
|
24085
24285
|
|
|
24286
|
+
// src/lib/nav-page-sync.ts
|
|
24287
|
+
function labelKeyFor(hrefKey) {
|
|
24288
|
+
return hrefKey.replace(/-href$/, "-label");
|
|
24289
|
+
}
|
|
24290
|
+
function isPageLinkKey(key) {
|
|
24291
|
+
return isNavbarHrefKey(key) || isFooterHrefKey(key);
|
|
24292
|
+
}
|
|
24293
|
+
function currentHref(key, anchor, content) {
|
|
24294
|
+
const stored = content[key];
|
|
24295
|
+
if (typeof stored === "string" && stored.length > 0) return stored;
|
|
24296
|
+
return anchor.getAttribute("href") ?? "";
|
|
24297
|
+
}
|
|
24298
|
+
function normalizePath2(value) {
|
|
24299
|
+
if (value.length > 1 && value.endsWith("/")) return value.slice(0, -1);
|
|
24300
|
+
return value;
|
|
24301
|
+
}
|
|
24302
|
+
function pointsAt(href, path) {
|
|
24303
|
+
const normalized = normalizePath2(href);
|
|
24304
|
+
const target = normalizePath2(path);
|
|
24305
|
+
if (normalized === target) return true;
|
|
24306
|
+
return (normalized.startsWith(`${target}#`) || normalized.startsWith(`${target}?`)) && target !== "/";
|
|
24307
|
+
}
|
|
24308
|
+
function retargetHref(href, oldPath, newPath) {
|
|
24309
|
+
const normalized = normalizePath2(href);
|
|
24310
|
+
const target = normalizePath2(oldPath);
|
|
24311
|
+
if (normalized === target) return newPath;
|
|
24312
|
+
return `${newPath}${normalized.slice(target.length)}`;
|
|
24313
|
+
}
|
|
24314
|
+
function setLabelText(key, text) {
|
|
24315
|
+
document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`).forEach((el) => {
|
|
24316
|
+
el.textContent = text;
|
|
24317
|
+
});
|
|
24318
|
+
}
|
|
24319
|
+
function commit(delta, deps) {
|
|
24320
|
+
if (Object.keys(delta).length === 0) return;
|
|
24321
|
+
deps.setEditContent({ ...deps.getEditContent(), ...delta });
|
|
24322
|
+
deps.postToParent({
|
|
24323
|
+
type: "ow:change",
|
|
24324
|
+
nodes: Object.entries(delta).map(([key, text]) => ({ key, text }))
|
|
24325
|
+
});
|
|
24326
|
+
}
|
|
24327
|
+
function navLinksTo(path, content) {
|
|
24328
|
+
return Array.from(document.querySelectorAll("[data-ohw-href-key]")).filter((anchor) => {
|
|
24329
|
+
const key = anchor.getAttribute("data-ohw-href-key");
|
|
24330
|
+
return isNavbarHrefKey(key) && pointsAt(currentHref(key, anchor, content), path);
|
|
24331
|
+
}).map((anchor) => anchor.getAttribute("data-ohw-href-key"));
|
|
24332
|
+
}
|
|
24333
|
+
function addNavLinkForPage(page, deps) {
|
|
24334
|
+
const content = deps.getEditContent();
|
|
24335
|
+
if (navLinksTo(page.path, content).length > 0) return false;
|
|
24336
|
+
const roots = listNavbarRootItems();
|
|
24337
|
+
const afterAnchor = roots[roots.length - 1] ?? null;
|
|
24338
|
+
let inserted;
|
|
24339
|
+
try {
|
|
24340
|
+
inserted = insertNavbarItem(page.path, page.title, afterAnchor);
|
|
24341
|
+
} catch {
|
|
24342
|
+
return false;
|
|
24343
|
+
}
|
|
24344
|
+
const { hrefKey, labelKey, index } = inserted;
|
|
24345
|
+
deps.applyLinkByKey(hrefKey, page.path);
|
|
24346
|
+
setLabelText(labelKey, page.title);
|
|
24347
|
+
commit(
|
|
24348
|
+
{
|
|
24349
|
+
[hrefKey]: page.path,
|
|
24350
|
+
[labelKey]: page.title,
|
|
24351
|
+
[NAV_COUNT_KEY]: String(index + 1),
|
|
24352
|
+
[NAV_ORDER_KEY]: getNavbarOrderJson()
|
|
24353
|
+
},
|
|
24354
|
+
deps
|
|
24355
|
+
);
|
|
24356
|
+
return true;
|
|
24357
|
+
}
|
|
24358
|
+
function retargetPageLinks(change, deps) {
|
|
24359
|
+
const { oldPath, newPath, oldTitle, newTitle } = change;
|
|
24360
|
+
if (!oldPath || !newPath || normalizePath2(oldPath) === normalizePath2(newPath)) return 0;
|
|
24361
|
+
const content = deps.getEditContent();
|
|
24362
|
+
const delta = {};
|
|
24363
|
+
for (const anchor of Array.from(document.querySelectorAll("[data-ohw-href-key]"))) {
|
|
24364
|
+
const hrefKey = anchor.getAttribute("data-ohw-href-key");
|
|
24365
|
+
if (!isPageLinkKey(hrefKey)) continue;
|
|
24366
|
+
const href = currentHref(hrefKey, anchor, content);
|
|
24367
|
+
if (!pointsAt(href, oldPath)) continue;
|
|
24368
|
+
const nextHref = retargetHref(href, oldPath, newPath);
|
|
24369
|
+
deps.applyLinkByKey(hrefKey, nextHref);
|
|
24370
|
+
delta[hrefKey] = nextHref;
|
|
24371
|
+
if (!oldTitle || !newTitle) continue;
|
|
24372
|
+
const labelKey = labelKeyFor(hrefKey);
|
|
24373
|
+
const label = content[labelKey] ?? anchor.querySelector('[data-ohw-editable="text"]')?.textContent ?? "";
|
|
24374
|
+
if (label.trim() !== oldTitle) continue;
|
|
24375
|
+
setLabelText(labelKey, newTitle);
|
|
24376
|
+
delta[labelKey] = newTitle;
|
|
24377
|
+
}
|
|
24378
|
+
commit(delta, deps);
|
|
24379
|
+
return Object.keys(delta).filter((key) => key.endsWith("-href")).length;
|
|
24380
|
+
}
|
|
24381
|
+
|
|
24086
24382
|
// src/ui/navbar-container-chrome.tsx
|
|
24087
24383
|
var import_lucide_react21 = require("lucide-react");
|
|
24088
24384
|
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
@@ -24970,7 +25266,7 @@ function getNavigationSelectionParent(el) {
|
|
|
24970
25266
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
24971
25267
|
return resolveFooterLinksContainerFrom(el);
|
|
24972
25268
|
}
|
|
24973
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
25269
|
+
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isFooterLinksContainer(el) || isInferredFooterGroup2(el)) {
|
|
24974
25270
|
return getNavigationRoot(el);
|
|
24975
25271
|
}
|
|
24976
25272
|
return null;
|
|
@@ -25192,7 +25488,6 @@ var ICONS = {
|
|
|
25192
25488
|
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"/>',
|
|
25193
25489
|
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"/>'
|
|
25194
25490
|
};
|
|
25195
|
-
var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
|
|
25196
25491
|
var SELECTION_CHROME_GAP2 = 4;
|
|
25197
25492
|
var TOOLBAR_STROKE_GAP2 = 4;
|
|
25198
25493
|
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
@@ -25290,7 +25585,7 @@ function applyVisibleViewport(el, parentScroll) {
|
|
|
25290
25585
|
el.style.top = `${top}px`;
|
|
25291
25586
|
el.style.height = `${height}px`;
|
|
25292
25587
|
}
|
|
25293
|
-
var
|
|
25588
|
+
var TOOLBAR_EDGE_MARGIN4 = 4;
|
|
25294
25589
|
function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
25295
25590
|
const isAbove = transform.includes("translateY(-100%)");
|
|
25296
25591
|
let visualTop = isAbove ? top - approxH : top;
|
|
@@ -25317,8 +25612,8 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
|
25317
25612
|
function clampToolbarLeft(centerX, toolbarWidth) {
|
|
25318
25613
|
const half = toolbarWidth / 2;
|
|
25319
25614
|
return Math.max(
|
|
25320
|
-
|
|
25321
|
-
Math.min(centerX, window.innerWidth -
|
|
25615
|
+
TOOLBAR_EDGE_MARGIN4 + half,
|
|
25616
|
+
Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN4 - half)
|
|
25322
25617
|
);
|
|
25323
25618
|
}
|
|
25324
25619
|
function calcToolbarPos(rect, parentScroll, toolbarW = 306) {
|
|
@@ -26198,21 +26493,6 @@ function OhhwellsBridge() {
|
|
|
26198
26493
|
const [isItemDragging, setIsItemDragging] = (0, import_react21.useState)(false);
|
|
26199
26494
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react21.useState)(false);
|
|
26200
26495
|
isFooterFrameSelectionRef.current = isFooterFrameSelection;
|
|
26201
|
-
const [floatingPanel, setFloatingPanel] = (0, import_react21.useState)(null);
|
|
26202
|
-
const floatingPanelOpenRef = (0, import_react21.useRef)(false);
|
|
26203
|
-
floatingPanelOpenRef.current = floatingPanel !== null;
|
|
26204
|
-
const floatingPanelRef = (0, import_react21.useRef)(null);
|
|
26205
|
-
floatingPanelRef.current = floatingPanel;
|
|
26206
|
-
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react21.useState)(null);
|
|
26207
|
-
const buttonCollectionDragRef = (0, import_react21.useRef)(null);
|
|
26208
|
-
const buttonDropInsertIndexRef = (0, import_react21.useRef)(null);
|
|
26209
|
-
const [buttonDropSlots, setButtonDropSlots] = (0, import_react21.useState)([]);
|
|
26210
|
-
const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react21.useState)(null);
|
|
26211
|
-
const buttonPointerDragRef = (0, import_react21.useRef)(null);
|
|
26212
|
-
const [buttonStyleTick, setButtonStyleTick] = (0, import_react21.useState)(0);
|
|
26213
|
-
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react21.useState)(null);
|
|
26214
|
-
const [editorViewport, setEditorViewport] = (0, import_react21.useState)("desktop");
|
|
26215
|
-
const [parentScrollSnap, setParentScrollSnap] = (0, import_react21.useState)(null);
|
|
26216
26496
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react21.useState)(null);
|
|
26217
26497
|
const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react21.useState)(null);
|
|
26218
26498
|
const footerDragRef = (0, import_react21.useRef)(null);
|
|
@@ -26238,6 +26518,21 @@ function OhhwellsBridge() {
|
|
|
26238
26518
|
const stylesRef = (0, import_react21.useRef)("");
|
|
26239
26519
|
const appliedDrawerRef = (0, import_react21.useRef)(null);
|
|
26240
26520
|
const pendingDeleteUndoRef = (0, import_react21.useRef)(null);
|
|
26521
|
+
const [floatingPanel, setFloatingPanel] = (0, import_react21.useState)(null);
|
|
26522
|
+
const floatingPanelOpenRef = (0, import_react21.useRef)(false);
|
|
26523
|
+
const floatingPanelRef = (0, import_react21.useRef)(null);
|
|
26524
|
+
floatingPanelRef.current = floatingPanel;
|
|
26525
|
+
const setFloatingPanelRef = (0, import_react21.useRef)(setFloatingPanel);
|
|
26526
|
+
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react21.useState)(null);
|
|
26527
|
+
const buttonCollectionDragRef = (0, import_react21.useRef)(null);
|
|
26528
|
+
const buttonDropInsertIndexRef = (0, import_react21.useRef)(null);
|
|
26529
|
+
const [buttonDropSlots, setButtonDropSlots] = (0, import_react21.useState)([]);
|
|
26530
|
+
const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react21.useState)(null);
|
|
26531
|
+
const buttonPointerDragRef = (0, import_react21.useRef)(null);
|
|
26532
|
+
const [buttonStyleTick, setButtonStyleTick] = (0, import_react21.useState)(0);
|
|
26533
|
+
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react21.useState)(null);
|
|
26534
|
+
const [editorViewport, setEditorViewport] = (0, import_react21.useState)("desktop");
|
|
26535
|
+
const [parentScrollSnap, setParentScrollSnap] = (0, import_react21.useState)(null);
|
|
26241
26536
|
const [sitePages, setSitePages] = (0, import_react21.useState)([]);
|
|
26242
26537
|
const collectionItemsRef = (0, import_react21.useRef)(/* @__PURE__ */ new Map());
|
|
26243
26538
|
const [sectionsByPath, setSectionsByPath] = (0, import_react21.useState)({});
|
|
@@ -26247,7 +26542,18 @@ function OhhwellsBridge() {
|
|
|
26247
26542
|
const linkPopoverOpenRef = (0, import_react21.useRef)(false);
|
|
26248
26543
|
const linkPopoverGraceUntilRef = (0, import_react21.useRef)(0);
|
|
26249
26544
|
setLinkPopoverRef.current = setLinkPopover;
|
|
26545
|
+
setFloatingPanelRef.current = setFloatingPanel;
|
|
26250
26546
|
linkPopoverSessionRef.current = linkPopover;
|
|
26547
|
+
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
26548
|
+
(0, import_react21.useEffect)(() => {
|
|
26549
|
+
const syncViewport = () => {
|
|
26550
|
+
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
26551
|
+
setEditorViewport((prev) => prev === next ? prev : next);
|
|
26552
|
+
};
|
|
26553
|
+
syncViewport();
|
|
26554
|
+
window.addEventListener("resize", syncViewport);
|
|
26555
|
+
return () => window.removeEventListener("resize", syncViewport);
|
|
26556
|
+
}, []);
|
|
26251
26557
|
(0, import_react21.useEffect)(() => {
|
|
26252
26558
|
setSectionOrderPersistHandler((entries) => {
|
|
26253
26559
|
const currentPath = window.location.pathname;
|
|
@@ -26396,6 +26702,43 @@ function OhhwellsBridge() {
|
|
|
26396
26702
|
if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
|
|
26397
26703
|
return () => window.removeEventListener("message", onSitePages);
|
|
26398
26704
|
}, [isEditMode, postToParent2]);
|
|
26705
|
+
(0, import_react21.useEffect)(() => {
|
|
26706
|
+
if (!isEditMode) return;
|
|
26707
|
+
const deps = {
|
|
26708
|
+
getEditContent: () => editContentRef.current,
|
|
26709
|
+
setEditContent: (next) => {
|
|
26710
|
+
editContentRef.current = next;
|
|
26711
|
+
},
|
|
26712
|
+
applyLinkByKey,
|
|
26713
|
+
postToParent: postToParent2
|
|
26714
|
+
};
|
|
26715
|
+
const onPageMessage = (e) => {
|
|
26716
|
+
if (e.data?.type === "ow:page-created") {
|
|
26717
|
+
const { path, title } = e.data;
|
|
26718
|
+
if (typeof path !== "string" || !path) return;
|
|
26719
|
+
if (addNavLinkForPage({ path, title: typeof title === "string" && title ? title : path }, deps)) {
|
|
26720
|
+
enforceLinkHrefs();
|
|
26721
|
+
}
|
|
26722
|
+
return;
|
|
26723
|
+
}
|
|
26724
|
+
if (e.data?.type === "ow:page-renamed") {
|
|
26725
|
+
const { oldPath, newPath, oldTitle, newTitle } = e.data;
|
|
26726
|
+
if (typeof oldPath !== "string" || typeof newPath !== "string") return;
|
|
26727
|
+
const moved = retargetPageLinks(
|
|
26728
|
+
{
|
|
26729
|
+
oldPath,
|
|
26730
|
+
newPath,
|
|
26731
|
+
oldTitle: typeof oldTitle === "string" ? oldTitle : void 0,
|
|
26732
|
+
newTitle: typeof newTitle === "string" ? newTitle : void 0
|
|
26733
|
+
},
|
|
26734
|
+
deps
|
|
26735
|
+
);
|
|
26736
|
+
if (moved > 0) enforceLinkHrefs();
|
|
26737
|
+
}
|
|
26738
|
+
};
|
|
26739
|
+
window.addEventListener("message", onPageMessage);
|
|
26740
|
+
return () => window.removeEventListener("message", onPageMessage);
|
|
26741
|
+
}, [isEditMode, postToParent2]);
|
|
26399
26742
|
(0, import_react21.useEffect)(() => {
|
|
26400
26743
|
if (!isEditMode || shouldUseDevFixtures()) return;
|
|
26401
26744
|
void loadAllSectionsManifest().then((manifest) => {
|
|
@@ -27944,6 +28287,7 @@ function OhhwellsBridge() {
|
|
|
27944
28287
|
applyAiFooterFromContent(content);
|
|
27945
28288
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
27946
28289
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
28290
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
27947
28291
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
27948
28292
|
}
|
|
27949
28293
|
applyBrandChrome(content);
|
|
@@ -27954,15 +28298,16 @@ function OhhwellsBridge() {
|
|
|
27954
28298
|
if (key === "__ohw_sections") continue;
|
|
27955
28299
|
if (key === AI_SECTIONS_KEY) continue;
|
|
27956
28300
|
if (key === AI_FOOTER_KEY) continue;
|
|
28301
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
28302
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27957
28303
|
if (key === BRAND_KIT_KEY) continue;
|
|
27958
28304
|
if (key === STYLE_STORE_KEY) continue;
|
|
27959
28305
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
27960
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
27961
28306
|
if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
|
|
27962
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27963
28307
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
27964
28308
|
continue;
|
|
27965
28309
|
}
|
|
28310
|
+
if (key.endsWith(SECTION_EMBED_SUFFIX)) continue;
|
|
27966
28311
|
if (applyVideoSettingNode(key, val)) continue;
|
|
27967
28312
|
if (applyCarouselNode(key, val)) continue;
|
|
27968
28313
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -28002,6 +28347,7 @@ function OhhwellsBridge() {
|
|
|
28002
28347
|
});
|
|
28003
28348
|
applyLinkByKey(key, val);
|
|
28004
28349
|
}
|
|
28350
|
+
applySectionEmbeds(content);
|
|
28005
28351
|
applyLogoFromContent(content);
|
|
28006
28352
|
applyLogoSizes(content);
|
|
28007
28353
|
reconcileNavbarItemsFromContent(content);
|
|
@@ -28190,20 +28536,22 @@ function OhhwellsBridge() {
|
|
|
28190
28536
|
}
|
|
28191
28537
|
applyAiFooterFromContent(content);
|
|
28192
28538
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
28539
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
28193
28540
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
28194
28541
|
}
|
|
28195
28542
|
for (const [key, val] of Object.entries(content)) {
|
|
28196
28543
|
if (key === "__ohw_sections") continue;
|
|
28197
28544
|
if (key === AI_SECTIONS_KEY) continue;
|
|
28198
28545
|
if (key === AI_FOOTER_KEY) continue;
|
|
28546
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
28547
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
28199
28548
|
if (key === BRAND_KIT_KEY) continue;
|
|
28200
28549
|
if (key === STYLE_STORE_KEY) continue;
|
|
28201
28550
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
28202
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
28203
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
28204
28551
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
28205
28552
|
continue;
|
|
28206
28553
|
}
|
|
28554
|
+
if (key.endsWith(SECTION_EMBED_SUFFIX)) continue;
|
|
28207
28555
|
if (applyVideoSettingNode(key, val)) continue;
|
|
28208
28556
|
if (applyCarouselNode(key, val)) continue;
|
|
28209
28557
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -28228,6 +28576,7 @@ function OhhwellsBridge() {
|
|
|
28228
28576
|
});
|
|
28229
28577
|
applyLinkByKey(key, val);
|
|
28230
28578
|
}
|
|
28579
|
+
applySectionEmbeds(content);
|
|
28231
28580
|
applyLogoFromContent(content);
|
|
28232
28581
|
reconcileNavbarItemsFromContent(content);
|
|
28233
28582
|
reconcileFooterOrderFromContent(content);
|
|
@@ -28467,26 +28816,11 @@ function OhhwellsBridge() {
|
|
|
28467
28816
|
const t2 = setTimeout(measure, 500);
|
|
28468
28817
|
const ro = new ResizeObserver(schedule);
|
|
28469
28818
|
ro.observe(document.body);
|
|
28470
|
-
let lastWidth = window.innerWidth;
|
|
28471
|
-
let resizeTimers = [];
|
|
28472
|
-
const clearResizeTimers = () => {
|
|
28473
|
-
resizeTimers.forEach(clearTimeout);
|
|
28474
|
-
resizeTimers = [];
|
|
28475
|
-
};
|
|
28476
|
-
const handleResize = () => {
|
|
28477
|
-
if (window.innerWidth === lastWidth) return;
|
|
28478
|
-
lastWidth = window.innerWidth;
|
|
28479
|
-
clearResizeTimers();
|
|
28480
|
-
resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
|
|
28481
|
-
};
|
|
28482
|
-
window.addEventListener("resize", handleResize);
|
|
28483
28819
|
return () => {
|
|
28484
28820
|
clearTimeout(t1);
|
|
28485
28821
|
clearTimeout(t2);
|
|
28486
28822
|
if (raf != null) cancelAnimationFrame(raf);
|
|
28487
28823
|
ro.disconnect();
|
|
28488
|
-
clearResizeTimers();
|
|
28489
|
-
window.removeEventListener("resize", handleResize);
|
|
28490
28824
|
};
|
|
28491
28825
|
}, [pathname, isEditMode, postToParent2]);
|
|
28492
28826
|
(0, import_react21.useEffect)(() => {
|
|
@@ -28783,6 +29117,13 @@ function OhhwellsBridge() {
|
|
|
28783
29117
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
28784
29118
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
28785
29119
|
if (isInsideLinkEditor(target)) return;
|
|
29120
|
+
if (isInsideFloatingPanel(target)) return;
|
|
29121
|
+
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
29122
|
+
if (target.closest(
|
|
29123
|
+
'[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
|
|
29124
|
+
)) {
|
|
29125
|
+
return;
|
|
29126
|
+
}
|
|
28786
29127
|
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
28787
29128
|
clearMediaSelectionRef.current();
|
|
28788
29129
|
}
|
|
@@ -28806,8 +29147,6 @@ function OhhwellsBridge() {
|
|
|
28806
29147
|
return;
|
|
28807
29148
|
}
|
|
28808
29149
|
}
|
|
28809
|
-
if (isInsideFloatingPanel(target)) return;
|
|
28810
|
-
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
28811
29150
|
const collectionItem = matchCollectionItemClick(target, collectionItemsRef.current);
|
|
28812
29151
|
if (collectionItem) {
|
|
28813
29152
|
e.preventDefault();
|
|
@@ -28819,11 +29158,6 @@ function OhhwellsBridge() {
|
|
|
28819
29158
|
});
|
|
28820
29159
|
return;
|
|
28821
29160
|
}
|
|
28822
|
-
if (target.closest(
|
|
28823
|
-
'[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
|
|
28824
|
-
)) {
|
|
28825
|
-
return;
|
|
28826
|
-
}
|
|
28827
29161
|
{
|
|
28828
29162
|
const formEl = getFormElement(target);
|
|
28829
29163
|
const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
|
|
@@ -28977,9 +29311,13 @@ function OhhwellsBridge() {
|
|
|
28977
29311
|
if (isIconEditable(editable) && !getSocialItem(editable)) {
|
|
28978
29312
|
e.preventDefault();
|
|
28979
29313
|
e.stopPropagation();
|
|
28980
|
-
selectIconElementRef.current(editable);
|
|
28981
29314
|
const aiIcon = editable.hasAttribute("data-ai-icon");
|
|
28982
29315
|
const featureIcon = aiIcon && /\.features\.\d+\.icon$/.test(editable.dataset.ohwKey ?? "");
|
|
29316
|
+
if (aiIcon) {
|
|
29317
|
+
aiSectionApiRef.current?.selectFromElement(editable);
|
|
29318
|
+
} else {
|
|
29319
|
+
selectIconElementRef.current(editable);
|
|
29320
|
+
}
|
|
28983
29321
|
postToParentRef.current({
|
|
28984
29322
|
type: "ow:icon-pick",
|
|
28985
29323
|
key: editable.dataset.ohwKey ?? "",
|
|
@@ -29207,6 +29545,9 @@ function OhhwellsBridge() {
|
|
|
29207
29545
|
setHoveredItemRect(null);
|
|
29208
29546
|
hoveredNavContainerRef.current = null;
|
|
29209
29547
|
setHoveredNavContainerRect(null);
|
|
29548
|
+
siblingHintElRef.current = null;
|
|
29549
|
+
setSiblingHintRect(null);
|
|
29550
|
+
setSiblingHintRects([]);
|
|
29210
29551
|
return;
|
|
29211
29552
|
}
|
|
29212
29553
|
{
|
|
@@ -29327,7 +29668,6 @@ function OhhwellsBridge() {
|
|
|
29327
29668
|
hoveredNavContainerRef.current = null;
|
|
29328
29669
|
setHoveredNavContainerRect(null);
|
|
29329
29670
|
hoveredItemElRef.current = editable;
|
|
29330
|
-
setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
|
|
29331
29671
|
}
|
|
29332
29672
|
}
|
|
29333
29673
|
}
|
|
@@ -30037,7 +30377,11 @@ function OhhwellsBridge() {
|
|
|
30037
30377
|
};
|
|
30038
30378
|
const handleMouseMove = (e) => {
|
|
30039
30379
|
const { clientX, clientY } = e;
|
|
30040
|
-
if (pointOwnedByFloatingPanel(clientX, clientY))
|
|
30380
|
+
if (pointOwnedByFloatingPanel(clientX, clientY)) {
|
|
30381
|
+
dismissImageHover();
|
|
30382
|
+
clearImageHover();
|
|
30383
|
+
return;
|
|
30384
|
+
}
|
|
30041
30385
|
if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
|
|
30042
30386
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
30043
30387
|
formHoverElRef.current = null;
|
|
@@ -30066,7 +30410,12 @@ function OhhwellsBridge() {
|
|
|
30066
30410
|
setHoveredItemRect(null);
|
|
30067
30411
|
hoveredNavContainerRef.current = null;
|
|
30068
30412
|
setHoveredNavContainerRect(null);
|
|
30413
|
+
siblingHintElRef.current = null;
|
|
30414
|
+
setSiblingHintRect(null);
|
|
30415
|
+
setSiblingHintRects([]);
|
|
30069
30416
|
dismissImageHover();
|
|
30417
|
+
clearImageHover();
|
|
30418
|
+
setSectionGap(null);
|
|
30070
30419
|
return;
|
|
30071
30420
|
}
|
|
30072
30421
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
@@ -30078,7 +30427,11 @@ function OhhwellsBridge() {
|
|
|
30078
30427
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
30079
30428
|
const { clientX, clientY } = e.data;
|
|
30080
30429
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
30081
|
-
if (pointOwnedByFloatingPanel(clientX, clientY))
|
|
30430
|
+
if (pointOwnedByFloatingPanel(clientX, clientY)) {
|
|
30431
|
+
dismissImageHover();
|
|
30432
|
+
clearImageHover();
|
|
30433
|
+
return;
|
|
30434
|
+
}
|
|
30082
30435
|
if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
|
|
30083
30436
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
30084
30437
|
probeSectionGapAt(clientX, clientY);
|
|
@@ -30458,6 +30811,7 @@ function OhhwellsBridge() {
|
|
|
30458
30811
|
applyAiFooterFromContent(content);
|
|
30459
30812
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
30460
30813
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
30814
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
30461
30815
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
30462
30816
|
}
|
|
30463
30817
|
applyBrandChrome(content);
|
|
@@ -30472,15 +30826,16 @@ function OhhwellsBridge() {
|
|
|
30472
30826
|
}
|
|
30473
30827
|
if (key === AI_SECTIONS_KEY) continue;
|
|
30474
30828
|
if (key === AI_FOOTER_KEY) continue;
|
|
30829
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
30830
|
+
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
30475
30831
|
if (key === BRAND_KIT_KEY) continue;
|
|
30476
30832
|
if (key === STYLE_STORE_KEY) continue;
|
|
30477
30833
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
30478
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
30479
30834
|
if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
|
|
30480
|
-
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
30481
30835
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
30482
30836
|
continue;
|
|
30483
30837
|
}
|
|
30838
|
+
if (key.endsWith(SECTION_EMBED_SUFFIX)) continue;
|
|
30484
30839
|
if (applyVideoSettingNode(key, val)) continue;
|
|
30485
30840
|
if (applyCarouselNode(key, val)) continue;
|
|
30486
30841
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -30506,6 +30861,7 @@ function OhhwellsBridge() {
|
|
|
30506
30861
|
});
|
|
30507
30862
|
applyLinkByKey(key, val);
|
|
30508
30863
|
}
|
|
30864
|
+
applySectionEmbeds(content);
|
|
30509
30865
|
applyLogoFromContent(content);
|
|
30510
30866
|
applyLogoSizes(content);
|
|
30511
30867
|
document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
|
|
@@ -31113,6 +31469,12 @@ function OhhwellsBridge() {
|
|
|
31113
31469
|
closeLinkPopoverRef.current();
|
|
31114
31470
|
return;
|
|
31115
31471
|
}
|
|
31472
|
+
if (floatingPanelOpenRef.current) {
|
|
31473
|
+
setFloatingPanelRef.current(null);
|
|
31474
|
+
deselectRef.current();
|
|
31475
|
+
deactivateRef.current();
|
|
31476
|
+
return;
|
|
31477
|
+
}
|
|
31116
31478
|
deselectRef.current();
|
|
31117
31479
|
deactivateRef.current();
|
|
31118
31480
|
clearMediaSelectionRef.current();
|
|
@@ -31501,7 +31863,7 @@ function OhhwellsBridge() {
|
|
|
31501
31863
|
const sectionEl = foundEl && !foundEl.hasAttribute("data-ohw-ai-template-hidden") && !foundEl.hasAttribute("data-ohw-ai-removed") && !foundEl.hasAttribute("data-ohw-ai-replaced-by") ? foundEl : null;
|
|
31502
31864
|
const nodes = sectionEl ? collectEditableNodes(void 0, sectionEl).filter(
|
|
31503
31865
|
(n) => n.key && !n.key.startsWith("__ohw_") && !["meta", "sections", "video-setting"].includes(n.type)
|
|
31504
|
-
).map((n) => ({ ...n, text: n.text ?? "", type: normalizeAiNodeType(n.type) })) : [];
|
|
31866
|
+
).map((n) => ({ ...n, text: n.text ?? "", type: normalizeAiNodeType(n.type) })).map((n) => withNodeFontSize(n, sectionEl)) : [];
|
|
31505
31867
|
const items = sectionEl ? collectItemGroups(sectionEl) : [];
|
|
31506
31868
|
const box = sectionEl?.getBoundingClientRect();
|
|
31507
31869
|
const rect = box ? {
|
|
@@ -31948,10 +32310,10 @@ function OhhwellsBridge() {
|
|
|
31948
32310
|
window.removeEventListener("message", handleDuplicateSection);
|
|
31949
32311
|
window.removeEventListener("message", handleDeactivate);
|
|
31950
32312
|
window.removeEventListener("message", handleSelectNav);
|
|
31951
|
-
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
31952
32313
|
window.removeEventListener("message", handleToastAction);
|
|
31953
32314
|
window.removeEventListener("message", handleFormCount);
|
|
31954
32315
|
window.removeEventListener("message", handleUiEscape);
|
|
32316
|
+
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
31955
32317
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
31956
32318
|
autoSaveTimers.current.clear();
|
|
31957
32319
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
@@ -32245,7 +32607,7 @@ function OhhwellsBridge() {
|
|
|
32245
32607
|
postToParent2({
|
|
32246
32608
|
type: "ow:ready",
|
|
32247
32609
|
version: "1",
|
|
32248
|
-
bridgeVersion: "0.1.
|
|
32610
|
+
bridgeVersion: "0.1.160-next.428",
|
|
32249
32611
|
path: pathname,
|
|
32250
32612
|
nodes: collectEditableNodes(editContentRef.current),
|
|
32251
32613
|
sections
|