@burdenoff/website-sdk 2026.828.5 → 2026.828.6
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.d.mts +11 -1
- package/dist/components/explore.d.ts +11 -1
- package/dist/components/explore.js +175 -57
- package/dist/components/explore.js.map +1 -1
- package/dist/components/explore.mjs +175 -58
- package/dist/components/explore.mjs.map +1 -1
- package/dist/hooks/index.js +104 -41
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +104 -41
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.js +174 -57
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +174 -57
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -38,6 +38,16 @@ interface ExplorePageProps {
|
|
|
38
38
|
/** Overrides `exploreCatalog.welcomeBody`. */
|
|
39
39
|
welcomeBody?: string;
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* The product's own logo, derived from the reference's origin.
|
|
43
|
+
*
|
|
44
|
+
* Every Burdenoff product site serves `/favicon.svg`, so the logo needs no registry and no
|
|
45
|
+
* bundled assets — the reference URL already names the product. Deliberately NOT
|
|
46
|
+
* `/favicon-512.png`: that path returns 200 with `text/html` because the SPA fallback
|
|
47
|
+
* answers unknown paths, so it would render as a broken image rather than 404 into the
|
|
48
|
+
* fallback below.
|
|
49
|
+
*/
|
|
50
|
+
declare function logoUrlOf(url: string): string | null;
|
|
41
51
|
declare function ExplorePage({ seo, productSlug, examplePrompts, className, heightMode, viewportOffset, onNavigate, onSend, welcomeTitle, welcomeBody, }: ExplorePageProps): react.JSX.Element;
|
|
42
52
|
|
|
43
|
-
export { ExplorePage, type ExplorePageProps };
|
|
53
|
+
export { ExplorePage, type ExplorePageProps, logoUrlOf };
|
|
@@ -38,6 +38,16 @@ interface ExplorePageProps {
|
|
|
38
38
|
/** Overrides `exploreCatalog.welcomeBody`. */
|
|
39
39
|
welcomeBody?: string;
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* The product's own logo, derived from the reference's origin.
|
|
43
|
+
*
|
|
44
|
+
* Every Burdenoff product site serves `/favicon.svg`, so the logo needs no registry and no
|
|
45
|
+
* bundled assets — the reference URL already names the product. Deliberately NOT
|
|
46
|
+
* `/favicon-512.png`: that path returns 200 with `text/html` because the SPA fallback
|
|
47
|
+
* answers unknown paths, so it would render as a broken image rather than 404 into the
|
|
48
|
+
* fallback below.
|
|
49
|
+
*/
|
|
50
|
+
declare function logoUrlOf(url: string): string | null;
|
|
41
51
|
declare function ExplorePage({ seo, productSlug, examplePrompts, className, heightMode, viewportOffset, onNavigate, onSend, welcomeTitle, welcomeBody, }: ExplorePageProps): react.JSX.Element;
|
|
42
52
|
|
|
43
|
-
export { ExplorePage, type ExplorePageProps };
|
|
53
|
+
export { ExplorePage, type ExplorePageProps, logoUrlOf };
|
|
@@ -1523,11 +1523,42 @@ function getRecognitionCtor() {
|
|
|
1523
1523
|
const w = window;
|
|
1524
1524
|
return w.SpeechRecognition ?? w.webkitSpeechRecognition ?? null;
|
|
1525
1525
|
}
|
|
1526
|
+
var MIC_DENIED_MESSAGE = "Microphone access was blocked. Allow it in your browser's site settings to dictate.";
|
|
1527
|
+
async function ensureMicrophoneAccess() {
|
|
1528
|
+
const media = typeof navigator === "undefined" ? void 0 : navigator.mediaDevices;
|
|
1529
|
+
if (!media?.getUserMedia) return { ok: true };
|
|
1530
|
+
try {
|
|
1531
|
+
const status = await navigator.permissions?.query({
|
|
1532
|
+
name: "microphone"
|
|
1533
|
+
});
|
|
1534
|
+
if (status?.state === "granted") return { ok: true };
|
|
1535
|
+
if (status?.state === "denied")
|
|
1536
|
+
return { ok: false, message: MIC_DENIED_MESSAGE };
|
|
1537
|
+
} catch {
|
|
1538
|
+
}
|
|
1539
|
+
try {
|
|
1540
|
+
const stream = await media.getUserMedia({ audio: true });
|
|
1541
|
+
for (const track of stream.getTracks()) track.stop();
|
|
1542
|
+
return { ok: true };
|
|
1543
|
+
} catch (error) {
|
|
1544
|
+
const name = typeof error === "object" && error !== null && "name" in error ? String(error.name) : "";
|
|
1545
|
+
if (name === "NotAllowedError" || name === "SecurityError") {
|
|
1546
|
+
return { ok: false, message: MIC_DENIED_MESSAGE };
|
|
1547
|
+
}
|
|
1548
|
+
if (name === "NotFoundError" || name === "DevicesNotFoundError") {
|
|
1549
|
+
return { ok: false, message: "No microphone was found." };
|
|
1550
|
+
}
|
|
1551
|
+
return {
|
|
1552
|
+
ok: false,
|
|
1553
|
+
message: "Dictation could not start. You can type instead."
|
|
1554
|
+
};
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1526
1557
|
function describeError(code) {
|
|
1527
1558
|
switch (code) {
|
|
1528
1559
|
case "not-allowed":
|
|
1529
1560
|
case "service-not-allowed":
|
|
1530
|
-
return
|
|
1561
|
+
return MIC_DENIED_MESSAGE;
|
|
1531
1562
|
case "no-speech":
|
|
1532
1563
|
return "I didn't catch anything \u2014 try again a little closer to the mic.";
|
|
1533
1564
|
case "audio-capture":
|
|
@@ -1550,11 +1581,22 @@ function useSpeechInput({
|
|
|
1550
1581
|
const [interim, setInterim] = React.useState("");
|
|
1551
1582
|
const [error, setError] = React.useState(null);
|
|
1552
1583
|
const recognitionRef = React.useRef(null);
|
|
1584
|
+
const startTokenRef = React.useRef(0);
|
|
1585
|
+
const beginRecognitionRef = React.useRef(null);
|
|
1586
|
+
const beginRecognition = React.useCallback(
|
|
1587
|
+
(Ctor, token) => {
|
|
1588
|
+
beginRecognitionRef.current?.(Ctor, token);
|
|
1589
|
+
},
|
|
1590
|
+
[]
|
|
1591
|
+
);
|
|
1553
1592
|
const finalRef = React.useRef(onFinalTranscript);
|
|
1554
1593
|
const errorRef = React.useRef(onError);
|
|
1555
1594
|
finalRef.current = onFinalTranscript;
|
|
1556
1595
|
errorRef.current = onError;
|
|
1557
1596
|
const stop = React.useCallback(() => {
|
|
1597
|
+
startTokenRef.current += 1;
|
|
1598
|
+
setListening(false);
|
|
1599
|
+
setInterim("");
|
|
1558
1600
|
const recognition = recognitionRef.current;
|
|
1559
1601
|
if (!recognition) return;
|
|
1560
1602
|
try {
|
|
@@ -1568,48 +1610,69 @@ function useSpeechInput({
|
|
|
1568
1610
|
const Ctor = getRecognitionCtor();
|
|
1569
1611
|
if (!Ctor) return;
|
|
1570
1612
|
if (recognitionRef.current) stop();
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
let pending = "";
|
|
1583
|
-
for (let i = event.resultIndex; i < event.results.length; i += 1) {
|
|
1584
|
-
const result = event.results[i];
|
|
1585
|
-
if (!result) continue;
|
|
1586
|
-
const text = result[0]?.transcript ?? "";
|
|
1587
|
-
if (result.isFinal) settled += text;
|
|
1588
|
-
else pending += text;
|
|
1613
|
+
setError(null);
|
|
1614
|
+
setListening(true);
|
|
1615
|
+
startTokenRef.current += 1;
|
|
1616
|
+
const token = startTokenRef.current;
|
|
1617
|
+
void ensureMicrophoneAccess().then((access) => {
|
|
1618
|
+
if (token !== startTokenRef.current) return;
|
|
1619
|
+
if (!access.ok) {
|
|
1620
|
+
setListening(false);
|
|
1621
|
+
setError(access.message);
|
|
1622
|
+
errorRef.current?.(access.message);
|
|
1623
|
+
return;
|
|
1589
1624
|
}
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1625
|
+
beginRecognition(Ctor, token);
|
|
1626
|
+
});
|
|
1627
|
+
}, [beginRecognition, stop]);
|
|
1628
|
+
const beginRecognitionImpl = React.useCallback(
|
|
1629
|
+
(Ctor, token) => {
|
|
1630
|
+
const recognition = new Ctor();
|
|
1631
|
+
recognition.lang = lang ?? (typeof navigator === "undefined" ? "en-US" : navigator.language || "en-US");
|
|
1632
|
+
recognition.continuous = true;
|
|
1633
|
+
recognition.interimResults = true;
|
|
1634
|
+
recognition.maxAlternatives = 1;
|
|
1635
|
+
recognition.onstart = () => {
|
|
1636
|
+
if (token !== startTokenRef.current) return;
|
|
1637
|
+
setError(null);
|
|
1638
|
+
setListening(true);
|
|
1639
|
+
};
|
|
1640
|
+
recognition.onresult = (event) => {
|
|
1641
|
+
let settled = "";
|
|
1642
|
+
let pending = "";
|
|
1643
|
+
for (let i = event.resultIndex; i < event.results.length; i += 1) {
|
|
1644
|
+
const result = event.results[i];
|
|
1645
|
+
if (!result) continue;
|
|
1646
|
+
const text = result[0]?.transcript ?? "";
|
|
1647
|
+
if (result.isFinal) settled += text;
|
|
1648
|
+
else pending += text;
|
|
1649
|
+
}
|
|
1650
|
+
setInterim(pending);
|
|
1651
|
+
if (settled.trim() !== "") finalRef.current(settled);
|
|
1652
|
+
};
|
|
1653
|
+
recognition.onerror = (event) => {
|
|
1654
|
+
const message = describeError(event.error);
|
|
1655
|
+
setListening(false);
|
|
1656
|
+
setInterim("");
|
|
1657
|
+
if (message !== "") {
|
|
1658
|
+
setError(message);
|
|
1659
|
+
errorRef.current?.(message);
|
|
1660
|
+
}
|
|
1661
|
+
};
|
|
1662
|
+
recognition.onend = () => {
|
|
1663
|
+
setListening(false);
|
|
1664
|
+
setInterim("");
|
|
1665
|
+
};
|
|
1666
|
+
recognitionRef.current = recognition;
|
|
1667
|
+
try {
|
|
1668
|
+
recognition.start();
|
|
1669
|
+
} catch {
|
|
1670
|
+
setListening(false);
|
|
1600
1671
|
}
|
|
1601
|
-
}
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
};
|
|
1606
|
-
recognitionRef.current = recognition;
|
|
1607
|
-
try {
|
|
1608
|
-
recognition.start();
|
|
1609
|
-
} catch {
|
|
1610
|
-
setListening(false);
|
|
1611
|
-
}
|
|
1612
|
-
}, [lang, stop]);
|
|
1672
|
+
},
|
|
1673
|
+
[lang]
|
|
1674
|
+
);
|
|
1675
|
+
beginRecognitionRef.current = beginRecognitionImpl;
|
|
1613
1676
|
const toggle = React.useCallback(() => {
|
|
1614
1677
|
if (listening) stop();
|
|
1615
1678
|
else start();
|
|
@@ -1850,10 +1913,33 @@ function initialOf(value, fallback) {
|
|
|
1850
1913
|
const source = (value || fallback).trim();
|
|
1851
1914
|
return source ? source.slice(0, 1).toUpperCase() : "?";
|
|
1852
1915
|
}
|
|
1916
|
+
function logoUrlOf(url) {
|
|
1917
|
+
try {
|
|
1918
|
+
const { origin, protocol } = new URL(url);
|
|
1919
|
+
if (protocol !== "https:" && protocol !== "http:") return null;
|
|
1920
|
+
return `${origin}/favicon.svg`;
|
|
1921
|
+
} catch {
|
|
1922
|
+
return null;
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1853
1925
|
function ReferenceCard({ reference }) {
|
|
1854
1926
|
const [imageFailed, setImageFailed] = React.useState(false);
|
|
1927
|
+
const [logoFailed, setLogoFailed] = React.useState(false);
|
|
1855
1928
|
const host = hostnameOf(reference.url);
|
|
1929
|
+
const logoUrl = logoUrlOf(reference.url);
|
|
1856
1930
|
const showImage = Boolean(reference.imageUrl) && !imageFailed;
|
|
1931
|
+
const showLogo = Boolean(logoUrl) && !logoFailed;
|
|
1932
|
+
const letterPlate = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full w-full items-center justify-center bg-gradient-to-br from-primary/25 via-primary/5 to-secondary", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold text-primary/70 sm:text-2xl", children: initialOf(reference.product, reference.title || host) }) });
|
|
1933
|
+
const logoImg = showLogo ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1934
|
+
"img",
|
|
1935
|
+
{
|
|
1936
|
+
src: logoUrl ?? "",
|
|
1937
|
+
alt: "",
|
|
1938
|
+
loading: "lazy",
|
|
1939
|
+
onError: () => setLogoFailed(true),
|
|
1940
|
+
className: "h-full w-full object-contain p-1.5 sm:p-0"
|
|
1941
|
+
}
|
|
1942
|
+
) : letterPlate;
|
|
1857
1943
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1858
1944
|
"a",
|
|
1859
1945
|
{
|
|
@@ -1861,9 +1947,10 @@ function ReferenceCard({ reference }) {
|
|
|
1861
1947
|
href: reference.url,
|
|
1862
1948
|
target: "_blank",
|
|
1863
1949
|
rel: "noopener noreferrer",
|
|
1864
|
-
className: "group flex flex-
|
|
1950
|
+
className: "group flex flex-row items-center gap-3 overflow-hidden rounded-xl border border-border bg-card p-2 transition-colors hover:border-primary/40 hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:flex-col sm:items-stretch sm:gap-0 sm:p-0",
|
|
1865
1951
|
children: [
|
|
1866
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative
|
|
1952
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-11 w-11 shrink-0 overflow-hidden rounded-lg bg-muted sm:hidden", children: logoImg }),
|
|
1953
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative hidden aspect-[16/9] w-full overflow-hidden bg-muted sm:block", children: showImage ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1867
1954
|
"img",
|
|
1868
1955
|
{
|
|
1869
1956
|
src: reference.imageUrl ?? "",
|
|
@@ -1872,17 +1959,22 @@ function ReferenceCard({ reference }) {
|
|
|
1872
1959
|
onError: () => setImageFailed(true),
|
|
1873
1960
|
className: "h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"
|
|
1874
1961
|
}
|
|
1875
|
-
) : (
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1962
|
+
) : showLogo ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full w-full items-center justify-center bg-gradient-to-br from-primary/15 via-transparent to-secondary/60 p-6", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1963
|
+
"img",
|
|
1964
|
+
{
|
|
1965
|
+
src: logoUrl ?? "",
|
|
1966
|
+
alt: "",
|
|
1967
|
+
loading: "lazy",
|
|
1968
|
+
onError: () => setLogoFailed(true),
|
|
1969
|
+
className: "max-h-full max-w-full object-contain"
|
|
1970
|
+
}
|
|
1971
|
+
) }) : letterPlate }),
|
|
1972
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5 sm:gap-1.5 sm:p-3", children: [
|
|
1881
1973
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "line-clamp-2 text-sm font-semibold leading-snug text-card-foreground", children: reference.title || host || reference.url }),
|
|
1882
|
-
reference.description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "line-clamp-2 text-xs leading-relaxed text-muted-foreground", children: reference.description }) : null,
|
|
1883
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
1884
|
-
reference.product ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full bg-secondary px-2 py-0.5 text-xs font-medium text-secondary-foreground", children: reference.product }) : null,
|
|
1885
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "
|
|
1974
|
+
reference.description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "line-clamp-2 text-xs leading-relaxed text-muted-foreground max-sm:hidden", children: reference.description }) : null,
|
|
1975
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 sm:mt-auto sm:pt-2", children: [
|
|
1976
|
+
reference.product ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full bg-secondary px-2 py-0.5 text-xs font-medium text-secondary-foreground max-sm:hidden", children: reference.product }) : null,
|
|
1977
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex min-w-0 items-center gap-1 text-xs text-muted-foreground sm:ml-auto", children: [
|
|
1886
1978
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-3 w-3 shrink-0" }),
|
|
1887
1979
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: host })
|
|
1888
1980
|
] })
|
|
@@ -1968,7 +2060,8 @@ function UserBubble({ message }) {
|
|
|
1968
2060
|
function AssistantBubble({
|
|
1969
2061
|
message,
|
|
1970
2062
|
activity,
|
|
1971
|
-
onNavigate
|
|
2063
|
+
onNavigate,
|
|
2064
|
+
anchorRef
|
|
1972
2065
|
}) {
|
|
1973
2066
|
const streaming = message.status === "PENDING" || message.status === "RUNNING";
|
|
1974
2067
|
const body = message.content || message.partialContent || "";
|
|
@@ -1976,9 +2069,10 @@ function AssistantBubble({
|
|
|
1976
2069
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1977
2070
|
"div",
|
|
1978
2071
|
{
|
|
2072
|
+
ref: anchorRef,
|
|
1979
2073
|
"data-boff-explore": "assistant",
|
|
1980
2074
|
"data-status": message.status,
|
|
1981
|
-
className: "flex gap-3",
|
|
2075
|
+
className: "flex scroll-mt-4 gap-3",
|
|
1982
2076
|
children: [
|
|
1983
2077
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1984
2078
|
"span",
|
|
@@ -2207,6 +2301,8 @@ function ExplorePage({
|
|
|
2207
2301
|
});
|
|
2208
2302
|
speechStopRef.current = speech.stop;
|
|
2209
2303
|
const scrollRef = React.useRef(null);
|
|
2304
|
+
const latestAssistantRef = React.useRef(null);
|
|
2305
|
+
const alignedForRef = React.useRef(null);
|
|
2210
2306
|
const stickToBottomRef = React.useRef(true);
|
|
2211
2307
|
const composingRef = React.useRef(false);
|
|
2212
2308
|
const busy = phase === "sending" || phase === "streaming";
|
|
@@ -2232,12 +2328,32 @@ function ExplorePage({
|
|
|
2232
2328
|
if (!el) return;
|
|
2233
2329
|
stickToBottomRef.current = el.scrollHeight - el.scrollTop - el.clientHeight < 80;
|
|
2234
2330
|
}, []);
|
|
2331
|
+
const latestAssistantId = React.useMemo(() => {
|
|
2332
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
2333
|
+
const message = messages[i];
|
|
2334
|
+
if (message && message.role === "ASSISTANT") return message.id;
|
|
2335
|
+
}
|
|
2336
|
+
return null;
|
|
2337
|
+
}, [messages]);
|
|
2235
2338
|
React.useEffect(() => {
|
|
2339
|
+
const el = scrollRef.current;
|
|
2340
|
+
const anchor = latestAssistantRef.current;
|
|
2341
|
+
if (!el || !anchor || !latestAssistantId) return;
|
|
2342
|
+
if (alignedForRef.current === latestAssistantId) return;
|
|
2236
2343
|
if (!stickToBottomRef.current) return;
|
|
2344
|
+
if (anchor.offsetHeight === 0) return;
|
|
2345
|
+
alignedForRef.current = latestAssistantId;
|
|
2346
|
+
const delta = anchor.getBoundingClientRect().top - el.getBoundingClientRect().top;
|
|
2347
|
+
el.scrollTop = Math.max(0, el.scrollTop + delta - 12);
|
|
2348
|
+
}, [latestAssistantId, messages]);
|
|
2349
|
+
React.useEffect(() => {
|
|
2350
|
+
if (!stickToBottomRef.current) return;
|
|
2351
|
+
if (latestAssistantId && alignedForRef.current === latestAssistantId)
|
|
2352
|
+
return;
|
|
2237
2353
|
const el = scrollRef.current;
|
|
2238
2354
|
if (!el) return;
|
|
2239
2355
|
el.scrollTop = el.scrollHeight;
|
|
2240
|
-
}, [
|
|
2356
|
+
}, [activity, latestAssistantId, messages]);
|
|
2241
2357
|
const submitDraft = React.useCallback(() => {
|
|
2242
2358
|
const text = draft.trim();
|
|
2243
2359
|
if (!text || overLimit || busy || !canSend) return;
|
|
@@ -2437,7 +2553,8 @@ function ExplorePage({
|
|
|
2437
2553
|
{
|
|
2438
2554
|
message,
|
|
2439
2555
|
activity,
|
|
2440
|
-
onNavigate
|
|
2556
|
+
onNavigate,
|
|
2557
|
+
anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0
|
|
2441
2558
|
},
|
|
2442
2559
|
message.id
|
|
2443
2560
|
)
|
|
@@ -2622,5 +2739,6 @@ function ExplorePage({
|
|
|
2622
2739
|
}
|
|
2623
2740
|
|
|
2624
2741
|
exports.ExplorePage = ExplorePage;
|
|
2742
|
+
exports.logoUrlOf = logoUrlOf;
|
|
2625
2743
|
//# sourceMappingURL=explore.js.map
|
|
2626
2744
|
//# sourceMappingURL=explore.js.map
|