@ohhwells/bridge 0.1.147 → 0.1.149-next.400
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +874 -731
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +914 -755
- package/dist/index.js.map +1 -1
- package/dist/pages.cjs +1 -1
- package/dist/pages.cjs.map +1 -1
- package/dist/pages.js +1 -1
- package/dist/pages.js.map +1 -1
- package/dist/styles.css +116 -0
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1571,7 +1571,19 @@ function brandTrackedFontFamily(doc, stack) {
|
|
|
1571
1571
|
}
|
|
1572
1572
|
var paintLockByEl = /* @__PURE__ */ new WeakMap();
|
|
1573
1573
|
var paintObserverByEl = /* @__PURE__ */ new WeakMap();
|
|
1574
|
-
var
|
|
1574
|
+
var PAINT_GUARD_ATTRS = {
|
|
1575
|
+
attributes: true,
|
|
1576
|
+
attributeFilter: ["style", "class"]
|
|
1577
|
+
};
|
|
1578
|
+
function paintGuarded(el, assignment, tokens) {
|
|
1579
|
+
const observer = paintObserverByEl.get(el);
|
|
1580
|
+
observer?.disconnect();
|
|
1581
|
+
try {
|
|
1582
|
+
paintButtonChrome(el, assignment, tokens);
|
|
1583
|
+
} finally {
|
|
1584
|
+
observer?.observe(el, PAINT_GUARD_ATTRS);
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1575
1587
|
function paintButtonChrome(el, assignment, tokens) {
|
|
1576
1588
|
const origin = captureButtonOrigin(el);
|
|
1577
1589
|
const chrome = tokens.variants[assignment.variant];
|
|
@@ -1610,14 +1622,11 @@ function paintButtonChrome(el, assignment, tokens) {
|
|
|
1610
1622
|
function guardTemplateHover(el) {
|
|
1611
1623
|
if (paintObserverByEl.has(el)) return;
|
|
1612
1624
|
const observer = new MutationObserver(() => {
|
|
1613
|
-
if (paintingButton) return;
|
|
1614
1625
|
const lock = paintLockByEl.get(el);
|
|
1615
1626
|
if (!lock) return;
|
|
1616
|
-
|
|
1617
|
-
paintButtonChrome(el, lock.assignment, lock.tokens);
|
|
1618
|
-
paintingButton = false;
|
|
1627
|
+
paintGuarded(el, lock.assignment, lock.tokens);
|
|
1619
1628
|
});
|
|
1620
|
-
observer.observe(el,
|
|
1629
|
+
observer.observe(el, PAINT_GUARD_ATTRS);
|
|
1621
1630
|
paintObserverByEl.set(el, observer);
|
|
1622
1631
|
}
|
|
1623
1632
|
function paintedTokensOf(el) {
|
|
@@ -1634,10 +1643,8 @@ function applyButtonStyle(el, assignment, tokens) {
|
|
|
1634
1643
|
}
|
|
1635
1644
|
};
|
|
1636
1645
|
paintLockByEl.set(el, { assignment, tokens: tracked });
|
|
1637
|
-
paintingButton = true;
|
|
1638
|
-
paintButtonChrome(el, assignment, tracked);
|
|
1639
|
-
paintingButton = false;
|
|
1640
1646
|
guardTemplateHover(el);
|
|
1647
|
+
paintGuarded(el, assignment, tracked);
|
|
1641
1648
|
}
|
|
1642
1649
|
function applyButtonStylesFromContent(doc, content) {
|
|
1643
1650
|
const assignments = readAssignments(content);
|
|
@@ -1719,7 +1726,8 @@ function labelElement2(el) {
|
|
|
1719
1726
|
return el.querySelector('[data-ohw-editable="text"], [data-ohw-editable="plain"]') ?? el.querySelector("[data-ohw-key]");
|
|
1720
1727
|
}
|
|
1721
1728
|
function buttonLabel(el) {
|
|
1722
|
-
|
|
1729
|
+
const label = labelElement2(el);
|
|
1730
|
+
return (label ? label.innerHTML : el.textContent ?? "").trim();
|
|
1723
1731
|
}
|
|
1724
1732
|
function buttonHref(el) {
|
|
1725
1733
|
return el.getAttribute("href") ?? "";
|
|
@@ -1858,7 +1866,7 @@ function duplicateButton(source, content) {
|
|
|
1858
1866
|
stampVariantClass(copy, copyAssignment.variant);
|
|
1859
1867
|
applyButtonStyle(copy, copyAssignment, paintedTokensOf(source) ?? tokens);
|
|
1860
1868
|
const copyLabelEl = labelElement2(copy);
|
|
1861
|
-
if (copyLabelEl) copyLabelEl.
|
|
1869
|
+
if (copyLabelEl) copyLabelEl.innerHTML = label;
|
|
1862
1870
|
let collection = buttonCollectionOf(source);
|
|
1863
1871
|
const collections = readCollections(content);
|
|
1864
1872
|
let collectionId = collection?.getAttribute(COLLECTION_ATTR) ?? "";
|
|
@@ -2184,7 +2192,7 @@ function applySnapshotContent(el, snapshot, content) {
|
|
|
2184
2192
|
const label = labelElement2(el);
|
|
2185
2193
|
if (label) {
|
|
2186
2194
|
if (label.getAttribute("data-ohw-key") !== labelKey) label.setAttribute("data-ohw-key", labelKey);
|
|
2187
|
-
if (label.
|
|
2195
|
+
if (label.innerHTML !== text) label.innerHTML = text;
|
|
2188
2196
|
}
|
|
2189
2197
|
}
|
|
2190
2198
|
function reconcileButtonCollections(doc, content) {
|
|
@@ -4269,7 +4277,7 @@ function buildNavLink(index, href, label, template) {
|
|
|
4269
4277
|
const span = document.createElement("span");
|
|
4270
4278
|
span.setAttribute("data-ohw-editable", "text");
|
|
4271
4279
|
span.setAttribute("data-ohw-key", `nav-${index}-label`);
|
|
4272
|
-
span.
|
|
4280
|
+
span.innerHTML = label;
|
|
4273
4281
|
anchor.appendChild(span);
|
|
4274
4282
|
return anchor;
|
|
4275
4283
|
}
|
|
@@ -6629,6 +6637,21 @@ function pricingCardFeatureCount(tree, index) {
|
|
|
6629
6637
|
const target = findPricingCollection(tree)?.children?.[index];
|
|
6630
6638
|
return target ? pricingFeatureList(target).length : 0;
|
|
6631
6639
|
}
|
|
6640
|
+
function prevailingFeatureIcon(features) {
|
|
6641
|
+
const counts = /* @__PURE__ */ new Map();
|
|
6642
|
+
for (const row of features) {
|
|
6643
|
+
const key = `${row.icon ?? ""}|${row.iconColor ?? ""}`;
|
|
6644
|
+
const entry = counts.get(key) ?? { count: 0, ...row.icon ? { icon: row.icon } : {}, ...row.iconColor ? { iconColor: row.iconColor } : {} };
|
|
6645
|
+
entry.count += 1;
|
|
6646
|
+
counts.set(key, entry);
|
|
6647
|
+
}
|
|
6648
|
+
let best = null;
|
|
6649
|
+
for (const entry of counts.values()) {
|
|
6650
|
+
if (!best || entry.count > best.count) best = entry;
|
|
6651
|
+
}
|
|
6652
|
+
if (!best) return {};
|
|
6653
|
+
return { ...best.icon ? { icon: best.icon } : {}, ...best.iconColor ? { iconColor: best.iconColor } : {} };
|
|
6654
|
+
}
|
|
6632
6655
|
function addPricingCardFeature(tree, index, text) {
|
|
6633
6656
|
return withPricingCollection(tree, (collection) => {
|
|
6634
6657
|
const children = collection.children;
|
|
@@ -6637,7 +6660,7 @@ function addPricingCardFeature(tree, index, text) {
|
|
|
6637
6660
|
const features = pricingFeatureList(target);
|
|
6638
6661
|
if (features.length >= PRICING_FEATURES_MAX) return false;
|
|
6639
6662
|
target.slots = target.slots ?? {};
|
|
6640
|
-
target.slots.features = [...features, { text }];
|
|
6663
|
+
target.slots.features = [...features, { text, ...prevailingFeatureIcon(features) }];
|
|
6641
6664
|
return true;
|
|
6642
6665
|
});
|
|
6643
6666
|
}
|
|
@@ -7820,7 +7843,7 @@ var AI_MOBILE_CSS = [
|
|
|
7820
7843
|
// page's first section. Top only (bottom needs no nav clearance); ~96px approximates the
|
|
7821
7844
|
// template nav's own height (measured ~94px) — there's no shared `--ohw-header-h` var to read
|
|
7822
7845
|
// an exact figure from (no live measurement exists), so this is a safe approximation, not a
|
|
7823
|
-
// pixel-exact fit. Horizontal spacing already comes from `data-ai-
|
|
7846
|
+
// pixel-exact fit. Horizontal spacing already comes from `data-ai-section-inner`.
|
|
7824
7847
|
'[data-ai-overlay-clearance] [data-ai-overlap-layer="overlay"]{padding-top:96px}',
|
|
7825
7848
|
// A full-bleed carousel's height is pure arithmetic: it spans the whole window, so 16/9 turns
|
|
7826
7849
|
// window width straight into height. Measured at 16/9 it came out ~90% of the viewport at EVERY
|
|
@@ -7836,8 +7859,10 @@ var AI_MOBILE_CSS = [
|
|
|
7836
7859
|
"[data-ai-section]{overflow-x:hidden}",
|
|
7837
7860
|
// `:not([data-ai-full-bleed])`: this `!important` gutter beat the inline `padding: 0` that a
|
|
7838
7861
|
// full-bleed section's container sets, so a carousel/media hero that is edge-to-edge on desktop
|
|
7839
|
-
// still got a 20px band of section background down both sides on a phone.
|
|
7840
|
-
|
|
7862
|
+
// still got a 20px band of section background down both sides on a phone. The footer's own
|
|
7863
|
+
// container keeps the unguarded rule below — `data-ai-full-bleed` can never appear on it.
|
|
7864
|
+
"[data-ai-section-inner]:not([data-ai-full-bleed]){padding:0 20px !important}",
|
|
7865
|
+
"[data-ai-container]{padding:0 20px !important}",
|
|
7841
7866
|
"[data-ai-row]{display:flex !important;flex-direction:column !important;align-items:stretch !important}",
|
|
7842
7867
|
"[data-ai-cell]{width:100%;min-width:0}",
|
|
7843
7868
|
// The rule above turns every row into a COLUMN flex container on phones, which silently breaks
|
|
@@ -8042,6 +8067,31 @@ function pricingCardEmphasis(featured, ctx, hasBg) {
|
|
|
8042
8067
|
function textAttrs(ctx, path) {
|
|
8043
8068
|
return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
|
|
8044
8069
|
}
|
|
8070
|
+
var AI_RESPONSIVE_CSS = [
|
|
8071
|
+
"@media (max-width: 960px) {",
|
|
8072
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
|
|
8073
|
+
' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
|
|
8074
|
+
"}",
|
|
8075
|
+
"@media (max-width: 640px) {",
|
|
8076
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
|
|
8077
|
+
" [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
|
|
8078
|
+
// Group containers flatten to a column on phones; span placements come along for free.
|
|
8079
|
+
// `:not([data-ai-group="overlap"])` for the same reason as the twin pair in AI_MOBILE_CSS — see
|
|
8080
|
+
// the comment there. This sheet's copy is the narrower selector, so without the exemption it
|
|
8081
|
+
// flattens an `overlap` hero below 640px even though the other rule stands down: measured a 390px
|
|
8082
|
+
// viewport with the heading/CTA in flow *under* the image, 219px of section background where the
|
|
8083
|
+
// layered text used to be.
|
|
8084
|
+
' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) { display: flex !important; flex-direction: column !important; }',
|
|
8085
|
+
' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) > * { grid-column: auto !important; }',
|
|
8086
|
+
// `:not([data-ai-full-bleed])` for the same reason as the twin rule in AI_MOBILE_CSS: this one
|
|
8087
|
+
// is narrower (0,2,0 vs 0,1,0) and also `!important`, so without the guard it wins outright and
|
|
8088
|
+
// a full-bleed hero gets its 20px side band back below 640px only — the one width where the
|
|
8089
|
+
// other rule had already been taught to stand down.
|
|
8090
|
+
" [data-ai-responsive] [data-ai-section-inner]:not([data-ai-full-bleed]) { padding-left: 20px !important; padding-right: 20px !important; }",
|
|
8091
|
+
" [data-ai-responsive] { overflow-x: hidden; }",
|
|
8092
|
+
" [data-ai-responsive] img { max-width: 100%; }",
|
|
8093
|
+
"}"
|
|
8094
|
+
].join("\n");
|
|
8045
8095
|
var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
8046
8096
|
function MediaBox({
|
|
8047
8097
|
refValue,
|
|
@@ -8096,7 +8146,7 @@ function MediaBox({
|
|
|
8096
8146
|
position: fill ? "absolute" : void 0,
|
|
8097
8147
|
inset: fill ? 0 : void 0,
|
|
8098
8148
|
width: fill ? "100%" : fixedSize ? "auto" : "100%",
|
|
8099
|
-
height: fill ? "100%" : void 0,
|
|
8149
|
+
height: fill ? "100%" : fixedSize ? height : void 0,
|
|
8100
8150
|
aspectRatio: fill ? void 0 : aspectRatio,
|
|
8101
8151
|
minHeight: fill || fixedSize ? void 0 : height ?? (aspectRatio ? void 0 : 180),
|
|
8102
8152
|
borderRadius: radius,
|
|
@@ -9592,7 +9642,7 @@ function CollectionBlock({ node, ctx, path }) {
|
|
|
9592
9642
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
9593
9643
|
"div",
|
|
9594
9644
|
{
|
|
9595
|
-
"data-ai-grid":
|
|
9645
|
+
"data-ai-grid": String(itemsPerRow),
|
|
9596
9646
|
"data-ohw-pricing-collection": isPricing ? "" : void 0,
|
|
9597
9647
|
style: {
|
|
9598
9648
|
display: "grid",
|
|
@@ -9894,7 +9944,7 @@ function renderNode(node, ctx, path, ambientAlign) {
|
|
|
9894
9944
|
},
|
|
9895
9945
|
children: [
|
|
9896
9946
|
i > 0 && ctx.heroOverlapFullBleed ? (
|
|
9897
|
-
// The section's `data-ai-
|
|
9947
|
+
// The section's `data-ai-section-inner` gave up its max-width/gutter so the base
|
|
9898
9948
|
// layer (this group's i===0 sibling) can span edge-to-edge — reintroduced here,
|
|
9899
9949
|
// scoped to just the overlay text, so a heading/copy/CTA stack doesn't stretch
|
|
9900
9950
|
// the full section width instead of reading at the usual content width.
|
|
@@ -10313,6 +10363,7 @@ function AiTreeRenderer({
|
|
|
10313
10363
|
...fillHeight ? { "data-ai-fill-height": "" } : {},
|
|
10314
10364
|
...needsOverlayClearance ? { "data-ai-overlay-clearance": "" } : {},
|
|
10315
10365
|
...bgAttrs,
|
|
10366
|
+
"data-ai-responsive": "",
|
|
10316
10367
|
style: {
|
|
10317
10368
|
position: "relative",
|
|
10318
10369
|
padding: `${padCss} 0`,
|
|
@@ -10326,12 +10377,13 @@ function AiTreeRenderer({
|
|
|
10326
10377
|
...fillHeight ? { display: "grid" } : {}
|
|
10327
10378
|
},
|
|
10328
10379
|
children: [
|
|
10329
|
-
|
|
10380
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
|
|
10330
10381
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
|
|
10382
|
+
isOverlay && backgroundUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
|
|
10331
10383
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
10332
10384
|
"div",
|
|
10333
10385
|
{
|
|
10334
|
-
"data-ai-
|
|
10386
|
+
"data-ai-section-inner": "",
|
|
10335
10387
|
...fullBleedMedia ? { "data-ai-full-bleed": "" } : {},
|
|
10336
10388
|
style: {
|
|
10337
10389
|
position: "relative",
|
|
@@ -10348,7 +10400,7 @@ function AiTreeRenderer({
|
|
|
10348
10400
|
children: tree.rows.map((row, r2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
10349
10401
|
"div",
|
|
10350
10402
|
{
|
|
10351
|
-
"data-ai-
|
|
10403
|
+
"data-ai-columns": "",
|
|
10352
10404
|
style: {
|
|
10353
10405
|
display: "grid",
|
|
10354
10406
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
@@ -10373,7 +10425,12 @@ function AiTreeRenderer({
|
|
|
10373
10425
|
// the full row height instead of clumping at the top.
|
|
10374
10426
|
...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
|
|
10375
10427
|
},
|
|
10376
|
-
children: renderNode(
|
|
10428
|
+
children: renderNode(
|
|
10429
|
+
block,
|
|
10430
|
+
ctx,
|
|
10431
|
+
`r${r2}.b${b}`,
|
|
10432
|
+
settings.alignment === "center" ? "center" : "left"
|
|
10433
|
+
)
|
|
10377
10434
|
},
|
|
10378
10435
|
b
|
|
10379
10436
|
))
|
|
@@ -11005,9 +11062,10 @@ function applyAiSectionsToDom(state, options) {
|
|
|
11005
11062
|
if (existing && existing.serialized === serialized && existing.container.isConnected) {
|
|
11006
11063
|
continue;
|
|
11007
11064
|
}
|
|
11008
|
-
const isNewMount = !existing || !existing.container.isConnected;
|
|
11009
11065
|
let container = existing?.container;
|
|
11066
|
+
let isNewMount = false;
|
|
11010
11067
|
if (!container || !container.isConnected) {
|
|
11068
|
+
isNewMount = true;
|
|
11011
11069
|
existing?.root.unmount();
|
|
11012
11070
|
container?.remove();
|
|
11013
11071
|
container = document.createElement("div");
|
|
@@ -17449,6 +17507,7 @@ function MediaOverlay({
|
|
|
17449
17507
|
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
17450
17508
|
);
|
|
17451
17509
|
}, [isVideo]);
|
|
17510
|
+
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
17452
17511
|
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
17453
17512
|
const box = {
|
|
17454
17513
|
position: "fixed",
|
|
@@ -17547,11 +17606,10 @@ function MediaOverlay({
|
|
|
17547
17606
|
className: "flex items-center justify-center cursor-pointer",
|
|
17548
17607
|
style: {
|
|
17549
17608
|
...box,
|
|
17550
|
-
//
|
|
17551
|
-
//
|
|
17552
|
-
//
|
|
17553
|
-
|
|
17554
|
-
pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
|
|
17609
|
+
// Visual only. `pointer-events: auto` on this full-bleed rect covered the navbar
|
|
17610
|
+
// (hero bg includes the absolute TopNav) and swallowed CTA press-drag. Text overlay
|
|
17611
|
+
// and cueOnly also need clicks to fall through — Replace / video controls opt back in.
|
|
17612
|
+
pointerEvents: "none",
|
|
17555
17613
|
// Selected: a firm component ring with no wash, so the image reads as chosen rather
|
|
17556
17614
|
// than hovered. Hover keeps the existing tinted preview.
|
|
17557
17615
|
boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
@@ -17578,17 +17636,17 @@ function MediaOverlay({
|
|
|
17578
17636
|
},
|
|
17579
17637
|
children: [
|
|
17580
17638
|
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
17581
|
-
|
|
17639
|
+
replaceLabel
|
|
17582
17640
|
]
|
|
17583
17641
|
}
|
|
17584
17642
|
),
|
|
17585
|
-
replaceMode
|
|
17643
|
+
showChrome && replaceMode !== "none" && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
17586
17644
|
Button,
|
|
17587
17645
|
{
|
|
17588
17646
|
"data-ohw-media-overlay": "",
|
|
17589
17647
|
variant: "outline",
|
|
17590
17648
|
size: "sm",
|
|
17591
|
-
"aria-label":
|
|
17649
|
+
"aria-label": replaceLabel,
|
|
17592
17650
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
17593
17651
|
style: {
|
|
17594
17652
|
...OVERLAY_BUTTON_STYLE,
|
|
@@ -17611,7 +17669,7 @@ function MediaOverlay({
|
|
|
17611
17669
|
},
|
|
17612
17670
|
children: [
|
|
17613
17671
|
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
17614
|
-
replaceMode === "full" ?
|
|
17672
|
+
replaceMode === "full" ? replaceLabel : null
|
|
17615
17673
|
]
|
|
17616
17674
|
}
|
|
17617
17675
|
)
|
|
@@ -18121,7 +18179,7 @@ function AiSectionOverlay({
|
|
|
18121
18179
|
|
|
18122
18180
|
// src/ui/ai-section/AiMediaStripOverlay.tsx
|
|
18123
18181
|
var import_react10 = require("react");
|
|
18124
|
-
var
|
|
18182
|
+
var import_lucide_react9 = require("lucide-react");
|
|
18125
18183
|
|
|
18126
18184
|
// src/lib/ai-media-strip-tree.ts
|
|
18127
18185
|
var MEDIA_STRIP_ITEM_MIN = 1;
|
|
@@ -18235,14 +18293,6 @@ function setMediaStripItemAsset(tree, index, assetId) {
|
|
|
18235
18293
|
return true;
|
|
18236
18294
|
});
|
|
18237
18295
|
}
|
|
18238
|
-
function setMediaStripItemAlt(tree, index, alt) {
|
|
18239
|
-
return withMediaStrip(tree, (block) => {
|
|
18240
|
-
const items = block.items;
|
|
18241
|
-
if (index < 0 || index >= items.length) return false;
|
|
18242
|
-
items[index] = { ...items[index], alt };
|
|
18243
|
-
return true;
|
|
18244
|
-
});
|
|
18245
|
-
}
|
|
18246
18296
|
function setMediaStripItemLink(tree, index, link) {
|
|
18247
18297
|
return withMediaStrip(tree, (block) => {
|
|
18248
18298
|
const items = block.items;
|
|
@@ -18260,11 +18310,117 @@ function setMediaStripItemLink(tree, index, link) {
|
|
|
18260
18310
|
});
|
|
18261
18311
|
}
|
|
18262
18312
|
|
|
18263
|
-
// src/ui/
|
|
18313
|
+
// src/ui/dialog.tsx
|
|
18314
|
+
var React9 = __toESM(require("react"), 1);
|
|
18315
|
+
var import_radix_ui6 = require("radix-ui");
|
|
18316
|
+
var import_lucide_react8 = require("lucide-react");
|
|
18264
18317
|
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
18265
|
-
|
|
18266
|
-
|
|
18267
|
-
|
|
18318
|
+
function Dialog2({
|
|
18319
|
+
...props
|
|
18320
|
+
}) {
|
|
18321
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_radix_ui6.Dialog.Root, { "data-slot": "dialog", ...props });
|
|
18322
|
+
}
|
|
18323
|
+
function DialogPortal({
|
|
18324
|
+
...props
|
|
18325
|
+
}) {
|
|
18326
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_radix_ui6.Dialog.Portal, { ...props });
|
|
18327
|
+
}
|
|
18328
|
+
function DialogOverlay({
|
|
18329
|
+
className,
|
|
18330
|
+
...props
|
|
18331
|
+
}) {
|
|
18332
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
18333
|
+
import_radix_ui6.Dialog.Overlay,
|
|
18334
|
+
{
|
|
18335
|
+
"data-slot": "dialog-overlay",
|
|
18336
|
+
"data-ohw-link-modal-root": "",
|
|
18337
|
+
className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
|
|
18338
|
+
...props
|
|
18339
|
+
}
|
|
18340
|
+
);
|
|
18341
|
+
}
|
|
18342
|
+
var DialogContent = React9.forwardRef(
|
|
18343
|
+
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
18344
|
+
const positionMode = container ? "absolute" : "fixed";
|
|
18345
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(DialogPortal, { container: container ?? void 0, children: [
|
|
18346
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
18347
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
18348
|
+
import_radix_ui6.Dialog.Content,
|
|
18349
|
+
{
|
|
18350
|
+
ref,
|
|
18351
|
+
"data-slot": "dialog-content",
|
|
18352
|
+
className: cn(
|
|
18353
|
+
positionMode,
|
|
18354
|
+
"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",
|
|
18355
|
+
"rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
|
|
18356
|
+
container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
|
|
18357
|
+
className
|
|
18358
|
+
),
|
|
18359
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
18360
|
+
...props,
|
|
18361
|
+
children: [
|
|
18362
|
+
children,
|
|
18363
|
+
showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
18364
|
+
import_radix_ui6.Dialog.Close,
|
|
18365
|
+
{
|
|
18366
|
+
type: "button",
|
|
18367
|
+
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
18368
|
+
"aria-label": "Close",
|
|
18369
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react8.X, { size: 16, "aria-hidden": true })
|
|
18370
|
+
}
|
|
18371
|
+
) : null
|
|
18372
|
+
]
|
|
18373
|
+
}
|
|
18374
|
+
)
|
|
18375
|
+
] });
|
|
18376
|
+
}
|
|
18377
|
+
);
|
|
18378
|
+
DialogContent.displayName = import_radix_ui6.Dialog.Content.displayName;
|
|
18379
|
+
function DialogHeader({
|
|
18380
|
+
className,
|
|
18381
|
+
...props
|
|
18382
|
+
}) {
|
|
18383
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
18384
|
+
}
|
|
18385
|
+
function DialogFooter({
|
|
18386
|
+
className,
|
|
18387
|
+
...props
|
|
18388
|
+
}) {
|
|
18389
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
18390
|
+
"div",
|
|
18391
|
+
{
|
|
18392
|
+
className: cn("flex items-center justify-end gap-2", className),
|
|
18393
|
+
...props
|
|
18394
|
+
}
|
|
18395
|
+
);
|
|
18396
|
+
}
|
|
18397
|
+
var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
18398
|
+
import_radix_ui6.Dialog.Title,
|
|
18399
|
+
{
|
|
18400
|
+
ref,
|
|
18401
|
+
className: cn(
|
|
18402
|
+
"text-lg font-semibold leading-none tracking-tight text-card-foreground",
|
|
18403
|
+
className
|
|
18404
|
+
),
|
|
18405
|
+
...props
|
|
18406
|
+
}
|
|
18407
|
+
));
|
|
18408
|
+
DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
|
|
18409
|
+
var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
18410
|
+
import_radix_ui6.Dialog.Description,
|
|
18411
|
+
{
|
|
18412
|
+
ref,
|
|
18413
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
18414
|
+
...props
|
|
18415
|
+
}
|
|
18416
|
+
));
|
|
18417
|
+
DialogDescription.displayName = import_radix_ui6.Dialog.Description.displayName;
|
|
18418
|
+
var DialogClose = import_radix_ui6.Dialog.Close;
|
|
18419
|
+
|
|
18420
|
+
// src/ui/ai-section/AiMediaStripOverlay.tsx
|
|
18421
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
18422
|
+
var PRIMARY3 = "var(--ohw-primary, #0885FE)";
|
|
18423
|
+
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]";
|
|
18268
18424
|
function findMediaStripItemElement(sectionId, index) {
|
|
18269
18425
|
const sectionEl = findByInstanceId(sectionId);
|
|
18270
18426
|
if (!sectionEl) return null;
|
|
@@ -18274,14 +18430,35 @@ function findMediaStripItemElement(sectionId, index) {
|
|
|
18274
18430
|
}
|
|
18275
18431
|
return null;
|
|
18276
18432
|
}
|
|
18277
|
-
function
|
|
18278
|
-
|
|
18433
|
+
function itemRefFromTarget(target) {
|
|
18434
|
+
if (!(target instanceof Element)) return null;
|
|
18435
|
+
if (target.closest(CHROME_SELECTOR)) return null;
|
|
18436
|
+
const itemEl = target.closest("[data-ohw-media-strip-item]");
|
|
18437
|
+
if (!itemEl) return null;
|
|
18438
|
+
const sectionEl = itemEl.closest("[data-ohw-section]");
|
|
18439
|
+
const unit = sectionEl ? movableUnit(sectionEl) : null;
|
|
18440
|
+
const sectionId = unit ? instanceIdOf(unit) || null : null;
|
|
18441
|
+
const index = Number(itemEl.dataset.ohwMediaStripIndex);
|
|
18442
|
+
if (!sectionId || Number.isNaN(index)) return null;
|
|
18443
|
+
return { sectionId, index };
|
|
18444
|
+
}
|
|
18445
|
+
function sameRef(a, b) {
|
|
18446
|
+
return a?.sectionId === b?.sectionId && a?.index === b?.index;
|
|
18447
|
+
}
|
|
18448
|
+
function rectOf(el) {
|
|
18279
18449
|
if (!el) return null;
|
|
18280
18450
|
const r2 = el.getBoundingClientRect();
|
|
18281
18451
|
if (r2.width <= 0 || r2.height <= 0) return null;
|
|
18282
18452
|
return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
|
|
18283
18453
|
}
|
|
18284
|
-
function
|
|
18454
|
+
function readRect2(ref) {
|
|
18455
|
+
return rectOf(ref && findMediaStripItemElement(ref.sectionId, ref.index));
|
|
18456
|
+
}
|
|
18457
|
+
function readStripRect(ref) {
|
|
18458
|
+
const item = ref && findMediaStripItemElement(ref.sectionId, ref.index);
|
|
18459
|
+
return rectOf(item?.closest("[data-ohw-media-strip]") ?? item);
|
|
18460
|
+
}
|
|
18461
|
+
function useLiveItemRect(ref, strip = false) {
|
|
18285
18462
|
const [rect, setRect] = (0, import_react10.useState)(null);
|
|
18286
18463
|
(0, import_react10.useEffect)(() => {
|
|
18287
18464
|
if (!ref) {
|
|
@@ -18289,7 +18466,7 @@ function useLiveItemRect(ref) {
|
|
|
18289
18466
|
return;
|
|
18290
18467
|
}
|
|
18291
18468
|
const update = () => {
|
|
18292
|
-
const next = readRect2(ref);
|
|
18469
|
+
const next = strip ? readStripRect(ref) : readRect2(ref);
|
|
18293
18470
|
setRect(
|
|
18294
18471
|
(prev) => prev && next && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
|
|
18295
18472
|
);
|
|
@@ -18304,9 +18481,49 @@ function useLiveItemRect(ref) {
|
|
|
18304
18481
|
window.removeEventListener("resize", update);
|
|
18305
18482
|
clearInterval(interval);
|
|
18306
18483
|
};
|
|
18307
|
-
}, [ref?.sectionId, ref?.index]);
|
|
18484
|
+
}, [ref?.sectionId, ref?.index, strip]);
|
|
18308
18485
|
return rect;
|
|
18309
18486
|
}
|
|
18487
|
+
var TOOLBAR_STRIP_GAP = 52;
|
|
18488
|
+
var TOOLBAR_STRIP_GAP_MOBILE = 42;
|
|
18489
|
+
var TOOLBAR_EDGE_MARGIN2 = 4;
|
|
18490
|
+
function StripToolbarSlot({ stripRect, children }) {
|
|
18491
|
+
const slotRef = (0, import_react10.useRef)(null);
|
|
18492
|
+
const [shift, setShift] = (0, import_react10.useState)(0);
|
|
18493
|
+
const centerX = stripRect.left + stripRect.width / 2;
|
|
18494
|
+
(0, import_react10.useLayoutEffect)(() => {
|
|
18495
|
+
const slot = slotRef.current;
|
|
18496
|
+
if (!slot) return;
|
|
18497
|
+
const clamp = () => {
|
|
18498
|
+
const w = slot.offsetWidth;
|
|
18499
|
+
if (w <= 0) return;
|
|
18500
|
+
const half = w / 2;
|
|
18501
|
+
const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
|
|
18502
|
+
setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
|
|
18503
|
+
};
|
|
18504
|
+
clamp();
|
|
18505
|
+
const ro = new ResizeObserver(clamp);
|
|
18506
|
+
ro.observe(slot);
|
|
18507
|
+
return () => ro.disconnect();
|
|
18508
|
+
}, [centerX, children]);
|
|
18509
|
+
const mobile = window.innerWidth <= 480;
|
|
18510
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18511
|
+
"div",
|
|
18512
|
+
{
|
|
18513
|
+
ref: slotRef,
|
|
18514
|
+
"data-ohw-bridge": "",
|
|
18515
|
+
"data-ohw-item-interaction": "",
|
|
18516
|
+
className: "pointer-events-auto fixed",
|
|
18517
|
+
style: {
|
|
18518
|
+
top: stripRect.top - (mobile ? TOOLBAR_STRIP_GAP_MOBILE : TOOLBAR_STRIP_GAP),
|
|
18519
|
+
left: centerX + shift,
|
|
18520
|
+
transform: "translate(-50%, -100%)",
|
|
18521
|
+
zIndex: 2147483645
|
|
18522
|
+
},
|
|
18523
|
+
children
|
|
18524
|
+
}
|
|
18525
|
+
);
|
|
18526
|
+
}
|
|
18310
18527
|
function requestValidateTree(postToParent2, tree) {
|
|
18311
18528
|
return new Promise((resolve) => {
|
|
18312
18529
|
const id = `ai-validate-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -18343,221 +18560,177 @@ function requestAssetPick(postToParent2) {
|
|
|
18343
18560
|
postToParent2({ type: "ow:asset-pick", id });
|
|
18344
18561
|
});
|
|
18345
18562
|
}
|
|
18346
|
-
function
|
|
18563
|
+
function ToolbarAction({
|
|
18347
18564
|
label,
|
|
18348
18565
|
onClick,
|
|
18349
|
-
disabled,
|
|
18350
|
-
active
|
|
18566
|
+
disabled = false,
|
|
18567
|
+
active = false,
|
|
18568
|
+
children
|
|
18351
18569
|
}) {
|
|
18352
|
-
|
|
18353
|
-
|
|
18354
|
-
{
|
|
18355
|
-
|
|
18356
|
-
|
|
18357
|
-
disabled,
|
|
18358
|
-
style: {
|
|
18359
|
-
height: 28,
|
|
18360
|
-
padding: "0 10px",
|
|
18361
|
-
display: "inline-flex",
|
|
18362
|
-
alignItems: "center",
|
|
18363
|
-
gap: 4,
|
|
18364
|
-
borderRadius: 999,
|
|
18365
|
-
border: "none",
|
|
18366
|
-
cursor: disabled ? "default" : "pointer",
|
|
18367
|
-
background: active ? OHW_BLUE_DARK : "#ffffff",
|
|
18368
|
-
color: active ? "#ffffff" : OHW_BLUE_DARK,
|
|
18369
|
-
opacity: disabled ? 0.4 : 1,
|
|
18370
|
-
fontSize: 12,
|
|
18371
|
-
lineHeight: "16px",
|
|
18372
|
-
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
18373
|
-
whiteSpace: "nowrap",
|
|
18374
|
-
flex: "0 0 auto"
|
|
18375
|
-
},
|
|
18376
|
-
children: label
|
|
18377
|
-
}
|
|
18378
|
-
);
|
|
18570
|
+
const button = /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, active, onClick, className: "size-8", children });
|
|
18571
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Tooltip, { children: [
|
|
18572
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "inline-flex", children: button }) : button }),
|
|
18573
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
|
|
18574
|
+
] });
|
|
18379
18575
|
}
|
|
18380
|
-
function
|
|
18381
|
-
|
|
18382
|
-
(0, import_react10.useEffect)(() => setDraft(value), [value]);
|
|
18383
|
-
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
18384
|
-
"div",
|
|
18385
|
-
{
|
|
18386
|
-
style: {
|
|
18387
|
-
display: "flex",
|
|
18388
|
-
alignItems: "center",
|
|
18389
|
-
gap: 6,
|
|
18390
|
-
height: 28,
|
|
18391
|
-
padding: "0 12px",
|
|
18392
|
-
borderRadius: 999,
|
|
18393
|
-
background: "#ffffff",
|
|
18394
|
-
width: "100%",
|
|
18395
|
-
maxWidth: 260,
|
|
18396
|
-
boxSizing: "border-box"
|
|
18397
|
-
},
|
|
18398
|
-
children: [
|
|
18399
|
-
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
18400
|
-
"span",
|
|
18401
|
-
{
|
|
18402
|
-
style: {
|
|
18403
|
-
flex: "0 0 auto",
|
|
18404
|
-
color: OHW_BLUE_DARK,
|
|
18405
|
-
fontSize: 10,
|
|
18406
|
-
fontWeight: 700,
|
|
18407
|
-
textTransform: "uppercase",
|
|
18408
|
-
letterSpacing: 0.4
|
|
18409
|
-
},
|
|
18410
|
-
children: "Alt"
|
|
18411
|
-
}
|
|
18412
|
-
),
|
|
18413
|
-
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
18414
|
-
"input",
|
|
18415
|
-
{
|
|
18416
|
-
type: "text",
|
|
18417
|
-
value: draft,
|
|
18418
|
-
onChange: (e) => setDraft(e.target.value),
|
|
18419
|
-
onBlur: () => {
|
|
18420
|
-
if (draft !== value) onCommit(draft);
|
|
18421
|
-
},
|
|
18422
|
-
onKeyDown: (e) => {
|
|
18423
|
-
if (e.key === "Enter") e.currentTarget.blur();
|
|
18424
|
-
if (e.key === "Escape") {
|
|
18425
|
-
setDraft(value);
|
|
18426
|
-
e.currentTarget.blur();
|
|
18427
|
-
}
|
|
18428
|
-
},
|
|
18429
|
-
placeholder: "Describe this image",
|
|
18430
|
-
"aria-label": "Image alt text",
|
|
18431
|
-
style: {
|
|
18432
|
-
flex: 1,
|
|
18433
|
-
minWidth: 0,
|
|
18434
|
-
border: "none",
|
|
18435
|
-
outline: "none",
|
|
18436
|
-
background: "transparent",
|
|
18437
|
-
fontSize: 12,
|
|
18438
|
-
lineHeight: "16px",
|
|
18439
|
-
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
18440
|
-
color: "#1f2937"
|
|
18441
|
-
}
|
|
18442
|
-
}
|
|
18443
|
-
)
|
|
18444
|
-
]
|
|
18445
|
-
}
|
|
18446
|
-
);
|
|
18576
|
+
function ToolbarSeparator() {
|
|
18577
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
|
|
18447
18578
|
}
|
|
18448
|
-
|
|
18449
|
-
|
|
18450
|
-
|
|
18451
|
-
|
|
18452
|
-
|
|
18453
|
-
|
|
18454
|
-
|
|
18455
|
-
|
|
18456
|
-
|
|
18457
|
-
|
|
18458
|
-
|
|
18459
|
-
|
|
18460
|
-
|
|
18461
|
-
|
|
18462
|
-
|
|
18463
|
-
|
|
18464
|
-
|
|
18465
|
-
|
|
18466
|
-
|
|
18579
|
+
function OptionMenu({
|
|
18580
|
+
label,
|
|
18581
|
+
value,
|
|
18582
|
+
options,
|
|
18583
|
+
onChange
|
|
18584
|
+
}) {
|
|
18585
|
+
const current = options.find((o) => o.value === value) ?? options[0];
|
|
18586
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
18587
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-xs text-muted-foreground", children: label }),
|
|
18588
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(DropdownMenu, { modal: false, children: [
|
|
18589
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
18590
|
+
"button",
|
|
18591
|
+
{
|
|
18592
|
+
type: "button",
|
|
18593
|
+
"aria-label": label,
|
|
18594
|
+
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",
|
|
18595
|
+
children: [
|
|
18596
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "flex-1 text-left", children: current.label }),
|
|
18597
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.ChevronDown, { size: 16, style: { pointerEvents: "none" } })
|
|
18598
|
+
]
|
|
18599
|
+
}
|
|
18600
|
+
) }),
|
|
18601
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[132px] min-w-[132px] p-1", children: options.map((option) => {
|
|
18602
|
+
const selected = option.value === value;
|
|
18603
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
18604
|
+
DropdownMenuItem,
|
|
18605
|
+
{
|
|
18606
|
+
role: "menuitemradio",
|
|
18607
|
+
"aria-checked": selected,
|
|
18608
|
+
onSelect: () => onChange(option.value),
|
|
18609
|
+
className: cn("grid grid-cols-[1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
|
|
18610
|
+
children: [
|
|
18611
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: option.label }),
|
|
18612
|
+
selected && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Check, { size: 16, className: "text-bridge-primary" })
|
|
18613
|
+
]
|
|
18614
|
+
},
|
|
18615
|
+
option.value
|
|
18616
|
+
);
|
|
18617
|
+
}) })
|
|
18618
|
+
] })
|
|
18619
|
+
] });
|
|
18620
|
+
}
|
|
18621
|
+
var VARIANTS = [
|
|
18622
|
+
{ value: "logos", label: "Logos" },
|
|
18623
|
+
{ value: "reel", label: "Reel" }
|
|
18624
|
+
];
|
|
18625
|
+
var ALIGNS = [
|
|
18626
|
+
{ value: "left", label: "Align left", Icon: import_lucide_react9.AlignLeft },
|
|
18627
|
+
{ value: "center", label: "Align center", Icon: import_lucide_react9.AlignCenter },
|
|
18628
|
+
{ value: "right", label: "Align right", Icon: import_lucide_react9.AlignRight }
|
|
18629
|
+
];
|
|
18630
|
+
var HOVERS = [
|
|
18631
|
+
{ value: "none", label: "None" },
|
|
18632
|
+
{ value: "lift", label: "Lift" },
|
|
18633
|
+
{ value: "zoom", label: "Zoom" },
|
|
18634
|
+
{ value: "fade", label: "Fade" }
|
|
18635
|
+
];
|
|
18467
18636
|
var HTTP_URL_RE = /^https?:\/\/\S+$/i;
|
|
18468
|
-
function
|
|
18469
|
-
|
|
18637
|
+
function LinkModal({
|
|
18638
|
+
href,
|
|
18639
|
+
linkTarget,
|
|
18640
|
+
onClose,
|
|
18641
|
+
onSave
|
|
18642
|
+
}) {
|
|
18643
|
+
const [draft, setDraft] = (0, import_react10.useState)(href);
|
|
18644
|
+
const [newTab, setNewTab] = (0, import_react10.useState)(linkTarget !== "same-tab");
|
|
18470
18645
|
const [invalid, setInvalid] = (0, import_react10.useState)(false);
|
|
18471
|
-
|
|
18472
|
-
setDraft(value);
|
|
18473
|
-
setInvalid(false);
|
|
18474
|
-
}, [value]);
|
|
18475
|
-
const commit = () => {
|
|
18646
|
+
const save = () => {
|
|
18476
18647
|
const next = draft.trim();
|
|
18477
|
-
if (next
|
|
18478
|
-
|
|
18479
|
-
|
|
18480
|
-
onCommit(next);
|
|
18481
|
-
};
|
|
18482
|
-
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
18483
|
-
"div",
|
|
18484
|
-
{
|
|
18485
|
-
style: {
|
|
18486
|
-
display: "flex",
|
|
18487
|
-
alignItems: "center",
|
|
18488
|
-
gap: 6,
|
|
18489
|
-
height: 28,
|
|
18490
|
-
padding: "0 12px",
|
|
18491
|
-
borderRadius: 999,
|
|
18492
|
-
background: "#ffffff",
|
|
18493
|
-
width: "100%",
|
|
18494
|
-
maxWidth: 260,
|
|
18495
|
-
boxSizing: "border-box",
|
|
18496
|
-
boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
|
|
18497
|
-
},
|
|
18498
|
-
children: [
|
|
18499
|
-
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
18500
|
-
"span",
|
|
18501
|
-
{
|
|
18502
|
-
style: {
|
|
18503
|
-
flex: "0 0 auto",
|
|
18504
|
-
color: OHW_BLUE_DARK,
|
|
18505
|
-
fontSize: 10,
|
|
18506
|
-
fontWeight: 700,
|
|
18507
|
-
textTransform: "uppercase",
|
|
18508
|
-
letterSpacing: 0.4
|
|
18509
|
-
},
|
|
18510
|
-
children: "Link"
|
|
18511
|
-
}
|
|
18512
|
-
),
|
|
18513
|
-
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
18514
|
-
"input",
|
|
18515
|
-
{
|
|
18516
|
-
type: "text",
|
|
18517
|
-
inputMode: "url",
|
|
18518
|
-
value: draft,
|
|
18519
|
-
onChange: (e) => setDraft(e.target.value),
|
|
18520
|
-
onBlur: commit,
|
|
18521
|
-
onKeyDown: (e) => {
|
|
18522
|
-
if (e.key === "Enter") e.currentTarget.blur();
|
|
18523
|
-
if (e.key === "Escape") {
|
|
18524
|
-
setDraft(value);
|
|
18525
|
-
setInvalid(false);
|
|
18526
|
-
e.currentTarget.blur();
|
|
18527
|
-
}
|
|
18528
|
-
},
|
|
18529
|
-
placeholder: "https://example.com",
|
|
18530
|
-
"aria-label": "Image link URL",
|
|
18531
|
-
"aria-invalid": invalid,
|
|
18532
|
-
style: {
|
|
18533
|
-
flex: 1,
|
|
18534
|
-
minWidth: 0,
|
|
18535
|
-
border: "none",
|
|
18536
|
-
outline: "none",
|
|
18537
|
-
background: "transparent",
|
|
18538
|
-
fontSize: 12,
|
|
18539
|
-
lineHeight: "16px",
|
|
18540
|
-
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
18541
|
-
color: "#1f2937"
|
|
18542
|
-
}
|
|
18543
|
-
}
|
|
18544
|
-
)
|
|
18545
|
-
]
|
|
18648
|
+
if (next && !HTTP_URL_RE.test(next)) {
|
|
18649
|
+
setInvalid(true);
|
|
18650
|
+
return;
|
|
18546
18651
|
}
|
|
18547
|
-
|
|
18652
|
+
onSave(next, newTab ? "new-tab" : "same-tab");
|
|
18653
|
+
onClose();
|
|
18654
|
+
};
|
|
18655
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Dialog2, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(DialogContent, { "data-ohw-link-modal-root": "", className: "max-w-[400px] gap-4 p-5", children: [
|
|
18656
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DialogTitle, { className: "text-base", children: "Image link" }) }),
|
|
18657
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col gap-3", children: [
|
|
18658
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18659
|
+
"input",
|
|
18660
|
+
{
|
|
18661
|
+
autoFocus: true,
|
|
18662
|
+
type: "text",
|
|
18663
|
+
inputMode: "url",
|
|
18664
|
+
value: draft,
|
|
18665
|
+
onChange: (e) => {
|
|
18666
|
+
setDraft(e.target.value);
|
|
18667
|
+
setInvalid(false);
|
|
18668
|
+
},
|
|
18669
|
+
onKeyDown: (e) => {
|
|
18670
|
+
if (e.key === "Enter") save();
|
|
18671
|
+
},
|
|
18672
|
+
placeholder: "https://example.com",
|
|
18673
|
+
"aria-label": "Image link URL",
|
|
18674
|
+
"aria-invalid": invalid,
|
|
18675
|
+
className: cn(
|
|
18676
|
+
"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",
|
|
18677
|
+
invalid && "border-destructive focus:border-destructive"
|
|
18678
|
+
)
|
|
18679
|
+
}
|
|
18680
|
+
),
|
|
18681
|
+
invalid && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-xs text-destructive", children: "Enter a full URL starting with http:// or https://" }),
|
|
18682
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { className: "flex items-center gap-2 text-[13px] text-foreground", children: [
|
|
18683
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { type: "checkbox", checked: newTab, onChange: (e) => setNewTab(e.target.checked) }),
|
|
18684
|
+
"Open in new tab"
|
|
18685
|
+
] })
|
|
18686
|
+
] }),
|
|
18687
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(DialogFooter, { children: [
|
|
18688
|
+
href && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18689
|
+
"button",
|
|
18690
|
+
{
|
|
18691
|
+
type: "button",
|
|
18692
|
+
onClick: () => {
|
|
18693
|
+
onSave("", "new-tab");
|
|
18694
|
+
onClose();
|
|
18695
|
+
},
|
|
18696
|
+
className: "mr-auto rounded-[6px] px-3 py-2 text-[13px] font-medium text-destructive transition-colors hover:bg-muted",
|
|
18697
|
+
children: "Remove link"
|
|
18698
|
+
}
|
|
18699
|
+
),
|
|
18700
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18701
|
+
"button",
|
|
18702
|
+
{
|
|
18703
|
+
type: "button",
|
|
18704
|
+
onClick: onClose,
|
|
18705
|
+
className: "rounded-[6px] px-3 py-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted",
|
|
18706
|
+
children: "Cancel"
|
|
18707
|
+
}
|
|
18708
|
+
),
|
|
18709
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18710
|
+
"button",
|
|
18711
|
+
{
|
|
18712
|
+
type: "button",
|
|
18713
|
+
onClick: save,
|
|
18714
|
+
className: "rounded-[6px] bg-bridge-primary px-3 py-2 text-[13px] font-medium text-primary-foreground transition-opacity hover:opacity-90",
|
|
18715
|
+
children: "Save"
|
|
18716
|
+
}
|
|
18717
|
+
)
|
|
18718
|
+
] })
|
|
18719
|
+
] }) });
|
|
18548
18720
|
}
|
|
18549
18721
|
function MediaStripToolbar({
|
|
18550
18722
|
entry,
|
|
18551
18723
|
index,
|
|
18552
18724
|
pending,
|
|
18553
18725
|
error,
|
|
18726
|
+
itemEditOn,
|
|
18727
|
+
onToggleItemEdit,
|
|
18554
18728
|
onSetVariant,
|
|
18555
18729
|
onSetAlign,
|
|
18556
18730
|
onSetHover,
|
|
18557
18731
|
onSetTreatment,
|
|
18558
18732
|
onResize,
|
|
18559
|
-
|
|
18560
|
-
onSetLink,
|
|
18733
|
+
onOpenLink,
|
|
18561
18734
|
onAddItem,
|
|
18562
18735
|
onRemoveItem,
|
|
18563
18736
|
onChangeImage,
|
|
@@ -18566,81 +18739,102 @@ function MediaStripToolbar({
|
|
|
18566
18739
|
}) {
|
|
18567
18740
|
const items = mediaStripItems(entry.tree);
|
|
18568
18741
|
const itemCount = items.length;
|
|
18569
|
-
const currentAlt = items[index]?.alt ?? "";
|
|
18570
|
-
const currentHref = items[index]?.href ?? "";
|
|
18571
|
-
const currentTarget = items[index]?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
|
|
18572
18742
|
const slots = findMediaStripSlots(entry.tree);
|
|
18573
18743
|
const variant = slots?.variant === "reel" ? "reel" : "logos";
|
|
18574
18744
|
const align = slots?.align === "left" || slots?.align === "right" ? slots.align : "center";
|
|
18575
18745
|
const hover = slots?.hover === "none" || slots?.hover === "lift" || slots?.hover === "zoom" || slots?.hover === "fade" ? slots.hover : "lift";
|
|
18576
18746
|
const treatment = slots?.treatment === "color" || slots?.treatment === "grayscale" ? slots.treatment : variant === "logos" ? "grayscale" : "color";
|
|
18577
18747
|
const sizeValue = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
|
|
18578
|
-
const
|
|
18579
|
-
const
|
|
18580
|
-
|
|
18581
|
-
gap: 6,
|
|
18582
|
-
flexWrap: "nowrap",
|
|
18583
|
-
justifyContent: "center",
|
|
18584
|
-
overflowX: "auto",
|
|
18585
|
-
WebkitOverflowScrolling: "touch",
|
|
18586
|
-
width: "100%",
|
|
18587
|
-
scrollbarWidth: "none"
|
|
18588
|
-
} : { display: "flex", gap: 6, flexWrap: "nowrap", justifyContent: "center" };
|
|
18589
|
-
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
18748
|
+
const mobile = window.innerWidth <= 480;
|
|
18749
|
+
const gatedLabel = (label) => itemEditOn ? label : "Turn on the star to edit this image";
|
|
18750
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
18590
18751
|
"div",
|
|
18591
18752
|
{
|
|
18592
18753
|
"data-ohw-bridge": "",
|
|
18593
18754
|
"data-ohw-toolbar": "",
|
|
18594
18755
|
onMouseDown: (e) => e.stopPropagation(),
|
|
18595
|
-
|
|
18596
|
-
|
|
18597
|
-
flexDirection: "column",
|
|
18598
|
-
gap: 6,
|
|
18599
|
-
alignItems: "center",
|
|
18600
|
-
background: OHW_BLUE,
|
|
18601
|
-
padding: 8,
|
|
18602
|
-
borderRadius: 12,
|
|
18603
|
-
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
18604
|
-
pointerEvents: pending ? "none" : "auto",
|
|
18605
|
-
opacity: pending ? 0.6 : 1,
|
|
18606
|
-
maxWidth: isMobile ? "calc(100vw - 24px)" : "none"
|
|
18607
|
-
},
|
|
18756
|
+
className: cn("flex flex-col items-center gap-1.5 font-sans", pending && "pointer-events-none opacity-60"),
|
|
18757
|
+
style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
|
|
18608
18758
|
children: [
|
|
18609
|
-
/* @__PURE__ */ (0,
|
|
18610
|
-
|
|
18611
|
-
|
|
18612
|
-
|
|
18613
|
-
|
|
18614
|
-
|
|
18615
|
-
|
|
18616
|
-
|
|
18617
|
-
|
|
18618
|
-
|
|
18619
|
-
|
|
18620
|
-
|
|
18621
|
-
|
|
18622
|
-
|
|
18623
|
-
|
|
18624
|
-
|
|
18625
|
-
|
|
18626
|
-
|
|
18627
|
-
|
|
18628
|
-
|
|
18629
|
-
|
|
18630
|
-
|
|
18631
|
-
|
|
18632
|
-
|
|
18633
|
-
|
|
18634
|
-
|
|
18635
|
-
|
|
18636
|
-
|
|
18637
|
-
|
|
18638
|
-
|
|
18639
|
-
|
|
18640
|
-
|
|
18759
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
18760
|
+
"div",
|
|
18761
|
+
{
|
|
18762
|
+
className: cn(
|
|
18763
|
+
"flex items-center gap-1 rounded-[10px] border border-border bg-background p-1 whitespace-nowrap",
|
|
18764
|
+
"shadow-[0px_10px_15px_-3px_rgba(0,0,0,0.1),0px_4px_6px_-4px_rgba(0,0,0,0.1)]",
|
|
18765
|
+
mobile ? "flex-wrap justify-center" : "flex-nowrap"
|
|
18766
|
+
),
|
|
18767
|
+
children: [
|
|
18768
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Tooltip, { children: [
|
|
18769
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18770
|
+
CustomToolbarButton,
|
|
18771
|
+
{
|
|
18772
|
+
type: "button",
|
|
18773
|
+
"aria-label": itemEditOn ? "Done editing this image" : "Edit this image",
|
|
18774
|
+
"aria-pressed": itemEditOn,
|
|
18775
|
+
onClick: onToggleItemEdit,
|
|
18776
|
+
className: "group size-8",
|
|
18777
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18778
|
+
import_lucide_react9.Star,
|
|
18779
|
+
{
|
|
18780
|
+
size: 16,
|
|
18781
|
+
fill: "currentColor",
|
|
18782
|
+
strokeWidth: 0,
|
|
18783
|
+
className: cn(
|
|
18784
|
+
"transition-colors",
|
|
18785
|
+
itemEditOn ? "text-[#f59e0b] group-hover:text-[#d97706]" : "text-[#d6d3d1] group-hover:text-[#fbbf24]"
|
|
18786
|
+
),
|
|
18787
|
+
style: { pointerEvents: "none" }
|
|
18788
|
+
}
|
|
18789
|
+
)
|
|
18790
|
+
}
|
|
18791
|
+
) }),
|
|
18792
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: itemEditOn ? "Done editing this image" : "Edit this image" })
|
|
18793
|
+
] }),
|
|
18794
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarSeparator, {}),
|
|
18795
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: gatedLabel("Change image"), onClick: onChangeImage, disabled: !itemEditOn, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Image, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
18796
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: gatedLabel("Link"), onClick: onOpenLink, disabled: !itemEditOn, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Link, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
18797
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: gatedLabel("Move left"), onClick: onMoveLeft, disabled: !itemEditOn || index <= 0, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.ArrowLeft, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
18798
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18799
|
+
ToolbarAction,
|
|
18800
|
+
{
|
|
18801
|
+
label: gatedLabel("Move right"),
|
|
18802
|
+
onClick: onMoveRight,
|
|
18803
|
+
disabled: !itemEditOn || index >= itemCount - 1,
|
|
18804
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.ArrowRight, { size: 16, style: { pointerEvents: "none" } })
|
|
18805
|
+
}
|
|
18806
|
+
),
|
|
18807
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: gatedLabel("Remove image"), onClick: onRemoveItem, disabled: !itemEditOn || itemCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.ImageMinus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
18808
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarSeparator, {}),
|
|
18809
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(OptionMenu, { label: "Layout", value: variant, options: VARIANTS, onChange: onSetVariant }),
|
|
18810
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(OptionMenu, { label: "Hover", value: hover, options: HOVERS, onChange: onSetHover }),
|
|
18811
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18812
|
+
ToolbarAction,
|
|
18813
|
+
{
|
|
18814
|
+
label: treatment === "grayscale" ? "Show in color" : "Show grayscale",
|
|
18815
|
+
active: treatment === "grayscale",
|
|
18816
|
+
onClick: () => onSetTreatment(treatment === "grayscale" ? "color" : "grayscale"),
|
|
18817
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Palette, { size: 16, style: { pointerEvents: "none" } })
|
|
18818
|
+
}
|
|
18819
|
+
),
|
|
18820
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarSeparator, {}),
|
|
18821
|
+
ALIGNS.map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label, active: align === value, onClick: () => onSetAlign(value), children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Icon, { size: 16, style: { pointerEvents: "none" } }) }, value)),
|
|
18822
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarSeparator, {}),
|
|
18823
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: "Smaller", onClick: () => onResize(-8), children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Minus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
18824
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "min-w-[40px] text-center text-xs tabular-nums text-muted-foreground", children: [
|
|
18825
|
+
sizeValue,
|
|
18826
|
+
"px"
|
|
18827
|
+
] }),
|
|
18828
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: "Larger", onClick: () => onResize(8), children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Plus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
18829
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarSeparator, {}),
|
|
18830
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: "Add image", onClick: onAddItem, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.ImagePlus, { size: 16, style: { pointerEvents: "none" } }) })
|
|
18831
|
+
]
|
|
18832
|
+
}
|
|
18833
|
+
),
|
|
18834
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
|
|
18641
18835
|
]
|
|
18642
18836
|
}
|
|
18643
|
-
);
|
|
18837
|
+
) });
|
|
18644
18838
|
}
|
|
18645
18839
|
function findMediaStripSlots(tree) {
|
|
18646
18840
|
const stack = tree.rows.flatMap((row) => row.blocks);
|
|
@@ -18659,31 +18853,23 @@ function AiMediaStripOverlay({
|
|
|
18659
18853
|
}) {
|
|
18660
18854
|
const [hover, setHover] = (0, import_react10.useState)(null);
|
|
18661
18855
|
const [active, setActive] = (0, import_react10.useState)(null);
|
|
18856
|
+
const [itemEditOn, setItemEditOn] = (0, import_react10.useState)(false);
|
|
18857
|
+
const [linkOpen, setLinkOpen] = (0, import_react10.useState)(false);
|
|
18662
18858
|
const [pending, setPending] = (0, import_react10.useState)(false);
|
|
18663
18859
|
const [error, setError] = (0, import_react10.useState)(null);
|
|
18664
18860
|
const activeRef = (0, import_react10.useRef)(null);
|
|
18665
18861
|
activeRef.current = active;
|
|
18862
|
+
const linkOpenRef = (0, import_react10.useRef)(false);
|
|
18863
|
+
linkOpenRef.current = linkOpen;
|
|
18666
18864
|
(0, import_react10.useEffect)(() => {
|
|
18667
18865
|
const onMove = (e) => {
|
|
18866
|
+
const ref = itemRefFromTarget(e.target);
|
|
18668
18867
|
const t = e.target;
|
|
18669
|
-
|
|
18670
|
-
|
|
18671
|
-
|
|
18672
|
-
|
|
18673
|
-
|
|
18674
|
-
if (!itemEl) {
|
|
18675
|
-
setHover(null);
|
|
18676
|
-
return;
|
|
18677
|
-
}
|
|
18678
|
-
const sectionEl = itemEl.closest("[data-ohw-section]");
|
|
18679
|
-
const unit = sectionEl ? movableUnit(sectionEl) : null;
|
|
18680
|
-
const sectionId = unit ? instanceIdOf(unit) || null : null;
|
|
18681
|
-
const index = Number(itemEl.dataset.ohwMediaStripIndex);
|
|
18682
|
-
if (!sectionId || Number.isNaN(index)) {
|
|
18683
|
-
setHover(null);
|
|
18684
|
-
return;
|
|
18685
|
-
}
|
|
18686
|
-
setHover({ sectionId, index });
|
|
18868
|
+
const overEditable = Boolean(t?.closest?.("[data-ohw-editable]"));
|
|
18869
|
+
setHover((prev) => {
|
|
18870
|
+
const next = ref && !overEditable ? ref : null;
|
|
18871
|
+
return sameRef(prev, next) ? prev : next;
|
|
18872
|
+
});
|
|
18687
18873
|
};
|
|
18688
18874
|
const onLeave = () => setHover(null);
|
|
18689
18875
|
document.addEventListener("mousemove", onMove, { passive: true });
|
|
@@ -18695,23 +18881,25 @@ function AiMediaStripOverlay({
|
|
|
18695
18881
|
}, []);
|
|
18696
18882
|
(0, import_react10.useEffect)(() => {
|
|
18697
18883
|
const onClick = (e) => {
|
|
18698
|
-
const current = activeRef.current;
|
|
18699
|
-
if (!current) return;
|
|
18700
18884
|
const t = e.target;
|
|
18701
|
-
if (!(t instanceof
|
|
18702
|
-
if (t.closest(
|
|
18703
|
-
const
|
|
18704
|
-
if (
|
|
18705
|
-
|
|
18885
|
+
if (!(t instanceof Element)) return;
|
|
18886
|
+
if (t.closest(CHROME_SELECTOR)) return;
|
|
18887
|
+
const ref = itemRefFromTarget(t);
|
|
18888
|
+
if (sameRef(activeRef.current, ref)) return;
|
|
18889
|
+
if (ref) clearInteractionChromeRef.current();
|
|
18890
|
+
setItemEditOn(false);
|
|
18706
18891
|
setError(null);
|
|
18892
|
+
setActive(ref);
|
|
18707
18893
|
};
|
|
18708
18894
|
document.addEventListener("click", onClick, true);
|
|
18709
18895
|
return () => document.removeEventListener("click", onClick, true);
|
|
18710
|
-
}, []);
|
|
18896
|
+
}, [clearInteractionChromeRef]);
|
|
18711
18897
|
(0, import_react10.useEffect)(() => {
|
|
18712
18898
|
const onBlur = () => {
|
|
18713
18899
|
if (!activeRef.current) return;
|
|
18714
18900
|
setActive(null);
|
|
18901
|
+
setItemEditOn(false);
|
|
18902
|
+
setLinkOpen(false);
|
|
18715
18903
|
setError(null);
|
|
18716
18904
|
};
|
|
18717
18905
|
window.addEventListener("blur", onBlur);
|
|
@@ -18721,7 +18909,10 @@ function AiMediaStripOverlay({
|
|
|
18721
18909
|
const onKeyDown = (e) => {
|
|
18722
18910
|
if (e.key !== "Escape") return;
|
|
18723
18911
|
if (!activeRef.current) return;
|
|
18912
|
+
if (linkOpenRef.current) return;
|
|
18913
|
+
if (document.querySelector('[data-ohw-more-menu][data-state="open"]')) return;
|
|
18724
18914
|
setActive(null);
|
|
18915
|
+
setItemEditOn(false);
|
|
18725
18916
|
setError(null);
|
|
18726
18917
|
};
|
|
18727
18918
|
document.addEventListener("keydown", onKeyDown);
|
|
@@ -18755,137 +18946,133 @@ function AiMediaStripOverlay({
|
|
|
18755
18946
|
tree: nextTree,
|
|
18756
18947
|
label: entry.label,
|
|
18757
18948
|
media: extraMedia ? { ...entry.media, ...extraMedia } : entry.media,
|
|
18758
|
-
...entry.brand ? { brand: entry.brand } : {}
|
|
18949
|
+
...entry.brand ? { brand: entry.brand } : {},
|
|
18950
|
+
// The user is already looking at the strip they just edited — recentering the viewport
|
|
18951
|
+
// on every edit reads as the section jumping around.
|
|
18952
|
+
skipScrollIntoView: true
|
|
18759
18953
|
});
|
|
18760
18954
|
return true;
|
|
18761
18955
|
},
|
|
18762
18956
|
[findEntry, postToParent2, applyTreeLocalRef]
|
|
18763
18957
|
);
|
|
18764
18958
|
const activeEntry = active ? findEntry(active.sectionId) : null;
|
|
18765
|
-
const hoverHandleRect = useLiveItemRect(!active && hover ? hover : null);
|
|
18766
18959
|
const activeItemRect = useLiveItemRect(active);
|
|
18767
|
-
const
|
|
18768
|
-
const
|
|
18769
|
-
|
|
18770
|
-
|
|
18771
|
-
|
|
18772
|
-
|
|
18773
|
-
|
|
18774
|
-
|
|
18775
|
-
|
|
18776
|
-
|
|
18777
|
-
|
|
18778
|
-
|
|
18779
|
-
|
|
18780
|
-
|
|
18781
|
-
|
|
18782
|
-
|
|
18783
|
-
|
|
18784
|
-
|
|
18785
|
-
|
|
18786
|
-
|
|
18787
|
-
|
|
18788
|
-
|
|
18789
|
-
|
|
18790
|
-
|
|
18791
|
-
|
|
18792
|
-
|
|
18793
|
-
|
|
18794
|
-
|
|
18795
|
-
|
|
18796
|
-
|
|
18797
|
-
|
|
18798
|
-
|
|
18799
|
-
|
|
18800
|
-
|
|
18801
|
-
activeItemRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
18802
|
-
ItemInteractionLayer,
|
|
18803
|
-
{
|
|
18804
|
-
rect: activeItemRect,
|
|
18805
|
-
state: toolbarState,
|
|
18806
|
-
toolbar: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
18807
|
-
MediaStripToolbar,
|
|
18808
|
-
{
|
|
18809
|
-
entry: activeEntry,
|
|
18810
|
-
index: active.index,
|
|
18811
|
-
pending,
|
|
18812
|
-
error,
|
|
18813
|
-
onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
|
|
18814
|
-
onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
|
|
18815
|
-
onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
|
|
18816
|
-
onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
|
|
18817
|
-
onResize: (delta) => {
|
|
18818
|
-
const slots = findMediaStripSlots(activeEntry.tree);
|
|
18819
|
-
const variant = slots?.variant === "reel" ? "reel" : "logos";
|
|
18820
|
-
const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
|
|
18821
|
-
void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
|
|
18822
|
-
},
|
|
18823
|
-
onSetAlt: (alt) => {
|
|
18824
|
-
void runMutation(active.sectionId, (tree) => setMediaStripItemAlt(tree, active.index, alt));
|
|
18825
|
-
},
|
|
18826
|
-
onSetLink: (href, linkTarget) => {
|
|
18960
|
+
const activeStripRect = useLiveItemRect(active, true);
|
|
18961
|
+
const hoverRect = useLiveItemRect(hover && !sameRef(hover, active) ? hover : null);
|
|
18962
|
+
const activeItems = activeEntry ? mediaStripItems(activeEntry.tree) : [];
|
|
18963
|
+
const activeItem = active ? activeItems[active.index] : void 0;
|
|
18964
|
+
const activeHref = activeItem?.href ?? "";
|
|
18965
|
+
const activeTarget = activeItem?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
|
|
18966
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
18967
|
+
hoverRect && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
|
|
18968
|
+
activeItemRect && activeStripRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
18969
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ItemInteractionLayer, { rect: activeItemRect, state: "active-top" }),
|
|
18970
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StripToolbarSlot, { stripRect: activeStripRect, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18971
|
+
MediaStripToolbar,
|
|
18972
|
+
{
|
|
18973
|
+
entry: activeEntry,
|
|
18974
|
+
index: active.index,
|
|
18975
|
+
pending,
|
|
18976
|
+
error,
|
|
18977
|
+
itemEditOn,
|
|
18978
|
+
onToggleItemEdit: () => setItemEditOn((on) => !on),
|
|
18979
|
+
onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
|
|
18980
|
+
onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
|
|
18981
|
+
onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
|
|
18982
|
+
onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
|
|
18983
|
+
onResize: (delta) => {
|
|
18984
|
+
const slots = findMediaStripSlots(activeEntry.tree);
|
|
18985
|
+
const variant = slots?.variant === "reel" ? "reel" : "logos";
|
|
18986
|
+
const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
|
|
18987
|
+
void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
|
|
18988
|
+
},
|
|
18989
|
+
onOpenLink: () => setLinkOpen(true),
|
|
18990
|
+
onAddItem: () => {
|
|
18991
|
+
void requestAssetPick(postToParent2).then((picked) => {
|
|
18992
|
+
if (!picked) return;
|
|
18993
|
+
const item = { assetId: picked.assetId, alt: "Logo" };
|
|
18827
18994
|
void runMutation(
|
|
18828
18995
|
active.sectionId,
|
|
18829
|
-
(tree) =>
|
|
18830
|
-
|
|
18831
|
-
|
|
18832
|
-
|
|
18833
|
-
void requestAssetPick(postToParent2).then((picked) => {
|
|
18834
|
-
if (!picked) return;
|
|
18835
|
-
const item = { assetId: picked.assetId, alt: "Logo" };
|
|
18836
|
-
void runMutation(
|
|
18837
|
-
active.sectionId,
|
|
18838
|
-
(tree) => addMediaStripItem(tree, item, active.index),
|
|
18839
|
-
{ [picked.assetId]: picked.url }
|
|
18840
|
-
).then((applied) => {
|
|
18841
|
-
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
18842
|
-
});
|
|
18843
|
-
});
|
|
18844
|
-
},
|
|
18845
|
-
onChangeImage: () => {
|
|
18846
|
-
void requestAssetPick(postToParent2).then((picked) => {
|
|
18847
|
-
if (!picked) return;
|
|
18848
|
-
void runMutation(
|
|
18849
|
-
active.sectionId,
|
|
18850
|
-
(tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
|
|
18851
|
-
{ [picked.assetId]: picked.url }
|
|
18852
|
-
);
|
|
18996
|
+
(tree) => addMediaStripItem(tree, item, active.index),
|
|
18997
|
+
{ [picked.assetId]: picked.url }
|
|
18998
|
+
).then((applied) => {
|
|
18999
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
18853
19000
|
});
|
|
18854
|
-
}
|
|
18855
|
-
|
|
18856
|
-
|
|
18857
|
-
|
|
18858
|
-
|
|
18859
|
-
|
|
18860
|
-
|
|
18861
|
-
|
|
18862
|
-
|
|
18863
|
-
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
|
|
18864
|
-
(applied) => {
|
|
18865
|
-
if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
|
|
18866
|
-
}
|
|
18867
|
-
);
|
|
18868
|
-
},
|
|
18869
|
-
onMoveRight: () => {
|
|
18870
|
-
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
|
|
18871
|
-
(applied) => {
|
|
18872
|
-
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
18873
|
-
}
|
|
19001
|
+
});
|
|
19002
|
+
},
|
|
19003
|
+
onChangeImage: () => {
|
|
19004
|
+
void requestAssetPick(postToParent2).then((picked) => {
|
|
19005
|
+
if (!picked) return;
|
|
19006
|
+
void runMutation(
|
|
19007
|
+
active.sectionId,
|
|
19008
|
+
(tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
|
|
19009
|
+
{ [picked.assetId]: picked.url }
|
|
18874
19010
|
);
|
|
18875
|
-
}
|
|
19011
|
+
});
|
|
19012
|
+
},
|
|
19013
|
+
onRemoveItem: () => {
|
|
19014
|
+
void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
|
|
19015
|
+
(applied) => {
|
|
19016
|
+
if (applied) setActive(null);
|
|
19017
|
+
}
|
|
19018
|
+
);
|
|
19019
|
+
},
|
|
19020
|
+
onMoveLeft: () => {
|
|
19021
|
+
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
|
|
19022
|
+
(applied) => {
|
|
19023
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
|
|
19024
|
+
}
|
|
19025
|
+
);
|
|
19026
|
+
},
|
|
19027
|
+
onMoveRight: () => {
|
|
19028
|
+
void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
|
|
19029
|
+
(applied) => {
|
|
19030
|
+
if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
|
|
19031
|
+
}
|
|
19032
|
+
);
|
|
18876
19033
|
}
|
|
18877
|
-
|
|
18878
|
-
}
|
|
18879
|
-
|
|
19034
|
+
}
|
|
19035
|
+
) }),
|
|
19036
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19037
|
+
"div",
|
|
19038
|
+
{
|
|
19039
|
+
"data-ohw-bridge": "",
|
|
19040
|
+
"data-ohw-item-interaction": "",
|
|
19041
|
+
"aria-hidden": true,
|
|
19042
|
+
className: "pointer-events-none fixed rounded-[4px] px-[7px] py-[3px] font-sans text-[11px] font-medium leading-none text-primary-foreground whitespace-nowrap",
|
|
19043
|
+
style: {
|
|
19044
|
+
top: activeItemRect.top + activeItemRect.height + 10,
|
|
19045
|
+
left: activeItemRect.left - 5,
|
|
19046
|
+
background: PRIMARY3,
|
|
19047
|
+
zIndex: 2147483644
|
|
19048
|
+
},
|
|
19049
|
+
children: "Media item"
|
|
19050
|
+
}
|
|
19051
|
+
),
|
|
19052
|
+
linkOpen && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
19053
|
+
LinkModal,
|
|
19054
|
+
{
|
|
19055
|
+
href: activeHref,
|
|
19056
|
+
linkTarget: activeTarget,
|
|
19057
|
+
onClose: () => setLinkOpen(false),
|
|
19058
|
+
onSave: (href, linkTarget) => {
|
|
19059
|
+
void runMutation(
|
|
19060
|
+
active.sectionId,
|
|
19061
|
+
(tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
|
|
19062
|
+
);
|
|
19063
|
+
}
|
|
19064
|
+
}
|
|
19065
|
+
)
|
|
19066
|
+
] })
|
|
18880
19067
|
] });
|
|
18881
19068
|
}
|
|
18882
19069
|
|
|
18883
19070
|
// src/ui/ai-section/AiPricingCardOverlay.tsx
|
|
18884
19071
|
var import_react11 = require("react");
|
|
18885
|
-
var
|
|
18886
|
-
var
|
|
19072
|
+
var import_lucide_react10 = require("lucide-react");
|
|
19073
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
18887
19074
|
var PRIMARY4 = "var(--ohw-primary, #0885FE)";
|
|
18888
|
-
var
|
|
19075
|
+
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]";
|
|
18889
19076
|
function findPricingCardElement(sectionId, index) {
|
|
18890
19077
|
const sectionEl = findByInstanceId(sectionId);
|
|
18891
19078
|
if (!sectionEl) return null;
|
|
@@ -18897,7 +19084,7 @@ function findPricingCardElement(sectionId, index) {
|
|
|
18897
19084
|
}
|
|
18898
19085
|
function cardRefFromTarget(target) {
|
|
18899
19086
|
if (!(target instanceof Element)) return null;
|
|
18900
|
-
if (target.closest(
|
|
19087
|
+
if (target.closest(CHROME_SELECTOR2)) return null;
|
|
18901
19088
|
const cardEl = target.closest("[data-ohw-pricing-card]");
|
|
18902
19089
|
if (!cardEl) return null;
|
|
18903
19090
|
const sectionEl = cardEl.closest("[data-ohw-section]");
|
|
@@ -18907,21 +19094,21 @@ function cardRefFromTarget(target) {
|
|
|
18907
19094
|
if (!sectionId || Number.isNaN(index)) return null;
|
|
18908
19095
|
return { sectionId, index };
|
|
18909
19096
|
}
|
|
18910
|
-
function
|
|
19097
|
+
function sameRef2(a, b) {
|
|
18911
19098
|
return a?.sectionId === b?.sectionId && a?.index === b?.index;
|
|
18912
19099
|
}
|
|
18913
|
-
function
|
|
19100
|
+
function rectOf2(el) {
|
|
18914
19101
|
if (!el) return null;
|
|
18915
19102
|
const r2 = el.getBoundingClientRect();
|
|
18916
19103
|
if (r2.width <= 0 || r2.height <= 0) return null;
|
|
18917
19104
|
return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
|
|
18918
19105
|
}
|
|
18919
19106
|
function readRect3(ref) {
|
|
18920
|
-
return
|
|
19107
|
+
return rectOf2(ref && findPricingCardElement(ref.sectionId, ref.index));
|
|
18921
19108
|
}
|
|
18922
19109
|
function readGridRect(ref) {
|
|
18923
19110
|
const card = ref && findPricingCardElement(ref.sectionId, ref.index);
|
|
18924
|
-
return
|
|
19111
|
+
return rectOf2(card?.closest("[data-ohw-pricing-collection]") ?? card);
|
|
18925
19112
|
}
|
|
18926
19113
|
function useLiveCardRect(ref, grid = false) {
|
|
18927
19114
|
const [rect, setRect] = (0, import_react11.useState)(null);
|
|
@@ -18951,7 +19138,7 @@ function useLiveCardRect(ref, grid = false) {
|
|
|
18951
19138
|
}
|
|
18952
19139
|
var TOOLBAR_GRID_GAP = 52;
|
|
18953
19140
|
var TOOLBAR_GRID_GAP_MOBILE = 42;
|
|
18954
|
-
var
|
|
19141
|
+
var TOOLBAR_EDGE_MARGIN3 = 4;
|
|
18955
19142
|
function GridToolbarSlot({ gridRect, children }) {
|
|
18956
19143
|
const slotRef = (0, import_react11.useRef)(null);
|
|
18957
19144
|
const [shift, setShift] = (0, import_react11.useState)(0);
|
|
@@ -18963,7 +19150,7 @@ function GridToolbarSlot({ gridRect, children }) {
|
|
|
18963
19150
|
const w = slot.offsetWidth;
|
|
18964
19151
|
if (w <= 0) return;
|
|
18965
19152
|
const half = w / 2;
|
|
18966
|
-
const clamped = Math.max(
|
|
19153
|
+
const clamped = Math.max(TOOLBAR_EDGE_MARGIN3 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN3 - half));
|
|
18967
19154
|
setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
|
|
18968
19155
|
};
|
|
18969
19156
|
clamp();
|
|
@@ -18972,7 +19159,7 @@ function GridToolbarSlot({ gridRect, children }) {
|
|
|
18972
19159
|
return () => ro.disconnect();
|
|
18973
19160
|
}, [centerX, children]);
|
|
18974
19161
|
const mobile = window.innerWidth <= 480;
|
|
18975
|
-
return /* @__PURE__ */ (0,
|
|
19162
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
18976
19163
|
"div",
|
|
18977
19164
|
{
|
|
18978
19165
|
ref: slotRef,
|
|
@@ -19007,7 +19194,7 @@ function requestValidateTree2(postToParent2, tree) {
|
|
|
19007
19194
|
});
|
|
19008
19195
|
}
|
|
19009
19196
|
function StyleSwatch({ style }) {
|
|
19010
|
-
return /* @__PURE__ */ (0,
|
|
19197
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19011
19198
|
"span",
|
|
19012
19199
|
{
|
|
19013
19200
|
"aria-hidden": true,
|
|
@@ -19021,35 +19208,35 @@ function StyleSwatch({ style }) {
|
|
|
19021
19208
|
);
|
|
19022
19209
|
}
|
|
19023
19210
|
function ButtonGlyph() {
|
|
19024
|
-
return /* @__PURE__ */ (0,
|
|
19025
|
-
/* @__PURE__ */ (0,
|
|
19026
|
-
/* @__PURE__ */ (0,
|
|
19211
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("svg", { width: "18", height: "12", viewBox: "0 0 18 12", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
|
|
19212
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("rect", { x: "0.75", y: "0.75", width: "16.5", height: "10.5", rx: "3", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
19213
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M5.5 6H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
19027
19214
|
] });
|
|
19028
19215
|
}
|
|
19029
19216
|
function FeatureGlyph({ mode }) {
|
|
19030
|
-
return /* @__PURE__ */ (0,
|
|
19031
|
-
/* @__PURE__ */ (0,
|
|
19032
|
-
/* @__PURE__ */ (0,
|
|
19033
|
-
/* @__PURE__ */ (0,
|
|
19034
|
-
/* @__PURE__ */ (0,
|
|
19035
|
-
/* @__PURE__ */ (0,
|
|
19036
|
-
mode === "add" && /* @__PURE__ */ (0,
|
|
19217
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
|
|
19218
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("circle", { cx: "8", cy: "8", r: "7.25", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
19219
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M5 8.2L7.2 10.3L11 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
19220
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("circle", { cx: "13.5", cy: "13.5", r: "4.25", fill: "var(--ohw-background, #ffffff)", stroke: "var(--ohw-background, #ffffff)", strokeWidth: "1" }),
|
|
19221
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("circle", { cx: "13.5", cy: "13.5", r: "3.75", fill: "var(--ohw-background, #ffffff)", stroke: PRIMARY4, strokeWidth: "1" }),
|
|
19222
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M11.5 13.5H15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" }),
|
|
19223
|
+
mode === "add" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M13.5 11.5V15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" })
|
|
19037
19224
|
] });
|
|
19038
19225
|
}
|
|
19039
|
-
function
|
|
19226
|
+
function ToolbarAction2({
|
|
19040
19227
|
label,
|
|
19041
19228
|
onClick,
|
|
19042
19229
|
disabled = false,
|
|
19043
19230
|
children
|
|
19044
19231
|
}) {
|
|
19045
|
-
const button = /* @__PURE__ */ (0,
|
|
19046
|
-
return /* @__PURE__ */ (0,
|
|
19047
|
-
/* @__PURE__ */ (0,
|
|
19048
|
-
/* @__PURE__ */ (0,
|
|
19232
|
+
const button = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, onClick, className: "size-8", children });
|
|
19233
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
|
|
19234
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "inline-flex", children: button }) : button }),
|
|
19235
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
|
|
19049
19236
|
] });
|
|
19050
19237
|
}
|
|
19051
|
-
function
|
|
19052
|
-
return /* @__PURE__ */ (0,
|
|
19238
|
+
function ToolbarSeparator2() {
|
|
19239
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
|
|
19053
19240
|
}
|
|
19054
19241
|
function CardStyleMenu({
|
|
19055
19242
|
value,
|
|
@@ -19057,7 +19244,7 @@ function CardStyleMenu({
|
|
|
19057
19244
|
disabled = false
|
|
19058
19245
|
}) {
|
|
19059
19246
|
const current = PRICING_CARD_STYLES.find((s) => s.value === value) ?? PRICING_CARD_STYLES[0];
|
|
19060
|
-
const trigger = /* @__PURE__ */ (0,
|
|
19247
|
+
const trigger = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
19061
19248
|
"button",
|
|
19062
19249
|
{
|
|
19063
19250
|
type: "button",
|
|
@@ -19068,28 +19255,28 @@ function CardStyleMenu({
|
|
|
19068
19255
|
disabled && "cursor-not-allowed opacity-40 hover:bg-transparent"
|
|
19069
19256
|
),
|
|
19070
19257
|
children: [
|
|
19071
|
-
/* @__PURE__ */ (0,
|
|
19072
|
-
/* @__PURE__ */ (0,
|
|
19073
|
-
/* @__PURE__ */ (0,
|
|
19258
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StyleSwatch, { style: current.value }),
|
|
19259
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "flex-1 text-left", children: current.label }),
|
|
19260
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.ChevronDown, { size: 16, style: { pointerEvents: "none" } })
|
|
19074
19261
|
]
|
|
19075
19262
|
}
|
|
19076
19263
|
);
|
|
19077
19264
|
if (disabled) {
|
|
19078
|
-
return /* @__PURE__ */ (0,
|
|
19079
|
-
/* @__PURE__ */ (0,
|
|
19080
|
-
/* @__PURE__ */ (0,
|
|
19081
|
-
/* @__PURE__ */ (0,
|
|
19082
|
-
/* @__PURE__ */ (0,
|
|
19265
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
19266
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
|
|
19267
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
|
|
19268
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "inline-flex", children: trigger }) }),
|
|
19269
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
|
|
19083
19270
|
] })
|
|
19084
19271
|
] });
|
|
19085
19272
|
}
|
|
19086
|
-
return /* @__PURE__ */ (0,
|
|
19087
|
-
/* @__PURE__ */ (0,
|
|
19088
|
-
/* @__PURE__ */ (0,
|
|
19089
|
-
/* @__PURE__ */ (0,
|
|
19090
|
-
/* @__PURE__ */ (0,
|
|
19273
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
19274
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
|
|
19275
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(DropdownMenu, { modal: false, children: [
|
|
19276
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuTrigger, { asChild: true, children: trigger }),
|
|
19277
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
|
|
19091
19278
|
const selected = style.value === value;
|
|
19092
|
-
return /* @__PURE__ */ (0,
|
|
19279
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
19093
19280
|
DropdownMenuItem,
|
|
19094
19281
|
{
|
|
19095
19282
|
role: "menuitemradio",
|
|
@@ -19097,9 +19284,9 @@ function CardStyleMenu({
|
|
|
19097
19284
|
onSelect: () => onChange(style.value),
|
|
19098
19285
|
className: cn("grid grid-cols-[18px_1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
|
|
19099
19286
|
children: [
|
|
19100
|
-
/* @__PURE__ */ (0,
|
|
19101
|
-
/* @__PURE__ */ (0,
|
|
19102
|
-
selected && /* @__PURE__ */ (0,
|
|
19287
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StyleSwatch, { style: style.value }),
|
|
19288
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: style.label }),
|
|
19289
|
+
selected && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Check, { size: 16, className: "text-bridge-primary" })
|
|
19103
19290
|
]
|
|
19104
19291
|
},
|
|
19105
19292
|
style.value
|
|
@@ -19129,7 +19316,7 @@ function PricingCardToolbar({
|
|
|
19129
19316
|
const style = pricingCardStyle(entry.tree, index);
|
|
19130
19317
|
const featuredTag = pricingCardFeaturedTag(entry.tree, index);
|
|
19131
19318
|
const mobile = window.innerWidth <= 480;
|
|
19132
|
-
return /* @__PURE__ */ (0,
|
|
19319
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
19133
19320
|
"div",
|
|
19134
19321
|
{
|
|
19135
19322
|
"data-ohw-bridge": "",
|
|
@@ -19141,7 +19328,7 @@ function PricingCardToolbar({
|
|
|
19141
19328
|
),
|
|
19142
19329
|
style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
|
|
19143
19330
|
children: [
|
|
19144
|
-
/* @__PURE__ */ (0,
|
|
19331
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
19145
19332
|
"div",
|
|
19146
19333
|
{
|
|
19147
19334
|
className: cn(
|
|
@@ -19150,8 +19337,8 @@ function PricingCardToolbar({
|
|
|
19150
19337
|
mobile ? "flex-wrap justify-center" : "flex-nowrap"
|
|
19151
19338
|
),
|
|
19152
19339
|
children: [
|
|
19153
|
-
/* @__PURE__ */ (0,
|
|
19154
|
-
/* @__PURE__ */ (0,
|
|
19340
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
|
|
19341
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19155
19342
|
CustomToolbarButton,
|
|
19156
19343
|
{
|
|
19157
19344
|
type: "button",
|
|
@@ -19159,8 +19346,8 @@ function PricingCardToolbar({
|
|
|
19159
19346
|
"aria-pressed": featuredTag,
|
|
19160
19347
|
onClick: () => onSetFeaturedTag(!featuredTag),
|
|
19161
19348
|
className: "group size-8",
|
|
19162
|
-
children: /* @__PURE__ */ (0,
|
|
19163
|
-
|
|
19349
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19350
|
+
import_lucide_react10.Star,
|
|
19164
19351
|
{
|
|
19165
19352
|
size: 16,
|
|
19166
19353
|
fill: "currentColor",
|
|
@@ -19174,25 +19361,25 @@ function PricingCardToolbar({
|
|
|
19174
19361
|
)
|
|
19175
19362
|
}
|
|
19176
19363
|
) }),
|
|
19177
|
-
/* @__PURE__ */ (0,
|
|
19364
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
|
|
19178
19365
|
] }),
|
|
19179
|
-
/* @__PURE__ */ (0,
|
|
19180
|
-
/* @__PURE__ */ (0,
|
|
19181
|
-
/* @__PURE__ */ (0,
|
|
19182
|
-
/* @__PURE__ */ (0,
|
|
19183
|
-
/* @__PURE__ */ (0,
|
|
19184
|
-
/* @__PURE__ */ (0,
|
|
19185
|
-
/* @__PURE__ */ (0,
|
|
19366
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator2, {}),
|
|
19367
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
|
|
19368
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator2, {}),
|
|
19369
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction2, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ButtonGlyph, {}) }),
|
|
19370
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction2, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "relative inline-flex", children: [
|
|
19371
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ButtonGlyph, {}),
|
|
19372
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.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" })
|
|
19186
19373
|
] }) }),
|
|
19187
|
-
/* @__PURE__ */ (0,
|
|
19188
|
-
/* @__PURE__ */ (0,
|
|
19189
|
-
/* @__PURE__ */ (0,
|
|
19190
|
-
/* @__PURE__ */ (0,
|
|
19191
|
-
/* @__PURE__ */ (0,
|
|
19374
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction2, { label: "Add feature", onClick: onAddFeature, disabled: featureCount >= 10, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(FeatureGlyph, { mode: "add" }) }),
|
|
19375
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction2, { label: "Remove feature", onClick: onRemoveFeature, disabled: featureCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(FeatureGlyph, { mode: "remove" }) }),
|
|
19376
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator2, {}),
|
|
19377
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction2, { label: "Add tier", onClick: onAddTier, disabled: collectionCount >= 4, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Plus, { size: 16, style: { pointerEvents: "none" } }) }),
|
|
19378
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction2, { label: "Remove tier", onClick: onRemoveTier, disabled: collectionCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Minus, { size: 16, style: { pointerEvents: "none" } }) })
|
|
19192
19379
|
]
|
|
19193
19380
|
}
|
|
19194
19381
|
),
|
|
19195
|
-
error && /* @__PURE__ */ (0,
|
|
19382
|
+
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 })
|
|
19196
19383
|
]
|
|
19197
19384
|
}
|
|
19198
19385
|
) });
|
|
@@ -19226,7 +19413,7 @@ function AiPricingCardOverlay({
|
|
|
19226
19413
|
const overEditable = Boolean(t?.closest?.("[data-ohw-editable], [data-ohw-role], a, button"));
|
|
19227
19414
|
setHover((prev) => {
|
|
19228
19415
|
const next = ref && !overEditable ? ref : null;
|
|
19229
|
-
return
|
|
19416
|
+
return sameRef2(prev, next) ? prev : next;
|
|
19230
19417
|
});
|
|
19231
19418
|
};
|
|
19232
19419
|
const onLeave = () => setHover(null);
|
|
@@ -19241,10 +19428,10 @@ function AiPricingCardOverlay({
|
|
|
19241
19428
|
const onClick = (e) => {
|
|
19242
19429
|
const t = e.target;
|
|
19243
19430
|
if (!(t instanceof Element)) return;
|
|
19244
|
-
if (t.closest(
|
|
19431
|
+
if (t.closest(CHROME_SELECTOR2)) return;
|
|
19245
19432
|
const ref = cardRefFromTarget(t);
|
|
19246
|
-
setActive((prev) =>
|
|
19247
|
-
if (!ref || !
|
|
19433
|
+
setActive((prev) => sameRef2(prev, ref) ? prev : ref);
|
|
19434
|
+
if (!ref || !sameRef2(activeRef.current, ref)) setError(null);
|
|
19248
19435
|
};
|
|
19249
19436
|
document.addEventListener("click", onClick, true);
|
|
19250
19437
|
return () => document.removeEventListener("click", onClick, true);
|
|
@@ -19309,12 +19496,12 @@ function AiPricingCardOverlay({
|
|
|
19309
19496
|
const activeEntry = active ? findEntry(active.sectionId) : null;
|
|
19310
19497
|
const activeCardRect = useLiveCardRect(active);
|
|
19311
19498
|
const activeGridRect = useLiveCardRect(active, true);
|
|
19312
|
-
const hoverRect = useLiveCardRect(hover && !
|
|
19313
|
-
return /* @__PURE__ */ (0,
|
|
19314
|
-
hoverRect && /* @__PURE__ */ (0,
|
|
19315
|
-
activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ (0,
|
|
19316
|
-
/* @__PURE__ */ (0,
|
|
19317
|
-
/* @__PURE__ */ (0,
|
|
19499
|
+
const hoverRect = useLiveCardRect(hover && !sameRef2(hover, active) ? hover : null);
|
|
19500
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
19501
|
+
hoverRect && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
|
|
19502
|
+
activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
19503
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: activeCardRect, state: "active-top" }),
|
|
19504
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(GridToolbarSlot, { gridRect: activeGridRect, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19318
19505
|
PricingCardToolbar,
|
|
19319
19506
|
{
|
|
19320
19507
|
entry: activeEntry,
|
|
@@ -19342,7 +19529,7 @@ function AiPricingCardOverlay({
|
|
|
19342
19529
|
onRemoveFeature: () => runMutation(active.sectionId, (tree) => removePricingCardFeature(tree, active.index))
|
|
19343
19530
|
}
|
|
19344
19531
|
) }),
|
|
19345
|
-
/* @__PURE__ */ (0,
|
|
19532
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
19346
19533
|
"div",
|
|
19347
19534
|
{
|
|
19348
19535
|
"data-ohw-bridge": "",
|
|
@@ -19364,7 +19551,7 @@ function AiPricingCardOverlay({
|
|
|
19364
19551
|
|
|
19365
19552
|
// src/ui/ai-section/AiVideoOverlay.tsx
|
|
19366
19553
|
var import_react12 = require("react");
|
|
19367
|
-
var
|
|
19554
|
+
var import_lucide_react11 = require("lucide-react");
|
|
19368
19555
|
|
|
19369
19556
|
// src/lib/ai-video-tree.ts
|
|
19370
19557
|
function resolveVideoBlock(tree, path) {
|
|
@@ -19435,10 +19622,10 @@ function extractYouTubeId(input) {
|
|
|
19435
19622
|
}
|
|
19436
19623
|
|
|
19437
19624
|
// src/ui/ai-section/AiVideoOverlay.tsx
|
|
19438
|
-
var
|
|
19625
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
19439
19626
|
var PRIMARY5 = "#0885FE";
|
|
19440
|
-
var
|
|
19441
|
-
var
|
|
19627
|
+
var OHW_BLUE = `var(--ohw-primary, ${PRIMARY5})`;
|
|
19628
|
+
var OHW_BLUE_DARK = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY5}) 60%, #000000)`;
|
|
19442
19629
|
function findVideoBlockElement(sectionId, path) {
|
|
19443
19630
|
const sectionEl = findByInstanceId(sectionId);
|
|
19444
19631
|
if (!sectionEl) return null;
|
|
@@ -19498,12 +19685,12 @@ function requestValidateTree3(postToParent2, tree) {
|
|
|
19498
19685
|
postToParent2({ type: "ow:ai-validate-tree-request", id, tree });
|
|
19499
19686
|
});
|
|
19500
19687
|
}
|
|
19501
|
-
function
|
|
19688
|
+
function Pill({
|
|
19502
19689
|
label,
|
|
19503
19690
|
onClick,
|
|
19504
19691
|
disabled
|
|
19505
19692
|
}) {
|
|
19506
|
-
return /* @__PURE__ */ (0,
|
|
19693
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19507
19694
|
"button",
|
|
19508
19695
|
{
|
|
19509
19696
|
type: "button",
|
|
@@ -19519,7 +19706,7 @@ function Pill2({
|
|
|
19519
19706
|
border: "none",
|
|
19520
19707
|
cursor: disabled ? "default" : "pointer",
|
|
19521
19708
|
background: "#ffffff",
|
|
19522
|
-
color:
|
|
19709
|
+
color: OHW_BLUE_DARK,
|
|
19523
19710
|
opacity: disabled ? 0.4 : 1,
|
|
19524
19711
|
fontSize: 12,
|
|
19525
19712
|
lineHeight: "16px",
|
|
@@ -19562,8 +19749,8 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
19562
19749
|
onCommit(id);
|
|
19563
19750
|
}
|
|
19564
19751
|
};
|
|
19565
|
-
return /* @__PURE__ */ (0,
|
|
19566
|
-
/* @__PURE__ */ (0,
|
|
19752
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 4, width: "100%", maxWidth: 280 }, children: [
|
|
19753
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
19567
19754
|
"div",
|
|
19568
19755
|
{
|
|
19569
19756
|
style: {
|
|
@@ -19579,12 +19766,12 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
19579
19766
|
boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
|
|
19580
19767
|
},
|
|
19581
19768
|
children: [
|
|
19582
|
-
/* @__PURE__ */ (0,
|
|
19769
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19583
19770
|
"span",
|
|
19584
19771
|
{
|
|
19585
19772
|
style: {
|
|
19586
19773
|
flex: "0 0 auto",
|
|
19587
|
-
color:
|
|
19774
|
+
color: OHW_BLUE_DARK,
|
|
19588
19775
|
fontSize: 10,
|
|
19589
19776
|
lineHeight: "16px",
|
|
19590
19777
|
fontWeight: 700,
|
|
@@ -19594,7 +19781,7 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
19594
19781
|
children: "Video"
|
|
19595
19782
|
}
|
|
19596
19783
|
),
|
|
19597
|
-
/* @__PURE__ */ (0,
|
|
19784
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19598
19785
|
"input",
|
|
19599
19786
|
{
|
|
19600
19787
|
type: "text",
|
|
@@ -19631,7 +19818,7 @@ function VideoUrlInput({ value, onCommit }) {
|
|
|
19631
19818
|
]
|
|
19632
19819
|
}
|
|
19633
19820
|
),
|
|
19634
|
-
invalid && /* @__PURE__ */ (0,
|
|
19821
|
+
invalid && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, textAlign: "center" }, children: "That doesn't look like a YouTube link \u2014 try pasting the video URL again." })
|
|
19635
19822
|
] });
|
|
19636
19823
|
}
|
|
19637
19824
|
function VideoToolbar({
|
|
@@ -19641,7 +19828,7 @@ function VideoToolbar({
|
|
|
19641
19828
|
onSetVideoId,
|
|
19642
19829
|
onRemove
|
|
19643
19830
|
}) {
|
|
19644
|
-
return /* @__PURE__ */ (0,
|
|
19831
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
19645
19832
|
"div",
|
|
19646
19833
|
{
|
|
19647
19834
|
"data-ohw-bridge": "",
|
|
@@ -19653,7 +19840,7 @@ function VideoToolbar({
|
|
|
19653
19840
|
gap: 6,
|
|
19654
19841
|
alignItems: "center",
|
|
19655
19842
|
width: 280,
|
|
19656
|
-
background:
|
|
19843
|
+
background: OHW_BLUE,
|
|
19657
19844
|
padding: 8,
|
|
19658
19845
|
borderRadius: 12,
|
|
19659
19846
|
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
@@ -19661,9 +19848,9 @@ function VideoToolbar({
|
|
|
19661
19848
|
opacity: pending ? 0.6 : 1
|
|
19662
19849
|
},
|
|
19663
19850
|
children: [
|
|
19664
|
-
/* @__PURE__ */ (0,
|
|
19665
|
-
/* @__PURE__ */ (0,
|
|
19666
|
-
error && /* @__PURE__ */ (0,
|
|
19851
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VideoUrlInput, { value: videoId, onCommit: onSetVideoId }),
|
|
19852
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Pill, { label: "Remove video", onClick: onRemove, disabled: !videoId }),
|
|
19853
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
|
|
19667
19854
|
]
|
|
19668
19855
|
}
|
|
19669
19856
|
);
|
|
@@ -19783,8 +19970,8 @@ function AiVideoOverlay({
|
|
|
19783
19970
|
const activeBlockRect = useLiveBlockRect(active);
|
|
19784
19971
|
const TOOLBAR_APPROX_H = 90;
|
|
19785
19972
|
const toolbarState = activeBlockRect && activeBlockRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
|
|
19786
|
-
return /* @__PURE__ */ (0,
|
|
19787
|
-
hoverHandleRect && hover && /* @__PURE__ */ (0,
|
|
19973
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
19974
|
+
hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19788
19975
|
"button",
|
|
19789
19976
|
{
|
|
19790
19977
|
type: "button",
|
|
@@ -19812,15 +19999,15 @@ function AiVideoOverlay({
|
|
|
19812
19999
|
fontSize: 14,
|
|
19813
20000
|
fontWeight: 700
|
|
19814
20001
|
},
|
|
19815
|
-
children: /* @__PURE__ */ (0,
|
|
20002
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react11.Star, { size: 14, style: { pointerEvents: "none" } })
|
|
19816
20003
|
}
|
|
19817
20004
|
),
|
|
19818
|
-
activeBlockRect && active && activeEntry && /* @__PURE__ */ (0,
|
|
20005
|
+
activeBlockRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19819
20006
|
ItemInteractionLayer,
|
|
19820
20007
|
{
|
|
19821
20008
|
rect: activeBlockRect,
|
|
19822
20009
|
state: toolbarState,
|
|
19823
|
-
toolbar: /* @__PURE__ */ (0,
|
|
20010
|
+
toolbar: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
19824
20011
|
VideoToolbar,
|
|
19825
20012
|
{
|
|
19826
20013
|
videoId: videoIdAt(activeEntry.tree, active.path),
|
|
@@ -19844,7 +20031,7 @@ function AiVideoOverlay({
|
|
|
19844
20031
|
|
|
19845
20032
|
// src/ui/ai-section/AiFadeCarouselOverlay.tsx
|
|
19846
20033
|
var import_react13 = require("react");
|
|
19847
|
-
var
|
|
20034
|
+
var import_lucide_react12 = require("lucide-react");
|
|
19848
20035
|
|
|
19849
20036
|
// src/lib/ai-carousel-tree.ts
|
|
19850
20037
|
function isCarouselBlock(node) {
|
|
@@ -19895,10 +20082,10 @@ function setCarouselAutoplay(tree, on) {
|
|
|
19895
20082
|
}
|
|
19896
20083
|
|
|
19897
20084
|
// src/ui/ai-section/AiFadeCarouselOverlay.tsx
|
|
19898
|
-
var
|
|
20085
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
19899
20086
|
var PRIMARY6 = "#0885FE";
|
|
19900
|
-
var
|
|
19901
|
-
var
|
|
20087
|
+
var OHW_BLUE2 = `var(--ohw-primary, ${PRIMARY6})`;
|
|
20088
|
+
var OHW_BLUE_DARK2 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY6}) 60%, #000000)`;
|
|
19902
20089
|
function findCarouselItemElement(sectionId, index) {
|
|
19903
20090
|
const sectionEl = findByInstanceId(sectionId);
|
|
19904
20091
|
if (!sectionEl) return null;
|
|
@@ -19977,8 +20164,8 @@ function requestAssetPick2(postToParent2) {
|
|
|
19977
20164
|
postToParent2({ type: "ow:asset-pick", id });
|
|
19978
20165
|
});
|
|
19979
20166
|
}
|
|
19980
|
-
function
|
|
19981
|
-
return /* @__PURE__ */ (0,
|
|
20167
|
+
function Pill2({ label, onClick, disabled }) {
|
|
20168
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
19982
20169
|
"button",
|
|
19983
20170
|
{
|
|
19984
20171
|
type: "button",
|
|
@@ -19994,7 +20181,7 @@ function Pill3({ label, onClick, disabled }) {
|
|
|
19994
20181
|
border: "none",
|
|
19995
20182
|
cursor: disabled ? "default" : "pointer",
|
|
19996
20183
|
background: "#ffffff",
|
|
19997
|
-
color:
|
|
20184
|
+
color: OHW_BLUE_DARK2,
|
|
19998
20185
|
opacity: disabled ? 0.4 : 1,
|
|
19999
20186
|
fontSize: 12,
|
|
20000
20187
|
lineHeight: "16px",
|
|
@@ -20012,7 +20199,7 @@ function TogglePill({
|
|
|
20012
20199
|
onToggle,
|
|
20013
20200
|
disabled
|
|
20014
20201
|
}) {
|
|
20015
|
-
return /* @__PURE__ */ (0,
|
|
20202
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
20016
20203
|
"button",
|
|
20017
20204
|
{
|
|
20018
20205
|
type: "button",
|
|
@@ -20031,7 +20218,7 @@ function TogglePill({
|
|
|
20031
20218
|
border: "none",
|
|
20032
20219
|
cursor: disabled ? "default" : "pointer",
|
|
20033
20220
|
background: "#ffffff",
|
|
20034
|
-
color:
|
|
20221
|
+
color: OHW_BLUE_DARK2,
|
|
20035
20222
|
opacity: disabled ? 0.4 : 1,
|
|
20036
20223
|
fontSize: 12,
|
|
20037
20224
|
lineHeight: "16px",
|
|
@@ -20041,7 +20228,7 @@ function TogglePill({
|
|
|
20041
20228
|
},
|
|
20042
20229
|
children: [
|
|
20043
20230
|
label,
|
|
20044
|
-
/* @__PURE__ */ (0,
|
|
20231
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20045
20232
|
"span",
|
|
20046
20233
|
{
|
|
20047
20234
|
"aria-hidden": true,
|
|
@@ -20054,10 +20241,10 @@ function TogglePill({
|
|
|
20054
20241
|
// Off is a grey track, not a washed-out blue: the pill's own white background already
|
|
20055
20242
|
// carries the brand colour in the text, and a pale blue track next to it read as
|
|
20056
20243
|
// "disabled control" rather than "switch that is off".
|
|
20057
|
-
background: on ?
|
|
20244
|
+
background: on ? OHW_BLUE_DARK2 : "#CBD5E1",
|
|
20058
20245
|
transition: "background 120ms ease"
|
|
20059
20246
|
},
|
|
20060
|
-
children: /* @__PURE__ */ (0,
|
|
20247
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20061
20248
|
"span",
|
|
20062
20249
|
{
|
|
20063
20250
|
style: {
|
|
@@ -20086,7 +20273,7 @@ function CarouselSlideToolbar({
|
|
|
20086
20273
|
onChangeImage,
|
|
20087
20274
|
onToggleAutoplay
|
|
20088
20275
|
}) {
|
|
20089
|
-
return /* @__PURE__ */ (0,
|
|
20276
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
20090
20277
|
"div",
|
|
20091
20278
|
{
|
|
20092
20279
|
"data-ohw-bridge": "",
|
|
@@ -20097,7 +20284,7 @@ function CarouselSlideToolbar({
|
|
|
20097
20284
|
flexDirection: "column",
|
|
20098
20285
|
gap: 6,
|
|
20099
20286
|
alignItems: "center",
|
|
20100
|
-
background:
|
|
20287
|
+
background: OHW_BLUE2,
|
|
20101
20288
|
padding: 8,
|
|
20102
20289
|
borderRadius: 12,
|
|
20103
20290
|
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
@@ -20109,11 +20296,11 @@ function CarouselSlideToolbar({
|
|
|
20109
20296
|
pointerEvents: pending ? "none" : "auto"
|
|
20110
20297
|
},
|
|
20111
20298
|
children: [
|
|
20112
|
-
/* @__PURE__ */ (0,
|
|
20113
|
-
/* @__PURE__ */ (0,
|
|
20114
|
-
/* @__PURE__ */ (0,
|
|
20299
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
|
|
20300
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Pill2, { label: "Change Image", onClick: onChangeImage }),
|
|
20301
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
|
|
20115
20302
|
] }),
|
|
20116
|
-
error && /* @__PURE__ */ (0,
|
|
20303
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
|
|
20117
20304
|
]
|
|
20118
20305
|
}
|
|
20119
20306
|
);
|
|
@@ -20253,8 +20440,8 @@ function AiFadeCarouselOverlay({
|
|
|
20253
20440
|
const activeItemRect = useLiveItemRect2(active);
|
|
20254
20441
|
const TOOLBAR_APPROX_H = 90;
|
|
20255
20442
|
const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
|
|
20256
|
-
return /* @__PURE__ */ (0,
|
|
20257
|
-
hoverHandleRect && hover && /* @__PURE__ */ (0,
|
|
20443
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
20444
|
+
hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20258
20445
|
"button",
|
|
20259
20446
|
{
|
|
20260
20447
|
type: "button",
|
|
@@ -20283,10 +20470,10 @@ function AiFadeCarouselOverlay({
|
|
|
20283
20470
|
fontSize: 14,
|
|
20284
20471
|
fontWeight: 700
|
|
20285
20472
|
},
|
|
20286
|
-
children: /* @__PURE__ */ (0,
|
|
20473
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react12.Star, { size: 14, style: { pointerEvents: "none" } })
|
|
20287
20474
|
}
|
|
20288
20475
|
),
|
|
20289
|
-
swapping && /* @__PURE__ */ (0,
|
|
20476
|
+
swapping && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20290
20477
|
"div",
|
|
20291
20478
|
{
|
|
20292
20479
|
ref: skeletonRef,
|
|
@@ -20304,15 +20491,15 @@ function AiFadeCarouselOverlay({
|
|
|
20304
20491
|
zIndex: 2147483646,
|
|
20305
20492
|
pointerEvents: "none"
|
|
20306
20493
|
},
|
|
20307
|
-
children: /* @__PURE__ */ (0,
|
|
20494
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("style", { children: MEDIA_SKELETON_CSS })
|
|
20308
20495
|
}
|
|
20309
20496
|
),
|
|
20310
|
-
activeItemRect && active && activeEntry && /* @__PURE__ */ (0,
|
|
20497
|
+
activeItemRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20311
20498
|
ItemInteractionLayer,
|
|
20312
20499
|
{
|
|
20313
20500
|
rect: activeItemRect,
|
|
20314
20501
|
state: toolbarState,
|
|
20315
|
-
toolbar: /* @__PURE__ */ (0,
|
|
20502
|
+
toolbar: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20316
20503
|
CarouselSlideToolbar,
|
|
20317
20504
|
{
|
|
20318
20505
|
pending,
|
|
@@ -20665,113 +20852,6 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
|
|
|
20665
20852
|
// src/ui/link-modal/LinkPopover.tsx
|
|
20666
20853
|
var import_react17 = require("react");
|
|
20667
20854
|
|
|
20668
|
-
// src/ui/dialog.tsx
|
|
20669
|
-
var React9 = __toESM(require("react"), 1);
|
|
20670
|
-
var import_radix_ui6 = require("radix-ui");
|
|
20671
|
-
var import_lucide_react12 = require("lucide-react");
|
|
20672
|
-
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
20673
|
-
function Dialog2({
|
|
20674
|
-
...props
|
|
20675
|
-
}) {
|
|
20676
|
-
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_radix_ui6.Dialog.Root, { "data-slot": "dialog", ...props });
|
|
20677
|
-
}
|
|
20678
|
-
function DialogPortal({
|
|
20679
|
-
...props
|
|
20680
|
-
}) {
|
|
20681
|
-
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_radix_ui6.Dialog.Portal, { ...props });
|
|
20682
|
-
}
|
|
20683
|
-
function DialogOverlay({
|
|
20684
|
-
className,
|
|
20685
|
-
...props
|
|
20686
|
-
}) {
|
|
20687
|
-
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20688
|
-
import_radix_ui6.Dialog.Overlay,
|
|
20689
|
-
{
|
|
20690
|
-
"data-slot": "dialog-overlay",
|
|
20691
|
-
"data-ohw-link-modal-root": "",
|
|
20692
|
-
className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
|
|
20693
|
-
...props
|
|
20694
|
-
}
|
|
20695
|
-
);
|
|
20696
|
-
}
|
|
20697
|
-
var DialogContent = React9.forwardRef(
|
|
20698
|
-
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
20699
|
-
const positionMode = container ? "absolute" : "fixed";
|
|
20700
|
-
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DialogPortal, { container: container ?? void 0, children: [
|
|
20701
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
20702
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
20703
|
-
import_radix_ui6.Dialog.Content,
|
|
20704
|
-
{
|
|
20705
|
-
ref,
|
|
20706
|
-
"data-slot": "dialog-content",
|
|
20707
|
-
className: cn(
|
|
20708
|
-
positionMode,
|
|
20709
|
-
"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",
|
|
20710
|
-
"rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
|
|
20711
|
-
container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
|
|
20712
|
-
className
|
|
20713
|
-
),
|
|
20714
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
20715
|
-
...props,
|
|
20716
|
-
children: [
|
|
20717
|
-
children,
|
|
20718
|
-
showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20719
|
-
import_radix_ui6.Dialog.Close,
|
|
20720
|
-
{
|
|
20721
|
-
type: "button",
|
|
20722
|
-
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
20723
|
-
"aria-label": "Close",
|
|
20724
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react12.X, { size: 16, "aria-hidden": true })
|
|
20725
|
-
}
|
|
20726
|
-
) : null
|
|
20727
|
-
]
|
|
20728
|
-
}
|
|
20729
|
-
)
|
|
20730
|
-
] });
|
|
20731
|
-
}
|
|
20732
|
-
);
|
|
20733
|
-
DialogContent.displayName = import_radix_ui6.Dialog.Content.displayName;
|
|
20734
|
-
function DialogHeader({
|
|
20735
|
-
className,
|
|
20736
|
-
...props
|
|
20737
|
-
}) {
|
|
20738
|
-
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
20739
|
-
}
|
|
20740
|
-
function DialogFooter({
|
|
20741
|
-
className,
|
|
20742
|
-
...props
|
|
20743
|
-
}) {
|
|
20744
|
-
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20745
|
-
"div",
|
|
20746
|
-
{
|
|
20747
|
-
className: cn("flex items-center justify-end gap-2", className),
|
|
20748
|
-
...props
|
|
20749
|
-
}
|
|
20750
|
-
);
|
|
20751
|
-
}
|
|
20752
|
-
var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20753
|
-
import_radix_ui6.Dialog.Title,
|
|
20754
|
-
{
|
|
20755
|
-
ref,
|
|
20756
|
-
className: cn(
|
|
20757
|
-
"text-lg font-semibold leading-none tracking-tight text-card-foreground",
|
|
20758
|
-
className
|
|
20759
|
-
),
|
|
20760
|
-
...props
|
|
20761
|
-
}
|
|
20762
|
-
));
|
|
20763
|
-
DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
|
|
20764
|
-
var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
20765
|
-
import_radix_ui6.Dialog.Description,
|
|
20766
|
-
{
|
|
20767
|
-
ref,
|
|
20768
|
-
className: cn("text-sm text-muted-foreground", className),
|
|
20769
|
-
...props
|
|
20770
|
-
}
|
|
20771
|
-
));
|
|
20772
|
-
DialogDescription.displayName = import_radix_ui6.Dialog.Description.displayName;
|
|
20773
|
-
var DialogClose = import_radix_ui6.Dialog.Close;
|
|
20774
|
-
|
|
20775
20855
|
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
20776
20856
|
var import_lucide_react16 = require("lucide-react");
|
|
20777
20857
|
|
|
@@ -21875,6 +21955,7 @@ function shouldUseDevFixtures() {
|
|
|
21875
21955
|
function getLogoElement(el) {
|
|
21876
21956
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
21877
21957
|
if (marked) return marked;
|
|
21958
|
+
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
21878
21959
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
21879
21960
|
if (!root) return null;
|
|
21880
21961
|
const anchor = el.closest("a");
|
|
@@ -24455,7 +24536,7 @@ function getNavigationSelectionParent(el) {
|
|
|
24455
24536
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
24456
24537
|
return resolveFooterLinksContainerFrom(el);
|
|
24457
24538
|
}
|
|
24458
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
24539
|
+
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)) {
|
|
24459
24540
|
return getNavigationRoot(el);
|
|
24460
24541
|
}
|
|
24461
24542
|
return null;
|
|
@@ -24677,7 +24758,6 @@ var ICONS = {
|
|
|
24677
24758
|
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"/>',
|
|
24678
24759
|
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"/>'
|
|
24679
24760
|
};
|
|
24680
|
-
var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
|
|
24681
24761
|
var SELECTION_CHROME_GAP2 = 4;
|
|
24682
24762
|
var TOOLBAR_STROKE_GAP2 = 4;
|
|
24683
24763
|
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
@@ -24775,7 +24855,7 @@ function applyVisibleViewport(el, parentScroll) {
|
|
|
24775
24855
|
el.style.top = `${top}px`;
|
|
24776
24856
|
el.style.height = `${height}px`;
|
|
24777
24857
|
}
|
|
24778
|
-
var
|
|
24858
|
+
var TOOLBAR_EDGE_MARGIN4 = 4;
|
|
24779
24859
|
function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
24780
24860
|
const isAbove = transform.includes("translateY(-100%)");
|
|
24781
24861
|
let visualTop = isAbove ? top - approxH : top;
|
|
@@ -24802,8 +24882,8 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
|
24802
24882
|
function clampToolbarLeft(centerX, toolbarWidth) {
|
|
24803
24883
|
const half = toolbarWidth / 2;
|
|
24804
24884
|
return Math.max(
|
|
24805
|
-
|
|
24806
|
-
Math.min(centerX, window.innerWidth -
|
|
24885
|
+
TOOLBAR_EDGE_MARGIN4 + half,
|
|
24886
|
+
Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN4 - half)
|
|
24807
24887
|
);
|
|
24808
24888
|
}
|
|
24809
24889
|
function calcToolbarPos(rect, parentScroll, toolbarW = 306) {
|
|
@@ -25693,21 +25773,6 @@ function OhhwellsBridge() {
|
|
|
25693
25773
|
const [isItemDragging, setIsItemDragging] = (0, import_react21.useState)(false);
|
|
25694
25774
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react21.useState)(false);
|
|
25695
25775
|
isFooterFrameSelectionRef.current = isFooterFrameSelection;
|
|
25696
|
-
const [floatingPanel, setFloatingPanel] = (0, import_react21.useState)(null);
|
|
25697
|
-
const floatingPanelOpenRef = (0, import_react21.useRef)(false);
|
|
25698
|
-
floatingPanelOpenRef.current = floatingPanel !== null;
|
|
25699
|
-
const floatingPanelRef = (0, import_react21.useRef)(null);
|
|
25700
|
-
floatingPanelRef.current = floatingPanel;
|
|
25701
|
-
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react21.useState)(null);
|
|
25702
|
-
const buttonCollectionDragRef = (0, import_react21.useRef)(null);
|
|
25703
|
-
const buttonDropInsertIndexRef = (0, import_react21.useRef)(null);
|
|
25704
|
-
const [buttonDropSlots, setButtonDropSlots] = (0, import_react21.useState)([]);
|
|
25705
|
-
const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react21.useState)(null);
|
|
25706
|
-
const buttonPointerDragRef = (0, import_react21.useRef)(null);
|
|
25707
|
-
const [buttonStyleTick, setButtonStyleTick] = (0, import_react21.useState)(0);
|
|
25708
|
-
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react21.useState)(null);
|
|
25709
|
-
const [editorViewport, setEditorViewport] = (0, import_react21.useState)("desktop");
|
|
25710
|
-
const [parentScrollSnap, setParentScrollSnap] = (0, import_react21.useState)(null);
|
|
25711
25776
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react21.useState)(null);
|
|
25712
25777
|
const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react21.useState)(null);
|
|
25713
25778
|
const footerDragRef = (0, import_react21.useRef)(null);
|
|
@@ -25733,6 +25798,21 @@ function OhhwellsBridge() {
|
|
|
25733
25798
|
const stylesRef = (0, import_react21.useRef)("");
|
|
25734
25799
|
const appliedDrawerRef = (0, import_react21.useRef)(null);
|
|
25735
25800
|
const pendingDeleteUndoRef = (0, import_react21.useRef)(null);
|
|
25801
|
+
const [floatingPanel, setFloatingPanel] = (0, import_react21.useState)(null);
|
|
25802
|
+
const floatingPanelOpenRef = (0, import_react21.useRef)(false);
|
|
25803
|
+
const floatingPanelRef = (0, import_react21.useRef)(null);
|
|
25804
|
+
floatingPanelRef.current = floatingPanel;
|
|
25805
|
+
const setFloatingPanelRef = (0, import_react21.useRef)(setFloatingPanel);
|
|
25806
|
+
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react21.useState)(null);
|
|
25807
|
+
const buttonCollectionDragRef = (0, import_react21.useRef)(null);
|
|
25808
|
+
const buttonDropInsertIndexRef = (0, import_react21.useRef)(null);
|
|
25809
|
+
const [buttonDropSlots, setButtonDropSlots] = (0, import_react21.useState)([]);
|
|
25810
|
+
const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react21.useState)(null);
|
|
25811
|
+
const buttonPointerDragRef = (0, import_react21.useRef)(null);
|
|
25812
|
+
const [buttonStyleTick, setButtonStyleTick] = (0, import_react21.useState)(0);
|
|
25813
|
+
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react21.useState)(null);
|
|
25814
|
+
const [editorViewport, setEditorViewport] = (0, import_react21.useState)("desktop");
|
|
25815
|
+
const [parentScrollSnap, setParentScrollSnap] = (0, import_react21.useState)(null);
|
|
25736
25816
|
const [sitePages, setSitePages] = (0, import_react21.useState)([]);
|
|
25737
25817
|
const [sectionsByPath, setSectionsByPath] = (0, import_react21.useState)({});
|
|
25738
25818
|
const sectionsPrefetchGenRef = (0, import_react21.useRef)(0);
|
|
@@ -25741,7 +25821,18 @@ function OhhwellsBridge() {
|
|
|
25741
25821
|
const linkPopoverOpenRef = (0, import_react21.useRef)(false);
|
|
25742
25822
|
const linkPopoverGraceUntilRef = (0, import_react21.useRef)(0);
|
|
25743
25823
|
setLinkPopoverRef.current = setLinkPopover;
|
|
25824
|
+
setFloatingPanelRef.current = setFloatingPanel;
|
|
25744
25825
|
linkPopoverSessionRef.current = linkPopover;
|
|
25826
|
+
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
25827
|
+
(0, import_react21.useEffect)(() => {
|
|
25828
|
+
const syncViewport = () => {
|
|
25829
|
+
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
25830
|
+
setEditorViewport((prev) => prev === next ? prev : next);
|
|
25831
|
+
};
|
|
25832
|
+
syncViewport();
|
|
25833
|
+
window.addEventListener("resize", syncViewport);
|
|
25834
|
+
return () => window.removeEventListener("resize", syncViewport);
|
|
25835
|
+
}, []);
|
|
25745
25836
|
(0, import_react21.useEffect)(() => {
|
|
25746
25837
|
setSectionOrderPersistHandler((entries) => {
|
|
25747
25838
|
const currentPath = window.location.pathname;
|
|
@@ -27436,6 +27527,7 @@ function OhhwellsBridge() {
|
|
|
27436
27527
|
applyAiFooterFromContent(content);
|
|
27437
27528
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
27438
27529
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
27530
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
27439
27531
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
27440
27532
|
}
|
|
27441
27533
|
applyBrandChrome(content);
|
|
@@ -27446,12 +27538,12 @@ function OhhwellsBridge() {
|
|
|
27446
27538
|
if (key === "__ohw_sections") continue;
|
|
27447
27539
|
if (key === AI_SECTIONS_KEY) continue;
|
|
27448
27540
|
if (key === AI_FOOTER_KEY) continue;
|
|
27541
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
27542
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27449
27543
|
if (key === BRAND_KIT_KEY) continue;
|
|
27450
27544
|
if (key === STYLE_STORE_KEY) continue;
|
|
27451
27545
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
27452
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
27453
27546
|
if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
|
|
27454
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27455
27547
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
27456
27548
|
continue;
|
|
27457
27549
|
}
|
|
@@ -27666,17 +27758,18 @@ function OhhwellsBridge() {
|
|
|
27666
27758
|
}
|
|
27667
27759
|
applyAiFooterFromContent(content);
|
|
27668
27760
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
27761
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
27669
27762
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
27670
27763
|
}
|
|
27671
27764
|
for (const [key, val] of Object.entries(content)) {
|
|
27672
27765
|
if (key === "__ohw_sections") continue;
|
|
27673
27766
|
if (key === AI_SECTIONS_KEY) continue;
|
|
27674
27767
|
if (key === AI_FOOTER_KEY) continue;
|
|
27768
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
27769
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27675
27770
|
if (key === BRAND_KIT_KEY) continue;
|
|
27676
27771
|
if (key === STYLE_STORE_KEY) continue;
|
|
27677
27772
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
27678
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
27679
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
27680
27773
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
27681
27774
|
continue;
|
|
27682
27775
|
}
|
|
@@ -27933,26 +28026,11 @@ function OhhwellsBridge() {
|
|
|
27933
28026
|
const t2 = setTimeout(measure, 500);
|
|
27934
28027
|
const ro = new ResizeObserver(schedule);
|
|
27935
28028
|
ro.observe(document.body);
|
|
27936
|
-
let lastWidth = window.innerWidth;
|
|
27937
|
-
let resizeTimers = [];
|
|
27938
|
-
const clearResizeTimers = () => {
|
|
27939
|
-
resizeTimers.forEach(clearTimeout);
|
|
27940
|
-
resizeTimers = [];
|
|
27941
|
-
};
|
|
27942
|
-
const handleResize = () => {
|
|
27943
|
-
if (window.innerWidth === lastWidth) return;
|
|
27944
|
-
lastWidth = window.innerWidth;
|
|
27945
|
-
clearResizeTimers();
|
|
27946
|
-
resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
|
|
27947
|
-
};
|
|
27948
|
-
window.addEventListener("resize", handleResize);
|
|
27949
28029
|
return () => {
|
|
27950
28030
|
clearTimeout(t1);
|
|
27951
28031
|
clearTimeout(t2);
|
|
27952
28032
|
if (raf != null) cancelAnimationFrame(raf);
|
|
27953
28033
|
ro.disconnect();
|
|
27954
|
-
clearResizeTimers();
|
|
27955
|
-
window.removeEventListener("resize", handleResize);
|
|
27956
28034
|
};
|
|
27957
28035
|
}, [pathname, isEditMode, postToParent2]);
|
|
27958
28036
|
(0, import_react21.useEffect)(() => {
|
|
@@ -28251,6 +28329,13 @@ function OhhwellsBridge() {
|
|
|
28251
28329
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
28252
28330
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
28253
28331
|
if (isInsideLinkEditor(target)) return;
|
|
28332
|
+
if (isInsideFloatingPanel(target)) return;
|
|
28333
|
+
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
28334
|
+
if (target.closest(
|
|
28335
|
+
'[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
|
|
28336
|
+
)) {
|
|
28337
|
+
return;
|
|
28338
|
+
}
|
|
28254
28339
|
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
28255
28340
|
clearMediaSelectionRef.current();
|
|
28256
28341
|
}
|
|
@@ -28274,13 +28359,6 @@ function OhhwellsBridge() {
|
|
|
28274
28359
|
return;
|
|
28275
28360
|
}
|
|
28276
28361
|
}
|
|
28277
|
-
if (isInsideFloatingPanel(target)) return;
|
|
28278
|
-
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
28279
|
-
if (target.closest(
|
|
28280
|
-
'[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
|
|
28281
|
-
)) {
|
|
28282
|
-
return;
|
|
28283
|
-
}
|
|
28284
28362
|
{
|
|
28285
28363
|
const formEl = getFormElement(target);
|
|
28286
28364
|
const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
|
|
@@ -28434,9 +28512,13 @@ function OhhwellsBridge() {
|
|
|
28434
28512
|
if (isIconEditable(editable) && !getSocialItem(editable)) {
|
|
28435
28513
|
e.preventDefault();
|
|
28436
28514
|
e.stopPropagation();
|
|
28437
|
-
selectIconElementRef.current(editable);
|
|
28438
28515
|
const aiIcon = editable.hasAttribute("data-ai-icon");
|
|
28439
28516
|
const featureIcon = aiIcon && /\.features\.\d+\.icon$/.test(editable.dataset.ohwKey ?? "");
|
|
28517
|
+
if (aiIcon) {
|
|
28518
|
+
aiSectionApiRef.current?.selectFromElement(editable);
|
|
28519
|
+
} else {
|
|
28520
|
+
selectIconElementRef.current(editable);
|
|
28521
|
+
}
|
|
28440
28522
|
postToParentRef.current({
|
|
28441
28523
|
type: "ow:icon-pick",
|
|
28442
28524
|
key: editable.dataset.ohwKey ?? "",
|
|
@@ -28664,6 +28746,9 @@ function OhhwellsBridge() {
|
|
|
28664
28746
|
setHoveredItemRect(null);
|
|
28665
28747
|
hoveredNavContainerRef.current = null;
|
|
28666
28748
|
setHoveredNavContainerRect(null);
|
|
28749
|
+
siblingHintElRef.current = null;
|
|
28750
|
+
setSiblingHintRect(null);
|
|
28751
|
+
setSiblingHintRects([]);
|
|
28667
28752
|
return;
|
|
28668
28753
|
}
|
|
28669
28754
|
{
|
|
@@ -28784,7 +28869,6 @@ function OhhwellsBridge() {
|
|
|
28784
28869
|
hoveredNavContainerRef.current = null;
|
|
28785
28870
|
setHoveredNavContainerRect(null);
|
|
28786
28871
|
hoveredItemElRef.current = editable;
|
|
28787
|
-
setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
|
|
28788
28872
|
}
|
|
28789
28873
|
}
|
|
28790
28874
|
}
|
|
@@ -29494,7 +29578,11 @@ function OhhwellsBridge() {
|
|
|
29494
29578
|
};
|
|
29495
29579
|
const handleMouseMove = (e) => {
|
|
29496
29580
|
const { clientX, clientY } = e;
|
|
29497
|
-
if (pointOwnedByFloatingPanel(clientX, clientY))
|
|
29581
|
+
if (pointOwnedByFloatingPanel(clientX, clientY)) {
|
|
29582
|
+
dismissImageHover();
|
|
29583
|
+
clearImageHover();
|
|
29584
|
+
return;
|
|
29585
|
+
}
|
|
29498
29586
|
if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
|
|
29499
29587
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
29500
29588
|
formHoverElRef.current = null;
|
|
@@ -29523,7 +29611,12 @@ function OhhwellsBridge() {
|
|
|
29523
29611
|
setHoveredItemRect(null);
|
|
29524
29612
|
hoveredNavContainerRef.current = null;
|
|
29525
29613
|
setHoveredNavContainerRect(null);
|
|
29614
|
+
siblingHintElRef.current = null;
|
|
29615
|
+
setSiblingHintRect(null);
|
|
29616
|
+
setSiblingHintRects([]);
|
|
29526
29617
|
dismissImageHover();
|
|
29618
|
+
clearImageHover();
|
|
29619
|
+
setSectionGap(null);
|
|
29527
29620
|
return;
|
|
29528
29621
|
}
|
|
29529
29622
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
@@ -29535,7 +29628,11 @@ function OhhwellsBridge() {
|
|
|
29535
29628
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
29536
29629
|
const { clientX, clientY } = e.data;
|
|
29537
29630
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
29538
|
-
if (pointOwnedByFloatingPanel(clientX, clientY))
|
|
29631
|
+
if (pointOwnedByFloatingPanel(clientX, clientY)) {
|
|
29632
|
+
dismissImageHover();
|
|
29633
|
+
clearImageHover();
|
|
29634
|
+
return;
|
|
29635
|
+
}
|
|
29539
29636
|
if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
|
|
29540
29637
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
29541
29638
|
probeSectionGapAt(clientX, clientY);
|
|
@@ -29915,6 +30012,7 @@ function OhhwellsBridge() {
|
|
|
29915
30012
|
applyAiFooterFromContent(content);
|
|
29916
30013
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
29917
30014
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
30015
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
29918
30016
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
29919
30017
|
}
|
|
29920
30018
|
applyBrandChrome(content);
|
|
@@ -29929,12 +30027,12 @@ function OhhwellsBridge() {
|
|
|
29929
30027
|
}
|
|
29930
30028
|
if (key === AI_SECTIONS_KEY) continue;
|
|
29931
30029
|
if (key === AI_FOOTER_KEY) continue;
|
|
30030
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
30031
|
+
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
29932
30032
|
if (key === BRAND_KIT_KEY) continue;
|
|
29933
30033
|
if (key === STYLE_STORE_KEY) continue;
|
|
29934
30034
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
29935
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
29936
30035
|
if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
|
|
29937
|
-
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
29938
30036
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
29939
30037
|
continue;
|
|
29940
30038
|
}
|
|
@@ -30309,6 +30407,44 @@ function OhhwellsBridge() {
|
|
|
30309
30407
|
});
|
|
30310
30408
|
};
|
|
30311
30409
|
window.addEventListener("message", handleAiSetStyles);
|
|
30410
|
+
const handleAiSetButtonStyle = (e) => {
|
|
30411
|
+
if (e.data?.type !== "ow:ai-set-button-style") return;
|
|
30412
|
+
const nodeKey = typeof e.data.hrefKey === "string" ? e.data.hrefKey : "";
|
|
30413
|
+
const keyed = nodeKey ? document.querySelector(
|
|
30414
|
+
`[data-ohw-href-key="${CSS.escape(nodeKey)}"], [data-ohw-key="${CSS.escape(nodeKey)}"]`
|
|
30415
|
+
) : null;
|
|
30416
|
+
const hrefKey = buttonId(keyed);
|
|
30417
|
+
const el = hrefKey ? document.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`) : null;
|
|
30418
|
+
const previous = editContentRef.current[BUTTON_ASSIGNMENTS_KEY] ?? "";
|
|
30419
|
+
if (!el || !hrefKey || !isCtaButton(el)) {
|
|
30420
|
+
postToParentRef.current({ type: "ow:ai-button-style-applied", ok: false, previous, value: previous });
|
|
30421
|
+
return;
|
|
30422
|
+
}
|
|
30423
|
+
const tokens = tokensFromButton(el);
|
|
30424
|
+
const current = assignmentFor(el, editContentRef.current, tokens);
|
|
30425
|
+
const patch = e.data.assignment;
|
|
30426
|
+
const next = {
|
|
30427
|
+
variant: patch?.variant ?? current.variant,
|
|
30428
|
+
size: patch?.size ?? current.size
|
|
30429
|
+
};
|
|
30430
|
+
const value = typeof e.data.assignments === "string" ? e.data.assignments : JSON.stringify(withAssignment(editContentRef.current, hrefKey, next));
|
|
30431
|
+
editContentRef.current = { ...editContentRef.current, [BUTTON_ASSIGNMENTS_KEY]: value };
|
|
30432
|
+
applyButtonStyle(el, next, tokens);
|
|
30433
|
+
postToParentRef.current({
|
|
30434
|
+
type: "ow:change",
|
|
30435
|
+
nodes: [{ key: BUTTON_ASSIGNMENTS_KEY, text: value }]
|
|
30436
|
+
});
|
|
30437
|
+
postToParentRef.current({
|
|
30438
|
+
type: "ow:ai-button-style-applied",
|
|
30439
|
+
ok: true,
|
|
30440
|
+
// The resolved id, which may differ from the key the editor sent — undo must target this one.
|
|
30441
|
+
hrefKey,
|
|
30442
|
+
previous,
|
|
30443
|
+
previousAssignment: current,
|
|
30444
|
+
value
|
|
30445
|
+
});
|
|
30446
|
+
};
|
|
30447
|
+
window.addEventListener("message", handleAiSetButtonStyle);
|
|
30312
30448
|
const handleGetBrand = (e) => {
|
|
30313
30449
|
if (e.data?.type !== "ow:get-brand") return;
|
|
30314
30450
|
const template = deriveTemplateBrand();
|
|
@@ -30532,6 +30668,12 @@ function OhhwellsBridge() {
|
|
|
30532
30668
|
closeLinkPopoverRef.current();
|
|
30533
30669
|
return;
|
|
30534
30670
|
}
|
|
30671
|
+
if (floatingPanelOpenRef.current) {
|
|
30672
|
+
setFloatingPanelRef.current(null);
|
|
30673
|
+
deselectRef.current();
|
|
30674
|
+
deactivateRef.current();
|
|
30675
|
+
return;
|
|
30676
|
+
}
|
|
30535
30677
|
deselectRef.current();
|
|
30536
30678
|
deactivateRef.current();
|
|
30537
30679
|
clearMediaSelectionRef.current();
|
|
@@ -31342,6 +31484,7 @@ function OhhwellsBridge() {
|
|
|
31342
31484
|
window.removeEventListener("message", handleAiSetSections);
|
|
31343
31485
|
window.removeEventListener("message", handleAiSetBrand);
|
|
31344
31486
|
window.removeEventListener("message", handleAiSetStyles);
|
|
31487
|
+
window.removeEventListener("message", handleAiSetButtonStyle);
|
|
31345
31488
|
window.removeEventListener("message", handleCollectItems);
|
|
31346
31489
|
window.removeEventListener("message", handleAiApplyItems);
|
|
31347
31490
|
window.removeEventListener("message", handleGetBrand);
|
|
@@ -31353,10 +31496,10 @@ function OhhwellsBridge() {
|
|
|
31353
31496
|
window.removeEventListener("message", handleDeleteSection);
|
|
31354
31497
|
window.removeEventListener("message", handleDuplicateSection);
|
|
31355
31498
|
window.removeEventListener("message", handleDeactivate);
|
|
31356
|
-
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
31357
31499
|
window.removeEventListener("message", handleToastAction);
|
|
31358
31500
|
window.removeEventListener("message", handleFormCount);
|
|
31359
31501
|
window.removeEventListener("message", handleUiEscape);
|
|
31502
|
+
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
31360
31503
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
31361
31504
|
autoSaveTimers.current.clear();
|
|
31362
31505
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
@@ -31650,7 +31793,7 @@ function OhhwellsBridge() {
|
|
|
31650
31793
|
postToParent2({
|
|
31651
31794
|
type: "ow:ready",
|
|
31652
31795
|
version: "1",
|
|
31653
|
-
bridgeVersion: "0.1.
|
|
31796
|
+
bridgeVersion: "0.1.149",
|
|
31654
31797
|
path: pathname,
|
|
31655
31798
|
nodes: collectEditableNodes(editContentRef.current),
|
|
31656
31799
|
sections
|