@burdenoff/website-sdk 2026.828.3 → 2026.828.5
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/client/index.js.map +1 -1
- package/dist/client/index.mjs.map +1 -1
- package/dist/components/contact.js.map +1 -1
- package/dist/components/contact.mjs.map +1 -1
- package/dist/components/explore-cta.js +9 -7
- package/dist/components/explore-cta.js.map +1 -1
- package/dist/components/explore-cta.mjs +9 -7
- package/dist/components/explore-cta.mjs.map +1 -1
- package/dist/components/explore.js +427 -41
- package/dist/components/explore.js.map +1 -1
- package/dist/components/explore.mjs +429 -43
- package/dist/components/explore.mjs.map +1 -1
- package/dist/components/newsletter.js.map +1 -1
- package/dist/components/newsletter.mjs.map +1 -1
- package/dist/components/partners.js.map +1 -1
- package/dist/components/partners.mjs.map +1 -1
- package/dist/components/pricing.js.map +1 -1
- package/dist/components/pricing.mjs.map +1 -1
- package/dist/components/resource-links.js.map +1 -1
- package/dist/components/resource-links.mjs.map +1 -1
- package/dist/components/social-links.js.map +1 -1
- package/dist/components/social-links.mjs.map +1 -1
- package/dist/components/unsubscribe.js.map +1 -1
- package/dist/components/unsubscribe.mjs.map +1 -1
- package/dist/components/waitlist.js.map +1 -1
- package/dist/components/waitlist.mjs.map +1 -1
- package/dist/content/index.js.map +1 -1
- package/dist/content/index.mjs.map +1 -1
- package/dist/hooks/index.d.mts +24 -1
- package/dist/hooks/index.d.ts +24 -1
- package/dist/hooks/index.js +235 -5
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +235 -6
- 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 +436 -48
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +437 -49
- package/dist/index.mjs.map +1 -1
- package/dist/product/index.js.map +1 -1
- package/dist/product/index.mjs.map +1 -1
- package/dist/store/index.js.map +1 -1
- package/dist/store/index.mjs.map +1 -1
- package/dist/{index-CUJTTlYx.d.mts → use-explore-chat-DhvZhH8f.d.mts} +21 -2
- package/dist/{index-CUJTTlYx.d.ts → use-explore-chat-DhvZhH8f.d.ts} +21 -2
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { createContext, useMemo, useContext, useState, useCallback, useLayoutEffect, useRef, useEffect } from 'react';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
|
-
import { Instagram, Youtube, Facebook, Github, Linkedin, Twitter, Mail, Phone, MapPin, Clock, Send, CheckCircle, Upload, Globe, ChevronDown, Search, Rocket, ArrowRight, Download, Sparkles, RotateCcw, Square, ArrowUp,
|
|
4
|
+
import { Instagram, Youtube, Facebook, Github, Linkedin, Twitter, Mail, Phone, MapPin, Clock, Send, CheckCircle, Upload, Globe, ChevronDown, Search, Rocket, ArrowRight, Download, Sparkles, RotateCcw, History, Trash2, Mic, Square, ArrowUp, BookOpenText, Layers, Link2, TriangleAlert, ChevronLeft, ChevronRight, FileText, ExternalLink } from 'lucide-react';
|
|
5
5
|
import ReCAPTCHA4 from 'react-google-recaptcha';
|
|
6
6
|
import { toast } from 'sonner';
|
|
7
7
|
import { Helmet } from 'react-helmet-async';
|
|
@@ -5246,6 +5246,8 @@ async function getRecaptchaV3Token(siteKey, action = EXPLORE_RECAPTCHA_ACTION) {
|
|
|
5246
5246
|
|
|
5247
5247
|
// src/hooks/use-explore-chat.ts
|
|
5248
5248
|
var DEFAULT_STORAGE_KEY = "boff.explore.v1";
|
|
5249
|
+
var HISTORY_SUFFIX = ".history";
|
|
5250
|
+
var MAX_ARCHIVED_CONVERSATIONS = 15;
|
|
5249
5251
|
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
5250
5252
|
var DEFAULT_POLL_TIMEOUT_MS = 9e4;
|
|
5251
5253
|
var POLL_REQUEST_TIMEOUT_MS = 1e4;
|
|
@@ -5384,10 +5386,58 @@ function classifyExploreError(code, serverMessage) {
|
|
|
5384
5386
|
retryable: true
|
|
5385
5387
|
};
|
|
5386
5388
|
}
|
|
5389
|
+
function historyKey(key) {
|
|
5390
|
+
return `${key}${HISTORY_SUFFIX}`;
|
|
5391
|
+
}
|
|
5392
|
+
function readArchive(key) {
|
|
5393
|
+
if (typeof window === "undefined") return [];
|
|
5394
|
+
try {
|
|
5395
|
+
const raw = window.localStorage.getItem(historyKey(key));
|
|
5396
|
+
if (!raw) return [];
|
|
5397
|
+
const parsed = JSON.parse(raw);
|
|
5398
|
+
if (!Array.isArray(parsed)) return [];
|
|
5399
|
+
return parsed.filter(
|
|
5400
|
+
(entry) => typeof entry === "object" && entry !== null && typeof entry.token === "string" && Array.isArray(entry.messages)
|
|
5401
|
+
);
|
|
5402
|
+
} catch {
|
|
5403
|
+
return [];
|
|
5404
|
+
}
|
|
5405
|
+
}
|
|
5406
|
+
function writeArchive(key, entries) {
|
|
5407
|
+
if (typeof window === "undefined") return;
|
|
5408
|
+
try {
|
|
5409
|
+
if (entries.length === 0) {
|
|
5410
|
+
window.localStorage.removeItem(historyKey(key));
|
|
5411
|
+
return;
|
|
5412
|
+
}
|
|
5413
|
+
window.localStorage.setItem(historyKey(key), JSON.stringify(entries));
|
|
5414
|
+
} catch {
|
|
5415
|
+
}
|
|
5416
|
+
}
|
|
5417
|
+
function upsertArchive(key, thread) {
|
|
5418
|
+
if (!thread.token) return readArchive(key);
|
|
5419
|
+
const real = thread.messages.filter(
|
|
5420
|
+
(m) => m.content.trim() !== "" || m.role === "USER"
|
|
5421
|
+
);
|
|
5422
|
+
if (real.length === 0) return readArchive(key);
|
|
5423
|
+
const firstUser = real.find((m) => m.role === "USER");
|
|
5424
|
+
const entry = {
|
|
5425
|
+
token: thread.token,
|
|
5426
|
+
title: (firstUser?.content ?? "Conversation").trim().slice(0, 80),
|
|
5427
|
+
updatedAt: real[real.length - 1]?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
5428
|
+
messageCount: real.length,
|
|
5429
|
+
focusProduct: thread.focusProduct,
|
|
5430
|
+
messages: real.slice(-20)
|
|
5431
|
+
};
|
|
5432
|
+
const rest = readArchive(key).filter((e) => e.token !== entry.token);
|
|
5433
|
+
const next = [entry, ...rest].slice(0, MAX_ARCHIVED_CONVERSATIONS);
|
|
5434
|
+
writeArchive(key, next);
|
|
5435
|
+
return next;
|
|
5436
|
+
}
|
|
5387
5437
|
function readPersisted(key) {
|
|
5388
5438
|
if (typeof window === "undefined") return null;
|
|
5389
5439
|
try {
|
|
5390
|
-
const raw = window.
|
|
5440
|
+
const raw = window.localStorage.getItem(key);
|
|
5391
5441
|
if (!raw) return null;
|
|
5392
5442
|
const parsed = JSON.parse(raw);
|
|
5393
5443
|
if (!parsed || typeof parsed !== "object") return null;
|
|
@@ -5432,6 +5482,8 @@ function useExploreChat(options = {}) {
|
|
|
5432
5482
|
const [remainingToday, setRemainingToday] = useState(null);
|
|
5433
5483
|
const [focusProduct, setFocusProductState] = useState(null);
|
|
5434
5484
|
const [turnCount, setTurnCount] = useState(0);
|
|
5485
|
+
const messagesRef = useRef([]);
|
|
5486
|
+
const [archive, setArchive] = useState([]);
|
|
5435
5487
|
const [hydrated, setHydrated] = useState(false);
|
|
5436
5488
|
const mountedRef = useRef(true);
|
|
5437
5489
|
const pollGenerationRef = useRef(0);
|
|
@@ -5469,6 +5521,7 @@ function useExploreChat(options = {}) {
|
|
|
5469
5521
|
setHydrated(true);
|
|
5470
5522
|
return;
|
|
5471
5523
|
}
|
|
5524
|
+
setArchive(readArchive(storageKey));
|
|
5472
5525
|
const stored = readPersisted(storageKey);
|
|
5473
5526
|
if (stored) {
|
|
5474
5527
|
conversationTokenRef.current = stored.conversationToken;
|
|
@@ -5497,13 +5550,28 @@ function useExploreChat(options = {}) {
|
|
|
5497
5550
|
focusProduct
|
|
5498
5551
|
};
|
|
5499
5552
|
if (!payload.conversationToken && payload.messages.length === 0 && !payload.focusProduct) {
|
|
5500
|
-
window.
|
|
5553
|
+
window.localStorage.removeItem(storageKey);
|
|
5501
5554
|
return;
|
|
5502
5555
|
}
|
|
5503
|
-
window.
|
|
5556
|
+
window.localStorage.setItem(storageKey, JSON.stringify(payload));
|
|
5504
5557
|
} catch {
|
|
5505
5558
|
}
|
|
5506
5559
|
}, [persist, hydrated, storageKey, messages, focusProduct]);
|
|
5560
|
+
useEffect(() => {
|
|
5561
|
+
messagesRef.current = messages;
|
|
5562
|
+
if (!persist || !hydrated) return;
|
|
5563
|
+
const settled = messages.some(
|
|
5564
|
+
(m) => m.role === "ASSISTANT" && (m.status === "COMPLETED" || m.status === "FAILED")
|
|
5565
|
+
);
|
|
5566
|
+
if (!settled) return;
|
|
5567
|
+
setArchive(
|
|
5568
|
+
upsertArchive(storageKey, {
|
|
5569
|
+
token: conversationTokenRef.current,
|
|
5570
|
+
messages,
|
|
5571
|
+
focusProduct: focusProductRef.current
|
|
5572
|
+
})
|
|
5573
|
+
);
|
|
5574
|
+
}, [messages, persist, hydrated, storageKey]);
|
|
5507
5575
|
useEffect(() => {
|
|
5508
5576
|
let cancelled = false;
|
|
5509
5577
|
const load = async () => {
|
|
@@ -5789,6 +5857,13 @@ function useExploreChat(options = {}) {
|
|
|
5789
5857
|
void send(text);
|
|
5790
5858
|
}, [cancelPolling, send]);
|
|
5791
5859
|
const reset = useCallback(() => {
|
|
5860
|
+
setArchive(
|
|
5861
|
+
upsertArchive(storageKey, {
|
|
5862
|
+
token: conversationTokenRef.current,
|
|
5863
|
+
messages: messagesRef.current,
|
|
5864
|
+
focusProduct: focusProductRef.current
|
|
5865
|
+
})
|
|
5866
|
+
);
|
|
5792
5867
|
cancelPolling();
|
|
5793
5868
|
inFlightRef.current = false;
|
|
5794
5869
|
conversationTokenRef.current = null;
|
|
@@ -5801,11 +5876,48 @@ function useExploreChat(options = {}) {
|
|
|
5801
5876
|
setPhase(catalogRef.current.enabled ? "ready" : "disabled");
|
|
5802
5877
|
if (typeof window !== "undefined") {
|
|
5803
5878
|
try {
|
|
5804
|
-
window.
|
|
5879
|
+
window.localStorage.removeItem(storageKey);
|
|
5805
5880
|
} catch {
|
|
5806
5881
|
}
|
|
5807
5882
|
}
|
|
5808
5883
|
}, [cancelPolling, storageKey]);
|
|
5884
|
+
const openConversation = useCallback(
|
|
5885
|
+
(token) => {
|
|
5886
|
+
const entry = readArchive(storageKey).find((e) => e.token === token);
|
|
5887
|
+
if (!entry) return;
|
|
5888
|
+
upsertArchive(storageKey, {
|
|
5889
|
+
token: conversationTokenRef.current,
|
|
5890
|
+
messages: messagesRef.current,
|
|
5891
|
+
focusProduct: focusProductRef.current
|
|
5892
|
+
});
|
|
5893
|
+
cancelPolling();
|
|
5894
|
+
inFlightRef.current = false;
|
|
5895
|
+
conversationTokenRef.current = entry.token;
|
|
5896
|
+
turnCountRef.current = entry.messages.filter(
|
|
5897
|
+
(m) => m.role === "USER"
|
|
5898
|
+
).length;
|
|
5899
|
+
setTurnCount(turnCountRef.current);
|
|
5900
|
+
setMessages(entry.messages);
|
|
5901
|
+
focusProductRef.current = entry.focusProduct;
|
|
5902
|
+
setFocusProductState(entry.focusProduct);
|
|
5903
|
+
setError(null);
|
|
5904
|
+
setPhase(catalogRef.current.enabled ? "ready" : "disabled");
|
|
5905
|
+
setArchive(readArchive(storageKey));
|
|
5906
|
+
},
|
|
5907
|
+
[cancelPolling, storageKey]
|
|
5908
|
+
);
|
|
5909
|
+
const deleteConversation = useCallback(
|
|
5910
|
+
(token) => {
|
|
5911
|
+
const next = readArchive(storageKey).filter((e) => e.token !== token);
|
|
5912
|
+
writeArchive(storageKey, next);
|
|
5913
|
+
setArchive(next);
|
|
5914
|
+
},
|
|
5915
|
+
[storageKey]
|
|
5916
|
+
);
|
|
5917
|
+
const clearHistory = useCallback(() => {
|
|
5918
|
+
writeArchive(storageKey, []);
|
|
5919
|
+
setArchive([]);
|
|
5920
|
+
}, [storageKey]);
|
|
5809
5921
|
const setFocusProduct = useCallback((slug) => {
|
|
5810
5922
|
focusProductRef.current = slug;
|
|
5811
5923
|
setFocusProductState(slug);
|
|
@@ -5834,7 +5946,11 @@ function useExploreChat(options = {}) {
|
|
|
5834
5946
|
stop,
|
|
5835
5947
|
retry,
|
|
5836
5948
|
reset,
|
|
5837
|
-
canSend
|
|
5949
|
+
canSend,
|
|
5950
|
+
history: archive,
|
|
5951
|
+
openConversation,
|
|
5952
|
+
deleteConversation,
|
|
5953
|
+
clearHistory
|
|
5838
5954
|
};
|
|
5839
5955
|
}
|
|
5840
5956
|
var optimisticCounter = 0;
|
|
@@ -5842,6 +5958,119 @@ function makeOptimisticId() {
|
|
|
5842
5958
|
optimisticCounter += 1;
|
|
5843
5959
|
return `boff-explore-local-${Date.now()}-${optimisticCounter}`;
|
|
5844
5960
|
}
|
|
5961
|
+
function getRecognitionCtor() {
|
|
5962
|
+
if (typeof window === "undefined") return null;
|
|
5963
|
+
const w = window;
|
|
5964
|
+
return w.SpeechRecognition ?? w.webkitSpeechRecognition ?? null;
|
|
5965
|
+
}
|
|
5966
|
+
function describeError(code) {
|
|
5967
|
+
switch (code) {
|
|
5968
|
+
case "not-allowed":
|
|
5969
|
+
case "service-not-allowed":
|
|
5970
|
+
return "Microphone access was blocked. Allow it in your browser's site settings to dictate.";
|
|
5971
|
+
case "no-speech":
|
|
5972
|
+
return "I didn't catch anything \u2014 try again a little closer to the mic.";
|
|
5973
|
+
case "audio-capture":
|
|
5974
|
+
return "No microphone was found.";
|
|
5975
|
+
case "network":
|
|
5976
|
+
return "Speech recognition needs a network connection.";
|
|
5977
|
+
case "aborted":
|
|
5978
|
+
return "";
|
|
5979
|
+
default:
|
|
5980
|
+
return "Dictation stopped unexpectedly. You can type instead.";
|
|
5981
|
+
}
|
|
5982
|
+
}
|
|
5983
|
+
function useSpeechInput({
|
|
5984
|
+
onFinalTranscript,
|
|
5985
|
+
lang,
|
|
5986
|
+
onError
|
|
5987
|
+
}) {
|
|
5988
|
+
const [supported] = useState(() => getRecognitionCtor() !== null);
|
|
5989
|
+
const [listening, setListening] = useState(false);
|
|
5990
|
+
const [interim, setInterim] = useState("");
|
|
5991
|
+
const [error, setError] = useState(null);
|
|
5992
|
+
const recognitionRef = useRef(null);
|
|
5993
|
+
const finalRef = useRef(onFinalTranscript);
|
|
5994
|
+
const errorRef = useRef(onError);
|
|
5995
|
+
finalRef.current = onFinalTranscript;
|
|
5996
|
+
errorRef.current = onError;
|
|
5997
|
+
const stop = useCallback(() => {
|
|
5998
|
+
const recognition = recognitionRef.current;
|
|
5999
|
+
if (!recognition) return;
|
|
6000
|
+
try {
|
|
6001
|
+
recognition.stop();
|
|
6002
|
+
} catch {
|
|
6003
|
+
}
|
|
6004
|
+
setListening(false);
|
|
6005
|
+
setInterim("");
|
|
6006
|
+
}, []);
|
|
6007
|
+
const start = useCallback(() => {
|
|
6008
|
+
const Ctor = getRecognitionCtor();
|
|
6009
|
+
if (!Ctor) return;
|
|
6010
|
+
if (recognitionRef.current) stop();
|
|
6011
|
+
const recognition = new Ctor();
|
|
6012
|
+
recognition.lang = lang ?? (typeof navigator === "undefined" ? "en-US" : navigator.language || "en-US");
|
|
6013
|
+
recognition.continuous = true;
|
|
6014
|
+
recognition.interimResults = true;
|
|
6015
|
+
recognition.maxAlternatives = 1;
|
|
6016
|
+
recognition.onstart = () => {
|
|
6017
|
+
setError(null);
|
|
6018
|
+
setListening(true);
|
|
6019
|
+
};
|
|
6020
|
+
recognition.onresult = (event) => {
|
|
6021
|
+
let settled = "";
|
|
6022
|
+
let pending = "";
|
|
6023
|
+
for (let i = event.resultIndex; i < event.results.length; i += 1) {
|
|
6024
|
+
const result = event.results[i];
|
|
6025
|
+
if (!result) continue;
|
|
6026
|
+
const text = result[0]?.transcript ?? "";
|
|
6027
|
+
if (result.isFinal) settled += text;
|
|
6028
|
+
else pending += text;
|
|
6029
|
+
}
|
|
6030
|
+
setInterim(pending);
|
|
6031
|
+
if (settled.trim() !== "") finalRef.current(settled);
|
|
6032
|
+
};
|
|
6033
|
+
recognition.onerror = (event) => {
|
|
6034
|
+
const message = describeError(event.error);
|
|
6035
|
+
setListening(false);
|
|
6036
|
+
setInterim("");
|
|
6037
|
+
if (message !== "") {
|
|
6038
|
+
setError(message);
|
|
6039
|
+
errorRef.current?.(message);
|
|
6040
|
+
}
|
|
6041
|
+
};
|
|
6042
|
+
recognition.onend = () => {
|
|
6043
|
+
setListening(false);
|
|
6044
|
+
setInterim("");
|
|
6045
|
+
};
|
|
6046
|
+
recognitionRef.current = recognition;
|
|
6047
|
+
try {
|
|
6048
|
+
recognition.start();
|
|
6049
|
+
} catch {
|
|
6050
|
+
setListening(false);
|
|
6051
|
+
}
|
|
6052
|
+
}, [lang, stop]);
|
|
6053
|
+
const toggle = useCallback(() => {
|
|
6054
|
+
if (listening) stop();
|
|
6055
|
+
else start();
|
|
6056
|
+
}, [listening, start, stop]);
|
|
6057
|
+
useEffect(
|
|
6058
|
+
() => () => {
|
|
6059
|
+
const recognition = recognitionRef.current;
|
|
6060
|
+
if (!recognition) return;
|
|
6061
|
+
recognition.onresult = null;
|
|
6062
|
+
recognition.onerror = null;
|
|
6063
|
+
recognition.onend = null;
|
|
6064
|
+
recognition.onstart = null;
|
|
6065
|
+
try {
|
|
6066
|
+
recognition.abort();
|
|
6067
|
+
} catch {
|
|
6068
|
+
}
|
|
6069
|
+
},
|
|
6070
|
+
[]
|
|
6071
|
+
);
|
|
6072
|
+
return { supported, listening, interim, error, start, stop, toggle };
|
|
6073
|
+
}
|
|
5845
6074
|
var EXPLORE_CSS = `
|
|
5846
6075
|
@keyframes boff-explore-pulse {
|
|
5847
6076
|
0%, 80%, 100% { opacity: 0.25; transform: translateY(0); }
|
|
@@ -6269,10 +6498,29 @@ function ExplorePage({
|
|
|
6269
6498
|
stop,
|
|
6270
6499
|
retry,
|
|
6271
6500
|
reset,
|
|
6272
|
-
canSend
|
|
6501
|
+
canSend,
|
|
6502
|
+
history,
|
|
6503
|
+
openConversation,
|
|
6504
|
+
deleteConversation,
|
|
6505
|
+
clearHistory
|
|
6273
6506
|
} = useExploreChat({ productSlug, pageUrl, onSend, examplePrompts });
|
|
6274
6507
|
const [draft, setDraft] = useState("");
|
|
6275
6508
|
const textareaRef = useRef(null);
|
|
6509
|
+
const [historyOpen, setHistoryOpen] = useState(false);
|
|
6510
|
+
const speechStopRef = useRef(() => void 0);
|
|
6511
|
+
const stopDictation = useCallback(() => {
|
|
6512
|
+
speechStopRef.current();
|
|
6513
|
+
}, []);
|
|
6514
|
+
const speech = useSpeechInput({
|
|
6515
|
+
onFinalTranscript: (text) => {
|
|
6516
|
+
setDraft((current) => {
|
|
6517
|
+
const joined = current.trim() === "" ? text.trimStart() : `${current.trimEnd()} ${text.trim()}`;
|
|
6518
|
+
return joined;
|
|
6519
|
+
});
|
|
6520
|
+
textareaRef.current?.focus();
|
|
6521
|
+
}
|
|
6522
|
+
});
|
|
6523
|
+
speechStopRef.current = speech.stop;
|
|
6276
6524
|
const scrollRef = useRef(null);
|
|
6277
6525
|
const stickToBottomRef = useRef(true);
|
|
6278
6526
|
const composingRef = useRef(false);
|
|
@@ -6308,11 +6556,12 @@ function ExplorePage({
|
|
|
6308
6556
|
const submitDraft = useCallback(() => {
|
|
6309
6557
|
const text = draft.trim();
|
|
6310
6558
|
if (!text || overLimit || busy || !canSend) return;
|
|
6559
|
+
stopDictation();
|
|
6311
6560
|
setDraft("");
|
|
6312
6561
|
stickToBottomRef.current = true;
|
|
6313
6562
|
void send(text);
|
|
6314
6563
|
textareaRef.current?.focus();
|
|
6315
|
-
}, [busy, canSend, draft, overLimit, send]);
|
|
6564
|
+
}, [busy, canSend, draft, overLimit, send, stopDictation]);
|
|
6316
6565
|
const sendPrompt = useCallback(
|
|
6317
6566
|
(prompt) => {
|
|
6318
6567
|
if (!canSend || busy) return;
|
|
@@ -6385,8 +6634,96 @@ function ExplorePage({
|
|
|
6385
6634
|
/* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "New chat" })
|
|
6386
6635
|
]
|
|
6387
6636
|
}
|
|
6388
|
-
)
|
|
6637
|
+
),
|
|
6638
|
+
history.length > 0 ? /* @__PURE__ */ jsxs(
|
|
6639
|
+
Button,
|
|
6640
|
+
{
|
|
6641
|
+
"data-boff-explore": "history-toggle",
|
|
6642
|
+
type: "button",
|
|
6643
|
+
size: "sm",
|
|
6644
|
+
variant: "ghost",
|
|
6645
|
+
className: "shrink-0 text-muted-foreground",
|
|
6646
|
+
"aria-expanded": historyOpen,
|
|
6647
|
+
onClick: () => {
|
|
6648
|
+
setHistoryOpen((open) => !open);
|
|
6649
|
+
},
|
|
6650
|
+
children: [
|
|
6651
|
+
/* @__PURE__ */ jsx(History, { className: "h-3.5 w-3.5" }),
|
|
6652
|
+
/* @__PURE__ */ jsxs("span", { className: "hidden sm:inline", children: [
|
|
6653
|
+
"History (",
|
|
6654
|
+
history.length,
|
|
6655
|
+
")"
|
|
6656
|
+
] })
|
|
6657
|
+
]
|
|
6658
|
+
}
|
|
6659
|
+
) : null
|
|
6389
6660
|
] }) : null,
|
|
6661
|
+
historyOpen && history.length > 0 ? /* @__PURE__ */ jsx(
|
|
6662
|
+
"div",
|
|
6663
|
+
{
|
|
6664
|
+
"data-boff-explore": "history-panel",
|
|
6665
|
+
className: "border-b border-border bg-muted/30 px-4 py-3",
|
|
6666
|
+
children: /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-3xl", children: [
|
|
6667
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
|
|
6668
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Your recent conversations" }),
|
|
6669
|
+
/* @__PURE__ */ jsxs(
|
|
6670
|
+
Button,
|
|
6671
|
+
{
|
|
6672
|
+
"data-boff-explore": "history-clear",
|
|
6673
|
+
type: "button",
|
|
6674
|
+
size: "sm",
|
|
6675
|
+
variant: "ghost",
|
|
6676
|
+
className: "h-7 shrink-0 text-xs text-muted-foreground hover:text-destructive",
|
|
6677
|
+
onClick: () => {
|
|
6678
|
+
clearHistory();
|
|
6679
|
+
setHistoryOpen(false);
|
|
6680
|
+
},
|
|
6681
|
+
children: [
|
|
6682
|
+
/* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" }),
|
|
6683
|
+
"Clear history"
|
|
6684
|
+
]
|
|
6685
|
+
}
|
|
6686
|
+
)
|
|
6687
|
+
] }),
|
|
6688
|
+
/* @__PURE__ */ jsx("ul", { className: "space-y-1", children: history.map((entry) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-1", children: [
|
|
6689
|
+
/* @__PURE__ */ jsxs(
|
|
6690
|
+
"button",
|
|
6691
|
+
{
|
|
6692
|
+
"data-boff-explore": "history-item",
|
|
6693
|
+
type: "button",
|
|
6694
|
+
className: "flex-1 truncate rounded-md px-2 py-1.5 text-left text-sm text-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
|
|
6695
|
+
onClick: () => {
|
|
6696
|
+
openConversation(entry.token);
|
|
6697
|
+
setHistoryOpen(false);
|
|
6698
|
+
},
|
|
6699
|
+
children: [
|
|
6700
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: entry.title }),
|
|
6701
|
+
/* @__PURE__ */ jsxs("span", { className: "ml-2 text-xs text-muted-foreground", children: [
|
|
6702
|
+
entry.messageCount,
|
|
6703
|
+
" message",
|
|
6704
|
+
entry.messageCount === 1 ? "" : "s"
|
|
6705
|
+
] })
|
|
6706
|
+
]
|
|
6707
|
+
}
|
|
6708
|
+
),
|
|
6709
|
+
/* @__PURE__ */ jsx(
|
|
6710
|
+
Button,
|
|
6711
|
+
{
|
|
6712
|
+
type: "button",
|
|
6713
|
+
size: "icon",
|
|
6714
|
+
variant: "ghost",
|
|
6715
|
+
className: "h-7 w-7 shrink-0 text-muted-foreground hover:text-destructive",
|
|
6716
|
+
"aria-label": `Delete conversation: ${entry.title}`,
|
|
6717
|
+
onClick: () => {
|
|
6718
|
+
deleteConversation(entry.token);
|
|
6719
|
+
},
|
|
6720
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
|
|
6721
|
+
}
|
|
6722
|
+
)
|
|
6723
|
+
] }, entry.token)) })
|
|
6724
|
+
] })
|
|
6725
|
+
}
|
|
6726
|
+
) : null,
|
|
6390
6727
|
/* @__PURE__ */ jsx(
|
|
6391
6728
|
"div",
|
|
6392
6729
|
{
|
|
@@ -6461,6 +6798,23 @@ function ExplorePage({
|
|
|
6461
6798
|
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"
|
|
6462
6799
|
}
|
|
6463
6800
|
),
|
|
6801
|
+
speech.supported ? /* @__PURE__ */ jsx(
|
|
6802
|
+
Button,
|
|
6803
|
+
{
|
|
6804
|
+
"data-boff-explore": "mic",
|
|
6805
|
+
"data-listening": speech.listening ? "true" : "false",
|
|
6806
|
+
type: "button",
|
|
6807
|
+
size: "icon",
|
|
6808
|
+
variant: speech.listening ? "default" : "ghost",
|
|
6809
|
+
disabled: composerDisabled,
|
|
6810
|
+
"aria-label": speech.listening ? "Stop dictating" : "Dictate your question",
|
|
6811
|
+
"aria-pressed": speech.listening,
|
|
6812
|
+
title: speech.listening ? "Stop dictating" : "Dictate your question",
|
|
6813
|
+
onClick: speech.toggle,
|
|
6814
|
+
className: cn(speech.listening && "animate-pulse"),
|
|
6815
|
+
children: /* @__PURE__ */ jsx(Mic, { className: "h-4 w-4" })
|
|
6816
|
+
}
|
|
6817
|
+
) : null,
|
|
6464
6818
|
busy ? /* @__PURE__ */ jsx(
|
|
6465
6819
|
Button,
|
|
6466
6820
|
{
|
|
@@ -6486,6 +6840,29 @@ function ExplorePage({
|
|
|
6486
6840
|
]
|
|
6487
6841
|
}
|
|
6488
6842
|
),
|
|
6843
|
+
speech.listening || speech.interim !== "" ? /* @__PURE__ */ jsxs(
|
|
6844
|
+
"p",
|
|
6845
|
+
{
|
|
6846
|
+
"data-boff-explore": "dictation",
|
|
6847
|
+
className: "mt-2 flex items-center gap-2 text-xs text-muted-foreground",
|
|
6848
|
+
"aria-live": "polite",
|
|
6849
|
+
children: [
|
|
6850
|
+
/* @__PURE__ */ jsxs("span", { className: "relative flex h-2 w-2 shrink-0", children: [
|
|
6851
|
+
/* @__PURE__ */ jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-primary opacity-75" }),
|
|
6852
|
+
/* @__PURE__ */ jsx("span", { className: "relative inline-flex h-2 w-2 rounded-full bg-primary" })
|
|
6853
|
+
] }),
|
|
6854
|
+
/* @__PURE__ */ jsx("span", { className: "italic", children: speech.interim !== "" ? speech.interim : "Listening\u2026" })
|
|
6855
|
+
]
|
|
6856
|
+
}
|
|
6857
|
+
) : null,
|
|
6858
|
+
speech.error !== null ? /* @__PURE__ */ jsx(
|
|
6859
|
+
"p",
|
|
6860
|
+
{
|
|
6861
|
+
"data-boff-explore": "dictation-error",
|
|
6862
|
+
className: "mt-2 text-xs text-destructive",
|
|
6863
|
+
children: speech.error
|
|
6864
|
+
}
|
|
6865
|
+
) : null,
|
|
6489
6866
|
/* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
|
|
6490
6867
|
/* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Enter to send \xB7 Shift + Enter for a new line" }),
|
|
6491
6868
|
remainingToday !== null ? /* @__PURE__ */ jsxs("span", { "data-boff-explore": "remaining", children: [
|
|
@@ -6509,39 +6886,48 @@ function ExplorePage({
|
|
|
6509
6886
|
}
|
|
6510
6887
|
)
|
|
6511
6888
|
] }),
|
|
6512
|
-
/* @__PURE__ */ jsxs(
|
|
6513
|
-
"
|
|
6514
|
-
|
|
6515
|
-
" ",
|
|
6516
|
-
"
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
"
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6889
|
+
/* @__PURE__ */ jsxs(
|
|
6890
|
+
"p",
|
|
6891
|
+
{
|
|
6892
|
+
"data-boff-explore": "disclaimer",
|
|
6893
|
+
className: "mt-2 text-xs leading-relaxed text-muted-foreground",
|
|
6894
|
+
children: [
|
|
6895
|
+
"Answers are generated from our public documentation and can be imperfect \u2014 check anything important against the linked sources.",
|
|
6896
|
+
" ",
|
|
6897
|
+
"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.",
|
|
6898
|
+
captchaOn ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6899
|
+
" ",
|
|
6900
|
+
"This site is protected by reCAPTCHA; the Google",
|
|
6901
|
+
" ",
|
|
6902
|
+
/* @__PURE__ */ jsx(
|
|
6903
|
+
"a",
|
|
6904
|
+
{
|
|
6905
|
+
href: "https://policies.google.com/privacy",
|
|
6906
|
+
target: "_blank",
|
|
6907
|
+
rel: "noopener noreferrer",
|
|
6908
|
+
className: "underline underline-offset-2 hover:text-foreground",
|
|
6909
|
+
children: "Privacy Policy"
|
|
6910
|
+
}
|
|
6911
|
+
),
|
|
6912
|
+
" ",
|
|
6913
|
+
"and",
|
|
6914
|
+
" ",
|
|
6915
|
+
/* @__PURE__ */ jsx(
|
|
6916
|
+
"a",
|
|
6917
|
+
{
|
|
6918
|
+
href: "https://policies.google.com/terms",
|
|
6919
|
+
target: "_blank",
|
|
6920
|
+
rel: "noopener noreferrer",
|
|
6921
|
+
className: "underline underline-offset-2 hover:text-foreground",
|
|
6922
|
+
children: "Terms of Service"
|
|
6923
|
+
}
|
|
6924
|
+
),
|
|
6925
|
+
" ",
|
|
6926
|
+
"apply."
|
|
6927
|
+
] }) : null
|
|
6928
|
+
]
|
|
6929
|
+
}
|
|
6930
|
+
)
|
|
6545
6931
|
]
|
|
6546
6932
|
}
|
|
6547
6933
|
) })
|
|
@@ -6591,11 +6977,12 @@ function ExploreCta({
|
|
|
6591
6977
|
onNavigate(href);
|
|
6592
6978
|
};
|
|
6593
6979
|
const classes = {
|
|
6594
|
-
//
|
|
6595
|
-
//
|
|
6596
|
-
//
|
|
6597
|
-
//
|
|
6598
|
-
|
|
6980
|
+
// A quiet icon control, deliberately NOT a second gradient pill: a header should carry one
|
|
6981
|
+
// primary CTA ("Get started"), and a competing coloured button next to it reads as clutter.
|
|
6982
|
+
// This matches the theme toggle's visual weight, so the row scans as [utilities] [CTA].
|
|
6983
|
+
// The prominent, labelled entry point to /explore is the floating bubble, which is visible
|
|
6984
|
+
// on every page without scrolling. `shrink-0` keeps it from squeezing the nav.
|
|
6985
|
+
header: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
|
|
6599
6986
|
mobile: "inline-flex w-full items-center gap-2 rounded-lg border border-border bg-card px-3 py-2 text-sm font-medium text-card-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
|
|
6600
6987
|
floating: "fixed bottom-5 right-5 z-40 inline-flex items-center gap-2 rounded-full bg-gradient-to-r from-primary to-primary/70 px-4 py-3 text-sm font-medium text-primary-foreground shadow-lg transition-opacity hover:opacity-90"
|
|
6601
6988
|
};
|
|
@@ -6623,7 +7010,7 @@ function ExploreCta({
|
|
|
6623
7010
|
{
|
|
6624
7011
|
className: cn(
|
|
6625
7012
|
"shrink-0",
|
|
6626
|
-
variant === "floating" ? "h-4 w-4" : "h-3.5 w-3.5"
|
|
7013
|
+
variant === "floating" ? "h-4 w-4" : variant === "header" ? "h-5 w-5" : "h-3.5 w-3.5"
|
|
6627
7014
|
),
|
|
6628
7015
|
"aria-hidden": "true"
|
|
6629
7016
|
}
|
|
@@ -6633,7 +7020,8 @@ function ExploreCta({
|
|
|
6633
7020
|
{
|
|
6634
7021
|
className: cn(
|
|
6635
7022
|
variant === "floating" && "hidden sm:inline",
|
|
6636
|
-
|
|
7023
|
+
// Never labelled in the header — see the class comment above.
|
|
7024
|
+
variant === "header" && "hidden"
|
|
6637
7025
|
),
|
|
6638
7026
|
children: label
|
|
6639
7027
|
}
|