@akropolys/kiku 1.6.3 → 1.6.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/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +119 -87
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +119 -87
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +22 -3
- package/dist/styles.css.map +1 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -4,7 +4,7 @@ import { SearchResult, AkropolysTheme, ChatSource, Product, VisualSearchResponse
|
|
|
4
4
|
interface SearchBarProps {
|
|
5
5
|
placeholder?: string;
|
|
6
6
|
limit?: number;
|
|
7
|
-
/** Debounce in ms — default
|
|
7
|
+
/** Debounce in ms — default 150 for instant type-ahead */
|
|
8
8
|
debounceMs?: number;
|
|
9
9
|
onSelect?: (result: SearchResult) => void;
|
|
10
10
|
className?: string;
|
|
@@ -65,12 +65,15 @@ interface KikuButtonProps {
|
|
|
65
65
|
};
|
|
66
66
|
/** Enable 🎙️ voice input via browser Web Speech API (free) */
|
|
67
67
|
enableVoice?: boolean;
|
|
68
|
+
/** BCP-47 tag for voice transcription (e.g. 'sw-KE', 'fr-FR'). Defaults to
|
|
69
|
+
the page's <html lang>, then the browser language. */
|
|
70
|
+
voiceLang?: string;
|
|
68
71
|
/** Enable 📷 visual style-match search via Gemini (requires backend GEMINI_API_KEY) */
|
|
69
72
|
enableVision?: boolean;
|
|
70
73
|
/** Optional category hint for visual search (e.g. 'dress', 'curtains') */
|
|
71
74
|
visionCategoryHint?: string;
|
|
72
75
|
}
|
|
73
|
-
declare function KikuButton({ label, title, placeholder, backdropColor, backdropBlur, className, onSelectSource, defaultCurrency, chips, theme, classNames, enableVoice, enableVision, visionCategoryHint, }: KikuButtonProps): React.JSX.Element;
|
|
76
|
+
declare function KikuButton({ label, title, placeholder, backdropColor, backdropBlur, className, onSelectSource, defaultCurrency, chips, theme, classNames, enableVoice, voiceLang, enableVision, visionCategoryHint, }: KikuButtonProps): React.JSX.Element;
|
|
74
77
|
|
|
75
78
|
interface SparkleProps {
|
|
76
79
|
productName: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { SearchResult, AkropolysTheme, ChatSource, Product, VisualSearchResponse
|
|
|
4
4
|
interface SearchBarProps {
|
|
5
5
|
placeholder?: string;
|
|
6
6
|
limit?: number;
|
|
7
|
-
/** Debounce in ms — default
|
|
7
|
+
/** Debounce in ms — default 150 for instant type-ahead */
|
|
8
8
|
debounceMs?: number;
|
|
9
9
|
onSelect?: (result: SearchResult) => void;
|
|
10
10
|
className?: string;
|
|
@@ -65,12 +65,15 @@ interface KikuButtonProps {
|
|
|
65
65
|
};
|
|
66
66
|
/** Enable 🎙️ voice input via browser Web Speech API (free) */
|
|
67
67
|
enableVoice?: boolean;
|
|
68
|
+
/** BCP-47 tag for voice transcription (e.g. 'sw-KE', 'fr-FR'). Defaults to
|
|
69
|
+
the page's <html lang>, then the browser language. */
|
|
70
|
+
voiceLang?: string;
|
|
68
71
|
/** Enable 📷 visual style-match search via Gemini (requires backend GEMINI_API_KEY) */
|
|
69
72
|
enableVision?: boolean;
|
|
70
73
|
/** Optional category hint for visual search (e.g. 'dress', 'curtains') */
|
|
71
74
|
visionCategoryHint?: string;
|
|
72
75
|
}
|
|
73
|
-
declare function KikuButton({ label, title, placeholder, backdropColor, backdropBlur, className, onSelectSource, defaultCurrency, chips, theme, classNames, enableVoice, enableVision, visionCategoryHint, }: KikuButtonProps): React.JSX.Element;
|
|
76
|
+
declare function KikuButton({ label, title, placeholder, backdropColor, backdropBlur, className, onSelectSource, defaultCurrency, chips, theme, classNames, enableVoice, voiceLang, enableVision, visionCategoryHint, }: KikuButtonProps): React.JSX.Element;
|
|
74
77
|
|
|
75
78
|
interface SparkleProps {
|
|
76
79
|
productName: string;
|
package/dist/index.js
CHANGED
|
@@ -52,7 +52,7 @@ var SearchIcon = () => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { wid
|
|
|
52
52
|
function SearchBar({
|
|
53
53
|
placeholder = "Search products\u2026",
|
|
54
54
|
limit = 10,
|
|
55
|
-
debounceMs =
|
|
55
|
+
debounceMs = 150,
|
|
56
56
|
onSelect,
|
|
57
57
|
className,
|
|
58
58
|
inputClassName,
|
|
@@ -63,10 +63,8 @@ function SearchBar({
|
|
|
63
63
|
}) {
|
|
64
64
|
const [query, setQuery] = (0, import_react.useState)("");
|
|
65
65
|
const [open, setOpen] = (0, import_react.useState)(false);
|
|
66
|
-
const
|
|
67
|
-
const { results, loading, search, clear } = (0, import_sdk.useSearch)();
|
|
66
|
+
const { results, loading, search, clear } = (0, import_sdk.useSearch)({ debounceMs });
|
|
68
67
|
const client = (0, import_sdk.useAkropolysContext)();
|
|
69
|
-
const timer = (0, import_react.useRef)();
|
|
70
68
|
const wrap = (0, import_react.useRef)(null);
|
|
71
69
|
const ignoreNextQueryChange = (0, import_react.useRef)(false);
|
|
72
70
|
(0, import_react.useEffect)(() => {
|
|
@@ -74,20 +72,13 @@ function SearchBar({
|
|
|
74
72
|
ignoreNextQueryChange.current = false;
|
|
75
73
|
return;
|
|
76
74
|
}
|
|
77
|
-
clearTimeout(timer.current);
|
|
78
75
|
if (!query.trim()) {
|
|
79
76
|
clear();
|
|
80
77
|
setOpen(false);
|
|
81
|
-
setIsDebouncing(false);
|
|
82
78
|
return;
|
|
83
79
|
}
|
|
84
80
|
setOpen(true);
|
|
85
|
-
|
|
86
|
-
timer.current = setTimeout(() => {
|
|
87
|
-
setIsDebouncing(false);
|
|
88
|
-
search(query, limit);
|
|
89
|
-
}, debounceMs);
|
|
90
|
-
return () => clearTimeout(timer.current);
|
|
81
|
+
search(query, limit);
|
|
91
82
|
}, [query]);
|
|
92
83
|
(0, import_react.useEffect)(() => {
|
|
93
84
|
const h = (e) => {
|
|
@@ -143,8 +134,8 @@ function SearchBar({
|
|
|
143
134
|
}
|
|
144
135
|
),
|
|
145
136
|
showDrop && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cn("hsk-sb-drop", classNames.dropdown, dropdownClassName), style: { position: "absolute" }, children: [
|
|
146
|
-
|
|
147
|
-
|
|
137
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hsk-sb-loading-bar" }),
|
|
138
|
+
loading && results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
148
139
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hsk-sb-skeleton-row", children: [
|
|
149
140
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "hsk-sb-skeleton-icon" }),
|
|
150
141
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hsk-sb-row-body", children: [
|
|
@@ -160,36 +151,52 @@ function SearchBar({
|
|
|
160
151
|
] })
|
|
161
152
|
] })
|
|
162
153
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
163
|
-
results.length === 0 && !loading &&
|
|
154
|
+
results.length === 0 && !loading && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hsk-sb-empty", children: [
|
|
164
155
|
"No results for \u201C",
|
|
165
156
|
query,
|
|
166
157
|
"\u201D"
|
|
167
158
|
] }),
|
|
168
|
-
results.map((r, i) =>
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
159
|
+
results.map((r, i) => {
|
|
160
|
+
if (renderResult) {
|
|
161
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
162
|
+
"div",
|
|
163
|
+
{
|
|
164
|
+
onClick: () => handleSelect(r),
|
|
165
|
+
className: "hsk-sb-fade",
|
|
166
|
+
style: { animationDelay: `${i * 18}ms` },
|
|
167
|
+
children: renderResult(r)
|
|
168
|
+
},
|
|
169
|
+
r.id
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
const thumb = r.entity.image ?? r.entity.thumbnail ?? r.entity.images?.[0];
|
|
173
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
174
|
+
"div",
|
|
175
|
+
{
|
|
176
|
+
className: cn("hsk-sb-row hsk-sb-fade", classNames.row),
|
|
177
|
+
style: { animationDelay: `${i * 18}ms` },
|
|
178
|
+
onClick: () => handleSelect(r),
|
|
179
|
+
children: [
|
|
180
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "hsk-sb-row-thumb", children: thumb ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
181
|
+
"img",
|
|
182
|
+
{
|
|
183
|
+
src: thumb,
|
|
184
|
+
alt: "",
|
|
185
|
+
loading: "lazy",
|
|
186
|
+
onError: (e) => {
|
|
187
|
+
e.currentTarget.style.display = "none";
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SearchIcon, {}) }),
|
|
191
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hsk-sb-row-body", children: [
|
|
192
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hsk-sb-row-title", children: r.entity.title ?? r.entity.name }),
|
|
193
|
+
(r.entity.category || r.entity.brand) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hsk-sb-row-sub", children: r.entity.category ?? r.entity.brand })
|
|
194
|
+
] })
|
|
195
|
+
]
|
|
196
|
+
},
|
|
197
|
+
r.id
|
|
198
|
+
);
|
|
199
|
+
})
|
|
193
200
|
] })
|
|
194
201
|
] })
|
|
195
202
|
] });
|
|
@@ -1727,18 +1734,7 @@ var getFriendlyError = (err) => {
|
|
|
1727
1734
|
return str;
|
|
1728
1735
|
}
|
|
1729
1736
|
};
|
|
1730
|
-
var
|
|
1731
|
-
var MK_NOUN = ["thunder", "falcon", "river", "ember", "tiger", "comet", "willow", "onyx"];
|
|
1732
|
-
function generateMagicWord() {
|
|
1733
|
-
return MK_ADJ[Math.floor(Math.random() * MK_ADJ.length)] + MK_NOUN[Math.floor(Math.random() * MK_NOUN.length)];
|
|
1734
|
-
}
|
|
1735
|
-
function parseMemoryKey(raw) {
|
|
1736
|
-
const cleaned = raw.trim().replace(/\s+/g, "");
|
|
1737
|
-
const m = cleaned.match(/^(\d{6,})([a-zA-Z].*)?$/);
|
|
1738
|
-
const phone = m?.[1] || cleaned.replace(/\D/g, "");
|
|
1739
|
-
const word = (m?.[2] || "").toLowerCase() || generateMagicWord();
|
|
1740
|
-
return { phone, word };
|
|
1741
|
-
}
|
|
1737
|
+
var KIKU_KEY_REVEAL_SECONDS = 60;
|
|
1742
1738
|
function parseThinking(text) {
|
|
1743
1739
|
const openMatch = text.match(/<\s*thinking\s*>/i);
|
|
1744
1740
|
if (!openMatch) {
|
|
@@ -1846,6 +1842,7 @@ function ChatModal({
|
|
|
1846
1842
|
theme,
|
|
1847
1843
|
classNames = {},
|
|
1848
1844
|
enableVoice = false,
|
|
1845
|
+
voiceLang,
|
|
1849
1846
|
enableVision = false,
|
|
1850
1847
|
visionCategoryHint
|
|
1851
1848
|
}) {
|
|
@@ -1879,7 +1876,7 @@ function ChatModal({
|
|
|
1879
1876
|
if (!hasSpeechAPI || voiceState !== "idle") return;
|
|
1880
1877
|
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
1881
1878
|
const recognition = new SR();
|
|
1882
|
-
recognition.lang = "en-US";
|
|
1879
|
+
recognition.lang = voiceLang || document.documentElement.lang || navigator.language || "en-US";
|
|
1883
1880
|
recognition.interimResults = true;
|
|
1884
1881
|
recognition.maxAlternatives = 1;
|
|
1885
1882
|
recognitionRef.current = recognition;
|
|
@@ -1912,7 +1909,7 @@ function ChatModal({
|
|
|
1912
1909
|
setVoiceState((prev) => prev === "listening" ? "idle" : prev);
|
|
1913
1910
|
};
|
|
1914
1911
|
recognition.start();
|
|
1915
|
-
}, [hasSpeechAPI, voiceState]);
|
|
1912
|
+
}, [hasSpeechAPI, voiceState, voiceLang]);
|
|
1916
1913
|
const stopVoice = (0, import_react5.useCallback)(() => {
|
|
1917
1914
|
recognitionRef.current?.stop();
|
|
1918
1915
|
setVoiceState("idle");
|
|
@@ -1927,14 +1924,11 @@ function ChatModal({
|
|
|
1927
1924
|
const [selectedProduct, setSelectedProduct] = (0, import_react5.useState)(null);
|
|
1928
1925
|
const bottomRef = (0, import_react5.useRef)(null);
|
|
1929
1926
|
const textareaRef = (0, import_react5.useRef)(null);
|
|
1930
|
-
const [
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
});
|
|
1936
|
-
const [paymentPhase, setPaymentPhase] = (0, import_react5.useState)("idle");
|
|
1937
|
-
const [memoryKey, setMemoryKey] = (0, import_react5.useState)(null);
|
|
1927
|
+
const [keyInput, setKeyInput] = (0, import_react5.useState)("");
|
|
1928
|
+
const [keyPhase, setKeyPhase] = (0, import_react5.useState)("idle");
|
|
1929
|
+
const [mintedKey, setMintedKey] = (0, import_react5.useState)(null);
|
|
1930
|
+
const [keyCountdown, setKeyCountdown] = (0, import_react5.useState)(KIKU_KEY_REVEAL_SECONDS);
|
|
1931
|
+
const [minting, setMinting] = (0, import_react5.useState)(false);
|
|
1938
1932
|
const [showKikuPicker, setShowKikuPicker] = (0, import_react5.useState)(false);
|
|
1939
1933
|
const [showAtPicker, setShowAtPicker] = (0, import_react5.useState)(false);
|
|
1940
1934
|
const [sessions, setSessions] = (0, import_react5.useState)(() => loadSessions());
|
|
@@ -1942,10 +1936,25 @@ function ChatModal({
|
|
|
1942
1936
|
const [replayMessages, setReplayMessages] = (0, import_react5.useState)(null);
|
|
1943
1937
|
(0, import_react5.useEffect)(() => {
|
|
1944
1938
|
if (!lastAction) return;
|
|
1945
|
-
if (lastAction.type === "
|
|
1946
|
-
|
|
1939
|
+
if (lastAction.type === "request_kiku_key") {
|
|
1940
|
+
setKeyPhase("prompt_key");
|
|
1947
1941
|
}
|
|
1948
1942
|
}, [lastAction]);
|
|
1943
|
+
(0, import_react5.useEffect)(() => {
|
|
1944
|
+
if (!mintedKey) return;
|
|
1945
|
+
setKeyCountdown(KIKU_KEY_REVEAL_SECONDS);
|
|
1946
|
+
const t = setInterval(() => {
|
|
1947
|
+
setKeyCountdown((s) => {
|
|
1948
|
+
if (s <= 1) {
|
|
1949
|
+
clearInterval(t);
|
|
1950
|
+
setMintedKey(null);
|
|
1951
|
+
return 0;
|
|
1952
|
+
}
|
|
1953
|
+
return s - 1;
|
|
1954
|
+
});
|
|
1955
|
+
}, 1e3);
|
|
1956
|
+
return () => clearInterval(t);
|
|
1957
|
+
}, [mintedKey]);
|
|
1949
1958
|
const isStringTheme = typeof theme === "string";
|
|
1950
1959
|
const hskThemeAttr = isStringTheme ? theme : void 0;
|
|
1951
1960
|
const customStyles = !isStringTheme && theme ? {
|
|
@@ -1955,16 +1964,30 @@ function ChatModal({
|
|
|
1955
1964
|
...theme?.fontFamily && { "--hsk-font": theme.fontFamily },
|
|
1956
1965
|
...theme?.borderRadius && { "--hsk-border-radius": theme.borderRadius }
|
|
1957
1966
|
} : void 0;
|
|
1958
|
-
const
|
|
1959
|
-
if (!phoneInput.trim()) return;
|
|
1960
|
-
const { phone, word } = parseMemoryKey(phoneInput);
|
|
1961
|
-
if (!phone) return;
|
|
1962
|
-
if (typeof window !== "undefined") localStorage.setItem("akropolys_user_phone", phone);
|
|
1963
|
-
client.setShopperIdentity(phone, word);
|
|
1964
|
-
setMemoryKey(phone + word);
|
|
1965
|
-
setPaymentPhase("idle");
|
|
1967
|
+
const retryLastMessage = async () => {
|
|
1966
1968
|
const lastUserMsg = [...messages].reverse().find((m) => m.role === "user");
|
|
1967
|
-
if (lastUserMsg) await
|
|
1969
|
+
if (lastUserMsg) await handleSend(lastUserMsg.content);
|
|
1970
|
+
};
|
|
1971
|
+
const handleUseExistingKey = async () => {
|
|
1972
|
+
const key = keyInput.trim();
|
|
1973
|
+
if (!key) return;
|
|
1974
|
+
client.setKikuKey(key);
|
|
1975
|
+
setKeyInput("");
|
|
1976
|
+
setKeyPhase("idle");
|
|
1977
|
+
await retryLastMessage();
|
|
1978
|
+
};
|
|
1979
|
+
const handleCreateKey = async () => {
|
|
1980
|
+
if (minting) return;
|
|
1981
|
+
setMinting(true);
|
|
1982
|
+
try {
|
|
1983
|
+
const key = await client.mintKikuKey();
|
|
1984
|
+
setMintedKey(key);
|
|
1985
|
+
setKeyPhase("idle");
|
|
1986
|
+
await retryLastMessage();
|
|
1987
|
+
} catch {
|
|
1988
|
+
} finally {
|
|
1989
|
+
setMinting(false);
|
|
1990
|
+
}
|
|
1968
1991
|
};
|
|
1969
1992
|
const msgsContainerRef = (0, import_react5.useRef)(null);
|
|
1970
1993
|
(0, import_react5.useEffect)(() => {
|
|
@@ -1999,7 +2022,7 @@ function ChatModal({
|
|
|
1999
2022
|
saveCurrentSession();
|
|
2000
2023
|
reset();
|
|
2001
2024
|
setReplayMessages(null);
|
|
2002
|
-
|
|
2025
|
+
setKeyPhase("idle");
|
|
2003
2026
|
}, [reset, saveCurrentSession]);
|
|
2004
2027
|
const handleSourceClick = (src) => {
|
|
2005
2028
|
setSelectedProduct(src);
|
|
@@ -2252,7 +2275,7 @@ function ChatModal({
|
|
|
2252
2275
|
] });
|
|
2253
2276
|
})(),
|
|
2254
2277
|
isLast && lastIntent === "compare" && sources.length >= 2 && !replayMessages && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ComparisonMatrix, { sources, defaultCurrency }),
|
|
2255
|
-
isLast && referencedIds.length > 0 && lastIntent !== "compare" && lastAction?.type !== "
|
|
2278
|
+
isLast && referencedIds.length > 0 && lastIntent !== "compare" && lastAction?.type !== "request_kiku_key" && lastAction?.type !== "awaiting_payment" && lastAction?.type !== "checkout" && lastAction?.type !== "capture" && lastAction?.type !== "delete" && lastAction?.type !== "view_history" && !msg.cartSnapshot && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2256
2279
|
SourcesCarousel,
|
|
2257
2280
|
{
|
|
2258
2281
|
sources,
|
|
@@ -2325,38 +2348,45 @@ function ChatModal({
|
|
|
2325
2348
|
] })
|
|
2326
2349
|
] }),
|
|
2327
2350
|
error && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-error", children: getFriendlyError(error) }),
|
|
2328
|
-
!replayMessages &&
|
|
2351
|
+
!replayMessages && keyPhase === "prompt_key" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-ai-msg", children: [
|
|
2329
2352
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparkleIcon2, {}) }),
|
|
2330
2353
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-ai-body", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-ai-text", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-phone-form", children: [
|
|
2331
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "hsk-cb-phone-label", children: "
|
|
2354
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "hsk-cb-phone-label", children: "Paste your kiku key \u2014 or create one" }),
|
|
2332
2355
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2333
2356
|
"input",
|
|
2334
2357
|
{
|
|
2335
2358
|
type: "text",
|
|
2336
2359
|
className: "hsk-cb-phone-input",
|
|
2337
|
-
placeholder: "
|
|
2338
|
-
value:
|
|
2339
|
-
onChange: (e) =>
|
|
2340
|
-
onKeyDown: (e) => e.key === "Enter" &&
|
|
2360
|
+
placeholder: "kiku_\u2026",
|
|
2361
|
+
value: keyInput,
|
|
2362
|
+
onChange: (e) => setKeyInput(e.target.value),
|
|
2363
|
+
onKeyDown: (e) => e.key === "Enter" && handleUseExistingKey(),
|
|
2341
2364
|
autoFocus: true
|
|
2342
2365
|
}
|
|
2343
2366
|
),
|
|
2344
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.
|
|
2367
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", gap: 8 }, children: [
|
|
2368
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: "hsk-cb-phone-submit", onClick: handleUseExistingKey, disabled: !keyInput.trim(), children: "Use my key" }),
|
|
2369
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: "hsk-cb-phone-submit", onClick: handleCreateKey, disabled: minting, children: minting ? "Creating\u2026" : "I'm new \u2014 create my key" })
|
|
2370
|
+
] })
|
|
2345
2371
|
] }) }) })
|
|
2346
2372
|
] }),
|
|
2347
|
-
!replayMessages &&
|
|
2373
|
+
!replayMessages && mintedKey && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-ai-msg", children: [
|
|
2348
2374
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparkleIcon2, {}) }),
|
|
2349
2375
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-ai-body", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-ai-text", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { padding: "10px 12px", border: "1px solid var(--hsk-border, #e5e5e5)", borderRadius: 8 }, children: [
|
|
2350
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { fontSize: 12, fontWeight: 600, marginBottom: 4 }, children: "\u{1F511} Your
|
|
2351
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { style: { display: "block", fontSize: 14, fontWeight: 700, marginBottom: 6, wordBreak: "break-all" }, children:
|
|
2376
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { fontSize: 12, fontWeight: 600, marginBottom: 4 }, children: "\u{1F511} Your kiku key \u2014 shown only once" }),
|
|
2377
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { style: { display: "block", fontSize: 14, fontWeight: 700, marginBottom: 6, wordBreak: "break-all" }, children: mintedKey }),
|
|
2352
2378
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
|
|
2353
2379
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: "hsk-cb-phone-submit", style: { padding: "4px 10px" }, onClick: () => {
|
|
2354
2380
|
try {
|
|
2355
|
-
navigator.clipboard?.writeText(
|
|
2381
|
+
navigator.clipboard?.writeText(mintedKey);
|
|
2356
2382
|
} catch {
|
|
2357
2383
|
}
|
|
2358
2384
|
}, children: "Copy" }),
|
|
2359
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.
|
|
2385
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { style: { fontSize: 11, opacity: 0.7 }, children: [
|
|
2386
|
+
"Disappears in ",
|
|
2387
|
+
keyCountdown,
|
|
2388
|
+
"s. Save it like a password \u2014 if lost, the memory it opens is lost with it."
|
|
2389
|
+
] })
|
|
2360
2390
|
] })
|
|
2361
2391
|
] }) }) })
|
|
2362
2392
|
] }),
|
|
@@ -2481,6 +2511,7 @@ function KikuButton({
|
|
|
2481
2511
|
theme,
|
|
2482
2512
|
classNames = {},
|
|
2483
2513
|
enableVoice = false,
|
|
2514
|
+
voiceLang,
|
|
2484
2515
|
enableVision = false,
|
|
2485
2516
|
visionCategoryHint
|
|
2486
2517
|
}) {
|
|
@@ -2550,6 +2581,7 @@ function KikuButton({
|
|
|
2550
2581
|
theme,
|
|
2551
2582
|
classNames,
|
|
2552
2583
|
enableVoice,
|
|
2584
|
+
voiceLang,
|
|
2553
2585
|
enableVision,
|
|
2554
2586
|
visionCategoryHint
|
|
2555
2587
|
}
|