@burdenoff/website-sdk 2026.830.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 +114 -3
- package/dist/components/contact.js +4 -1
- package/dist/components/contact.js.map +1 -1
- package/dist/components/contact.mjs +4 -1
- package/dist/components/contact.mjs.map +1 -1
- package/dist/components/explore.d.mts +24 -3
- package/dist/components/explore.d.ts +24 -3
- package/dist/components/explore.js +690 -236
- package/dist/components/explore.js.map +1 -1
- package/dist/components/explore.mjs +690 -238
- package/dist/components/explore.mjs.map +1 -1
- package/dist/components/newsletter.js +4 -1
- package/dist/components/newsletter.js.map +1 -1
- package/dist/components/newsletter.mjs +4 -1
- package/dist/components/newsletter.mjs.map +1 -1
- package/dist/components/partners.js +23 -13
- package/dist/components/partners.js.map +1 -1
- package/dist/components/partners.mjs +23 -13
- package/dist/components/partners.mjs.map +1 -1
- package/dist/components/pricing.js +4 -1
- package/dist/components/pricing.js.map +1 -1
- package/dist/components/pricing.mjs +4 -1
- package/dist/components/pricing.mjs.map +1 -1
- package/dist/components/unsubscribe.js +4 -1
- package/dist/components/unsubscribe.js.map +1 -1
- package/dist/components/unsubscribe.mjs +4 -1
- package/dist/components/unsubscribe.mjs.map +1 -1
- package/dist/components/waitlist.js +4 -1
- package/dist/components/waitlist.js.map +1 -1
- package/dist/components/waitlist.mjs +4 -1
- package/dist/components/waitlist.mjs.map +1 -1
- package/dist/content/index.js +23 -13
- package/dist/content/index.js.map +1 -1
- package/dist/content/index.mjs +23 -13
- package/dist/content/index.mjs.map +1 -1
- package/dist/{use-explore-chat-B8xKGid5.d.mts → explore-types-CLw19R76.d.mts} +1 -143
- package/dist/{use-explore-chat-B8xKGid5.d.ts → explore-types-CLw19R76.d.ts} +1 -143
- package/dist/hooks/index.d.mts +2 -1
- package/dist/hooks/index.d.ts +2 -1
- package/dist/hooks/index.js +4 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +4 -1
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.d.mts +141 -2
- package/dist/index.d.ts +141 -2
- package/dist/index.js +2025 -400
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2021 -403
- package/dist/index.mjs.map +1 -1
- package/dist/seo/index.js +4 -1
- package/dist/seo/index.js.map +1 -1
- package/dist/seo/index.mjs +4 -1
- package/dist/seo/index.mjs.map +1 -1
- package/dist/store/index.js +23 -13
- package/dist/store/index.js.map +1 -1
- package/dist/store/index.mjs +23 -13
- package/dist/store/index.mjs.map +1 -1
- package/dist/use-explore-chat-CvW-kyIm.d.mts +145 -0
- package/dist/use-explore-chat-DdGBimiz.d.ts +145 -0
- package/package.json +1 -1
|
@@ -84,6 +84,8 @@ var EN = {
|
|
|
84
84
|
askHuman: "ask a human",
|
|
85
85
|
prevSuggestion: "Previous suggestion",
|
|
86
86
|
nextSuggestion: "Next suggestion",
|
|
87
|
+
conceptIllustration: "Concept illustration",
|
|
88
|
+
opensInNewTab: "opens in a new tab",
|
|
87
89
|
capabilities: [
|
|
88
90
|
"Grounded in our own docs",
|
|
89
91
|
"Compare across the ecosystem",
|
|
@@ -133,6 +135,8 @@ var ZH = {
|
|
|
133
135
|
askHuman: "\u8054\u7CFB\u6211\u4EEC",
|
|
134
136
|
prevSuggestion: "\u4E0A\u4E00\u4E2A\u5EFA\u8BAE",
|
|
135
137
|
nextSuggestion: "\u4E0B\u4E00\u4E2A\u5EFA\u8BAE",
|
|
138
|
+
conceptIllustration: "\u6982\u5FF5\u793A\u610F\u56FE",
|
|
139
|
+
opensInNewTab: "\u5728\u65B0\u6807\u7B7E\u9875\u4E2D\u6253\u5F00",
|
|
136
140
|
capabilities: ["\u57FA\u4E8E\u6211\u4EEC\u81EA\u5DF1\u7684\u6587\u6863", "\u8DE8\u4EA7\u54C1\u5BF9\u6BD4", "\u76F4\u8FBE\u6B63\u786E\u7684\u9875\u9762"],
|
|
137
141
|
prompts: [
|
|
138
142
|
"\u8FD9\u4E2A\u4EA7\u54C1\u5230\u5E95\u80FD\u505A\u4EC0\u4E48\uFF1F",
|
|
@@ -178,6 +182,8 @@ var HI = {
|
|
|
178
182
|
askHuman: "\u0939\u092E\u0938\u0947 \u0938\u0902\u092A\u0930\u094D\u0915 \u0915\u0930\u0947\u0902",
|
|
179
183
|
prevSuggestion: "\u092A\u093F\u091B\u0932\u093E \u0938\u0941\u091D\u093E\u0935",
|
|
180
184
|
nextSuggestion: "\u0905\u0917\u0932\u093E \u0938\u0941\u091D\u093E\u0935",
|
|
185
|
+
conceptIllustration: "\u0905\u0935\u0927\u093E\u0930\u0923\u093E \u091A\u093F\u0924\u094D\u0930\u0923",
|
|
186
|
+
opensInNewTab: "\u0928\u090F \u091F\u0948\u092C \u092E\u0947\u0902 \u0916\u0941\u0932\u0924\u093E \u0939\u0948",
|
|
181
187
|
capabilities: [
|
|
182
188
|
"\u0939\u092E\u093E\u0930\u0947 \u0905\u092A\u0928\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924",
|
|
183
189
|
"\u0938\u092D\u0940 \u0909\u0924\u094D\u092A\u093E\u0926\u094B\u0902 \u0915\u0940 \u0924\u0941\u0932\u0928\u093E \u0915\u0930\u0947\u0902",
|
|
@@ -227,6 +233,8 @@ var ES = {
|
|
|
227
233
|
askHuman: "habla con una persona",
|
|
228
234
|
prevSuggestion: "Sugerencia anterior",
|
|
229
235
|
nextSuggestion: "Sugerencia siguiente",
|
|
236
|
+
conceptIllustration: "Ilustraci\xF3n del concepto",
|
|
237
|
+
opensInNewTab: "se abre en una pesta\xF1a nueva",
|
|
230
238
|
capabilities: [
|
|
231
239
|
"Basado en nuestra documentaci\xF3n",
|
|
232
240
|
"Compara todo el ecosistema",
|
|
@@ -276,6 +284,8 @@ var AR = {
|
|
|
276
284
|
askHuman: "\u062A\u062D\u062F\u0651\u062B \u0625\u0644\u0649 \u0634\u062E\u0635",
|
|
277
285
|
prevSuggestion: "\u0627\u0644\u0627\u0642\u062A\u0631\u0627\u062D \u0627\u0644\u0633\u0627\u0628\u0642",
|
|
278
286
|
nextSuggestion: "\u0627\u0644\u0627\u0642\u062A\u0631\u0627\u062D \u0627\u0644\u062A\u0627\u0644\u064A",
|
|
287
|
+
conceptIllustration: "\u0631\u0633\u0645 \u062A\u0648\u0636\u064A\u062D\u064A \u0644\u0644\u0645\u0641\u0647\u0648\u0645",
|
|
288
|
+
opensInNewTab: "\u064A\u064F\u0641\u062A\u062D \u0641\u064A \u0639\u0644\u0627\u0645\u0629 \u062A\u0628\u0648\u064A\u0628 \u062C\u062F\u064A\u062F\u0629",
|
|
279
289
|
capabilities: [
|
|
280
290
|
"\u0645\u0628\u0646\u064A \u0639\u0644\u0649 \u0648\u062B\u0627\u0626\u0642\u0646\u0627",
|
|
281
291
|
"\u0642\u0627\u0631\u0646 \u0639\u0628\u0631 \u0627\u0644\u0645\u0646\u0638\u0648\u0645\u0629",
|
|
@@ -325,6 +335,8 @@ var TA = {
|
|
|
325
335
|
askHuman: "\u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BC8\u0BA4\u0BCD \u0BA4\u0BCA\u0B9F\u0BB0\u0BCD\u0BAA\u0BC1 \u0B95\u0BCA\u0BB3\u0BCD\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
|
|
326
336
|
prevSuggestion: "\u0BAE\u0BC1\u0BA8\u0BCD\u0BA4\u0BC8\u0BAF \u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8",
|
|
327
337
|
nextSuggestion: "\u0B85\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4 \u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8",
|
|
338
|
+
conceptIllustration: "\u0B95\u0BB0\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1 \u0BB5\u0BBF\u0BB3\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BAE\u0BCD",
|
|
339
|
+
opensInNewTab: "\u0BAA\u0BC1\u0BA4\u0BBF\u0BAF \u0BA4\u0BBE\u0BB5\u0BB2\u0BBF\u0BB2\u0BCD \u0BA4\u0BBF\u0BB1\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD",
|
|
328
340
|
capabilities: [
|
|
329
341
|
"\u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B9A\u0BCA\u0BA8\u0BCD\u0BA4 \u0B86\u0BB5\u0BA3\u0B99\u0BCD\u0B95\u0BB3\u0BBF\u0BA9\u0BCD \u0B85\u0B9F\u0BBF\u0BAA\u0BCD\u0BAA\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD",
|
|
330
342
|
"\u0BA4\u0BAF\u0BBE\u0BB0\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BC8 \u0B92\u0BAA\u0BCD\u0BAA\u0BBF\u0B9F\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
|
|
@@ -365,19 +377,26 @@ function exploreStrings(locale) {
|
|
|
365
377
|
function fill(template, values) {
|
|
366
378
|
return template.replace(/\{(\w+)\}/g, (match, key) => values[key] ?? match);
|
|
367
379
|
}
|
|
380
|
+
function MarkdownLink({
|
|
381
|
+
href,
|
|
382
|
+
children,
|
|
383
|
+
// react-markdown passes the hast node to every override; it is not a DOM attribute.
|
|
384
|
+
node: _node,
|
|
385
|
+
...props
|
|
386
|
+
}) {
|
|
387
|
+
const isExternal = typeof href === "string" && (href.startsWith("http://") || href.startsWith("https://"));
|
|
388
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
389
|
+
"a",
|
|
390
|
+
{
|
|
391
|
+
href,
|
|
392
|
+
...props,
|
|
393
|
+
...isExternal ? { target: "_blank", rel: "noopener noreferrer" } : { rel: "noopener noreferrer" },
|
|
394
|
+
children
|
|
395
|
+
}
|
|
396
|
+
);
|
|
397
|
+
}
|
|
368
398
|
var defaultComponents = {
|
|
369
|
-
a:
|
|
370
|
-
const isExternal = typeof href === "string" && (href.startsWith("http://") || href.startsWith("https://"));
|
|
371
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
372
|
-
"a",
|
|
373
|
-
{
|
|
374
|
-
href,
|
|
375
|
-
...props,
|
|
376
|
-
...isExternal ? { target: "_blank", rel: "noopener noreferrer" } : { rel: "noopener noreferrer" },
|
|
377
|
-
children
|
|
378
|
-
}
|
|
379
|
-
);
|
|
380
|
-
}
|
|
399
|
+
a: MarkdownLink
|
|
381
400
|
};
|
|
382
401
|
function Markdown({
|
|
383
402
|
children,
|
|
@@ -938,10 +957,13 @@ var ECOSYSTEM_PRODUCTS = [
|
|
|
938
957
|
name: "VibeControls",
|
|
939
958
|
websiteUrl: "https://vibecontrols.com"
|
|
940
959
|
},
|
|
960
|
+
// FluidGrids ships on www.fluidgrids.ai — fluidgrids.com only redirects there. The explore
|
|
961
|
+
// catalog and the site's own sitemap use this origin, and so must the fallback catalog
|
|
962
|
+
// built from this list, or /explore rejects FluidGrids concept images until it loads.
|
|
941
963
|
{
|
|
942
964
|
slug: "fluidgrids",
|
|
943
965
|
name: "FluidGrids",
|
|
944
|
-
websiteUrl: "https://fluidgrids.
|
|
966
|
+
websiteUrl: "https://www.fluidgrids.ai"
|
|
945
967
|
},
|
|
946
968
|
// Botlit ships on botlit.ai — botlit.com does not resolve.
|
|
947
969
|
{ slug: "botlit", name: "Botlit", websiteUrl: "https://www.botlit.ai" },
|
|
@@ -2245,6 +2267,9 @@ function resolveImageUrl(image, base) {
|
|
|
2245
2267
|
return image;
|
|
2246
2268
|
}
|
|
2247
2269
|
}
|
|
2270
|
+
function serializeJsonLd(data) {
|
|
2271
|
+
return JSON.stringify(data).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
2272
|
+
}
|
|
2248
2273
|
function PageHead({
|
|
2249
2274
|
title,
|
|
2250
2275
|
description,
|
|
@@ -2286,7 +2311,7 @@ function PageHead({
|
|
|
2286
2311
|
fullImageUrl && /* @__PURE__ */ jsxRuntime.jsx("meta", { name: "twitter:image", content: fullImageUrl }),
|
|
2287
2312
|
twitterHandle && /* @__PURE__ */ jsxRuntime.jsx("meta", { name: "twitter:creator", content: twitterHandle }),
|
|
2288
2313
|
/* @__PURE__ */ jsxRuntime.jsx("meta", { name: "theme-color", content: themeColor }),
|
|
2289
|
-
structuredDataItems.map((data, index) => /* @__PURE__ */ jsxRuntime.jsx("script", { type: "application/ld+json", children:
|
|
2314
|
+
structuredDataItems.map((data, index) => /* @__PURE__ */ jsxRuntime.jsx("script", { type: "application/ld+json", children: serializeJsonLd(data) }, `ld-${index}`)),
|
|
2290
2315
|
additionalMeta?.map((meta, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2291
2316
|
"meta",
|
|
2292
2317
|
{
|
|
@@ -2493,6 +2518,7 @@ function toPayload(staged) {
|
|
|
2493
2518
|
textContent
|
|
2494
2519
|
}));
|
|
2495
2520
|
}
|
|
2521
|
+
var SHORT_VIEWPORT_PX = 420;
|
|
2496
2522
|
var EXPLORE_CSS = `
|
|
2497
2523
|
@keyframes boff-explore-pulse {
|
|
2498
2524
|
0%, 80%, 100% { opacity: 0.25; transform: translateY(0); }
|
|
@@ -2527,6 +2553,12 @@ var EXPLORE_CSS = `
|
|
|
2527
2553
|
.boff-explore-scroll {
|
|
2528
2554
|
scrollbar-width: thin;
|
|
2529
2555
|
scrollbar-color: hsl(var(--border)) transparent;
|
|
2556
|
+
/* Stop the transcript handing its scroll to the page. Without this, the first
|
|
2557
|
+
swipe that exhausts the transcript chains to the document \u2014 and on a host site
|
|
2558
|
+
that is 65-70% footer, which is how a phone ends up showing nothing but the
|
|
2559
|
+
footer. Engines that do not support this property ignore the line and keep
|
|
2560
|
+
today's behaviour; the scroll correction above covers them. */
|
|
2561
|
+
overscroll-behavior: contain;
|
|
2530
2562
|
}
|
|
2531
2563
|
.boff-explore-scroll::-webkit-scrollbar { width: 10px; }
|
|
2532
2564
|
.boff-explore-scroll::-webkit-scrollbar-track { background: transparent; }
|
|
@@ -2644,6 +2676,68 @@ var EXPLORE_CSS = `
|
|
|
2644
2676
|
.boff-explore-busy::after { animation: none; }
|
|
2645
2677
|
.boff-explore-rise { animation: none; opacity: 1; transform: none; }
|
|
2646
2678
|
}
|
|
2679
|
+
|
|
2680
|
+
/* ---- Pane height ----------------------------------------------------------------------
|
|
2681
|
+
This used to be one inline declaration, \`height: calc(100dvh - 64px)\`, and it carried two
|
|
2682
|
+
defects. An inline style cannot carry a fallback, so every engine without \`dvh\` (iOS
|
|
2683
|
+
Safari < 15.4, Chrome/WebView < 108, Samsung Internet < 21, Firefox < 101) dropped it
|
|
2684
|
+
whole; and the 64px came from a prop hard-coded to 64 on all 41 host pages that matches
|
|
2685
|
+
none of them \u2014 the burdenoff/algoshred chrome is 80px, the sticky-header sites are 65.
|
|
2686
|
+
|
|
2687
|
+
A class plus custom properties lets the cascade do the work: \`vh\` is the floor and \`dvh\`
|
|
2688
|
+
an upgrade where it exists, while the two measured values stay *lengths*, never a height.
|
|
2689
|
+
That distinction is the whole prerender contract. The host sites snapshot \`/explore\` by
|
|
2690
|
+
loading the built SPA in headless Chromium and writing the POST-HYDRATION DOM to
|
|
2691
|
+
dist/explore/index.html, so every attribute and inline value this component sets after
|
|
2692
|
+
mount IS the static HTML CloudFront serves. A measured pixel *height* would therefore
|
|
2693
|
+
hand every phone the prerender viewport's height until the bundle executes; a measured
|
|
2694
|
+
*offset* is a site-header height, which is the same on every device to within a few
|
|
2695
|
+
pixels, and the height built from it stays viewport-relative on the visitor's own screen.
|
|
2696
|
+
|
|
2697
|
+
--boff-explore-offset chrome above the pane (measured root top; the prop pre-measure)
|
|
2698
|
+
--boff-explore-inset the slice of the layout viewport hidden below the visible area \u2014
|
|
2699
|
+
the on-screen keyboard, which \`dvh\` does not track. Zero unless
|
|
2700
|
+
something is actually covering the bottom, so a snapshot taken
|
|
2701
|
+
with no keyboard open never carries it. */
|
|
2702
|
+
.boff-explore-viewport {
|
|
2703
|
+
height: calc(100vh - var(--boff-explore-offset, 0px) - var(--boff-explore-inset, 0px));
|
|
2704
|
+
}
|
|
2705
|
+
@supports (height: 100dvh) {
|
|
2706
|
+
.boff-explore-viewport {
|
|
2707
|
+
height: calc(100dvh - var(--boff-explore-offset, 0px) - var(--boff-explore-inset, 0px));
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2711
|
+
/* Landscape phones and other short viewports: a one-screen pane leaves a ~124px transcript
|
|
2712
|
+
sliver under ~610px of chrome and content. At or below the threshold the pane stops
|
|
2713
|
+
pretending to be a window and lets the page's own scrolling carry the transcript. The
|
|
2714
|
+
min-height is the available height rather than a fixed rem value, so the fallback can
|
|
2715
|
+
never be taller than the screen it is rescuing. */
|
|
2716
|
+
@media (max-height: ${SHORT_VIEWPORT_PX}px) {
|
|
2717
|
+
.boff-explore-viewport {
|
|
2718
|
+
height: auto;
|
|
2719
|
+
min-height: calc(100vh - var(--boff-explore-offset, 0px));
|
|
2720
|
+
}
|
|
2721
|
+
}
|
|
2722
|
+
@supports (height: 100dvh) {
|
|
2723
|
+
@media (max-height: ${SHORT_VIEWPORT_PX}px) {
|
|
2724
|
+
.boff-explore-viewport {
|
|
2725
|
+
min-height: calc(100dvh - var(--boff-explore-offset, 0px));
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
|
|
2730
|
+
/* ---- Composer dock --------------------------------------------------------------------
|
|
2731
|
+
Three declarations, each the fallback for the one after it: a plain 1rem where \`max()\`
|
|
2732
|
+
is unknown, then the measured overlap of any FOREIGN fixed chrome sitting over the
|
|
2733
|
+
composer (the host sites' cookie banner is 229px tall and lands exactly there), then the
|
|
2734
|
+
same plus the home-indicator inset. \`--boff-explore-chrome\` is set on the root only once
|
|
2735
|
+
an overlap has actually been measured, so everywhere else this collapses to 1rem. */
|
|
2736
|
+
.boff-explore-composer {
|
|
2737
|
+
padding-bottom: 1rem;
|
|
2738
|
+
padding-bottom: max(1rem, var(--boff-explore-chrome, 0px));
|
|
2739
|
+
padding-bottom: max(1rem, env(safe-area-inset-bottom), var(--boff-explore-chrome, 0px));
|
|
2740
|
+
}
|
|
2647
2741
|
`;
|
|
2648
2742
|
function ExploreStyles() {
|
|
2649
2743
|
return /* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: EXPLORE_CSS } });
|
|
@@ -2665,6 +2759,8 @@ var CAPABILITIES = [
|
|
|
2665
2759
|
body: "Get the sources and next steps \u2014 pricing, docs, a demo \u2014 without hunting."
|
|
2666
2760
|
}
|
|
2667
2761
|
];
|
|
2762
|
+
var MIN_VISIBLE_FRACTION = 0.25;
|
|
2763
|
+
var SDK_OVERLAY_SELECTOR = "[data-boff-explore]";
|
|
2668
2764
|
var CTA_VARIANTS = {
|
|
2669
2765
|
CONTACT: "default",
|
|
2670
2766
|
WAITLIST: "default",
|
|
@@ -2680,6 +2776,28 @@ function normalizeOffset(offset) {
|
|
|
2680
2776
|
if (offset === void 0) return "0px";
|
|
2681
2777
|
return typeof offset === "number" ? `${offset}px` : offset;
|
|
2682
2778
|
}
|
|
2779
|
+
function isOwnElement(el, root) {
|
|
2780
|
+
if (el === document.body || el === document.documentElement) return true;
|
|
2781
|
+
if (root.contains(el)) return true;
|
|
2782
|
+
return el.closest(SDK_OVERLAY_SELECTOR) !== null;
|
|
2783
|
+
}
|
|
2784
|
+
function visualViewportHeight() {
|
|
2785
|
+
return window.visualViewport?.height ?? window.innerHeight;
|
|
2786
|
+
}
|
|
2787
|
+
function clamp(value, min, max) {
|
|
2788
|
+
return Math.min(Math.max(value, min), max);
|
|
2789
|
+
}
|
|
2790
|
+
function isRestoredNavigation() {
|
|
2791
|
+
const entries = window.performance?.getEntriesByType?.("navigation");
|
|
2792
|
+
const entry = entries?.[0];
|
|
2793
|
+
if (!entry) return true;
|
|
2794
|
+
const navigation = entry;
|
|
2795
|
+
return navigation.type === "reload" || navigation.type === "back_forward";
|
|
2796
|
+
}
|
|
2797
|
+
function pageOwnsScrolling(el) {
|
|
2798
|
+
if (window.innerHeight > SHORT_VIEWPORT_PX) return false;
|
|
2799
|
+
return el.scrollHeight - el.clientHeight <= 1;
|
|
2800
|
+
}
|
|
2683
2801
|
function isInternalPath(url) {
|
|
2684
2802
|
return url.startsWith("/") && !url.startsWith("//");
|
|
2685
2803
|
}
|
|
@@ -2703,6 +2821,93 @@ function logoUrlOf(url) {
|
|
|
2703
2821
|
return null;
|
|
2704
2822
|
}
|
|
2705
2823
|
}
|
|
2824
|
+
function inlineImageOrigins(products) {
|
|
2825
|
+
const origins = /* @__PURE__ */ new Set();
|
|
2826
|
+
for (const product of products) {
|
|
2827
|
+
let url;
|
|
2828
|
+
try {
|
|
2829
|
+
url = new URL(product.website);
|
|
2830
|
+
} catch {
|
|
2831
|
+
continue;
|
|
2832
|
+
}
|
|
2833
|
+
if (url.protocol !== "https:") continue;
|
|
2834
|
+
const apex = url.hostname.replace(/^www\./, "");
|
|
2835
|
+
const port = url.port ? `:${url.port}` : "";
|
|
2836
|
+
origins.add(`https://${apex}${port}`);
|
|
2837
|
+
origins.add(`https://www.${apex}${port}`);
|
|
2838
|
+
}
|
|
2839
|
+
return origins;
|
|
2840
|
+
}
|
|
2841
|
+
function isInlineImageAllowed(src, origins) {
|
|
2842
|
+
if (typeof src !== "string" || src === "") return false;
|
|
2843
|
+
let url;
|
|
2844
|
+
try {
|
|
2845
|
+
url = new URL(src);
|
|
2846
|
+
} catch {
|
|
2847
|
+
return false;
|
|
2848
|
+
}
|
|
2849
|
+
if (url.protocol !== "https:" || url.username || url.password) return false;
|
|
2850
|
+
return origins.has(url.origin);
|
|
2851
|
+
}
|
|
2852
|
+
var InlineImageScopeContext = React.createContext(null);
|
|
2853
|
+
var InsideLinkContext = React.createContext(false);
|
|
2854
|
+
function AnswerLink(props) {
|
|
2855
|
+
return /* @__PURE__ */ jsxRuntime.jsx(InsideLinkContext.Provider, { value: true, children: /* @__PURE__ */ jsxRuntime.jsx(MarkdownLink, { ...props }) });
|
|
2856
|
+
}
|
|
2857
|
+
var INLINE_IMAGE_FRAME = "relative inline-block max-w-full overflow-hidden rounded-xl border border-border bg-muted align-top shadow-sm";
|
|
2858
|
+
function InlineConceptImage({ src, alt }) {
|
|
2859
|
+
const scope = React.useContext(InlineImageScopeContext);
|
|
2860
|
+
const insideLink = React.useContext(InsideLinkContext);
|
|
2861
|
+
if (!scope || !scope.enabled || !isInlineImageAllowed(src, scope.origins) || scope.failed.has(src)) {
|
|
2862
|
+
return null;
|
|
2863
|
+
}
|
|
2864
|
+
const { strings: T, onFailed } = scope;
|
|
2865
|
+
const picture = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2866
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2867
|
+
"img",
|
|
2868
|
+
{
|
|
2869
|
+
src,
|
|
2870
|
+
alt: alt ?? "",
|
|
2871
|
+
loading: "lazy",
|
|
2872
|
+
decoding: "async",
|
|
2873
|
+
onError: () => onFailed(src),
|
|
2874
|
+
className: "block h-auto max-h-80 w-auto max-w-full object-contain"
|
|
2875
|
+
}
|
|
2876
|
+
),
|
|
2877
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2878
|
+
"span",
|
|
2879
|
+
{
|
|
2880
|
+
"aria-hidden": "true",
|
|
2881
|
+
className: "pointer-events-none absolute left-2 top-2 rounded-full border border-border bg-background/90 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-foreground shadow-sm",
|
|
2882
|
+
children: T.conceptIllustration
|
|
2883
|
+
}
|
|
2884
|
+
)
|
|
2885
|
+
] });
|
|
2886
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { "data-boff-explore": "inline-image", className: "my-3 block", children: insideLink ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: INLINE_IMAGE_FRAME, children: picture }) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2887
|
+
"a",
|
|
2888
|
+
{
|
|
2889
|
+
href: src,
|
|
2890
|
+
target: "_blank",
|
|
2891
|
+
rel: "noopener noreferrer",
|
|
2892
|
+
className: cn(
|
|
2893
|
+
INLINE_IMAGE_FRAME,
|
|
2894
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
2895
|
+
),
|
|
2896
|
+
children: [
|
|
2897
|
+
picture,
|
|
2898
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "sr-only", children: [
|
|
2899
|
+
"(",
|
|
2900
|
+
T.opensInNewTab,
|
|
2901
|
+
")"
|
|
2902
|
+
] })
|
|
2903
|
+
]
|
|
2904
|
+
}
|
|
2905
|
+
) });
|
|
2906
|
+
}
|
|
2907
|
+
var ANSWER_MARKDOWN_COMPONENTS = {
|
|
2908
|
+
a: AnswerLink,
|
|
2909
|
+
img: InlineConceptImage
|
|
2910
|
+
};
|
|
2706
2911
|
function ReferenceCard({
|
|
2707
2912
|
reference,
|
|
2708
2913
|
onFollow
|
|
@@ -2885,6 +3090,7 @@ function AssistantBubble({
|
|
|
2885
3090
|
strings: T,
|
|
2886
3091
|
message,
|
|
2887
3092
|
activity,
|
|
3093
|
+
imageOrigins,
|
|
2888
3094
|
onNavigate,
|
|
2889
3095
|
anchorRef,
|
|
2890
3096
|
onFollow,
|
|
@@ -2893,6 +3099,25 @@ function AssistantBubble({
|
|
|
2893
3099
|
const streaming = message.status === "PENDING" || message.status === "RUNNING";
|
|
2894
3100
|
const body = message.content || message.partialContent || "";
|
|
2895
3101
|
const failed = message.status === "FAILED";
|
|
3102
|
+
const completed = message.status === "COMPLETED";
|
|
3103
|
+
const [failedImages, setFailedImages] = React.useState(
|
|
3104
|
+
() => /* @__PURE__ */ new Set()
|
|
3105
|
+
);
|
|
3106
|
+
const markImageFailed = React.useCallback((src) => {
|
|
3107
|
+
setFailedImages(
|
|
3108
|
+
(current) => current.has(src) ? current : new Set(current).add(src)
|
|
3109
|
+
);
|
|
3110
|
+
}, []);
|
|
3111
|
+
const imageScope = React.useMemo(
|
|
3112
|
+
() => ({
|
|
3113
|
+
strings: T,
|
|
3114
|
+
enabled: completed,
|
|
3115
|
+
origins: imageOrigins,
|
|
3116
|
+
failed: failedImages,
|
|
3117
|
+
onFailed: markImageFailed
|
|
3118
|
+
}),
|
|
3119
|
+
[T, completed, imageOrigins, failedImages, markImageFailed]
|
|
3120
|
+
);
|
|
2896
3121
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2897
3122
|
"div",
|
|
2898
3123
|
{
|
|
@@ -2939,7 +3164,7 @@ function AssistantBubble({
|
|
|
2939
3164
|
}
|
|
2940
3165
|
) : null,
|
|
2941
3166
|
body ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl rounded-tl-md border border-border bg-card px-4 py-3 shadow-sm", children: [
|
|
2942
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "boff-prose boff-prose-sm boff-explore-body min-w-0 text-card-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(Markdown, { children: body }) }),
|
|
3167
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "boff-prose boff-prose-sm boff-explore-body min-w-0 text-card-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(InlineImageScopeContext.Provider, { value: imageScope, children: /* @__PURE__ */ jsxRuntime.jsx(Markdown, { components: ANSWER_MARKDOWN_COMPONENTS, children: body }) }) }),
|
|
2943
3168
|
streaming ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "boff-explore-caret", "aria-hidden": "true" }) : null
|
|
2944
3169
|
] }) : null,
|
|
2945
3170
|
streaming ? /* @__PURE__ */ jsxRuntime.jsx(ThinkingIndicator, { activity }) : null,
|
|
@@ -3421,6 +3646,8 @@ function ExplorePage({
|
|
|
3421
3646
|
const pickQueueRef = React.useRef(Promise.resolve());
|
|
3422
3647
|
const [shareLabel, setShareLabel] = React.useState(T.share);
|
|
3423
3648
|
const [shareUrl, setShareUrl] = React.useState(null);
|
|
3649
|
+
const rootRef = React.useRef(null);
|
|
3650
|
+
const composerRef = React.useRef(null);
|
|
3424
3651
|
const scrollRef = React.useRef(null);
|
|
3425
3652
|
const latestAssistantRef = React.useRef(null);
|
|
3426
3653
|
const alignedForRef = React.useRef(null);
|
|
@@ -3438,17 +3665,206 @@ function ExplorePage({
|
|
|
3438
3665
|
() => catalog.products.find((p) => p.slug === focusProduct)?.name ?? null,
|
|
3439
3666
|
[catalog.products, focusProduct]
|
|
3440
3667
|
);
|
|
3668
|
+
const imageOrigins = React.useMemo(
|
|
3669
|
+
() => inlineImageOrigins(catalog.products),
|
|
3670
|
+
[catalog.products]
|
|
3671
|
+
);
|
|
3441
3672
|
React.useEffect(() => {
|
|
3442
3673
|
const el = textareaRef.current;
|
|
3443
3674
|
if (!el) return;
|
|
3444
3675
|
el.style.height = "auto";
|
|
3445
3676
|
el.style.height = `${Math.min(el.scrollHeight, 200)}px`;
|
|
3446
3677
|
}, [draft]);
|
|
3678
|
+
const [paneOffset, setPaneOffset] = React.useState(null);
|
|
3679
|
+
const [bottomInset, setBottomInset] = React.useState(0);
|
|
3680
|
+
const paneOffsetRef = React.useRef(0);
|
|
3681
|
+
const measurePane = React.useCallback(() => {
|
|
3682
|
+
if (heightMode !== "viewport") return;
|
|
3683
|
+
const el = rootRef.current;
|
|
3684
|
+
if (!el) return;
|
|
3685
|
+
const layoutHeight = window.innerHeight;
|
|
3686
|
+
if (layoutHeight === 0) return;
|
|
3687
|
+
const top = Math.round(
|
|
3688
|
+
clamp(el.getBoundingClientRect().top, 0, layoutHeight)
|
|
3689
|
+
);
|
|
3690
|
+
const viewport = window.visualViewport;
|
|
3691
|
+
const inset = viewport ? Math.round(
|
|
3692
|
+
clamp(
|
|
3693
|
+
layoutHeight - viewport.height - viewport.offsetTop,
|
|
3694
|
+
0,
|
|
3695
|
+
layoutHeight
|
|
3696
|
+
)
|
|
3697
|
+
) : 0;
|
|
3698
|
+
paneOffsetRef.current = top;
|
|
3699
|
+
setPaneOffset((current) => current === top ? current : top);
|
|
3700
|
+
setBottomInset((current) => current === inset ? current : inset);
|
|
3701
|
+
}, [heightMode]);
|
|
3702
|
+
const [chromeOverlap, setChromeOverlap] = React.useState(0);
|
|
3703
|
+
const measureChrome = React.useCallback(() => {
|
|
3704
|
+
const root = rootRef.current;
|
|
3705
|
+
const dock = composerRef.current;
|
|
3706
|
+
if (!root || !dock) return;
|
|
3707
|
+
if (typeof document.elementFromPoint !== "function") return;
|
|
3708
|
+
const viewportHeight = visualViewportHeight();
|
|
3709
|
+
const rect = dock.getBoundingClientRect();
|
|
3710
|
+
if (rect.width === 0 || viewportHeight === 0) return;
|
|
3711
|
+
if (rect.bottom <= 0 || rect.top >= viewportHeight) return;
|
|
3712
|
+
const edge = Math.min(rect.bottom, viewportHeight);
|
|
3713
|
+
const hit = document.elementFromPoint(rect.left + rect.width / 2, edge - 1);
|
|
3714
|
+
if (!hit || isOwnElement(hit, root)) {
|
|
3715
|
+
setChromeOverlap(0);
|
|
3716
|
+
return;
|
|
3717
|
+
}
|
|
3718
|
+
const overlap = Math.round(edge - hit.getBoundingClientRect().top);
|
|
3719
|
+
setChromeOverlap(overlap > 0 && overlap < viewportHeight ? overlap : 0);
|
|
3720
|
+
}, []);
|
|
3721
|
+
const remeasure = React.useCallback(() => {
|
|
3722
|
+
measurePane();
|
|
3723
|
+
measureChrome();
|
|
3724
|
+
}, [measurePane, measureChrome]);
|
|
3725
|
+
React.useEffect(() => {
|
|
3726
|
+
if (typeof window === "undefined") return;
|
|
3727
|
+
let frame = 0;
|
|
3728
|
+
const run = () => {
|
|
3729
|
+
frame = 0;
|
|
3730
|
+
remeasure();
|
|
3731
|
+
};
|
|
3732
|
+
const schedule = () => {
|
|
3733
|
+
if (frame) return;
|
|
3734
|
+
if (typeof window.requestAnimationFrame !== "function") {
|
|
3735
|
+
remeasure();
|
|
3736
|
+
return;
|
|
3737
|
+
}
|
|
3738
|
+
frame = window.requestAnimationFrame(run);
|
|
3739
|
+
};
|
|
3740
|
+
remeasure();
|
|
3741
|
+
const viewport = window.visualViewport;
|
|
3742
|
+
window.addEventListener("resize", schedule);
|
|
3743
|
+
window.addEventListener("orientationchange", schedule);
|
|
3744
|
+
viewport?.addEventListener("resize", schedule);
|
|
3745
|
+
viewport?.addEventListener("scroll", schedule);
|
|
3746
|
+
const observer = typeof MutationObserver === "function" ? new MutationObserver((records) => {
|
|
3747
|
+
const el = rootRef.current;
|
|
3748
|
+
if (el && records.every((record) => el.contains(record.target)))
|
|
3749
|
+
return;
|
|
3750
|
+
schedule();
|
|
3751
|
+
}) : null;
|
|
3752
|
+
observer?.observe(document.body, { childList: true, subtree: true });
|
|
3753
|
+
return () => {
|
|
3754
|
+
if (frame) window.cancelAnimationFrame(frame);
|
|
3755
|
+
window.removeEventListener("resize", schedule);
|
|
3756
|
+
window.removeEventListener("orientationchange", schedule);
|
|
3757
|
+
viewport?.removeEventListener("resize", schedule);
|
|
3758
|
+
viewport?.removeEventListener("scroll", schedule);
|
|
3759
|
+
observer?.disconnect();
|
|
3760
|
+
setPaneOffset(null);
|
|
3761
|
+
setBottomInset(0);
|
|
3762
|
+
setChromeOverlap(0);
|
|
3763
|
+
};
|
|
3764
|
+
}, [remeasure]);
|
|
3765
|
+
React.useEffect(() => {
|
|
3766
|
+
measureChrome();
|
|
3767
|
+
}, [measureChrome, paneOffset, bottomInset]);
|
|
3768
|
+
React.useEffect(() => {
|
|
3769
|
+
if (heightMode !== "viewport" || typeof window === "undefined") return;
|
|
3770
|
+
const { history: browserHistory } = window;
|
|
3771
|
+
const previousRestoration = "scrollRestoration" in browserHistory ? browserHistory.scrollRestoration : null;
|
|
3772
|
+
if (previousRestoration !== null)
|
|
3773
|
+
browserHistory.scrollRestoration = "manual";
|
|
3774
|
+
let frame = 0;
|
|
3775
|
+
let visitorMoved = false;
|
|
3776
|
+
const onVisitorMove = () => {
|
|
3777
|
+
visitorMoved = true;
|
|
3778
|
+
};
|
|
3779
|
+
const align = () => {
|
|
3780
|
+
if (visitorMoved) return;
|
|
3781
|
+
const el = rootRef.current;
|
|
3782
|
+
if (!el) return;
|
|
3783
|
+
const viewportHeight = visualViewportHeight();
|
|
3784
|
+
const rect = el.getBoundingClientRect();
|
|
3785
|
+
if (rect.height === 0 || viewportHeight === 0) return;
|
|
3786
|
+
const visible = Math.min(rect.bottom, viewportHeight) - Math.max(rect.top, 0);
|
|
3787
|
+
const reachable = Math.min(rect.height, viewportHeight);
|
|
3788
|
+
if (visible >= reachable * MIN_VISIBLE_FRACTION) return;
|
|
3789
|
+
window.scrollTo({
|
|
3790
|
+
top: Math.max(0, window.scrollY + rect.top),
|
|
3791
|
+
left: window.scrollX,
|
|
3792
|
+
behavior: "auto"
|
|
3793
|
+
});
|
|
3794
|
+
if (typeof document.elementFromPoint === "function") {
|
|
3795
|
+
const probe = document.elementFromPoint(
|
|
3796
|
+
Math.max(0, rect.left + rect.width / 2),
|
|
3797
|
+
1
|
|
3798
|
+
);
|
|
3799
|
+
if (probe && !isOwnElement(probe, el)) {
|
|
3800
|
+
const chrome = probe.getBoundingClientRect().bottom;
|
|
3801
|
+
if (chrome > 0 && chrome < viewportHeight / 2) {
|
|
3802
|
+
window.scrollBy({ top: -chrome, left: 0, behavior: "auto" });
|
|
3803
|
+
}
|
|
3804
|
+
}
|
|
3805
|
+
}
|
|
3806
|
+
remeasure();
|
|
3807
|
+
};
|
|
3808
|
+
const alignIfRestored = () => {
|
|
3809
|
+
if (!isRestoredNavigation()) return;
|
|
3810
|
+
align();
|
|
3811
|
+
};
|
|
3812
|
+
alignIfRestored();
|
|
3813
|
+
if (typeof window.requestAnimationFrame === "function") {
|
|
3814
|
+
frame = window.requestAnimationFrame(alignIfRestored);
|
|
3815
|
+
}
|
|
3816
|
+
const onPageShow = (event) => {
|
|
3817
|
+
if (!event.persisted) {
|
|
3818
|
+
alignIfRestored();
|
|
3819
|
+
return;
|
|
3820
|
+
}
|
|
3821
|
+
visitorMoved = false;
|
|
3822
|
+
align();
|
|
3823
|
+
};
|
|
3824
|
+
window.addEventListener("pageshow", onPageShow);
|
|
3825
|
+
window.addEventListener("wheel", onVisitorMove, { passive: true });
|
|
3826
|
+
window.addEventListener("touchmove", onVisitorMove, { passive: true });
|
|
3827
|
+
window.addEventListener("keydown", onVisitorMove, { passive: true });
|
|
3828
|
+
return () => {
|
|
3829
|
+
if (frame) window.cancelAnimationFrame(frame);
|
|
3830
|
+
window.removeEventListener("pageshow", onPageShow);
|
|
3831
|
+
window.removeEventListener("wheel", onVisitorMove);
|
|
3832
|
+
window.removeEventListener("touchmove", onVisitorMove);
|
|
3833
|
+
window.removeEventListener("keydown", onVisitorMove);
|
|
3834
|
+
if (previousRestoration !== null)
|
|
3835
|
+
browserHistory.scrollRestoration = previousRestoration;
|
|
3836
|
+
};
|
|
3837
|
+
}, [heightMode, remeasure]);
|
|
3447
3838
|
const handleScroll = React.useCallback(() => {
|
|
3448
3839
|
const el = scrollRef.current;
|
|
3449
3840
|
if (!el) return;
|
|
3450
3841
|
stickToBottomRef.current = el.scrollHeight - el.scrollTop - el.clientHeight < 80;
|
|
3451
3842
|
}, []);
|
|
3843
|
+
React.useEffect(() => {
|
|
3844
|
+
if (typeof window === "undefined") return;
|
|
3845
|
+
let frame = 0;
|
|
3846
|
+
const run = () => {
|
|
3847
|
+
frame = 0;
|
|
3848
|
+
const el = scrollRef.current;
|
|
3849
|
+
const dock = composerRef.current;
|
|
3850
|
+
if (!el || !dock) return;
|
|
3851
|
+
if (!pageOwnsScrolling(el)) return;
|
|
3852
|
+
stickToBottomRef.current = dock.getBoundingClientRect().bottom - visualViewportHeight() < 80;
|
|
3853
|
+
};
|
|
3854
|
+
const schedule = () => {
|
|
3855
|
+
if (frame) return;
|
|
3856
|
+
if (typeof window.requestAnimationFrame !== "function") {
|
|
3857
|
+
run();
|
|
3858
|
+
return;
|
|
3859
|
+
}
|
|
3860
|
+
frame = window.requestAnimationFrame(run);
|
|
3861
|
+
};
|
|
3862
|
+
window.addEventListener("scroll", schedule, { passive: true });
|
|
3863
|
+
return () => {
|
|
3864
|
+
if (frame) window.cancelAnimationFrame(frame);
|
|
3865
|
+
window.removeEventListener("scroll", schedule);
|
|
3866
|
+
};
|
|
3867
|
+
}, []);
|
|
3452
3868
|
const latestAssistantId = React.useMemo(() => {
|
|
3453
3869
|
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
3454
3870
|
const message = messages[i];
|
|
@@ -3464,16 +3880,32 @@ function ExplorePage({
|
|
|
3464
3880
|
if (!stickToBottomRef.current) return;
|
|
3465
3881
|
if (anchor.offsetHeight === 0) return;
|
|
3466
3882
|
alignedForRef.current = latestAssistantId;
|
|
3467
|
-
|
|
3468
|
-
|
|
3883
|
+
if (!pageOwnsScrolling(el)) {
|
|
3884
|
+
const delta2 = anchor.getBoundingClientRect().top - el.getBoundingClientRect().top;
|
|
3885
|
+
el.scrollTop = Math.max(0, el.scrollTop + delta2 - 12);
|
|
3886
|
+
return;
|
|
3887
|
+
}
|
|
3888
|
+
const delta = Math.round(
|
|
3889
|
+
anchor.getBoundingClientRect().top - paneOffsetRef.current - 12
|
|
3890
|
+
);
|
|
3891
|
+
if (delta !== 0) window.scrollBy({ top: delta, left: 0, behavior: "auto" });
|
|
3469
3892
|
}, [latestAssistantId, messages]);
|
|
3470
3893
|
React.useEffect(() => {
|
|
3894
|
+
if (messages.length === 0) return;
|
|
3471
3895
|
if (!stickToBottomRef.current) return;
|
|
3472
3896
|
if (latestAssistantId && alignedForRef.current === latestAssistantId)
|
|
3473
3897
|
return;
|
|
3474
3898
|
const el = scrollRef.current;
|
|
3475
3899
|
if (!el) return;
|
|
3476
|
-
el
|
|
3900
|
+
if (!pageOwnsScrolling(el)) {
|
|
3901
|
+
el.scrollTop = el.scrollHeight;
|
|
3902
|
+
return;
|
|
3903
|
+
}
|
|
3904
|
+
const dock = composerRef.current ?? el;
|
|
3905
|
+
const delta = Math.round(
|
|
3906
|
+
dock.getBoundingClientRect().bottom - visualViewportHeight()
|
|
3907
|
+
);
|
|
3908
|
+
if (delta > 0) window.scrollBy({ top: delta, left: 0, behavior: "auto" });
|
|
3477
3909
|
}, [activity, latestAssistantId, messages]);
|
|
3478
3910
|
const handleShare = React.useCallback(async () => {
|
|
3479
3911
|
setShareLabel(T.copying);
|
|
@@ -3571,16 +4003,27 @@ function ExplorePage({
|
|
|
3571
4003
|
const captchaOn = Boolean(
|
|
3572
4004
|
catalog.captchaRequired && catalog.recaptchaSiteKey
|
|
3573
4005
|
);
|
|
3574
|
-
const rootStyle =
|
|
4006
|
+
const rootStyle = {};
|
|
4007
|
+
if (heightMode === "viewport") {
|
|
4008
|
+
rootStyle["--boff-explore-offset"] = paneOffset === null ? normalizeOffset(viewportOffset) : `${paneOffset}px`;
|
|
4009
|
+
if (bottomInset > 0) {
|
|
4010
|
+
rootStyle["--boff-explore-inset"] = `${bottomInset}px`;
|
|
4011
|
+
}
|
|
4012
|
+
}
|
|
4013
|
+
if (chromeOverlap > 0) {
|
|
4014
|
+
rootStyle["--boff-explore-chrome"] = `${chromeOverlap}px`;
|
|
4015
|
+
}
|
|
3575
4016
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3576
4017
|
"div",
|
|
3577
4018
|
{
|
|
4019
|
+
ref: rootRef,
|
|
3578
4020
|
"data-boff-explore": "page",
|
|
3579
4021
|
"data-phase": phase,
|
|
3580
4022
|
"data-locale": activeLocale,
|
|
3581
4023
|
dir: rtl ? "rtl" : void 0,
|
|
3582
4024
|
className: cn(
|
|
3583
4025
|
"flex w-full min-w-0 flex-col overflow-x-hidden bg-background text-foreground",
|
|
4026
|
+
heightMode === "viewport" && "boff-explore-viewport",
|
|
3584
4027
|
heightMode === "auto" && "min-h-[70vh]",
|
|
3585
4028
|
className
|
|
3586
4029
|
),
|
|
@@ -3768,6 +4211,7 @@ function ExplorePage({
|
|
|
3768
4211
|
strings: T,
|
|
3769
4212
|
message,
|
|
3770
4213
|
activity,
|
|
4214
|
+
imageOrigins,
|
|
3771
4215
|
onNavigate,
|
|
3772
4216
|
anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0,
|
|
3773
4217
|
onFollow: (kind, url) => recordClick(message.id, kind, url),
|
|
@@ -3813,255 +4257,265 @@ function ExplorePage({
|
|
|
3813
4257
|
]
|
|
3814
4258
|
}
|
|
3815
4259
|
) : null,
|
|
3816
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3817
|
-
"
|
|
4260
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4261
|
+
"div",
|
|
3818
4262
|
{
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
"
|
|
4263
|
+
ref: composerRef,
|
|
4264
|
+
"data-boff-explore": "composer-dock",
|
|
4265
|
+
className: "boff-explore-composer border-t border-border bg-background/85 px-4 pt-3 backdrop-blur-md",
|
|
4266
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4267
|
+
"form",
|
|
4268
|
+
{
|
|
4269
|
+
"data-boff-explore": "composer",
|
|
4270
|
+
className: "mx-auto w-full max-w-3xl",
|
|
4271
|
+
onSubmit: (event) => {
|
|
4272
|
+
event.preventDefault();
|
|
4273
|
+
submitDraft();
|
|
4274
|
+
},
|
|
4275
|
+
children: [
|
|
4276
|
+
error ? /* @__PURE__ */ jsxRuntime.jsx(ErrorBanner, { error, onRetry: retry, onReset: reset }) : null,
|
|
4277
|
+
staged.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4278
|
+
"ul",
|
|
3835
4279
|
{
|
|
3836
|
-
"data-boff-explore": "
|
|
3837
|
-
"
|
|
3838
|
-
|
|
4280
|
+
"data-boff-explore": "attachments",
|
|
4281
|
+
className: "mb-2 flex flex-wrap gap-1.5",
|
|
4282
|
+
"aria-label": T.attach,
|
|
4283
|
+
children: staged.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4284
|
+
"li",
|
|
4285
|
+
{
|
|
4286
|
+
"data-boff-explore": "attachment",
|
|
4287
|
+
"data-text-extracted": entry.textExtracted ? "true" : "false",
|
|
4288
|
+
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",
|
|
4289
|
+
children: [
|
|
4290
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { className: "h-3 w-3 shrink-0 text-muted-foreground" }),
|
|
4291
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", title: entry.name, children: entry.name }),
|
|
4292
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "shrink-0 text-muted-foreground", children: [
|
|
4293
|
+
formatBytes(entry.size),
|
|
4294
|
+
entry.textExtracted ? "" : ` \xB7 ${T.attachmentNameOnly}`
|
|
4295
|
+
] }),
|
|
4296
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4297
|
+
"button",
|
|
4298
|
+
{
|
|
4299
|
+
type: "button",
|
|
4300
|
+
"data-boff-explore": "attachment-remove",
|
|
4301
|
+
onClick: () => removeAttachment(entry.id),
|
|
4302
|
+
"aria-label": fill(T.removeAttachment, { name: entry.name }),
|
|
4303
|
+
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",
|
|
4304
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3" })
|
|
4305
|
+
}
|
|
4306
|
+
)
|
|
4307
|
+
]
|
|
4308
|
+
},
|
|
4309
|
+
entry.id
|
|
4310
|
+
))
|
|
4311
|
+
}
|
|
4312
|
+
) : null,
|
|
4313
|
+
attachmentNotice !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4314
|
+
"p",
|
|
4315
|
+
{
|
|
4316
|
+
"data-boff-explore": "attachment-notice",
|
|
4317
|
+
role: "status",
|
|
4318
|
+
className: "mb-2 text-xs text-destructive",
|
|
4319
|
+
children: attachmentNotice
|
|
4320
|
+
}
|
|
4321
|
+
) : null,
|
|
4322
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4323
|
+
"div",
|
|
4324
|
+
{
|
|
4325
|
+
className: cn(
|
|
4326
|
+
"flex min-w-0 items-end gap-2 rounded-2xl border bg-card p-2 shadow-sm transition-all",
|
|
4327
|
+
busy && "boff-explore-busy",
|
|
4328
|
+
overLimit ? "border-destructive/60" : "border-border focus-within:border-primary/40 focus-within:ring-1 focus-within:ring-ring"
|
|
4329
|
+
),
|
|
3839
4330
|
children: [
|
|
3840
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { className: "h-3 w-3 shrink-0 text-muted-foreground" }),
|
|
3841
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", title: entry.name, children: entry.name }),
|
|
3842
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "shrink-0 text-muted-foreground", children: [
|
|
3843
|
-
formatBytes(entry.size),
|
|
3844
|
-
entry.textExtracted ? "" : ` \xB7 ${T.attachmentNameOnly}`
|
|
3845
|
-
] }),
|
|
3846
4331
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3847
|
-
|
|
4332
|
+
Textarea,
|
|
4333
|
+
{
|
|
4334
|
+
ref: textareaRef,
|
|
4335
|
+
value: draft,
|
|
4336
|
+
rows: 1,
|
|
4337
|
+
disabled: composerDisabled,
|
|
4338
|
+
onChange: (event) => setDraft(event.target.value),
|
|
4339
|
+
onKeyDown: handleKeyDown,
|
|
4340
|
+
onCompositionStart: () => {
|
|
4341
|
+
composingRef.current = true;
|
|
4342
|
+
},
|
|
4343
|
+
onCompositionEnd: () => {
|
|
4344
|
+
composingRef.current = false;
|
|
4345
|
+
},
|
|
4346
|
+
"aria-label": "Ask a question",
|
|
4347
|
+
placeholder: composerDisabled ? phase === "limited" ? "Message limit reached \u2014 please try again later" : "Explore is unavailable right now" : focusedProductName ? fill(T.placeholderProduct, {
|
|
4348
|
+
product: focusedProductName
|
|
4349
|
+
}) : T.placeholder,
|
|
4350
|
+
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"
|
|
4351
|
+
}
|
|
4352
|
+
),
|
|
4353
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4354
|
+
"input",
|
|
4355
|
+
{
|
|
4356
|
+
ref: fileInputRef,
|
|
4357
|
+
type: "file",
|
|
4358
|
+
multiple: true,
|
|
4359
|
+
className: "hidden",
|
|
4360
|
+
onChange: (event) => {
|
|
4361
|
+
void handleFilesPicked(event.target.files);
|
|
4362
|
+
event.target.value = "";
|
|
4363
|
+
}
|
|
4364
|
+
}
|
|
4365
|
+
),
|
|
4366
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4367
|
+
Button,
|
|
4368
|
+
{
|
|
4369
|
+
"data-boff-explore": "attach",
|
|
4370
|
+
type: "button",
|
|
4371
|
+
size: "icon",
|
|
4372
|
+
variant: "ghost",
|
|
4373
|
+
disabled: composerDisabled || staged.length >= MAX_ATTACHMENTS,
|
|
4374
|
+
"aria-label": T.attach,
|
|
4375
|
+
title: `${T.attach} \u2014 ${fill(T.attachHint, {
|
|
4376
|
+
max: String(MAX_ATTACHMENTS),
|
|
4377
|
+
size: String(MAX_ATTACHMENT_BYTES / (1024 * 1024))
|
|
4378
|
+
})}`,
|
|
4379
|
+
onClick: () => fileInputRef.current?.click(),
|
|
4380
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { className: "h-4 w-4" })
|
|
4381
|
+
}
|
|
4382
|
+
),
|
|
4383
|
+
speech.supported ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4384
|
+
Button,
|
|
3848
4385
|
{
|
|
4386
|
+
"data-boff-explore": "mic",
|
|
4387
|
+
"data-listening": speech.listening ? "true" : "false",
|
|
3849
4388
|
type: "button",
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
4389
|
+
size: "icon",
|
|
4390
|
+
variant: speech.listening ? "default" : "ghost",
|
|
4391
|
+
disabled: composerDisabled,
|
|
4392
|
+
"aria-label": speech.listening ? T.stopDictating : T.dictate,
|
|
4393
|
+
"aria-pressed": speech.listening,
|
|
4394
|
+
title: speech.listening ? T.stopDictating : T.dictate,
|
|
4395
|
+
onClick: speech.toggle,
|
|
4396
|
+
className: cn(speech.listening && "animate-pulse"),
|
|
4397
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, { className: "h-4 w-4" })
|
|
4398
|
+
}
|
|
4399
|
+
) : null,
|
|
4400
|
+
busy ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4401
|
+
Button,
|
|
4402
|
+
{
|
|
4403
|
+
"data-boff-explore": "stop",
|
|
4404
|
+
type: "button",
|
|
4405
|
+
size: "icon",
|
|
4406
|
+
variant: "secondary",
|
|
4407
|
+
"aria-label": T.stop,
|
|
4408
|
+
onClick: stop,
|
|
4409
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Square, { className: "h-4 w-4" })
|
|
4410
|
+
}
|
|
4411
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
4412
|
+
Button,
|
|
4413
|
+
{
|
|
4414
|
+
"data-boff-explore": "send",
|
|
4415
|
+
type: "submit",
|
|
4416
|
+
size: "icon",
|
|
4417
|
+
disabled: !canSubmit,
|
|
4418
|
+
"aria-label": T.send,
|
|
4419
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-4 w-4" })
|
|
3855
4420
|
}
|
|
3856
4421
|
)
|
|
3857
4422
|
]
|
|
3858
|
-
}
|
|
3859
|
-
entry.id
|
|
3860
|
-
))
|
|
3861
|
-
}
|
|
3862
|
-
) : null,
|
|
3863
|
-
attachmentNotice !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3864
|
-
"p",
|
|
3865
|
-
{
|
|
3866
|
-
"data-boff-explore": "attachment-notice",
|
|
3867
|
-
role: "status",
|
|
3868
|
-
className: "mb-2 text-xs text-destructive",
|
|
3869
|
-
children: attachmentNotice
|
|
3870
|
-
}
|
|
3871
|
-
) : null,
|
|
3872
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3873
|
-
"div",
|
|
3874
|
-
{
|
|
3875
|
-
className: cn(
|
|
3876
|
-
"flex min-w-0 items-end gap-2 rounded-2xl border bg-card p-2 shadow-sm transition-all",
|
|
3877
|
-
busy && "boff-explore-busy",
|
|
3878
|
-
overLimit ? "border-destructive/60" : "border-border focus-within:border-primary/40 focus-within:ring-1 focus-within:ring-ring"
|
|
4423
|
+
}
|
|
3879
4424
|
),
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
4425
|
+
speech.listening || speech.interim !== "" ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4426
|
+
"p",
|
|
4427
|
+
{
|
|
4428
|
+
"data-boff-explore": "dictation",
|
|
4429
|
+
className: "mt-2 flex items-center gap-2 text-xs text-muted-foreground",
|
|
4430
|
+
"aria-live": "polite",
|
|
4431
|
+
children: [
|
|
4432
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-2 w-2 shrink-0", children: [
|
|
4433
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-primary opacity-75" }),
|
|
4434
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex h-2 w-2 rounded-full bg-primary" })
|
|
4435
|
+
] }),
|
|
4436
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "italic", children: speech.interim !== "" ? speech.interim : "Listening\u2026" })
|
|
4437
|
+
]
|
|
4438
|
+
}
|
|
4439
|
+
) : null,
|
|
4440
|
+
speech.error !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4441
|
+
"p",
|
|
4442
|
+
{
|
|
4443
|
+
"data-boff-explore": "dictation-error",
|
|
4444
|
+
className: "mt-2 text-xs text-destructive",
|
|
4445
|
+
children: speech.error
|
|
4446
|
+
}
|
|
4447
|
+
) : null,
|
|
4448
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
|
|
4449
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: "Enter to send \xB7 Shift + Enter for a new line" }),
|
|
4450
|
+
remainingToday !== null ? /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-boff-explore": "remaining", children: [
|
|
4451
|
+
remainingToday,
|
|
4452
|
+
" message",
|
|
4453
|
+
remainingToday === 1 ? "" : "s",
|
|
4454
|
+
" left today"
|
|
4455
|
+
] }) : null,
|
|
4456
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4457
|
+
"span",
|
|
3883
4458
|
{
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
onCompositionEnd: () => {
|
|
3894
|
-
composingRef.current = false;
|
|
3895
|
-
},
|
|
3896
|
-
"aria-label": "Ask a question",
|
|
3897
|
-
placeholder: composerDisabled ? phase === "limited" ? "Message limit reached \u2014 please try again later" : "Explore is unavailable right now" : focusedProductName ? fill(T.placeholderProduct, {
|
|
3898
|
-
product: focusedProductName
|
|
3899
|
-
}) : T.placeholder,
|
|
3900
|
-
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"
|
|
4459
|
+
className: cn(
|
|
4460
|
+
"ml-auto tabular-nums",
|
|
4461
|
+
overLimit && "font-medium text-destructive"
|
|
4462
|
+
),
|
|
4463
|
+
children: [
|
|
4464
|
+
draft.length.toLocaleString(),
|
|
4465
|
+
" / ",
|
|
4466
|
+
maxLength.toLocaleString()
|
|
4467
|
+
]
|
|
3901
4468
|
}
|
|
3902
|
-
)
|
|
4469
|
+
)
|
|
4470
|
+
] }),
|
|
4471
|
+
shareUrl ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center gap-2", children: [
|
|
3903
4472
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3904
4473
|
"input",
|
|
3905
4474
|
{
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
event.target.value = "";
|
|
3913
|
-
}
|
|
4475
|
+
"data-boff-explore": "share-url",
|
|
4476
|
+
readOnly: true,
|
|
4477
|
+
value: shareUrl,
|
|
4478
|
+
"aria-label": "Read-only link to this conversation",
|
|
4479
|
+
onFocus: (event) => event.currentTarget.select(),
|
|
4480
|
+
className: "min-w-0 flex-1 rounded-md border border-border bg-muted px-2 py-1 text-xs text-muted-foreground"
|
|
3914
4481
|
}
|
|
3915
4482
|
),
|
|
3916
4483
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3917
|
-
|
|
3918
|
-
{
|
|
3919
|
-
"data-boff-explore": "attach",
|
|
3920
|
-
type: "button",
|
|
3921
|
-
size: "icon",
|
|
3922
|
-
variant: "ghost",
|
|
3923
|
-
disabled: composerDisabled || staged.length >= MAX_ATTACHMENTS,
|
|
3924
|
-
"aria-label": T.attach,
|
|
3925
|
-
title: `${T.attach} \u2014 ${fill(T.attachHint, {
|
|
3926
|
-
max: String(MAX_ATTACHMENTS),
|
|
3927
|
-
size: String(MAX_ATTACHMENT_BYTES / (1024 * 1024))
|
|
3928
|
-
})}`,
|
|
3929
|
-
onClick: () => fileInputRef.current?.click(),
|
|
3930
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { className: "h-4 w-4" })
|
|
3931
|
-
}
|
|
3932
|
-
),
|
|
3933
|
-
speech.supported ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3934
|
-
Button,
|
|
4484
|
+
"button",
|
|
3935
4485
|
{
|
|
3936
|
-
"data-boff-explore": "mic",
|
|
3937
|
-
"data-listening": speech.listening ? "true" : "false",
|
|
3938
4486
|
type: "button",
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
"aria-label": speech.listening ? T.stopDictating : T.dictate,
|
|
3943
|
-
"aria-pressed": speech.listening,
|
|
3944
|
-
title: speech.listening ? T.stopDictating : T.dictate,
|
|
3945
|
-
onClick: speech.toggle,
|
|
3946
|
-
className: cn(speech.listening && "animate-pulse"),
|
|
3947
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, { className: "h-4 w-4" })
|
|
4487
|
+
className: "shrink-0 text-xs underline underline-offset-2",
|
|
4488
|
+
onClick: () => setShareUrl(null),
|
|
4489
|
+
children: "Done"
|
|
3948
4490
|
}
|
|
3949
|
-
)
|
|
3950
|
-
|
|
3951
|
-
|
|
4491
|
+
)
|
|
4492
|
+
] }) : null,
|
|
4493
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
|
|
4494
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: T.disclaimerShort }),
|
|
4495
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4496
|
+
"button",
|
|
3952
4497
|
{
|
|
3953
|
-
"data-boff-explore": "stop",
|
|
3954
4498
|
type: "button",
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
"
|
|
3958
|
-
|
|
3959
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Square, { className: "h-4 w-4" })
|
|
3960
|
-
}
|
|
3961
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3962
|
-
Button,
|
|
3963
|
-
{
|
|
3964
|
-
"data-boff-explore": "send",
|
|
3965
|
-
type: "submit",
|
|
3966
|
-
size: "icon",
|
|
3967
|
-
disabled: !canSubmit,
|
|
3968
|
-
"aria-label": T.send,
|
|
3969
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-4 w-4" })
|
|
4499
|
+
"data-boff-explore": "disclaimer",
|
|
4500
|
+
onClick: () => setDisclaimerOpen(true),
|
|
4501
|
+
className: "shrink-0 underline underline-offset-2 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
4502
|
+
children: T.disclaimer
|
|
3970
4503
|
}
|
|
3971
4504
|
)
|
|
3972
|
-
]
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
"p",
|
|
3977
|
-
{
|
|
3978
|
-
"data-boff-explore": "dictation",
|
|
3979
|
-
className: "mt-2 flex items-center gap-2 text-xs text-muted-foreground",
|
|
3980
|
-
"aria-live": "polite",
|
|
3981
|
-
children: [
|
|
3982
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-2 w-2 shrink-0", children: [
|
|
3983
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-primary opacity-75" }),
|
|
3984
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex h-2 w-2 rounded-full bg-primary" })
|
|
3985
|
-
] }),
|
|
3986
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "italic", children: speech.interim !== "" ? speech.interim : "Listening\u2026" })
|
|
3987
|
-
]
|
|
3988
|
-
}
|
|
3989
|
-
) : null,
|
|
3990
|
-
speech.error !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3991
|
-
"p",
|
|
3992
|
-
{
|
|
3993
|
-
"data-boff-explore": "dictation-error",
|
|
3994
|
-
className: "mt-2 text-xs text-destructive",
|
|
3995
|
-
children: speech.error
|
|
3996
|
-
}
|
|
3997
|
-
) : null,
|
|
3998
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
|
|
3999
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: "Enter to send \xB7 Shift + Enter for a new line" }),
|
|
4000
|
-
remainingToday !== null ? /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-boff-explore": "remaining", children: [
|
|
4001
|
-
remainingToday,
|
|
4002
|
-
" message",
|
|
4003
|
-
remainingToday === 1 ? "" : "s",
|
|
4004
|
-
" left today"
|
|
4005
|
-
] }) : null,
|
|
4006
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4007
|
-
"span",
|
|
4008
|
-
{
|
|
4009
|
-
className: cn(
|
|
4010
|
-
"ml-auto tabular-nums",
|
|
4011
|
-
overLimit && "font-medium text-destructive"
|
|
4012
|
-
),
|
|
4013
|
-
children: [
|
|
4014
|
-
draft.length.toLocaleString(),
|
|
4015
|
-
" / ",
|
|
4016
|
-
maxLength.toLocaleString()
|
|
4017
|
-
]
|
|
4018
|
-
}
|
|
4019
|
-
)
|
|
4020
|
-
] }),
|
|
4021
|
-
shareUrl ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center gap-2", children: [
|
|
4022
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4023
|
-
"input",
|
|
4024
|
-
{
|
|
4025
|
-
"data-boff-explore": "share-url",
|
|
4026
|
-
readOnly: true,
|
|
4027
|
-
value: shareUrl,
|
|
4028
|
-
"aria-label": "Read-only link to this conversation",
|
|
4029
|
-
onFocus: (event) => event.currentTarget.select(),
|
|
4030
|
-
className: "min-w-0 flex-1 rounded-md border border-border bg-muted px-2 py-1 text-xs text-muted-foreground"
|
|
4031
|
-
}
|
|
4032
|
-
),
|
|
4033
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4034
|
-
"button",
|
|
4035
|
-
{
|
|
4036
|
-
type: "button",
|
|
4037
|
-
className: "shrink-0 text-xs underline underline-offset-2",
|
|
4038
|
-
onClick: () => setShareUrl(null),
|
|
4039
|
-
children: "Done"
|
|
4040
|
-
}
|
|
4041
|
-
)
|
|
4042
|
-
] }) : null,
|
|
4043
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
|
|
4044
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: T.disclaimerShort }),
|
|
4045
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4046
|
-
"button",
|
|
4047
|
-
{
|
|
4048
|
-
type: "button",
|
|
4049
|
-
"data-boff-explore": "disclaimer",
|
|
4050
|
-
onClick: () => setDisclaimerOpen(true),
|
|
4051
|
-
className: "shrink-0 underline underline-offset-2 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
4052
|
-
children: T.disclaimer
|
|
4053
|
-
}
|
|
4054
|
-
)
|
|
4055
|
-
] })
|
|
4056
|
-
]
|
|
4505
|
+
] })
|
|
4506
|
+
]
|
|
4507
|
+
}
|
|
4508
|
+
)
|
|
4057
4509
|
}
|
|
4058
|
-
)
|
|
4510
|
+
)
|
|
4059
4511
|
]
|
|
4060
4512
|
}
|
|
4061
4513
|
);
|
|
4062
4514
|
}
|
|
4063
4515
|
|
|
4064
4516
|
exports.ExplorePage = ExplorePage;
|
|
4517
|
+
exports.inlineImageOrigins = inlineImageOrigins;
|
|
4518
|
+
exports.isInlineImageAllowed = isInlineImageAllowed;
|
|
4065
4519
|
exports.logoUrlOf = logoUrlOf;
|
|
4066
4520
|
//# sourceMappingURL=explore.js.map
|
|
4067
4521
|
//# sourceMappingURL=explore.js.map
|