@burdenoff/website-sdk 2026.828.6 → 2026.829.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/dist/components/explore.js +402 -190
- package/dist/components/explore.js.map +1 -1
- package/dist/components/explore.mjs +404 -192
- package/dist/components/explore.mjs.map +1 -1
- package/dist/hooks/index.js +111 -69
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +111 -69
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +402 -190
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +402 -190
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { createContext, useMemo, useState, useRef, useCallback, useEffect, useContext } from 'react';
|
|
3
|
-
import { Sparkles, RotateCcw, History, Trash2, Mic, Square, ArrowUp, BookOpenText, Layers, Link2, TriangleAlert, ExternalLink } from 'lucide-react';
|
|
3
|
+
import { Sparkles, RotateCcw, History, Trash2, Mic, Square, ArrowUp, BookOpenText, Layers, Link2, TriangleAlert, ChevronLeft, ChevronRight, ExternalLink } from 'lucide-react';
|
|
4
4
|
import ReactMarkdown from 'react-markdown';
|
|
5
5
|
import rehypeSanitize from 'rehype-sanitize';
|
|
6
6
|
import remarkGfm from 'remark-gfm';
|
|
7
|
-
import { jsx, jsxs
|
|
7
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
8
8
|
import { Helmet } from 'react-helmet-async';
|
|
9
9
|
import { Slot } from '@radix-ui/react-slot';
|
|
10
10
|
import { cva } from 'class-variance-authority';
|
|
@@ -1497,23 +1497,37 @@ function getRecognitionCtor() {
|
|
|
1497
1497
|
const w = window;
|
|
1498
1498
|
return w.SpeechRecognition ?? w.webkitSpeechRecognition ?? null;
|
|
1499
1499
|
}
|
|
1500
|
+
function isTouchDevice() {
|
|
1501
|
+
if (typeof window === "undefined" || !window.matchMedia) return false;
|
|
1502
|
+
try {
|
|
1503
|
+
return window.matchMedia("(pointer: coarse)").matches;
|
|
1504
|
+
} catch {
|
|
1505
|
+
return false;
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1500
1508
|
var MIC_DENIED_MESSAGE = "Microphone access was blocked. Allow it in your browser's site settings to dictate.";
|
|
1509
|
+
var MIC_UNAVAILABLE_MESSAGE = "Dictation isn't available in this browser. You can type instead.";
|
|
1510
|
+
var RELEASE_SETTLE_MS = 250;
|
|
1511
|
+
var RETRY_DELAY_MS = 350;
|
|
1512
|
+
var sleep = (ms) => new Promise((resolve) => {
|
|
1513
|
+
setTimeout(resolve, ms);
|
|
1514
|
+
});
|
|
1501
1515
|
async function ensureMicrophoneAccess() {
|
|
1502
1516
|
const media = typeof navigator === "undefined" ? void 0 : navigator.mediaDevices;
|
|
1503
|
-
if (!media?.getUserMedia)
|
|
1517
|
+
if (!media?.getUserMedia)
|
|
1518
|
+
return { ok: true, confirmed: false, primed: false };
|
|
1504
1519
|
try {
|
|
1505
1520
|
const status = await navigator.permissions?.query({
|
|
1506
1521
|
name: "microphone"
|
|
1507
1522
|
});
|
|
1508
|
-
if (status?.state === "granted")
|
|
1509
|
-
|
|
1510
|
-
return { ok: false, message: MIC_DENIED_MESSAGE };
|
|
1523
|
+
if (status?.state === "granted")
|
|
1524
|
+
return { ok: true, confirmed: true, primed: false };
|
|
1511
1525
|
} catch {
|
|
1512
1526
|
}
|
|
1513
1527
|
try {
|
|
1514
1528
|
const stream = await media.getUserMedia({ audio: true });
|
|
1515
1529
|
for (const track of stream.getTracks()) track.stop();
|
|
1516
|
-
return { ok: true };
|
|
1530
|
+
return { ok: true, confirmed: true, primed: true };
|
|
1517
1531
|
} catch (error) {
|
|
1518
1532
|
const name = typeof error === "object" && error !== null && "name" in error ? String(error.name) : "";
|
|
1519
1533
|
if (name === "NotAllowedError" || name === "SecurityError") {
|
|
@@ -1556,19 +1570,18 @@ function useSpeechInput({
|
|
|
1556
1570
|
const [error, setError] = useState(null);
|
|
1557
1571
|
const recognitionRef = useRef(null);
|
|
1558
1572
|
const startTokenRef = useRef(0);
|
|
1559
|
-
const
|
|
1560
|
-
const
|
|
1561
|
-
|
|
1562
|
-
beginRecognitionRef.current?.(Ctor, token);
|
|
1563
|
-
},
|
|
1564
|
-
[]
|
|
1565
|
-
);
|
|
1573
|
+
const micConfirmedRef = useRef(false);
|
|
1574
|
+
const wantsListeningRef = useRef(false);
|
|
1575
|
+
const retriedRef = useRef(false);
|
|
1566
1576
|
const finalRef = useRef(onFinalTranscript);
|
|
1567
1577
|
const errorRef = useRef(onError);
|
|
1568
1578
|
finalRef.current = onFinalTranscript;
|
|
1569
1579
|
errorRef.current = onError;
|
|
1580
|
+
const langRef = useRef(lang);
|
|
1581
|
+
langRef.current = lang;
|
|
1570
1582
|
const stop = useCallback(() => {
|
|
1571
1583
|
startTokenRef.current += 1;
|
|
1584
|
+
wantsListeningRef.current = false;
|
|
1572
1585
|
setListening(false);
|
|
1573
1586
|
setInterim("");
|
|
1574
1587
|
const recognition = recognitionRef.current;
|
|
@@ -1577,82 +1590,111 @@ function useSpeechInput({
|
|
|
1577
1590
|
recognition.stop();
|
|
1578
1591
|
} catch {
|
|
1579
1592
|
}
|
|
1580
|
-
setListening(false);
|
|
1581
|
-
setInterim("");
|
|
1582
1593
|
}, []);
|
|
1583
|
-
const
|
|
1594
|
+
const openSession = useCallback((token) => {
|
|
1584
1595
|
const Ctor = getRecognitionCtor();
|
|
1585
|
-
if (!Ctor) return;
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1596
|
+
if (!Ctor || token !== startTokenRef.current) return;
|
|
1597
|
+
const recognition = new Ctor();
|
|
1598
|
+
recognition.lang = langRef.current ?? (typeof navigator === "undefined" ? "en-US" : navigator.language || "en-US");
|
|
1599
|
+
recognition.continuous = !isTouchDevice();
|
|
1600
|
+
recognition.interimResults = true;
|
|
1601
|
+
recognition.maxAlternatives = 1;
|
|
1602
|
+
recognition.onstart = () => {
|
|
1603
|
+
if (token !== startTokenRef.current) return;
|
|
1604
|
+
setError(null);
|
|
1605
|
+
setListening(true);
|
|
1606
|
+
};
|
|
1607
|
+
recognition.onresult = (event) => {
|
|
1608
|
+
if (token !== startTokenRef.current) return;
|
|
1609
|
+
let settled = "";
|
|
1610
|
+
let pending = "";
|
|
1611
|
+
for (let i = event.resultIndex; i < event.results.length; i += 1) {
|
|
1612
|
+
const result = event.results[i];
|
|
1613
|
+
if (!result) continue;
|
|
1614
|
+
const text = result[0]?.transcript ?? "";
|
|
1615
|
+
if (result.isFinal) settled += text;
|
|
1616
|
+
else pending += text;
|
|
1617
|
+
}
|
|
1618
|
+
setInterim(pending);
|
|
1619
|
+
if (settled.trim() !== "") finalRef.current(settled);
|
|
1620
|
+
};
|
|
1621
|
+
recognition.onerror = (event) => {
|
|
1622
|
+
if (token !== startTokenRef.current) return;
|
|
1623
|
+
if ((event.error === "not-allowed" || event.error === "service-not-allowed") && micConfirmedRef.current && !retriedRef.current) {
|
|
1624
|
+
retriedRef.current = true;
|
|
1625
|
+
void sleep(RETRY_DELAY_MS).then(() => {
|
|
1626
|
+
if (token !== startTokenRef.current || !wantsListeningRef.current)
|
|
1627
|
+
return;
|
|
1628
|
+
openSessionRef.current?.(token);
|
|
1629
|
+
});
|
|
1630
|
+
return;
|
|
1631
|
+
}
|
|
1632
|
+
const message = micConfirmedRef.current && (event.error === "not-allowed" || event.error === "service-not-allowed") ? MIC_UNAVAILABLE_MESSAGE : describeError(event.error);
|
|
1633
|
+
wantsListeningRef.current = false;
|
|
1634
|
+
setListening(false);
|
|
1635
|
+
setInterim("");
|
|
1636
|
+
if (message !== "") {
|
|
1637
|
+
setError(message);
|
|
1638
|
+
errorRef.current?.(message);
|
|
1639
|
+
}
|
|
1640
|
+
};
|
|
1641
|
+
recognition.onend = () => {
|
|
1642
|
+
if (token !== startTokenRef.current) return;
|
|
1643
|
+
setInterim("");
|
|
1644
|
+
if (wantsListeningRef.current && isTouchDevice()) {
|
|
1645
|
+
void sleep(120).then(() => {
|
|
1646
|
+
if (token !== startTokenRef.current || !wantsListeningRef.current)
|
|
1647
|
+
return;
|
|
1648
|
+
openSessionRef.current?.(token);
|
|
1649
|
+
});
|
|
1650
|
+
return;
|
|
1651
|
+
}
|
|
1652
|
+
setListening(false);
|
|
1653
|
+
};
|
|
1654
|
+
recognitionRef.current = recognition;
|
|
1655
|
+
try {
|
|
1656
|
+
recognition.start();
|
|
1657
|
+
} catch {
|
|
1658
|
+
wantsListeningRef.current = false;
|
|
1659
|
+
setListening(false);
|
|
1660
|
+
}
|
|
1661
|
+
}, []);
|
|
1662
|
+
const openSessionRef = useRef(null);
|
|
1663
|
+
openSessionRef.current = openSession;
|
|
1664
|
+
const start = useCallback(() => {
|
|
1665
|
+
if (!getRecognitionCtor()) return;
|
|
1589
1666
|
startTokenRef.current += 1;
|
|
1590
1667
|
const token = startTokenRef.current;
|
|
1591
|
-
|
|
1668
|
+
wantsListeningRef.current = true;
|
|
1669
|
+
retriedRef.current = false;
|
|
1670
|
+
micConfirmedRef.current = false;
|
|
1671
|
+
setError(null);
|
|
1672
|
+
setListening(true);
|
|
1673
|
+
void ensureMicrophoneAccess().then(async (access) => {
|
|
1592
1674
|
if (token !== startTokenRef.current) return;
|
|
1593
1675
|
if (!access.ok) {
|
|
1676
|
+
wantsListeningRef.current = false;
|
|
1594
1677
|
setListening(false);
|
|
1595
1678
|
setError(access.message);
|
|
1596
1679
|
errorRef.current?.(access.message);
|
|
1597
1680
|
return;
|
|
1598
1681
|
}
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
const beginRecognitionImpl = useCallback(
|
|
1603
|
-
(Ctor, token) => {
|
|
1604
|
-
const recognition = new Ctor();
|
|
1605
|
-
recognition.lang = lang ?? (typeof navigator === "undefined" ? "en-US" : navigator.language || "en-US");
|
|
1606
|
-
recognition.continuous = true;
|
|
1607
|
-
recognition.interimResults = true;
|
|
1608
|
-
recognition.maxAlternatives = 1;
|
|
1609
|
-
recognition.onstart = () => {
|
|
1682
|
+
micConfirmedRef.current = access.confirmed;
|
|
1683
|
+
if (access.primed) {
|
|
1684
|
+
await sleep(RELEASE_SETTLE_MS);
|
|
1610
1685
|
if (token !== startTokenRef.current) return;
|
|
1611
|
-
setError(null);
|
|
1612
|
-
setListening(true);
|
|
1613
|
-
};
|
|
1614
|
-
recognition.onresult = (event) => {
|
|
1615
|
-
let settled = "";
|
|
1616
|
-
let pending = "";
|
|
1617
|
-
for (let i = event.resultIndex; i < event.results.length; i += 1) {
|
|
1618
|
-
const result = event.results[i];
|
|
1619
|
-
if (!result) continue;
|
|
1620
|
-
const text = result[0]?.transcript ?? "";
|
|
1621
|
-
if (result.isFinal) settled += text;
|
|
1622
|
-
else pending += text;
|
|
1623
|
-
}
|
|
1624
|
-
setInterim(pending);
|
|
1625
|
-
if (settled.trim() !== "") finalRef.current(settled);
|
|
1626
|
-
};
|
|
1627
|
-
recognition.onerror = (event) => {
|
|
1628
|
-
const message = describeError(event.error);
|
|
1629
|
-
setListening(false);
|
|
1630
|
-
setInterim("");
|
|
1631
|
-
if (message !== "") {
|
|
1632
|
-
setError(message);
|
|
1633
|
-
errorRef.current?.(message);
|
|
1634
|
-
}
|
|
1635
|
-
};
|
|
1636
|
-
recognition.onend = () => {
|
|
1637
|
-
setListening(false);
|
|
1638
|
-
setInterim("");
|
|
1639
|
-
};
|
|
1640
|
-
recognitionRef.current = recognition;
|
|
1641
|
-
try {
|
|
1642
|
-
recognition.start();
|
|
1643
|
-
} catch {
|
|
1644
|
-
setListening(false);
|
|
1645
1686
|
}
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
);
|
|
1649
|
-
beginRecognitionRef.current = beginRecognitionImpl;
|
|
1687
|
+
openSessionRef.current?.(token);
|
|
1688
|
+
});
|
|
1689
|
+
}, []);
|
|
1650
1690
|
const toggle = useCallback(() => {
|
|
1651
1691
|
if (listening) stop();
|
|
1652
1692
|
else start();
|
|
1653
1693
|
}, [listening, start, stop]);
|
|
1654
1694
|
useEffect(
|
|
1655
1695
|
() => () => {
|
|
1696
|
+
startTokenRef.current += 1;
|
|
1697
|
+
wantsListeningRef.current = false;
|
|
1656
1698
|
const recognition = recognitionRef.current;
|
|
1657
1699
|
if (!recognition) return;
|
|
1658
1700
|
recognition.onresult = null;
|
|
@@ -1836,6 +1878,50 @@ var EXPLORE_CSS = `
|
|
|
1836
1878
|
border-radius: 9999px;
|
|
1837
1879
|
background-clip: content-box;
|
|
1838
1880
|
}
|
|
1881
|
+
|
|
1882
|
+
/* The product strip scrolls inside itself; a visible scrollbar would read as a broken
|
|
1883
|
+
layout rather than an affordance, and reserving its gutter shifts the chips. */
|
|
1884
|
+
.boff-explore-strip {
|
|
1885
|
+
scrollbar-width: none;
|
|
1886
|
+
-ms-overflow-style: none;
|
|
1887
|
+
}
|
|
1888
|
+
.boff-explore-strip::-webkit-scrollbar { display: none; }
|
|
1889
|
+
|
|
1890
|
+
@keyframes boff-explore-fade-in {
|
|
1891
|
+
from { opacity: 0; transform: translateY(2px); }
|
|
1892
|
+
to { opacity: 1; transform: none; }
|
|
1893
|
+
}
|
|
1894
|
+
.boff-explore-fade { animation: boff-explore-fade-in 220ms ease-out; }
|
|
1895
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1896
|
+
.boff-explore-fade { animation: none; }
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
/* Nothing inside an answer may widen the page. Model output carries long URLs, code and
|
|
1900
|
+
tables \u2014 each of those overflows a phone by default, and one overflowing child makes the
|
|
1901
|
+
WHOLE document horizontally scrollable, not just the bubble. */
|
|
1902
|
+
.boff-explore-body,
|
|
1903
|
+
.boff-explore-body p,
|
|
1904
|
+
.boff-explore-body li,
|
|
1905
|
+
.boff-explore-body a,
|
|
1906
|
+
.boff-explore-body h1,
|
|
1907
|
+
.boff-explore-body h2,
|
|
1908
|
+
.boff-explore-body h3 {
|
|
1909
|
+
overflow-wrap: anywhere;
|
|
1910
|
+
word-break: break-word;
|
|
1911
|
+
}
|
|
1912
|
+
.boff-explore-body pre {
|
|
1913
|
+
overflow-x: auto;
|
|
1914
|
+
max-width: 100%;
|
|
1915
|
+
}
|
|
1916
|
+
.boff-explore-body table {
|
|
1917
|
+
display: block;
|
|
1918
|
+
overflow-x: auto;
|
|
1919
|
+
max-width: 100%;
|
|
1920
|
+
}
|
|
1921
|
+
.boff-explore-body img {
|
|
1922
|
+
max-width: 100%;
|
|
1923
|
+
height: auto;
|
|
1924
|
+
}
|
|
1839
1925
|
`;
|
|
1840
1926
|
function ExploreStyles() {
|
|
1841
1927
|
return /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: EXPLORE_CSS } });
|
|
@@ -1857,7 +1943,6 @@ var CAPABILITIES = [
|
|
|
1857
1943
|
body: "Get the sources and next steps \u2014 pricing, docs, a demo \u2014 without hunting."
|
|
1858
1944
|
}
|
|
1859
1945
|
];
|
|
1860
|
-
var PRODUCT_CHIP_PREVIEW = 12;
|
|
1861
1946
|
var CTA_VARIANTS = {
|
|
1862
1947
|
CONTACT: "default",
|
|
1863
1948
|
WAITLIST: "default",
|
|
@@ -2058,7 +2143,7 @@ function AssistantBubble({
|
|
|
2058
2143
|
),
|
|
2059
2144
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-3", children: [
|
|
2060
2145
|
body ? /* @__PURE__ */ jsxs("div", { className: "rounded-2xl rounded-tl-md border border-border bg-card px-4 py-3 shadow-sm", children: [
|
|
2061
|
-
/* @__PURE__ */ jsx("div", { className: "boff-prose boff-prose-sm text-card-foreground", children: /* @__PURE__ */ jsx(Markdown, { children: body }) }),
|
|
2146
|
+
/* @__PURE__ */ jsx("div", { className: "boff-prose boff-prose-sm boff-explore-body min-w-0 text-card-foreground", children: /* @__PURE__ */ jsx(Markdown, { children: body }) }),
|
|
2062
2147
|
streaming ? /* @__PURE__ */ jsx("span", { className: "boff-explore-caret", "aria-hidden": "true" }) : null
|
|
2063
2148
|
] }) : null,
|
|
2064
2149
|
streaming ? /* @__PURE__ */ jsx(ThinkingIndicator, { activity }) : null,
|
|
@@ -2120,6 +2205,200 @@ function ErrorBanner({
|
|
|
2120
2205
|
}
|
|
2121
2206
|
);
|
|
2122
2207
|
}
|
|
2208
|
+
function PromptCarousel({
|
|
2209
|
+
prompts,
|
|
2210
|
+
onPrompt,
|
|
2211
|
+
disabled
|
|
2212
|
+
}) {
|
|
2213
|
+
const [index, setIndex] = useState(0);
|
|
2214
|
+
const [paused, setPaused] = useState(false);
|
|
2215
|
+
const count = prompts.length;
|
|
2216
|
+
const current = prompts[index % count] ?? prompts[0] ?? "";
|
|
2217
|
+
const go = useCallback(
|
|
2218
|
+
(delta) => {
|
|
2219
|
+
setIndex((i) => (i + delta + count) % count);
|
|
2220
|
+
},
|
|
2221
|
+
[count]
|
|
2222
|
+
);
|
|
2223
|
+
useEffect(() => {
|
|
2224
|
+
if (paused || disabled || count < 2) return;
|
|
2225
|
+
if (typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) {
|
|
2226
|
+
return;
|
|
2227
|
+
}
|
|
2228
|
+
const timer = setInterval(() => setIndex((i) => (i + 1) % count), 4500);
|
|
2229
|
+
return () => clearInterval(timer);
|
|
2230
|
+
}, [paused, disabled, count]);
|
|
2231
|
+
if (count === 0) return null;
|
|
2232
|
+
return /* @__PURE__ */ jsxs(
|
|
2233
|
+
"div",
|
|
2234
|
+
{
|
|
2235
|
+
className: "flex min-w-0 items-center gap-1.5",
|
|
2236
|
+
onMouseEnter: () => setPaused(true),
|
|
2237
|
+
onMouseLeave: () => setPaused(false),
|
|
2238
|
+
onFocusCapture: () => setPaused(true),
|
|
2239
|
+
onBlurCapture: () => setPaused(false),
|
|
2240
|
+
children: [
|
|
2241
|
+
count > 1 ? /* @__PURE__ */ jsx(
|
|
2242
|
+
"button",
|
|
2243
|
+
{
|
|
2244
|
+
type: "button",
|
|
2245
|
+
"aria-label": "Previous suggestion",
|
|
2246
|
+
onClick: () => go(-1),
|
|
2247
|
+
className: "hidden h-8 w-8 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:inline-flex",
|
|
2248
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
|
|
2249
|
+
}
|
|
2250
|
+
) : null,
|
|
2251
|
+
/* @__PURE__ */ jsxs(
|
|
2252
|
+
"button",
|
|
2253
|
+
{
|
|
2254
|
+
"data-boff-explore": "chip",
|
|
2255
|
+
"data-chip-kind": "prompt",
|
|
2256
|
+
type: "button",
|
|
2257
|
+
disabled,
|
|
2258
|
+
onClick: () => onPrompt(current),
|
|
2259
|
+
className: "boff-explore-fade group flex min-w-0 flex-1 items-center gap-2 rounded-full border border-border bg-card px-4 py-2 text-left text-sm text-card-foreground shadow-sm transition-colors hover:border-primary/50 hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2260
|
+
children: [
|
|
2261
|
+
/* @__PURE__ */ jsx(Sparkles, { className: "h-3.5 w-3.5 shrink-0 text-primary" }),
|
|
2262
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: current }),
|
|
2263
|
+
/* @__PURE__ */ jsx(ArrowUp, { className: "ml-auto h-3.5 w-3.5 shrink-0 rotate-45 text-muted-foreground transition-colors group-hover:text-primary" })
|
|
2264
|
+
]
|
|
2265
|
+
},
|
|
2266
|
+
current
|
|
2267
|
+
),
|
|
2268
|
+
count > 1 ? /* @__PURE__ */ jsx(
|
|
2269
|
+
"button",
|
|
2270
|
+
{
|
|
2271
|
+
type: "button",
|
|
2272
|
+
"aria-label": "Next suggestion",
|
|
2273
|
+
onClick: () => go(1),
|
|
2274
|
+
className: "inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2275
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
|
|
2276
|
+
}
|
|
2277
|
+
) : null
|
|
2278
|
+
]
|
|
2279
|
+
}
|
|
2280
|
+
);
|
|
2281
|
+
}
|
|
2282
|
+
function ProductStrip({
|
|
2283
|
+
products,
|
|
2284
|
+
focusProduct,
|
|
2285
|
+
onFocus
|
|
2286
|
+
}) {
|
|
2287
|
+
const [expanded, setExpanded] = useState(false);
|
|
2288
|
+
const chipClass = (active) => cn(
|
|
2289
|
+
"shrink-0 rounded-full border px-3 py-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2290
|
+
active ? "border-primary bg-primary text-primary-foreground" : "border-border bg-card text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
2291
|
+
);
|
|
2292
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
2293
|
+
/* @__PURE__ */ jsxs(
|
|
2294
|
+
"div",
|
|
2295
|
+
{
|
|
2296
|
+
className: cn(
|
|
2297
|
+
"boff-explore-strip flex min-w-0 flex-1 gap-2",
|
|
2298
|
+
expanded ? "flex-wrap" : "flex-nowrap overflow-x-auto"
|
|
2299
|
+
),
|
|
2300
|
+
children: [
|
|
2301
|
+
/* @__PURE__ */ jsx(
|
|
2302
|
+
"button",
|
|
2303
|
+
{
|
|
2304
|
+
"data-boff-explore": "chip",
|
|
2305
|
+
"data-chip-kind": "product",
|
|
2306
|
+
"data-product": "all",
|
|
2307
|
+
type: "button",
|
|
2308
|
+
"aria-pressed": focusProduct === null,
|
|
2309
|
+
onClick: () => onFocus(null),
|
|
2310
|
+
className: chipClass(focusProduct === null),
|
|
2311
|
+
children: "All products"
|
|
2312
|
+
}
|
|
2313
|
+
),
|
|
2314
|
+
products.map((product) => /* @__PURE__ */ jsx(
|
|
2315
|
+
"button",
|
|
2316
|
+
{
|
|
2317
|
+
"data-boff-explore": "chip",
|
|
2318
|
+
"data-chip-kind": "product",
|
|
2319
|
+
"data-product": product.slug,
|
|
2320
|
+
type: "button",
|
|
2321
|
+
"aria-pressed": focusProduct === product.slug,
|
|
2322
|
+
title: product.tagline ?? product.name,
|
|
2323
|
+
onClick: () => onFocus(focusProduct === product.slug ? null : product.slug),
|
|
2324
|
+
className: chipClass(focusProduct === product.slug),
|
|
2325
|
+
children: product.name
|
|
2326
|
+
},
|
|
2327
|
+
product.slug
|
|
2328
|
+
))
|
|
2329
|
+
]
|
|
2330
|
+
}
|
|
2331
|
+
),
|
|
2332
|
+
products.length > 0 ? /* @__PURE__ */ jsx(
|
|
2333
|
+
"button",
|
|
2334
|
+
{
|
|
2335
|
+
type: "button",
|
|
2336
|
+
"data-boff-explore": "products-toggle",
|
|
2337
|
+
onClick: () => setExpanded((v) => !v),
|
|
2338
|
+
className: "shrink-0 whitespace-nowrap rounded-full px-2 py-1 text-xs font-medium text-primary underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2339
|
+
children: expanded ? "Show less" : `All ${products.length}`
|
|
2340
|
+
}
|
|
2341
|
+
) : null
|
|
2342
|
+
] });
|
|
2343
|
+
}
|
|
2344
|
+
function DisclaimerDialog({
|
|
2345
|
+
open,
|
|
2346
|
+
onClose,
|
|
2347
|
+
captchaOn
|
|
2348
|
+
}) {
|
|
2349
|
+
const closeRef = useRef(null);
|
|
2350
|
+
useEffect(() => {
|
|
2351
|
+
if (!open) return;
|
|
2352
|
+
const onKey = (event) => {
|
|
2353
|
+
if (event.key === "Escape") onClose();
|
|
2354
|
+
};
|
|
2355
|
+
document.addEventListener("keydown", onKey);
|
|
2356
|
+
closeRef.current?.focus();
|
|
2357
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
2358
|
+
}, [open, onClose]);
|
|
2359
|
+
if (!open) return null;
|
|
2360
|
+
return /* @__PURE__ */ jsx(
|
|
2361
|
+
"div",
|
|
2362
|
+
{
|
|
2363
|
+
"data-boff-explore": "disclaimer-dialog",
|
|
2364
|
+
role: "dialog",
|
|
2365
|
+
"aria-modal": "true",
|
|
2366
|
+
"aria-label": "How this assistant works",
|
|
2367
|
+
className: "fixed inset-0 z-50 flex items-end justify-center bg-foreground/40 p-4 backdrop-blur-sm sm:items-center",
|
|
2368
|
+
onClick: onClose,
|
|
2369
|
+
children: /* @__PURE__ */ jsxs(
|
|
2370
|
+
"div",
|
|
2371
|
+
{
|
|
2372
|
+
className: "w-full max-w-md rounded-2xl border border-border bg-card p-5 shadow-xl",
|
|
2373
|
+
onClick: (event) => event.stopPropagation(),
|
|
2374
|
+
children: [
|
|
2375
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
2376
|
+
/* @__PURE__ */ jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(TriangleAlert, { className: "h-4 w-4" }) }),
|
|
2377
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
2378
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-card-foreground", children: "How this assistant works" }),
|
|
2379
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-2 text-xs leading-relaxed text-muted-foreground", children: [
|
|
2380
|
+
/* @__PURE__ */ jsx("p", { children: "Answers are generated from our public documentation and can be imperfect \u2014 check anything important against the linked sources." }),
|
|
2381
|
+
/* @__PURE__ */ jsx("p", { children: "Conversations are saved in this browser so you can come back to them, and are also stored on our servers to help us improve these answers. Please don't share personal or confidential information." }),
|
|
2382
|
+
captchaOn ? /* @__PURE__ */ jsx("p", { children: "Protected by reCAPTCHA \u2014 the Google Privacy Policy and Terms of Service apply." }) : null
|
|
2383
|
+
] })
|
|
2384
|
+
] })
|
|
2385
|
+
] }),
|
|
2386
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-end", children: /* @__PURE__ */ jsx(
|
|
2387
|
+
Button,
|
|
2388
|
+
{
|
|
2389
|
+
ref: closeRef,
|
|
2390
|
+
size: "sm",
|
|
2391
|
+
variant: "secondary",
|
|
2392
|
+
onClick: onClose,
|
|
2393
|
+
children: "Got it"
|
|
2394
|
+
}
|
|
2395
|
+
) })
|
|
2396
|
+
]
|
|
2397
|
+
}
|
|
2398
|
+
)
|
|
2399
|
+
}
|
|
2400
|
+
);
|
|
2401
|
+
}
|
|
2123
2402
|
function WelcomeState({
|
|
2124
2403
|
title,
|
|
2125
2404
|
body,
|
|
@@ -2130,21 +2409,19 @@ function WelcomeState({
|
|
|
2130
2409
|
onFocus,
|
|
2131
2410
|
disabled
|
|
2132
2411
|
}) {
|
|
2133
|
-
|
|
2134
|
-
const visibleProducts = showAllProducts ? products : products.slice(0, PRODUCT_CHIP_PREVIEW);
|
|
2135
|
-
return /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-3xl px-4 py-10 sm:py-14", children: [
|
|
2412
|
+
return /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-3xl px-4 py-8 sm:py-12", children: [
|
|
2136
2413
|
/* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
2137
2414
|
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 rounded-full border border-border bg-muted px-3 py-1 text-xs font-medium text-muted-foreground", children: [
|
|
2138
2415
|
/* @__PURE__ */ jsx(Sparkles, { className: "h-3.5 w-3.5" }),
|
|
2139
2416
|
"AI answers, grounded in our documentation"
|
|
2140
2417
|
] }),
|
|
2141
|
-
/* @__PURE__ */ jsx("h1", { className: "mt-
|
|
2142
|
-
/* @__PURE__ */ jsx("p", { className: "mx-auto mt-
|
|
2418
|
+
/* @__PURE__ */ jsx("h1", { className: "mt-4 text-balance break-words text-2xl font-bold tracking-tight sm:text-4xl", children: title }),
|
|
2419
|
+
/* @__PURE__ */ jsx("p", { className: "mx-auto mt-2.5 max-w-2xl text-pretty text-sm leading-relaxed text-muted-foreground sm:text-lg", children: body })
|
|
2143
2420
|
] }),
|
|
2144
|
-
/* @__PURE__ */ jsx("ul", { className: "mt-
|
|
2421
|
+
/* @__PURE__ */ jsx("ul", { className: "mt-7 grid gap-2.5 sm:grid-cols-3", children: CAPABILITIES.map(({ icon: Icon, title: capTitle, body: capBody }) => /* @__PURE__ */ jsxs(
|
|
2145
2422
|
"li",
|
|
2146
2423
|
{
|
|
2147
|
-
className: "rounded-xl border border-border bg-card p-
|
|
2424
|
+
className: "rounded-xl border border-border/70 bg-card/60 p-3.5 text-left transition-colors hover:border-border",
|
|
2148
2425
|
children: [
|
|
2149
2426
|
/* @__PURE__ */ jsx("span", { className: "mb-2.5 flex h-8 w-8 items-center justify-center rounded-lg bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }) }),
|
|
2150
2427
|
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-card-foreground", children: capTitle }),
|
|
@@ -2153,72 +2430,27 @@ function WelcomeState({
|
|
|
2153
2430
|
},
|
|
2154
2431
|
capTitle
|
|
2155
2432
|
)) }),
|
|
2156
|
-
prompts.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "mt-
|
|
2157
|
-
/* @__PURE__ */ jsx("p", { className: "mb-2
|
|
2158
|
-
/* @__PURE__ */ jsx(
|
|
2159
|
-
|
|
2433
|
+
prompts.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "mt-8", children: [
|
|
2434
|
+
/* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Try asking" }),
|
|
2435
|
+
/* @__PURE__ */ jsx(
|
|
2436
|
+
PromptCarousel,
|
|
2160
2437
|
{
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
className: "group inline-flex max-w-full items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-left text-sm text-card-foreground transition-colors hover:border-primary/40 hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2167
|
-
children: [
|
|
2168
|
-
/* @__PURE__ */ jsx("span", { className: "truncate", children: prompt }),
|
|
2169
|
-
/* @__PURE__ */ jsx(ArrowUp, { className: "h-3 w-3 shrink-0 rotate-45 text-muted-foreground transition-colors group-hover:text-primary" })
|
|
2170
|
-
]
|
|
2171
|
-
},
|
|
2172
|
-
prompt
|
|
2173
|
-
)) })
|
|
2438
|
+
prompts,
|
|
2439
|
+
onPrompt,
|
|
2440
|
+
disabled
|
|
2441
|
+
}
|
|
2442
|
+
)
|
|
2174
2443
|
] }) : null,
|
|
2175
|
-
products.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "mt-
|
|
2176
|
-
/* @__PURE__ */ jsx("p", { className: "mb-2
|
|
2177
|
-
/* @__PURE__ */
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
"aria-pressed": focusProduct === null,
|
|
2186
|
-
onClick: () => onFocus(null),
|
|
2187
|
-
className: cn(
|
|
2188
|
-
"rounded-full border px-3 py-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2189
|
-
focusProduct === null ? "border-primary bg-primary text-primary-foreground" : "border-border bg-card text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
2190
|
-
),
|
|
2191
|
-
children: "All products"
|
|
2192
|
-
}
|
|
2193
|
-
),
|
|
2194
|
-
visibleProducts.map((product) => /* @__PURE__ */ jsx(
|
|
2195
|
-
"button",
|
|
2196
|
-
{
|
|
2197
|
-
"data-boff-explore": "chip",
|
|
2198
|
-
"data-chip-kind": "product",
|
|
2199
|
-
"data-product": product.slug,
|
|
2200
|
-
type: "button",
|
|
2201
|
-
"aria-pressed": focusProduct === product.slug,
|
|
2202
|
-
title: product.tagline ?? product.name,
|
|
2203
|
-
onClick: () => onFocus(focusProduct === product.slug ? null : product.slug),
|
|
2204
|
-
className: cn(
|
|
2205
|
-
"rounded-full border px-3 py-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2206
|
-
focusProduct === product.slug ? "border-primary bg-primary text-primary-foreground" : "border-border bg-card text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
2207
|
-
),
|
|
2208
|
-
children: product.name
|
|
2209
|
-
},
|
|
2210
|
-
product.slug
|
|
2211
|
-
)),
|
|
2212
|
-
products.length > PRODUCT_CHIP_PREVIEW ? /* @__PURE__ */ jsx(
|
|
2213
|
-
"button",
|
|
2214
|
-
{
|
|
2215
|
-
type: "button",
|
|
2216
|
-
onClick: () => setShowAllProducts((v) => !v),
|
|
2217
|
-
className: "rounded-full px-3 py-1 text-xs font-medium text-primary underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2218
|
-
children: showAllProducts ? "Show fewer" : `Show all ${products.length}`
|
|
2219
|
-
}
|
|
2220
|
-
) : null
|
|
2221
|
-
] })
|
|
2444
|
+
products.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
|
|
2445
|
+
/* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Focus on a product" }),
|
|
2446
|
+
/* @__PURE__ */ jsx(
|
|
2447
|
+
ProductStrip,
|
|
2448
|
+
{
|
|
2449
|
+
products,
|
|
2450
|
+
focusProduct,
|
|
2451
|
+
onFocus
|
|
2452
|
+
}
|
|
2453
|
+
)
|
|
2222
2454
|
] }) : null
|
|
2223
2455
|
] });
|
|
2224
2456
|
}
|
|
@@ -2274,6 +2506,7 @@ function ExplorePage({
|
|
|
2274
2506
|
}
|
|
2275
2507
|
});
|
|
2276
2508
|
speechStopRef.current = speech.stop;
|
|
2509
|
+
const [disclaimerOpen, setDisclaimerOpen] = useState(false);
|
|
2277
2510
|
const scrollRef = useRef(null);
|
|
2278
2511
|
const latestAssistantRef = useRef(null);
|
|
2279
2512
|
const alignedForRef = useRef(null);
|
|
@@ -2366,7 +2599,7 @@ function ExplorePage({
|
|
|
2366
2599
|
"data-boff-explore": "page",
|
|
2367
2600
|
"data-phase": phase,
|
|
2368
2601
|
className: cn(
|
|
2369
|
-
"flex w-full flex-col bg-background text-foreground",
|
|
2602
|
+
"flex w-full min-w-0 flex-col overflow-x-hidden bg-background text-foreground",
|
|
2370
2603
|
heightMode === "auto" && "min-h-[70vh]",
|
|
2371
2604
|
className
|
|
2372
2605
|
),
|
|
@@ -2508,7 +2741,7 @@ function ExplorePage({
|
|
|
2508
2741
|
role: "log",
|
|
2509
2742
|
"aria-live": "polite",
|
|
2510
2743
|
"aria-label": "Explore conversation",
|
|
2511
|
-
className: "boff-explore-scroll min-h-0 flex-1 overflow-y-auto",
|
|
2744
|
+
className: "boff-explore-scroll min-h-0 min-w-0 flex-1 overflow-y-auto overflow-x-hidden",
|
|
2512
2745
|
children: showWelcome ? /* @__PURE__ */ jsx(
|
|
2513
2746
|
WelcomeState,
|
|
2514
2747
|
{
|
|
@@ -2521,7 +2754,7 @@ function ExplorePage({
|
|
|
2521
2754
|
onFocus: setFocusProduct,
|
|
2522
2755
|
disabled: !canSend || busy
|
|
2523
2756
|
}
|
|
2524
|
-
) : /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-3xl space-y-6 px-4 py-6", children: messages.map(
|
|
2757
|
+
) : /* @__PURE__ */ jsx("div", { className: "mx-auto w-full min-w-0 max-w-3xl space-y-6 px-4 py-6", children: messages.map(
|
|
2525
2758
|
(message) => message.role === "USER" ? /* @__PURE__ */ jsx(UserBubble, { message }, message.id) : /* @__PURE__ */ jsx(
|
|
2526
2759
|
AssistantBubble,
|
|
2527
2760
|
{
|
|
@@ -2535,7 +2768,15 @@ function ExplorePage({
|
|
|
2535
2768
|
) })
|
|
2536
2769
|
}
|
|
2537
2770
|
),
|
|
2538
|
-
/* @__PURE__ */ jsx(
|
|
2771
|
+
/* @__PURE__ */ jsx(
|
|
2772
|
+
DisclaimerDialog,
|
|
2773
|
+
{
|
|
2774
|
+
open: disclaimerOpen,
|
|
2775
|
+
onClose: () => setDisclaimerOpen(false),
|
|
2776
|
+
captchaOn
|
|
2777
|
+
}
|
|
2778
|
+
),
|
|
2779
|
+
/* @__PURE__ */ jsx("div", { className: "border-t border-border bg-background/85 px-4 pb-[max(1rem,env(safe-area-inset-bottom))] pt-3 backdrop-blur-md", children: /* @__PURE__ */ jsxs(
|
|
2539
2780
|
"form",
|
|
2540
2781
|
{
|
|
2541
2782
|
"data-boff-explore": "composer",
|
|
@@ -2550,7 +2791,7 @@ function ExplorePage({
|
|
|
2550
2791
|
"div",
|
|
2551
2792
|
{
|
|
2552
2793
|
className: cn(
|
|
2553
|
-
"flex items-end gap-2 rounded-2xl border bg-card p-2 shadow-sm transition-
|
|
2794
|
+
"flex min-w-0 items-end gap-2 rounded-2xl border bg-card p-2 shadow-sm transition-all",
|
|
2554
2795
|
overLimit ? "border-destructive/60" : "border-border focus-within:border-primary/40 focus-within:ring-1 focus-within:ring-ring"
|
|
2555
2796
|
),
|
|
2556
2797
|
children: [
|
|
@@ -2571,7 +2812,7 @@ function ExplorePage({
|
|
|
2571
2812
|
},
|
|
2572
2813
|
"aria-label": "Ask a question",
|
|
2573
2814
|
placeholder: composerDisabled ? phase === "limited" ? "Message limit reached \u2014 please try again later" : "Explore is unavailable right now" : focusedProductName ? `Ask about ${focusedProductName}\u2026` : "Ask anything about our products\u2026",
|
|
2574
|
-
className: "max-h-[200px] min-h-[44px] flex-1 resize-none border-0 bg-transparent px-2 py-2.5 text-sm shadow-none focus-visible:ring-0 md:text-sm"
|
|
2815
|
+
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-sm shadow-none focus-visible:ring-0 md:text-sm"
|
|
2575
2816
|
}
|
|
2576
2817
|
),
|
|
2577
2818
|
speech.supported ? /* @__PURE__ */ jsx(
|
|
@@ -2662,48 +2903,19 @@ function ExplorePage({
|
|
|
2662
2903
|
}
|
|
2663
2904
|
)
|
|
2664
2905
|
] }),
|
|
2665
|
-
/* @__PURE__ */ jsxs(
|
|
2666
|
-
"
|
|
2667
|
-
|
|
2668
|
-
"
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
"
|
|
2672
|
-
|
|
2673
|
-
"
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
/* @__PURE__ */ jsx(
|
|
2679
|
-
"a",
|
|
2680
|
-
{
|
|
2681
|
-
href: "https://policies.google.com/privacy",
|
|
2682
|
-
target: "_blank",
|
|
2683
|
-
rel: "noopener noreferrer",
|
|
2684
|
-
className: "underline underline-offset-2 hover:text-foreground",
|
|
2685
|
-
children: "Privacy Policy"
|
|
2686
|
-
}
|
|
2687
|
-
),
|
|
2688
|
-
" ",
|
|
2689
|
-
"and",
|
|
2690
|
-
" ",
|
|
2691
|
-
/* @__PURE__ */ jsx(
|
|
2692
|
-
"a",
|
|
2693
|
-
{
|
|
2694
|
-
href: "https://policies.google.com/terms",
|
|
2695
|
-
target: "_blank",
|
|
2696
|
-
rel: "noopener noreferrer",
|
|
2697
|
-
className: "underline underline-offset-2 hover:text-foreground",
|
|
2698
|
-
children: "Terms of Service"
|
|
2699
|
-
}
|
|
2700
|
-
),
|
|
2701
|
-
" ",
|
|
2702
|
-
"apply."
|
|
2703
|
-
] }) : null
|
|
2704
|
-
]
|
|
2705
|
-
}
|
|
2706
|
-
)
|
|
2906
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
|
|
2907
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: "Grounded in our docs \u2014 check anything important." }),
|
|
2908
|
+
/* @__PURE__ */ jsx(
|
|
2909
|
+
"button",
|
|
2910
|
+
{
|
|
2911
|
+
type: "button",
|
|
2912
|
+
"data-boff-explore": "disclaimer",
|
|
2913
|
+
onClick: () => setDisclaimerOpen(true),
|
|
2914
|
+
className: "shrink-0 underline underline-offset-2 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2915
|
+
children: "Disclaimer"
|
|
2916
|
+
}
|
|
2917
|
+
)
|
|
2918
|
+
] })
|
|
2707
2919
|
]
|
|
2708
2920
|
}
|
|
2709
2921
|
) })
|