@burdenoff/website-sdk 2026.921.1 → 2026.922.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/components/explore.d.mts +10 -2
- package/dist/components/explore.d.ts +10 -2
- package/dist/components/explore.js +536 -221
- package/dist/components/explore.js.map +1 -1
- package/dist/components/explore.mjs +536 -221
- package/dist/components/explore.mjs.map +1 -1
- package/dist/index.js +536 -221
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +536 -221
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8029,6 +8029,7 @@ function toPayload(staged) {
|
|
|
8029
8029
|
textContent
|
|
8030
8030
|
}));
|
|
8031
8031
|
}
|
|
8032
|
+
var SHORT_VIEWPORT_PX = 420;
|
|
8032
8033
|
var EXPLORE_CSS = `
|
|
8033
8034
|
@keyframes boff-explore-pulse {
|
|
8034
8035
|
0%, 80%, 100% { opacity: 0.25; transform: translateY(0); }
|
|
@@ -8063,6 +8064,12 @@ var EXPLORE_CSS = `
|
|
|
8063
8064
|
.boff-explore-scroll {
|
|
8064
8065
|
scrollbar-width: thin;
|
|
8065
8066
|
scrollbar-color: hsl(var(--border)) transparent;
|
|
8067
|
+
/* Stop the transcript handing its scroll to the page. Without this, the first
|
|
8068
|
+
swipe that exhausts the transcript chains to the document \u2014 and on a host site
|
|
8069
|
+
that is 65-70% footer, which is how a phone ends up showing nothing but the
|
|
8070
|
+
footer. Engines that do not support this property ignore the line and keep
|
|
8071
|
+
today's behaviour; the scroll correction above covers them. */
|
|
8072
|
+
overscroll-behavior: contain;
|
|
8066
8073
|
}
|
|
8067
8074
|
.boff-explore-scroll::-webkit-scrollbar { width: 10px; }
|
|
8068
8075
|
.boff-explore-scroll::-webkit-scrollbar-track { background: transparent; }
|
|
@@ -8180,6 +8187,68 @@ var EXPLORE_CSS = `
|
|
|
8180
8187
|
.boff-explore-busy::after { animation: none; }
|
|
8181
8188
|
.boff-explore-rise { animation: none; opacity: 1; transform: none; }
|
|
8182
8189
|
}
|
|
8190
|
+
|
|
8191
|
+
/* ---- Pane height ----------------------------------------------------------------------
|
|
8192
|
+
This used to be one inline declaration, \`height: calc(100dvh - 64px)\`, and it carried two
|
|
8193
|
+
defects. An inline style cannot carry a fallback, so every engine without \`dvh\` (iOS
|
|
8194
|
+
Safari < 15.4, Chrome/WebView < 108, Samsung Internet < 21, Firefox < 101) dropped it
|
|
8195
|
+
whole; and the 64px came from a prop hard-coded to 64 on all 41 host pages that matches
|
|
8196
|
+
none of them \u2014 the burdenoff/algoshred chrome is 80px, the sticky-header sites are 65.
|
|
8197
|
+
|
|
8198
|
+
A class plus custom properties lets the cascade do the work: \`vh\` is the floor and \`dvh\`
|
|
8199
|
+
an upgrade where it exists, while the two measured values stay *lengths*, never a height.
|
|
8200
|
+
That distinction is the whole prerender contract. The host sites snapshot \`/explore\` by
|
|
8201
|
+
loading the built SPA in headless Chromium and writing the POST-HYDRATION DOM to
|
|
8202
|
+
dist/explore/index.html, so every attribute and inline value this component sets after
|
|
8203
|
+
mount IS the static HTML CloudFront serves. A measured pixel *height* would therefore
|
|
8204
|
+
hand every phone the prerender viewport's height until the bundle executes; a measured
|
|
8205
|
+
*offset* is a site-header height, which is the same on every device to within a few
|
|
8206
|
+
pixels, and the height built from it stays viewport-relative on the visitor's own screen.
|
|
8207
|
+
|
|
8208
|
+
--boff-explore-offset chrome above the pane (measured root top; the prop pre-measure)
|
|
8209
|
+
--boff-explore-inset the slice of the layout viewport hidden below the visible area \u2014
|
|
8210
|
+
the on-screen keyboard, which \`dvh\` does not track. Zero unless
|
|
8211
|
+
something is actually covering the bottom, so a snapshot taken
|
|
8212
|
+
with no keyboard open never carries it. */
|
|
8213
|
+
.boff-explore-viewport {
|
|
8214
|
+
height: calc(100vh - var(--boff-explore-offset, 0px) - var(--boff-explore-inset, 0px));
|
|
8215
|
+
}
|
|
8216
|
+
@supports (height: 100dvh) {
|
|
8217
|
+
.boff-explore-viewport {
|
|
8218
|
+
height: calc(100dvh - var(--boff-explore-offset, 0px) - var(--boff-explore-inset, 0px));
|
|
8219
|
+
}
|
|
8220
|
+
}
|
|
8221
|
+
|
|
8222
|
+
/* Landscape phones and other short viewports: a one-screen pane leaves a ~124px transcript
|
|
8223
|
+
sliver under ~610px of chrome and content. At or below the threshold the pane stops
|
|
8224
|
+
pretending to be a window and lets the page's own scrolling carry the transcript. The
|
|
8225
|
+
min-height is the available height rather than a fixed rem value, so the fallback can
|
|
8226
|
+
never be taller than the screen it is rescuing. */
|
|
8227
|
+
@media (max-height: ${SHORT_VIEWPORT_PX}px) {
|
|
8228
|
+
.boff-explore-viewport {
|
|
8229
|
+
height: auto;
|
|
8230
|
+
min-height: calc(100vh - var(--boff-explore-offset, 0px));
|
|
8231
|
+
}
|
|
8232
|
+
}
|
|
8233
|
+
@supports (height: 100dvh) {
|
|
8234
|
+
@media (max-height: ${SHORT_VIEWPORT_PX}px) {
|
|
8235
|
+
.boff-explore-viewport {
|
|
8236
|
+
min-height: calc(100dvh - var(--boff-explore-offset, 0px));
|
|
8237
|
+
}
|
|
8238
|
+
}
|
|
8239
|
+
}
|
|
8240
|
+
|
|
8241
|
+
/* ---- Composer dock --------------------------------------------------------------------
|
|
8242
|
+
Three declarations, each the fallback for the one after it: a plain 1rem where \`max()\`
|
|
8243
|
+
is unknown, then the measured overlap of any FOREIGN fixed chrome sitting over the
|
|
8244
|
+
composer (the host sites' cookie banner is 229px tall and lands exactly there), then the
|
|
8245
|
+
same plus the home-indicator inset. \`--boff-explore-chrome\` is set on the root only once
|
|
8246
|
+
an overlap has actually been measured, so everywhere else this collapses to 1rem. */
|
|
8247
|
+
.boff-explore-composer {
|
|
8248
|
+
padding-bottom: 1rem;
|
|
8249
|
+
padding-bottom: max(1rem, var(--boff-explore-chrome, 0px));
|
|
8250
|
+
padding-bottom: max(1rem, env(safe-area-inset-bottom), var(--boff-explore-chrome, 0px));
|
|
8251
|
+
}
|
|
8183
8252
|
`;
|
|
8184
8253
|
function ExploreStyles() {
|
|
8185
8254
|
return /* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: EXPLORE_CSS } });
|
|
@@ -8201,6 +8270,8 @@ var CAPABILITIES = [
|
|
|
8201
8270
|
body: "Get the sources and next steps \u2014 pricing, docs, a demo \u2014 without hunting."
|
|
8202
8271
|
}
|
|
8203
8272
|
];
|
|
8273
|
+
var MIN_VISIBLE_FRACTION = 0.25;
|
|
8274
|
+
var SDK_OVERLAY_SELECTOR = "[data-boff-explore]";
|
|
8204
8275
|
var CTA_VARIANTS = {
|
|
8205
8276
|
CONTACT: "default",
|
|
8206
8277
|
WAITLIST: "default",
|
|
@@ -8216,6 +8287,28 @@ function normalizeOffset(offset) {
|
|
|
8216
8287
|
if (offset === void 0) return "0px";
|
|
8217
8288
|
return typeof offset === "number" ? `${offset}px` : offset;
|
|
8218
8289
|
}
|
|
8290
|
+
function isOwnElement(el, root) {
|
|
8291
|
+
if (el === document.body || el === document.documentElement) return true;
|
|
8292
|
+
if (root.contains(el)) return true;
|
|
8293
|
+
return el.closest(SDK_OVERLAY_SELECTOR) !== null;
|
|
8294
|
+
}
|
|
8295
|
+
function visualViewportHeight() {
|
|
8296
|
+
return window.visualViewport?.height ?? window.innerHeight;
|
|
8297
|
+
}
|
|
8298
|
+
function clamp(value, min, max) {
|
|
8299
|
+
return Math.min(Math.max(value, min), max);
|
|
8300
|
+
}
|
|
8301
|
+
function isRestoredNavigation() {
|
|
8302
|
+
const entries = window.performance?.getEntriesByType?.("navigation");
|
|
8303
|
+
const entry = entries?.[0];
|
|
8304
|
+
if (!entry) return true;
|
|
8305
|
+
const navigation = entry;
|
|
8306
|
+
return navigation.type === "reload" || navigation.type === "back_forward";
|
|
8307
|
+
}
|
|
8308
|
+
function pageOwnsScrolling(el) {
|
|
8309
|
+
if (window.innerHeight > SHORT_VIEWPORT_PX) return false;
|
|
8310
|
+
return el.scrollHeight - el.clientHeight <= 1;
|
|
8311
|
+
}
|
|
8219
8312
|
function isInternalPath(url) {
|
|
8220
8313
|
return url.startsWith("/") && !url.startsWith("//");
|
|
8221
8314
|
}
|
|
@@ -9064,6 +9157,8 @@ function ExplorePage({
|
|
|
9064
9157
|
const pickQueueRef = React.useRef(Promise.resolve());
|
|
9065
9158
|
const [shareLabel, setShareLabel] = React.useState(T.share);
|
|
9066
9159
|
const [shareUrl, setShareUrl] = React.useState(null);
|
|
9160
|
+
const rootRef = React.useRef(null);
|
|
9161
|
+
const composerRef = React.useRef(null);
|
|
9067
9162
|
const scrollRef = React.useRef(null);
|
|
9068
9163
|
const latestAssistantRef = React.useRef(null);
|
|
9069
9164
|
const alignedForRef = React.useRef(null);
|
|
@@ -9091,11 +9186,196 @@ function ExplorePage({
|
|
|
9091
9186
|
el.style.height = "auto";
|
|
9092
9187
|
el.style.height = `${Math.min(el.scrollHeight, 200)}px`;
|
|
9093
9188
|
}, [draft]);
|
|
9189
|
+
const [paneOffset, setPaneOffset] = React.useState(null);
|
|
9190
|
+
const [bottomInset, setBottomInset] = React.useState(0);
|
|
9191
|
+
const paneOffsetRef = React.useRef(0);
|
|
9192
|
+
const measurePane = React.useCallback(() => {
|
|
9193
|
+
if (heightMode !== "viewport") return;
|
|
9194
|
+
const el = rootRef.current;
|
|
9195
|
+
if (!el) return;
|
|
9196
|
+
const layoutHeight = window.innerHeight;
|
|
9197
|
+
if (layoutHeight === 0) return;
|
|
9198
|
+
const top = Math.round(
|
|
9199
|
+
clamp(el.getBoundingClientRect().top, 0, layoutHeight)
|
|
9200
|
+
);
|
|
9201
|
+
const viewport = window.visualViewport;
|
|
9202
|
+
const inset = viewport ? Math.round(
|
|
9203
|
+
clamp(
|
|
9204
|
+
layoutHeight - viewport.height - viewport.offsetTop,
|
|
9205
|
+
0,
|
|
9206
|
+
layoutHeight
|
|
9207
|
+
)
|
|
9208
|
+
) : 0;
|
|
9209
|
+
paneOffsetRef.current = top;
|
|
9210
|
+
setPaneOffset((current) => current === top ? current : top);
|
|
9211
|
+
setBottomInset((current) => current === inset ? current : inset);
|
|
9212
|
+
}, [heightMode]);
|
|
9213
|
+
const [chromeOverlap, setChromeOverlap] = React.useState(0);
|
|
9214
|
+
const measureChrome = React.useCallback(() => {
|
|
9215
|
+
const root = rootRef.current;
|
|
9216
|
+
const dock = composerRef.current;
|
|
9217
|
+
if (!root || !dock) return;
|
|
9218
|
+
if (typeof document.elementFromPoint !== "function") return;
|
|
9219
|
+
const viewportHeight = visualViewportHeight();
|
|
9220
|
+
const rect = dock.getBoundingClientRect();
|
|
9221
|
+
if (rect.width === 0 || viewportHeight === 0) return;
|
|
9222
|
+
if (rect.bottom <= 0 || rect.top >= viewportHeight) return;
|
|
9223
|
+
const edge = Math.min(rect.bottom, viewportHeight);
|
|
9224
|
+
const hit = document.elementFromPoint(rect.left + rect.width / 2, edge - 1);
|
|
9225
|
+
if (!hit || isOwnElement(hit, root)) {
|
|
9226
|
+
setChromeOverlap(0);
|
|
9227
|
+
return;
|
|
9228
|
+
}
|
|
9229
|
+
const overlap = Math.round(edge - hit.getBoundingClientRect().top);
|
|
9230
|
+
setChromeOverlap(overlap > 0 && overlap < viewportHeight ? overlap : 0);
|
|
9231
|
+
}, []);
|
|
9232
|
+
const remeasure = React.useCallback(() => {
|
|
9233
|
+
measurePane();
|
|
9234
|
+
measureChrome();
|
|
9235
|
+
}, [measurePane, measureChrome]);
|
|
9236
|
+
React.useEffect(() => {
|
|
9237
|
+
if (typeof window === "undefined") return;
|
|
9238
|
+
let frame = 0;
|
|
9239
|
+
const run = () => {
|
|
9240
|
+
frame = 0;
|
|
9241
|
+
remeasure();
|
|
9242
|
+
};
|
|
9243
|
+
const schedule = () => {
|
|
9244
|
+
if (frame) return;
|
|
9245
|
+
if (typeof window.requestAnimationFrame !== "function") {
|
|
9246
|
+
remeasure();
|
|
9247
|
+
return;
|
|
9248
|
+
}
|
|
9249
|
+
frame = window.requestAnimationFrame(run);
|
|
9250
|
+
};
|
|
9251
|
+
remeasure();
|
|
9252
|
+
const viewport = window.visualViewport;
|
|
9253
|
+
window.addEventListener("resize", schedule);
|
|
9254
|
+
window.addEventListener("orientationchange", schedule);
|
|
9255
|
+
viewport?.addEventListener("resize", schedule);
|
|
9256
|
+
viewport?.addEventListener("scroll", schedule);
|
|
9257
|
+
const observer = typeof MutationObserver === "function" ? new MutationObserver((records) => {
|
|
9258
|
+
const el = rootRef.current;
|
|
9259
|
+
if (el && records.every((record) => el.contains(record.target)))
|
|
9260
|
+
return;
|
|
9261
|
+
schedule();
|
|
9262
|
+
}) : null;
|
|
9263
|
+
observer?.observe(document.body, { childList: true, subtree: true });
|
|
9264
|
+
return () => {
|
|
9265
|
+
if (frame) window.cancelAnimationFrame(frame);
|
|
9266
|
+
window.removeEventListener("resize", schedule);
|
|
9267
|
+
window.removeEventListener("orientationchange", schedule);
|
|
9268
|
+
viewport?.removeEventListener("resize", schedule);
|
|
9269
|
+
viewport?.removeEventListener("scroll", schedule);
|
|
9270
|
+
observer?.disconnect();
|
|
9271
|
+
setPaneOffset(null);
|
|
9272
|
+
setBottomInset(0);
|
|
9273
|
+
setChromeOverlap(0);
|
|
9274
|
+
};
|
|
9275
|
+
}, [remeasure]);
|
|
9276
|
+
React.useEffect(() => {
|
|
9277
|
+
measureChrome();
|
|
9278
|
+
}, [measureChrome, paneOffset, bottomInset]);
|
|
9279
|
+
React.useEffect(() => {
|
|
9280
|
+
if (heightMode !== "viewport" || typeof window === "undefined") return;
|
|
9281
|
+
const { history: browserHistory } = window;
|
|
9282
|
+
const previousRestoration = "scrollRestoration" in browserHistory ? browserHistory.scrollRestoration : null;
|
|
9283
|
+
if (previousRestoration !== null)
|
|
9284
|
+
browserHistory.scrollRestoration = "manual";
|
|
9285
|
+
let frame = 0;
|
|
9286
|
+
let visitorMoved = false;
|
|
9287
|
+
const onVisitorMove = () => {
|
|
9288
|
+
visitorMoved = true;
|
|
9289
|
+
};
|
|
9290
|
+
const align = () => {
|
|
9291
|
+
if (visitorMoved) return;
|
|
9292
|
+
const el = rootRef.current;
|
|
9293
|
+
if (!el) return;
|
|
9294
|
+
const viewportHeight = visualViewportHeight();
|
|
9295
|
+
const rect = el.getBoundingClientRect();
|
|
9296
|
+
if (rect.height === 0 || viewportHeight === 0) return;
|
|
9297
|
+
const visible = Math.min(rect.bottom, viewportHeight) - Math.max(rect.top, 0);
|
|
9298
|
+
const reachable = Math.min(rect.height, viewportHeight);
|
|
9299
|
+
if (visible >= reachable * MIN_VISIBLE_FRACTION) return;
|
|
9300
|
+
window.scrollTo({
|
|
9301
|
+
top: Math.max(0, window.scrollY + rect.top),
|
|
9302
|
+
left: window.scrollX,
|
|
9303
|
+
behavior: "auto"
|
|
9304
|
+
});
|
|
9305
|
+
if (typeof document.elementFromPoint === "function") {
|
|
9306
|
+
const probe = document.elementFromPoint(
|
|
9307
|
+
Math.max(0, rect.left + rect.width / 2),
|
|
9308
|
+
1
|
|
9309
|
+
);
|
|
9310
|
+
if (probe && !isOwnElement(probe, el)) {
|
|
9311
|
+
const chrome = probe.getBoundingClientRect().bottom;
|
|
9312
|
+
if (chrome > 0 && chrome < viewportHeight / 2) {
|
|
9313
|
+
window.scrollBy({ top: -chrome, left: 0, behavior: "auto" });
|
|
9314
|
+
}
|
|
9315
|
+
}
|
|
9316
|
+
}
|
|
9317
|
+
remeasure();
|
|
9318
|
+
};
|
|
9319
|
+
const alignIfRestored = () => {
|
|
9320
|
+
if (!isRestoredNavigation()) return;
|
|
9321
|
+
align();
|
|
9322
|
+
};
|
|
9323
|
+
alignIfRestored();
|
|
9324
|
+
if (typeof window.requestAnimationFrame === "function") {
|
|
9325
|
+
frame = window.requestAnimationFrame(alignIfRestored);
|
|
9326
|
+
}
|
|
9327
|
+
const onPageShow = (event) => {
|
|
9328
|
+
if (!event.persisted) {
|
|
9329
|
+
alignIfRestored();
|
|
9330
|
+
return;
|
|
9331
|
+
}
|
|
9332
|
+
visitorMoved = false;
|
|
9333
|
+
align();
|
|
9334
|
+
};
|
|
9335
|
+
window.addEventListener("pageshow", onPageShow);
|
|
9336
|
+
window.addEventListener("wheel", onVisitorMove, { passive: true });
|
|
9337
|
+
window.addEventListener("touchmove", onVisitorMove, { passive: true });
|
|
9338
|
+
window.addEventListener("keydown", onVisitorMove, { passive: true });
|
|
9339
|
+
return () => {
|
|
9340
|
+
if (frame) window.cancelAnimationFrame(frame);
|
|
9341
|
+
window.removeEventListener("pageshow", onPageShow);
|
|
9342
|
+
window.removeEventListener("wheel", onVisitorMove);
|
|
9343
|
+
window.removeEventListener("touchmove", onVisitorMove);
|
|
9344
|
+
window.removeEventListener("keydown", onVisitorMove);
|
|
9345
|
+
if (previousRestoration !== null)
|
|
9346
|
+
browserHistory.scrollRestoration = previousRestoration;
|
|
9347
|
+
};
|
|
9348
|
+
}, [heightMode, remeasure]);
|
|
9094
9349
|
const handleScroll = React.useCallback(() => {
|
|
9095
9350
|
const el = scrollRef.current;
|
|
9096
9351
|
if (!el) return;
|
|
9097
9352
|
stickToBottomRef.current = el.scrollHeight - el.scrollTop - el.clientHeight < 80;
|
|
9098
9353
|
}, []);
|
|
9354
|
+
React.useEffect(() => {
|
|
9355
|
+
if (typeof window === "undefined") return;
|
|
9356
|
+
let frame = 0;
|
|
9357
|
+
const run = () => {
|
|
9358
|
+
frame = 0;
|
|
9359
|
+
const el = scrollRef.current;
|
|
9360
|
+
const dock = composerRef.current;
|
|
9361
|
+
if (!el || !dock) return;
|
|
9362
|
+
if (!pageOwnsScrolling(el)) return;
|
|
9363
|
+
stickToBottomRef.current = dock.getBoundingClientRect().bottom - visualViewportHeight() < 80;
|
|
9364
|
+
};
|
|
9365
|
+
const schedule = () => {
|
|
9366
|
+
if (frame) return;
|
|
9367
|
+
if (typeof window.requestAnimationFrame !== "function") {
|
|
9368
|
+
run();
|
|
9369
|
+
return;
|
|
9370
|
+
}
|
|
9371
|
+
frame = window.requestAnimationFrame(run);
|
|
9372
|
+
};
|
|
9373
|
+
window.addEventListener("scroll", schedule, { passive: true });
|
|
9374
|
+
return () => {
|
|
9375
|
+
if (frame) window.cancelAnimationFrame(frame);
|
|
9376
|
+
window.removeEventListener("scroll", schedule);
|
|
9377
|
+
};
|
|
9378
|
+
}, []);
|
|
9099
9379
|
const latestAssistantId = React.useMemo(() => {
|
|
9100
9380
|
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
9101
9381
|
const message = messages[i];
|
|
@@ -9111,16 +9391,32 @@ function ExplorePage({
|
|
|
9111
9391
|
if (!stickToBottomRef.current) return;
|
|
9112
9392
|
if (anchor.offsetHeight === 0) return;
|
|
9113
9393
|
alignedForRef.current = latestAssistantId;
|
|
9114
|
-
|
|
9115
|
-
|
|
9394
|
+
if (!pageOwnsScrolling(el)) {
|
|
9395
|
+
const delta2 = anchor.getBoundingClientRect().top - el.getBoundingClientRect().top;
|
|
9396
|
+
el.scrollTop = Math.max(0, el.scrollTop + delta2 - 12);
|
|
9397
|
+
return;
|
|
9398
|
+
}
|
|
9399
|
+
const delta = Math.round(
|
|
9400
|
+
anchor.getBoundingClientRect().top - paneOffsetRef.current - 12
|
|
9401
|
+
);
|
|
9402
|
+
if (delta !== 0) window.scrollBy({ top: delta, left: 0, behavior: "auto" });
|
|
9116
9403
|
}, [latestAssistantId, messages]);
|
|
9117
9404
|
React.useEffect(() => {
|
|
9405
|
+
if (messages.length === 0) return;
|
|
9118
9406
|
if (!stickToBottomRef.current) return;
|
|
9119
9407
|
if (latestAssistantId && alignedForRef.current === latestAssistantId)
|
|
9120
9408
|
return;
|
|
9121
9409
|
const el = scrollRef.current;
|
|
9122
9410
|
if (!el) return;
|
|
9123
|
-
el
|
|
9411
|
+
if (!pageOwnsScrolling(el)) {
|
|
9412
|
+
el.scrollTop = el.scrollHeight;
|
|
9413
|
+
return;
|
|
9414
|
+
}
|
|
9415
|
+
const dock = composerRef.current ?? el;
|
|
9416
|
+
const delta = Math.round(
|
|
9417
|
+
dock.getBoundingClientRect().bottom - visualViewportHeight()
|
|
9418
|
+
);
|
|
9419
|
+
if (delta > 0) window.scrollBy({ top: delta, left: 0, behavior: "auto" });
|
|
9124
9420
|
}, [activity, latestAssistantId, messages]);
|
|
9125
9421
|
const handleShare = React.useCallback(async () => {
|
|
9126
9422
|
setShareLabel(T.copying);
|
|
@@ -9218,16 +9514,27 @@ function ExplorePage({
|
|
|
9218
9514
|
const captchaOn = Boolean(
|
|
9219
9515
|
catalog.captchaRequired && catalog.recaptchaSiteKey
|
|
9220
9516
|
);
|
|
9221
|
-
const rootStyle =
|
|
9517
|
+
const rootStyle = {};
|
|
9518
|
+
if (heightMode === "viewport") {
|
|
9519
|
+
rootStyle["--boff-explore-offset"] = paneOffset === null ? normalizeOffset(viewportOffset) : `${paneOffset}px`;
|
|
9520
|
+
if (bottomInset > 0) {
|
|
9521
|
+
rootStyle["--boff-explore-inset"] = `${bottomInset}px`;
|
|
9522
|
+
}
|
|
9523
|
+
}
|
|
9524
|
+
if (chromeOverlap > 0) {
|
|
9525
|
+
rootStyle["--boff-explore-chrome"] = `${chromeOverlap}px`;
|
|
9526
|
+
}
|
|
9222
9527
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9223
9528
|
"div",
|
|
9224
9529
|
{
|
|
9530
|
+
ref: rootRef,
|
|
9225
9531
|
"data-boff-explore": "page",
|
|
9226
9532
|
"data-phase": phase,
|
|
9227
9533
|
"data-locale": activeLocale,
|
|
9228
9534
|
dir: rtl ? "rtl" : void 0,
|
|
9229
9535
|
className: cn(
|
|
9230
9536
|
"flex w-full min-w-0 flex-col overflow-x-hidden bg-background text-foreground",
|
|
9537
|
+
heightMode === "viewport" && "boff-explore-viewport",
|
|
9231
9538
|
heightMode === "auto" && "min-h-[70vh]",
|
|
9232
9539
|
className
|
|
9233
9540
|
),
|
|
@@ -9461,249 +9768,257 @@ function ExplorePage({
|
|
|
9461
9768
|
]
|
|
9462
9769
|
}
|
|
9463
9770
|
) : null,
|
|
9464
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9465
|
-
"
|
|
9771
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9772
|
+
"div",
|
|
9466
9773
|
{
|
|
9467
|
-
|
|
9468
|
-
|
|
9469
|
-
|
|
9470
|
-
|
|
9471
|
-
|
|
9472
|
-
|
|
9473
|
-
|
|
9474
|
-
|
|
9475
|
-
|
|
9476
|
-
|
|
9477
|
-
|
|
9478
|
-
|
|
9479
|
-
|
|
9480
|
-
|
|
9481
|
-
|
|
9482
|
-
"
|
|
9774
|
+
ref: composerRef,
|
|
9775
|
+
"data-boff-explore": "composer-dock",
|
|
9776
|
+
className: "boff-explore-composer border-t border-border bg-background/85 px-4 pt-3 backdrop-blur-md",
|
|
9777
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9778
|
+
"form",
|
|
9779
|
+
{
|
|
9780
|
+
"data-boff-explore": "composer",
|
|
9781
|
+
className: "mx-auto w-full max-w-3xl",
|
|
9782
|
+
onSubmit: (event) => {
|
|
9783
|
+
event.preventDefault();
|
|
9784
|
+
submitDraft();
|
|
9785
|
+
},
|
|
9786
|
+
children: [
|
|
9787
|
+
error ? /* @__PURE__ */ jsxRuntime.jsx(ErrorBanner, { error, onRetry: retry, onReset: reset }) : null,
|
|
9788
|
+
staged.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
9789
|
+
"ul",
|
|
9790
|
+
{
|
|
9791
|
+
"data-boff-explore": "attachments",
|
|
9792
|
+
className: "mb-2 flex flex-wrap gap-1.5",
|
|
9793
|
+
"aria-label": T.attach,
|
|
9794
|
+
children: staged.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9795
|
+
"li",
|
|
9796
|
+
{
|
|
9797
|
+
"data-boff-explore": "attachment",
|
|
9798
|
+
"data-text-extracted": entry.textExtracted ? "true" : "false",
|
|
9799
|
+
className: "flex max-w-full items-center gap-1.5 rounded-full border border-border bg-muted/60 py-1 pl-2.5 pr-1 text-xs",
|
|
9800
|
+
children: [
|
|
9801
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { className: "h-3 w-3 shrink-0 text-muted-foreground" }),
|
|
9802
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", title: entry.name, children: entry.name }),
|
|
9803
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "shrink-0 text-muted-foreground", children: [
|
|
9804
|
+
formatBytes(entry.size),
|
|
9805
|
+
entry.textExtracted ? "" : ` \xB7 ${T.attachmentNameOnly}`
|
|
9806
|
+
] }),
|
|
9807
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9808
|
+
"button",
|
|
9809
|
+
{
|
|
9810
|
+
type: "button",
|
|
9811
|
+
"data-boff-explore": "attachment-remove",
|
|
9812
|
+
onClick: () => removeAttachment(entry.id),
|
|
9813
|
+
"aria-label": fill(T.removeAttachment, { name: entry.name }),
|
|
9814
|
+
className: "ml-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-background hover:text-foreground",
|
|
9815
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3" })
|
|
9816
|
+
}
|
|
9817
|
+
)
|
|
9818
|
+
]
|
|
9819
|
+
},
|
|
9820
|
+
entry.id
|
|
9821
|
+
))
|
|
9822
|
+
}
|
|
9823
|
+
) : null,
|
|
9824
|
+
attachmentNotice !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
9825
|
+
"p",
|
|
9483
9826
|
{
|
|
9484
|
-
"data-boff-explore": "attachment",
|
|
9485
|
-
|
|
9486
|
-
className: "
|
|
9827
|
+
"data-boff-explore": "attachment-notice",
|
|
9828
|
+
role: "status",
|
|
9829
|
+
className: "mb-2 text-xs text-destructive",
|
|
9830
|
+
children: attachmentNotice
|
|
9831
|
+
}
|
|
9832
|
+
) : null,
|
|
9833
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9834
|
+
"div",
|
|
9835
|
+
{
|
|
9836
|
+
className: cn(
|
|
9837
|
+
"flex min-w-0 items-end gap-2 rounded-2xl border bg-card p-2 shadow-sm transition-all",
|
|
9838
|
+
busy && "boff-explore-busy",
|
|
9839
|
+
overLimit ? "border-destructive/60" : "border-border focus-within:border-primary/40 focus-within:ring-1 focus-within:ring-ring"
|
|
9840
|
+
),
|
|
9487
9841
|
children: [
|
|
9488
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { className: "h-3 w-3 shrink-0 text-muted-foreground" }),
|
|
9489
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", title: entry.name, children: entry.name }),
|
|
9490
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "shrink-0 text-muted-foreground", children: [
|
|
9491
|
-
formatBytes(entry.size),
|
|
9492
|
-
entry.textExtracted ? "" : ` \xB7 ${T.attachmentNameOnly}`
|
|
9493
|
-
] }),
|
|
9494
9842
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9495
|
-
|
|
9843
|
+
Textarea,
|
|
9496
9844
|
{
|
|
9845
|
+
ref: textareaRef,
|
|
9846
|
+
value: draft,
|
|
9847
|
+
rows: 1,
|
|
9848
|
+
disabled: composerDisabled,
|
|
9849
|
+
onChange: (event) => setDraft(event.target.value),
|
|
9850
|
+
onKeyDown: handleKeyDown,
|
|
9851
|
+
onCompositionStart: () => {
|
|
9852
|
+
composingRef.current = true;
|
|
9853
|
+
},
|
|
9854
|
+
onCompositionEnd: () => {
|
|
9855
|
+
composingRef.current = false;
|
|
9856
|
+
},
|
|
9857
|
+
"aria-label": "Ask a question",
|
|
9858
|
+
placeholder: composerDisabled ? phase === "limited" ? "Message limit reached \u2014 please try again later" : "Explore is unavailable right now" : focusedProductName ? fill(T.placeholderProduct, {
|
|
9859
|
+
product: focusedProductName
|
|
9860
|
+
}) : T.placeholder,
|
|
9861
|
+
className: "max-h-[200px] min-h-[44px] w-full min-w-0 flex-1 resize-none border-0 bg-transparent px-2 py-2.5 text-base shadow-none focus-visible:ring-0 sm:text-sm"
|
|
9862
|
+
}
|
|
9863
|
+
),
|
|
9864
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9865
|
+
"input",
|
|
9866
|
+
{
|
|
9867
|
+
ref: fileInputRef,
|
|
9868
|
+
type: "file",
|
|
9869
|
+
multiple: true,
|
|
9870
|
+
className: "hidden",
|
|
9871
|
+
onChange: (event) => {
|
|
9872
|
+
void handleFilesPicked(event.target.files);
|
|
9873
|
+
event.target.value = "";
|
|
9874
|
+
}
|
|
9875
|
+
}
|
|
9876
|
+
),
|
|
9877
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9878
|
+
Button,
|
|
9879
|
+
{
|
|
9880
|
+
"data-boff-explore": "attach",
|
|
9881
|
+
type: "button",
|
|
9882
|
+
size: "icon",
|
|
9883
|
+
variant: "ghost",
|
|
9884
|
+
disabled: composerDisabled || staged.length >= MAX_ATTACHMENTS,
|
|
9885
|
+
"aria-label": T.attach,
|
|
9886
|
+
title: `${T.attach} \u2014 ${fill(T.attachHint, {
|
|
9887
|
+
max: String(MAX_ATTACHMENTS),
|
|
9888
|
+
size: String(MAX_ATTACHMENT_BYTES / (1024 * 1024))
|
|
9889
|
+
})}`,
|
|
9890
|
+
onClick: () => fileInputRef.current?.click(),
|
|
9891
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { className: "h-4 w-4" })
|
|
9892
|
+
}
|
|
9893
|
+
),
|
|
9894
|
+
speech.supported ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
9895
|
+
Button,
|
|
9896
|
+
{
|
|
9897
|
+
"data-boff-explore": "mic",
|
|
9898
|
+
"data-listening": speech.listening ? "true" : "false",
|
|
9497
9899
|
type: "button",
|
|
9498
|
-
|
|
9499
|
-
|
|
9500
|
-
|
|
9501
|
-
|
|
9502
|
-
|
|
9900
|
+
size: "icon",
|
|
9901
|
+
variant: speech.listening ? "default" : "ghost",
|
|
9902
|
+
disabled: composerDisabled,
|
|
9903
|
+
"aria-label": speech.listening ? T.stopDictating : T.dictate,
|
|
9904
|
+
"aria-pressed": speech.listening,
|
|
9905
|
+
title: speech.listening ? T.stopDictating : T.dictate,
|
|
9906
|
+
onClick: speech.toggle,
|
|
9907
|
+
className: cn(speech.listening && "animate-pulse"),
|
|
9908
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, { className: "h-4 w-4" })
|
|
9909
|
+
}
|
|
9910
|
+
) : null,
|
|
9911
|
+
busy ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
9912
|
+
Button,
|
|
9913
|
+
{
|
|
9914
|
+
"data-boff-explore": "stop",
|
|
9915
|
+
type: "button",
|
|
9916
|
+
size: "icon",
|
|
9917
|
+
variant: "secondary",
|
|
9918
|
+
"aria-label": T.stop,
|
|
9919
|
+
onClick: stop,
|
|
9920
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Square, { className: "h-4 w-4" })
|
|
9921
|
+
}
|
|
9922
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
9923
|
+
Button,
|
|
9924
|
+
{
|
|
9925
|
+
"data-boff-explore": "send",
|
|
9926
|
+
type: "submit",
|
|
9927
|
+
size: "icon",
|
|
9928
|
+
disabled: !canSubmit,
|
|
9929
|
+
"aria-label": T.send,
|
|
9930
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-4 w-4" })
|
|
9503
9931
|
}
|
|
9504
9932
|
)
|
|
9505
9933
|
]
|
|
9506
|
-
}
|
|
9507
|
-
entry.id
|
|
9508
|
-
))
|
|
9509
|
-
}
|
|
9510
|
-
) : null,
|
|
9511
|
-
attachmentNotice !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
9512
|
-
"p",
|
|
9513
|
-
{
|
|
9514
|
-
"data-boff-explore": "attachment-notice",
|
|
9515
|
-
role: "status",
|
|
9516
|
-
className: "mb-2 text-xs text-destructive",
|
|
9517
|
-
children: attachmentNotice
|
|
9518
|
-
}
|
|
9519
|
-
) : null,
|
|
9520
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9521
|
-
"div",
|
|
9522
|
-
{
|
|
9523
|
-
className: cn(
|
|
9524
|
-
"flex min-w-0 items-end gap-2 rounded-2xl border bg-card p-2 shadow-sm transition-all",
|
|
9525
|
-
busy && "boff-explore-busy",
|
|
9526
|
-
overLimit ? "border-destructive/60" : "border-border focus-within:border-primary/40 focus-within:ring-1 focus-within:ring-ring"
|
|
9934
|
+
}
|
|
9527
9935
|
),
|
|
9528
|
-
|
|
9529
|
-
|
|
9530
|
-
|
|
9936
|
+
speech.listening || speech.interim !== "" ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9937
|
+
"p",
|
|
9938
|
+
{
|
|
9939
|
+
"data-boff-explore": "dictation",
|
|
9940
|
+
className: "mt-2 flex items-center gap-2 text-xs text-muted-foreground",
|
|
9941
|
+
"aria-live": "polite",
|
|
9942
|
+
children: [
|
|
9943
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-2 w-2 shrink-0", children: [
|
|
9944
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-primary opacity-75" }),
|
|
9945
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex h-2 w-2 rounded-full bg-primary" })
|
|
9946
|
+
] }),
|
|
9947
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "italic", children: speech.interim !== "" ? speech.interim : "Listening\u2026" })
|
|
9948
|
+
]
|
|
9949
|
+
}
|
|
9950
|
+
) : null,
|
|
9951
|
+
speech.error !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
9952
|
+
"p",
|
|
9953
|
+
{
|
|
9954
|
+
"data-boff-explore": "dictation-error",
|
|
9955
|
+
className: "mt-2 text-xs text-destructive",
|
|
9956
|
+
children: speech.error
|
|
9957
|
+
}
|
|
9958
|
+
) : null,
|
|
9959
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
|
|
9960
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: "Enter to send \xB7 Shift + Enter for a new line" }),
|
|
9961
|
+
remainingToday !== null ? /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-boff-explore": "remaining", children: [
|
|
9962
|
+
remainingToday,
|
|
9963
|
+
" message",
|
|
9964
|
+
remainingToday === 1 ? "" : "s",
|
|
9965
|
+
" left today"
|
|
9966
|
+
] }) : null,
|
|
9967
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9968
|
+
"span",
|
|
9531
9969
|
{
|
|
9532
|
-
|
|
9533
|
-
|
|
9534
|
-
|
|
9535
|
-
|
|
9536
|
-
|
|
9537
|
-
|
|
9538
|
-
|
|
9539
|
-
|
|
9540
|
-
|
|
9541
|
-
onCompositionEnd: () => {
|
|
9542
|
-
composingRef.current = false;
|
|
9543
|
-
},
|
|
9544
|
-
"aria-label": "Ask a question",
|
|
9545
|
-
placeholder: composerDisabled ? phase === "limited" ? "Message limit reached \u2014 please try again later" : "Explore is unavailable right now" : focusedProductName ? fill(T.placeholderProduct, {
|
|
9546
|
-
product: focusedProductName
|
|
9547
|
-
}) : T.placeholder,
|
|
9548
|
-
className: "max-h-[200px] min-h-[44px] w-full min-w-0 flex-1 resize-none border-0 bg-transparent px-2 py-2.5 text-base shadow-none focus-visible:ring-0 sm:text-sm"
|
|
9970
|
+
className: cn(
|
|
9971
|
+
"ml-auto tabular-nums",
|
|
9972
|
+
overLimit && "font-medium text-destructive"
|
|
9973
|
+
),
|
|
9974
|
+
children: [
|
|
9975
|
+
draft.length.toLocaleString(),
|
|
9976
|
+
" / ",
|
|
9977
|
+
maxLength.toLocaleString()
|
|
9978
|
+
]
|
|
9549
9979
|
}
|
|
9550
|
-
)
|
|
9980
|
+
)
|
|
9981
|
+
] }),
|
|
9982
|
+
shareUrl ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center gap-2", children: [
|
|
9551
9983
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9552
9984
|
"input",
|
|
9553
9985
|
{
|
|
9554
|
-
|
|
9555
|
-
|
|
9556
|
-
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9560
|
-
event.target.value = "";
|
|
9561
|
-
}
|
|
9986
|
+
"data-boff-explore": "share-url",
|
|
9987
|
+
readOnly: true,
|
|
9988
|
+
value: shareUrl,
|
|
9989
|
+
"aria-label": "Read-only link to this conversation",
|
|
9990
|
+
onFocus: (event) => event.currentTarget.select(),
|
|
9991
|
+
className: "min-w-0 flex-1 rounded-md border border-border bg-muted px-2 py-1 text-xs text-muted-foreground"
|
|
9562
9992
|
}
|
|
9563
9993
|
),
|
|
9564
9994
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9565
|
-
|
|
9995
|
+
"button",
|
|
9566
9996
|
{
|
|
9567
|
-
"data-boff-explore": "attach",
|
|
9568
9997
|
type: "button",
|
|
9569
|
-
|
|
9570
|
-
|
|
9571
|
-
|
|
9572
|
-
"aria-label": T.attach,
|
|
9573
|
-
title: `${T.attach} \u2014 ${fill(T.attachHint, {
|
|
9574
|
-
max: String(MAX_ATTACHMENTS),
|
|
9575
|
-
size: String(MAX_ATTACHMENT_BYTES / (1024 * 1024))
|
|
9576
|
-
})}`,
|
|
9577
|
-
onClick: () => fileInputRef.current?.click(),
|
|
9578
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { className: "h-4 w-4" })
|
|
9998
|
+
className: "shrink-0 text-xs underline underline-offset-2",
|
|
9999
|
+
onClick: () => setShareUrl(null),
|
|
10000
|
+
children: "Done"
|
|
9579
10001
|
}
|
|
9580
|
-
)
|
|
9581
|
-
|
|
9582
|
-
|
|
9583
|
-
|
|
9584
|
-
|
|
9585
|
-
|
|
9586
|
-
type: "button",
|
|
9587
|
-
size: "icon",
|
|
9588
|
-
variant: speech.listening ? "default" : "ghost",
|
|
9589
|
-
disabled: composerDisabled,
|
|
9590
|
-
"aria-label": speech.listening ? T.stopDictating : T.dictate,
|
|
9591
|
-
"aria-pressed": speech.listening,
|
|
9592
|
-
title: speech.listening ? T.stopDictating : T.dictate,
|
|
9593
|
-
onClick: speech.toggle,
|
|
9594
|
-
className: cn(speech.listening && "animate-pulse"),
|
|
9595
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, { className: "h-4 w-4" })
|
|
9596
|
-
}
|
|
9597
|
-
) : null,
|
|
9598
|
-
busy ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
9599
|
-
Button,
|
|
10002
|
+
)
|
|
10003
|
+
] }) : null,
|
|
10004
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
|
|
10005
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: T.disclaimerShort }),
|
|
10006
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10007
|
+
"button",
|
|
9600
10008
|
{
|
|
9601
|
-
"data-boff-explore": "stop",
|
|
9602
10009
|
type: "button",
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
"
|
|
9606
|
-
|
|
9607
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Square, { className: "h-4 w-4" })
|
|
9608
|
-
}
|
|
9609
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
9610
|
-
Button,
|
|
9611
|
-
{
|
|
9612
|
-
"data-boff-explore": "send",
|
|
9613
|
-
type: "submit",
|
|
9614
|
-
size: "icon",
|
|
9615
|
-
disabled: !canSubmit,
|
|
9616
|
-
"aria-label": T.send,
|
|
9617
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-4 w-4" })
|
|
10010
|
+
"data-boff-explore": "disclaimer",
|
|
10011
|
+
onClick: () => setDisclaimerOpen(true),
|
|
10012
|
+
className: "shrink-0 underline underline-offset-2 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
10013
|
+
children: T.disclaimer
|
|
9618
10014
|
}
|
|
9619
10015
|
)
|
|
9620
|
-
]
|
|
9621
|
-
|
|
9622
|
-
|
|
9623
|
-
|
|
9624
|
-
"p",
|
|
9625
|
-
{
|
|
9626
|
-
"data-boff-explore": "dictation",
|
|
9627
|
-
className: "mt-2 flex items-center gap-2 text-xs text-muted-foreground",
|
|
9628
|
-
"aria-live": "polite",
|
|
9629
|
-
children: [
|
|
9630
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-2 w-2 shrink-0", children: [
|
|
9631
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-primary opacity-75" }),
|
|
9632
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex h-2 w-2 rounded-full bg-primary" })
|
|
9633
|
-
] }),
|
|
9634
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "italic", children: speech.interim !== "" ? speech.interim : "Listening\u2026" })
|
|
9635
|
-
]
|
|
9636
|
-
}
|
|
9637
|
-
) : null,
|
|
9638
|
-
speech.error !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
9639
|
-
"p",
|
|
9640
|
-
{
|
|
9641
|
-
"data-boff-explore": "dictation-error",
|
|
9642
|
-
className: "mt-2 text-xs text-destructive",
|
|
9643
|
-
children: speech.error
|
|
9644
|
-
}
|
|
9645
|
-
) : null,
|
|
9646
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
|
|
9647
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: "Enter to send \xB7 Shift + Enter for a new line" }),
|
|
9648
|
-
remainingToday !== null ? /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-boff-explore": "remaining", children: [
|
|
9649
|
-
remainingToday,
|
|
9650
|
-
" message",
|
|
9651
|
-
remainingToday === 1 ? "" : "s",
|
|
9652
|
-
" left today"
|
|
9653
|
-
] }) : null,
|
|
9654
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9655
|
-
"span",
|
|
9656
|
-
{
|
|
9657
|
-
className: cn(
|
|
9658
|
-
"ml-auto tabular-nums",
|
|
9659
|
-
overLimit && "font-medium text-destructive"
|
|
9660
|
-
),
|
|
9661
|
-
children: [
|
|
9662
|
-
draft.length.toLocaleString(),
|
|
9663
|
-
" / ",
|
|
9664
|
-
maxLength.toLocaleString()
|
|
9665
|
-
]
|
|
9666
|
-
}
|
|
9667
|
-
)
|
|
9668
|
-
] }),
|
|
9669
|
-
shareUrl ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center gap-2", children: [
|
|
9670
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9671
|
-
"input",
|
|
9672
|
-
{
|
|
9673
|
-
"data-boff-explore": "share-url",
|
|
9674
|
-
readOnly: true,
|
|
9675
|
-
value: shareUrl,
|
|
9676
|
-
"aria-label": "Read-only link to this conversation",
|
|
9677
|
-
onFocus: (event) => event.currentTarget.select(),
|
|
9678
|
-
className: "min-w-0 flex-1 rounded-md border border-border bg-muted px-2 py-1 text-xs text-muted-foreground"
|
|
9679
|
-
}
|
|
9680
|
-
),
|
|
9681
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9682
|
-
"button",
|
|
9683
|
-
{
|
|
9684
|
-
type: "button",
|
|
9685
|
-
className: "shrink-0 text-xs underline underline-offset-2",
|
|
9686
|
-
onClick: () => setShareUrl(null),
|
|
9687
|
-
children: "Done"
|
|
9688
|
-
}
|
|
9689
|
-
)
|
|
9690
|
-
] }) : null,
|
|
9691
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
|
|
9692
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: T.disclaimerShort }),
|
|
9693
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9694
|
-
"button",
|
|
9695
|
-
{
|
|
9696
|
-
type: "button",
|
|
9697
|
-
"data-boff-explore": "disclaimer",
|
|
9698
|
-
onClick: () => setDisclaimerOpen(true),
|
|
9699
|
-
className: "shrink-0 underline underline-offset-2 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
9700
|
-
children: T.disclaimer
|
|
9701
|
-
}
|
|
9702
|
-
)
|
|
9703
|
-
] })
|
|
9704
|
-
]
|
|
10016
|
+
] })
|
|
10017
|
+
]
|
|
10018
|
+
}
|
|
10019
|
+
)
|
|
9705
10020
|
}
|
|
9706
|
-
)
|
|
10021
|
+
)
|
|
9707
10022
|
]
|
|
9708
10023
|
}
|
|
9709
10024
|
);
|