@supernal/interface-nextjs 1.0.26 → 1.0.28
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 +174 -5
- package/dist/index.d.ts +174 -5
- package/dist/index.js +1279 -638
- package/dist/index.mjs +1149 -514
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -7,7 +7,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
7
7
|
});
|
|
8
8
|
|
|
9
9
|
// src/components/SupernalProvider.tsx
|
|
10
|
-
import { useEffect as
|
|
10
|
+
import { useEffect as useEffect15 } from "react";
|
|
11
11
|
|
|
12
12
|
// src/contexts/ChatInputContext.tsx
|
|
13
13
|
import { createContext, useContext, useCallback, useRef } from "react";
|
|
@@ -34,12 +34,12 @@ function ChatInputProvider({ children }) {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
// src/contexts/ChatProvider.tsx
|
|
37
|
-
import { createContext as
|
|
37
|
+
import { createContext as createContext3, useContext as useContext3, useState as useState2, useCallback as useCallback3, useEffect as useEffect2, useRef as useRef3 } from "react";
|
|
38
38
|
|
|
39
39
|
// src/lib/ChatAIInterface.ts
|
|
40
40
|
import {
|
|
41
41
|
AIInterface
|
|
42
|
-
} from "@supernal/interface";
|
|
42
|
+
} from "@supernal/interface/browser";
|
|
43
43
|
|
|
44
44
|
// src/lib/ToolManager.ts
|
|
45
45
|
import { setDefaultToolReporter, setGlobalToolReporter } from "@supernal/interface/browser";
|
|
@@ -178,17 +178,466 @@ var DemoAIInterface = class extends AIInterface {
|
|
|
178
178
|
}
|
|
179
179
|
};
|
|
180
180
|
|
|
181
|
-
// src/
|
|
181
|
+
// src/lib/ClaudeClient.ts
|
|
182
|
+
var COST_PER_1K = {
|
|
183
|
+
"claude-sonnet-4-20250514": { input: 3e-3, output: 0.015 },
|
|
184
|
+
"claude-3-5-sonnet-20241022": { input: 3e-3, output: 0.015 },
|
|
185
|
+
"claude-3-opus-20240229": { input: 0.015, output: 0.075 },
|
|
186
|
+
"claude-3-haiku-20240307": { input: 25e-5, output: 125e-5 }
|
|
187
|
+
};
|
|
188
|
+
var ClaudeClient = class {
|
|
189
|
+
constructor(config) {
|
|
190
|
+
this.apiKey = config.apiKey;
|
|
191
|
+
this.model = config.model || "claude-sonnet-4-20250514";
|
|
192
|
+
this.maxTokens = config.maxTokens || 4096;
|
|
193
|
+
this.systemPrompt = config.systemPrompt || "You are a helpful AI assistant integrated into a web application. Be concise and helpful.";
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Send a message to Claude and get a response
|
|
197
|
+
*/
|
|
198
|
+
async sendMessage(userMessage, options = {}) {
|
|
199
|
+
const messages = [
|
|
200
|
+
...options.messages || [],
|
|
201
|
+
{ role: "user", content: userMessage }
|
|
202
|
+
];
|
|
203
|
+
try {
|
|
204
|
+
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
|
205
|
+
method: "POST",
|
|
206
|
+
headers: {
|
|
207
|
+
"Content-Type": "application/json",
|
|
208
|
+
"x-api-key": this.apiKey,
|
|
209
|
+
"anthropic-version": "2023-06-01",
|
|
210
|
+
"anthropic-dangerous-direct-browser-access": "true"
|
|
211
|
+
},
|
|
212
|
+
body: JSON.stringify({
|
|
213
|
+
model: this.model,
|
|
214
|
+
max_tokens: options.maxTokens || this.maxTokens,
|
|
215
|
+
system: options.systemPrompt || this.systemPrompt,
|
|
216
|
+
messages: messages.map((m) => ({
|
|
217
|
+
role: m.role,
|
|
218
|
+
content: m.content
|
|
219
|
+
})),
|
|
220
|
+
temperature: options.temperature
|
|
221
|
+
})
|
|
222
|
+
});
|
|
223
|
+
if (!response.ok) {
|
|
224
|
+
const errorData = await response.json().catch(() => ({}));
|
|
225
|
+
if (response.status === 401) {
|
|
226
|
+
return {
|
|
227
|
+
success: false,
|
|
228
|
+
message: "Invalid API key. Please check your API key and try again.",
|
|
229
|
+
error: "INVALID_API_KEY"
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
if (response.status === 429) {
|
|
233
|
+
return {
|
|
234
|
+
success: false,
|
|
235
|
+
message: "Rate limit exceeded. Please wait a moment and try again.",
|
|
236
|
+
error: "RATE_LIMITED"
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
if (response.status === 400) {
|
|
240
|
+
return {
|
|
241
|
+
success: false,
|
|
242
|
+
message: errorData.error?.message || "Invalid request",
|
|
243
|
+
error: "BAD_REQUEST"
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
success: false,
|
|
248
|
+
message: errorData.error?.message || `API error: ${response.status}`,
|
|
249
|
+
error: "API_ERROR"
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
const data = await response.json();
|
|
253
|
+
const textContent = data.content.find((c) => c.type === "text");
|
|
254
|
+
const responseText = textContent?.text || "";
|
|
255
|
+
const modelCosts = COST_PER_1K[this.model] || COST_PER_1K["claude-sonnet-4-20250514"];
|
|
256
|
+
const inputCost = data.usage.input_tokens / 1e3 * modelCosts.input;
|
|
257
|
+
const outputCost = data.usage.output_tokens / 1e3 * modelCosts.output;
|
|
258
|
+
return {
|
|
259
|
+
success: true,
|
|
260
|
+
message: responseText,
|
|
261
|
+
response: data,
|
|
262
|
+
usage: {
|
|
263
|
+
inputTokens: data.usage.input_tokens,
|
|
264
|
+
outputTokens: data.usage.output_tokens,
|
|
265
|
+
estimatedCost: inputCost + outputCost
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
} catch (err) {
|
|
269
|
+
console.error("ClaudeClient error:", err);
|
|
270
|
+
if (err instanceof TypeError && err.message.includes("fetch")) {
|
|
271
|
+
return {
|
|
272
|
+
success: false,
|
|
273
|
+
message: "Network error. Please check your connection.",
|
|
274
|
+
error: "NETWORK_ERROR"
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
success: false,
|
|
279
|
+
message: err instanceof Error ? err.message : "Unknown error occurred",
|
|
280
|
+
error: "UNKNOWN_ERROR"
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Update the API key
|
|
286
|
+
*/
|
|
287
|
+
setApiKey(apiKey) {
|
|
288
|
+
this.apiKey = apiKey;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Update the model
|
|
292
|
+
*/
|
|
293
|
+
setModel(model) {
|
|
294
|
+
this.model = model;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Update the system prompt
|
|
298
|
+
*/
|
|
299
|
+
setSystemPrompt(systemPrompt) {
|
|
300
|
+
this.systemPrompt = systemPrompt;
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
function createClaudeClient(config) {
|
|
304
|
+
return new ClaudeClient(config);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// src/contexts/ApiKeyContext.tsx
|
|
308
|
+
import React2, { createContext as createContext2, useContext as useContext2 } from "react";
|
|
309
|
+
|
|
310
|
+
// src/hooks/useApiKeyStorage.ts
|
|
311
|
+
import { useState, useCallback as useCallback2, useEffect, useRef as useRef2 } from "react";
|
|
312
|
+
var STORAGE_KEY = "supernal-api-key";
|
|
313
|
+
var ENCRYPTED_STORAGE_KEY = "supernal-vault-v1";
|
|
314
|
+
function validateApiKeyFormat(key) {
|
|
315
|
+
if (!key || key.trim() === "") {
|
|
316
|
+
return { valid: false, error: "API key is required" };
|
|
317
|
+
}
|
|
318
|
+
if (!key.startsWith("sk-ant-")) {
|
|
319
|
+
return { valid: false, error: 'Invalid format. Keys start with "sk-ant-"' };
|
|
320
|
+
}
|
|
321
|
+
if (key.length < 50) {
|
|
322
|
+
return { valid: false, error: "API key appears too short" };
|
|
323
|
+
}
|
|
324
|
+
return { valid: true };
|
|
325
|
+
}
|
|
326
|
+
function maskApiKey(key) {
|
|
327
|
+
if (key.length <= 14) return "\u2022".repeat(key.length);
|
|
328
|
+
return `${key.slice(0, 10)}...${key.slice(-4)}`;
|
|
329
|
+
}
|
|
330
|
+
async function validateApiKeyWithAnthropic(apiKey) {
|
|
331
|
+
try {
|
|
332
|
+
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
|
333
|
+
method: "POST",
|
|
334
|
+
headers: {
|
|
335
|
+
"Content-Type": "application/json",
|
|
336
|
+
"x-api-key": apiKey,
|
|
337
|
+
"anthropic-version": "2023-06-01",
|
|
338
|
+
"anthropic-dangerous-direct-browser-access": "true"
|
|
339
|
+
},
|
|
340
|
+
body: JSON.stringify({
|
|
341
|
+
model: "claude-sonnet-4-20250514",
|
|
342
|
+
max_tokens: 1,
|
|
343
|
+
messages: [{ role: "user", content: "hi" }]
|
|
344
|
+
})
|
|
345
|
+
});
|
|
346
|
+
if (response.ok) {
|
|
347
|
+
return { valid: true };
|
|
348
|
+
}
|
|
349
|
+
const data = await response.json().catch(() => ({}));
|
|
350
|
+
if (response.status === 401) {
|
|
351
|
+
return { valid: false, error: "Invalid API key" };
|
|
352
|
+
}
|
|
353
|
+
if (response.status === 403) {
|
|
354
|
+
return { valid: false, error: "API key does not have permission" };
|
|
355
|
+
}
|
|
356
|
+
if (response.status === 429) {
|
|
357
|
+
return { valid: true };
|
|
358
|
+
}
|
|
359
|
+
return { valid: false, error: data.error?.message || "Validation failed" };
|
|
360
|
+
} catch (err) {
|
|
361
|
+
console.warn("Could not validate API key with Anthropic:", err);
|
|
362
|
+
return validateApiKeyFormat(apiKey);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
var SALT_LENGTH = 32;
|
|
366
|
+
var IV_LENGTH = 12;
|
|
367
|
+
var ITERATIONS = 1e5;
|
|
368
|
+
async function deriveKey(passphrase, salt) {
|
|
369
|
+
const keyMaterial = await crypto.subtle.importKey(
|
|
370
|
+
"raw",
|
|
371
|
+
new TextEncoder().encode(passphrase),
|
|
372
|
+
"PBKDF2",
|
|
373
|
+
false,
|
|
374
|
+
["deriveKey"]
|
|
375
|
+
);
|
|
376
|
+
const saltBuffer = salt.buffer.slice(salt.byteOffset, salt.byteOffset + salt.byteLength);
|
|
377
|
+
return crypto.subtle.deriveKey(
|
|
378
|
+
{ name: "PBKDF2", salt: saltBuffer, iterations: ITERATIONS, hash: "SHA-256" },
|
|
379
|
+
keyMaterial,
|
|
380
|
+
{ name: "AES-GCM", length: 256 },
|
|
381
|
+
false,
|
|
382
|
+
["encrypt", "decrypt"]
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
async function encryptValue(key, plaintext, salt) {
|
|
386
|
+
const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));
|
|
387
|
+
const ivBuffer = iv.buffer.slice(iv.byteOffset, iv.byteOffset + iv.byteLength);
|
|
388
|
+
const ciphertext = await crypto.subtle.encrypt(
|
|
389
|
+
{ name: "AES-GCM", iv: ivBuffer },
|
|
390
|
+
key,
|
|
391
|
+
new TextEncoder().encode(plaintext)
|
|
392
|
+
);
|
|
393
|
+
return {
|
|
394
|
+
version: 1,
|
|
395
|
+
ciphertext: arrayBufferToBase64(ciphertext),
|
|
396
|
+
salt: uint8ArrayToBase64(salt),
|
|
397
|
+
iv: uint8ArrayToBase64(iv),
|
|
398
|
+
encryptedAt: Date.now()
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
async function decryptValue(key, entry) {
|
|
402
|
+
const ciphertext = base64ToArrayBuffer(entry.ciphertext);
|
|
403
|
+
const iv = base64ToUint8Array(entry.iv);
|
|
404
|
+
const ivBuffer = iv.buffer.slice(iv.byteOffset, iv.byteOffset + iv.byteLength);
|
|
405
|
+
const plaintext = await crypto.subtle.decrypt(
|
|
406
|
+
{ name: "AES-GCM", iv: ivBuffer },
|
|
407
|
+
key,
|
|
408
|
+
ciphertext
|
|
409
|
+
);
|
|
410
|
+
return new TextDecoder().decode(plaintext);
|
|
411
|
+
}
|
|
412
|
+
function arrayBufferToBase64(buffer) {
|
|
413
|
+
const bytes = new Uint8Array(buffer);
|
|
414
|
+
let binary = "";
|
|
415
|
+
for (let i = 0; i < bytes.byteLength; i++) {
|
|
416
|
+
binary += String.fromCharCode(bytes[i]);
|
|
417
|
+
}
|
|
418
|
+
return btoa(binary);
|
|
419
|
+
}
|
|
420
|
+
function base64ToArrayBuffer(base64) {
|
|
421
|
+
const binary = atob(base64);
|
|
422
|
+
const bytes = new Uint8Array(binary.length);
|
|
423
|
+
for (let i = 0; i < binary.length; i++) {
|
|
424
|
+
bytes[i] = binary.charCodeAt(i);
|
|
425
|
+
}
|
|
426
|
+
return bytes.buffer;
|
|
427
|
+
}
|
|
428
|
+
function uint8ArrayToBase64(array) {
|
|
429
|
+
const buffer = array.buffer.slice(array.byteOffset, array.byteOffset + array.byteLength);
|
|
430
|
+
return arrayBufferToBase64(buffer);
|
|
431
|
+
}
|
|
432
|
+
function base64ToUint8Array(base64) {
|
|
433
|
+
return new Uint8Array(base64ToArrayBuffer(base64));
|
|
434
|
+
}
|
|
435
|
+
function loadEncryptedEntry() {
|
|
436
|
+
if (typeof window === "undefined") return null;
|
|
437
|
+
try {
|
|
438
|
+
const stored = localStorage.getItem(ENCRYPTED_STORAGE_KEY);
|
|
439
|
+
if (stored) {
|
|
440
|
+
const entry = JSON.parse(stored);
|
|
441
|
+
if (entry.version === 1 && entry.ciphertext && entry.salt) {
|
|
442
|
+
return entry;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
} catch {
|
|
446
|
+
}
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
function useApiKeyStorage(options = {}) {
|
|
450
|
+
const [state, setState] = useState({
|
|
451
|
+
apiKey: null,
|
|
452
|
+
status: options.encrypted ? "locked" : "none",
|
|
453
|
+
error: null,
|
|
454
|
+
maskedKey: null
|
|
455
|
+
});
|
|
456
|
+
const derivedKeyRef = useRef2(null);
|
|
457
|
+
const saltRef = useRef2(null);
|
|
458
|
+
useEffect(() => {
|
|
459
|
+
if (typeof window === "undefined") return;
|
|
460
|
+
if (options.encrypted) {
|
|
461
|
+
const entry = loadEncryptedEntry();
|
|
462
|
+
if (entry) {
|
|
463
|
+
setState((prev) => ({ ...prev, status: "locked" }));
|
|
464
|
+
} else {
|
|
465
|
+
setState((prev) => ({ ...prev, status: "locked" }));
|
|
466
|
+
}
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
try {
|
|
470
|
+
const saved = localStorage.getItem(STORAGE_KEY);
|
|
471
|
+
if (saved) {
|
|
472
|
+
const validation = validateApiKeyFormat(saved);
|
|
473
|
+
setState({
|
|
474
|
+
apiKey: saved,
|
|
475
|
+
status: validation.valid ? "valid" : "invalid",
|
|
476
|
+
error: validation.error || null,
|
|
477
|
+
maskedKey: maskApiKey(saved)
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
} catch (err) {
|
|
481
|
+
console.error("Failed to load API key from storage:", err);
|
|
482
|
+
}
|
|
483
|
+
}, [options.encrypted]);
|
|
484
|
+
const unlock = useCallback2(async (passphrase) => {
|
|
485
|
+
if (!options.encrypted) {
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
488
|
+
try {
|
|
489
|
+
const entry = loadEncryptedEntry();
|
|
490
|
+
if (entry) {
|
|
491
|
+
const salt = base64ToUint8Array(entry.salt);
|
|
492
|
+
const key = await deriveKey(passphrase, salt);
|
|
493
|
+
try {
|
|
494
|
+
const apiKey = await decryptValue(key, entry);
|
|
495
|
+
derivedKeyRef.current = key;
|
|
496
|
+
saltRef.current = salt;
|
|
497
|
+
const validation = validateApiKeyFormat(apiKey);
|
|
498
|
+
setState({
|
|
499
|
+
apiKey,
|
|
500
|
+
status: validation.valid ? "valid" : "invalid",
|
|
501
|
+
error: validation.error || null,
|
|
502
|
+
maskedKey: maskApiKey(apiKey)
|
|
503
|
+
});
|
|
504
|
+
return true;
|
|
505
|
+
} catch {
|
|
506
|
+
options.onPassphraseInvalid?.();
|
|
507
|
+
return false;
|
|
508
|
+
}
|
|
509
|
+
} else {
|
|
510
|
+
const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));
|
|
511
|
+
const key = await deriveKey(passphrase, salt);
|
|
512
|
+
derivedKeyRef.current = key;
|
|
513
|
+
saltRef.current = salt;
|
|
514
|
+
setState((prev) => ({
|
|
515
|
+
...prev,
|
|
516
|
+
status: "none"
|
|
517
|
+
// Unlocked but no key yet
|
|
518
|
+
}));
|
|
519
|
+
return true;
|
|
520
|
+
}
|
|
521
|
+
} catch (error) {
|
|
522
|
+
console.error("[useApiKeyStorage] Unlock failed:", error);
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
}, [options.encrypted, options.onPassphraseInvalid]);
|
|
526
|
+
const lock = useCallback2(() => {
|
|
527
|
+
if (!options.encrypted) return;
|
|
528
|
+
derivedKeyRef.current = null;
|
|
529
|
+
setState((prev) => ({
|
|
530
|
+
...prev,
|
|
531
|
+
status: "locked",
|
|
532
|
+
apiKey: null,
|
|
533
|
+
maskedKey: null
|
|
534
|
+
}));
|
|
535
|
+
}, [options.encrypted]);
|
|
536
|
+
const setApiKey = useCallback2(async (key, validate = true) => {
|
|
537
|
+
const formatValidation = validateApiKeyFormat(key);
|
|
538
|
+
if (!formatValidation.valid) {
|
|
539
|
+
setState({
|
|
540
|
+
apiKey: null,
|
|
541
|
+
status: "invalid",
|
|
542
|
+
error: formatValidation.error || "Invalid API key",
|
|
543
|
+
maskedKey: null
|
|
544
|
+
});
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
setState({
|
|
548
|
+
apiKey: key,
|
|
549
|
+
status: validate ? "validating" : "valid",
|
|
550
|
+
error: null,
|
|
551
|
+
maskedKey: maskApiKey(key)
|
|
552
|
+
});
|
|
553
|
+
try {
|
|
554
|
+
if (options.encrypted && derivedKeyRef.current && saltRef.current) {
|
|
555
|
+
const entry = await encryptValue(derivedKeyRef.current, key, saltRef.current);
|
|
556
|
+
localStorage.setItem(ENCRYPTED_STORAGE_KEY, JSON.stringify(entry));
|
|
557
|
+
} else {
|
|
558
|
+
localStorage.setItem(STORAGE_KEY, key);
|
|
559
|
+
}
|
|
560
|
+
} catch (err) {
|
|
561
|
+
console.error("Failed to save API key:", err);
|
|
562
|
+
}
|
|
563
|
+
if (validate) {
|
|
564
|
+
const liveValidation = await validateApiKeyWithAnthropic(key);
|
|
565
|
+
setState((prev) => ({
|
|
566
|
+
...prev,
|
|
567
|
+
status: liveValidation.valid ? "valid" : "invalid",
|
|
568
|
+
error: liveValidation.error || null
|
|
569
|
+
}));
|
|
570
|
+
return liveValidation.valid;
|
|
571
|
+
}
|
|
572
|
+
return true;
|
|
573
|
+
}, [options.encrypted]);
|
|
574
|
+
const clearApiKey = useCallback2(() => {
|
|
575
|
+
try {
|
|
576
|
+
if (options.encrypted) {
|
|
577
|
+
localStorage.removeItem(ENCRYPTED_STORAGE_KEY);
|
|
578
|
+
} else {
|
|
579
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
580
|
+
}
|
|
581
|
+
} catch (err) {
|
|
582
|
+
console.error("Failed to clear API key:", err);
|
|
583
|
+
}
|
|
584
|
+
setState({
|
|
585
|
+
apiKey: null,
|
|
586
|
+
status: options.encrypted ? "locked" : "none",
|
|
587
|
+
error: null,
|
|
588
|
+
maskedKey: null
|
|
589
|
+
});
|
|
590
|
+
}, [options.encrypted]);
|
|
591
|
+
const revalidate = useCallback2(async () => {
|
|
592
|
+
if (!state.apiKey) return false;
|
|
593
|
+
return setApiKey(state.apiKey, true);
|
|
594
|
+
}, [state.apiKey, setApiKey]);
|
|
595
|
+
return {
|
|
596
|
+
...state,
|
|
597
|
+
hasApiKey: !!state.apiKey && state.status === "valid",
|
|
598
|
+
isLocked: state.status === "locked",
|
|
599
|
+
setApiKey,
|
|
600
|
+
clearApiKey,
|
|
601
|
+
revalidate,
|
|
602
|
+
unlock,
|
|
603
|
+
lock
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// src/contexts/ApiKeyContext.tsx
|
|
182
608
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
183
|
-
var
|
|
609
|
+
var ApiKeyContext = createContext2(null);
|
|
610
|
+
function ApiKeyProvider({ children, initialApiKey }) {
|
|
611
|
+
const apiKeyStorage = useApiKeyStorage();
|
|
612
|
+
React2.useEffect(() => {
|
|
613
|
+
if (initialApiKey && !apiKeyStorage.apiKey && apiKeyStorage.status === "none") {
|
|
614
|
+
apiKeyStorage.setApiKey(initialApiKey, false);
|
|
615
|
+
}
|
|
616
|
+
}, [initialApiKey, apiKeyStorage]);
|
|
617
|
+
return /* @__PURE__ */ jsx2(ApiKeyContext.Provider, { value: apiKeyStorage, children });
|
|
618
|
+
}
|
|
619
|
+
function useApiKey() {
|
|
620
|
+
const context = useContext2(ApiKeyContext);
|
|
621
|
+
if (!context) {
|
|
622
|
+
throw new Error("useApiKey must be used within ApiKeyProvider");
|
|
623
|
+
}
|
|
624
|
+
return context;
|
|
625
|
+
}
|
|
626
|
+
function useApiKeyOptional() {
|
|
627
|
+
return useContext2(ApiKeyContext);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// src/contexts/ChatProvider.tsx
|
|
631
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
632
|
+
var ChatContext = createContext3(null);
|
|
184
633
|
function useChatContext() {
|
|
185
|
-
const context =
|
|
634
|
+
const context = useContext3(ChatContext);
|
|
186
635
|
if (!context) {
|
|
187
636
|
throw new Error("useChatContext must be used within ChatProvider");
|
|
188
637
|
}
|
|
189
638
|
return context;
|
|
190
639
|
}
|
|
191
|
-
var
|
|
640
|
+
var STORAGE_KEY2 = "supernal-chat-messages";
|
|
192
641
|
var MAX_MESSAGES = 100;
|
|
193
642
|
function getInitialMessages() {
|
|
194
643
|
return [
|
|
@@ -233,14 +682,30 @@ function getInitialMessages() {
|
|
|
233
682
|
function ChatProvider({
|
|
234
683
|
children,
|
|
235
684
|
mode = "fuzzy",
|
|
236
|
-
apiKey,
|
|
685
|
+
apiKey: propApiKey,
|
|
237
686
|
onToolExecute
|
|
238
687
|
}) {
|
|
239
|
-
const [messages, setMessages] =
|
|
240
|
-
|
|
688
|
+
const [messages, setMessages] = useState2([]);
|
|
689
|
+
const apiKeyContext = useApiKeyOptional();
|
|
690
|
+
const activeApiKey = apiKeyContext?.hasApiKey ? apiKeyContext.apiKey : propApiKey;
|
|
691
|
+
const isAiMode = !!activeApiKey;
|
|
692
|
+
const claudeClientRef = useRef3(null);
|
|
693
|
+
useEffect2(() => {
|
|
694
|
+
if (activeApiKey) {
|
|
695
|
+
claudeClientRef.current = new ClaudeClient({
|
|
696
|
+
apiKey: activeApiKey,
|
|
697
|
+
systemPrompt: `You are a helpful AI assistant integrated into a web application powered by Supernal Interface.
|
|
698
|
+
You can help users navigate the application and perform tasks.
|
|
699
|
+
Be concise, friendly, and helpful. Use markdown formatting when appropriate.`
|
|
700
|
+
});
|
|
701
|
+
} else {
|
|
702
|
+
claudeClientRef.current = null;
|
|
703
|
+
}
|
|
704
|
+
}, [activeApiKey]);
|
|
705
|
+
useEffect2(() => {
|
|
241
706
|
if (typeof window === "undefined") return;
|
|
242
707
|
try {
|
|
243
|
-
const saved = localStorage.getItem(
|
|
708
|
+
const saved = localStorage.getItem(STORAGE_KEY2);
|
|
244
709
|
if (saved) {
|
|
245
710
|
const loaded = JSON.parse(saved).map((m) => ({
|
|
246
711
|
...m,
|
|
@@ -255,24 +720,24 @@ function ChatProvider({
|
|
|
255
720
|
setMessages(getInitialMessages());
|
|
256
721
|
}
|
|
257
722
|
}, []);
|
|
258
|
-
const [isLoading, setIsLoading] =
|
|
259
|
-
const [aiInterface] =
|
|
260
|
-
|
|
723
|
+
const [isLoading, setIsLoading] = useState2(false);
|
|
724
|
+
const [aiInterface] = useState2(() => new DemoAIInterface());
|
|
725
|
+
useEffect2(() => {
|
|
261
726
|
if (onToolExecute) {
|
|
262
727
|
return aiInterface.onToolExecution((result) => {
|
|
263
728
|
onToolExecute(result.toolName, result);
|
|
264
729
|
});
|
|
265
730
|
}
|
|
266
731
|
}, [aiInterface, onToolExecute]);
|
|
267
|
-
|
|
732
|
+
useEffect2(() => {
|
|
268
733
|
try {
|
|
269
734
|
const toSave = messages.slice(-MAX_MESSAGES);
|
|
270
|
-
localStorage.setItem(
|
|
735
|
+
localStorage.setItem(STORAGE_KEY2, JSON.stringify(toSave));
|
|
271
736
|
} catch (error) {
|
|
272
737
|
console.error("Failed to save messages:", error);
|
|
273
738
|
}
|
|
274
739
|
}, [messages]);
|
|
275
|
-
const sendMessage =
|
|
740
|
+
const sendMessage = useCallback3(async (text) => {
|
|
276
741
|
const userMessage = {
|
|
277
742
|
id: Date.now().toString(),
|
|
278
743
|
text,
|
|
@@ -282,14 +747,31 @@ function ChatProvider({
|
|
|
282
747
|
setMessages((prev) => [...prev, userMessage]);
|
|
283
748
|
setIsLoading(true);
|
|
284
749
|
try {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
750
|
+
if (claudeClientRef.current) {
|
|
751
|
+
const conversationHistory = messages.slice(-20).filter((m) => m.type === "user" || m.type === "ai").map((m) => ({
|
|
752
|
+
role: m.type === "user" ? "user" : "assistant",
|
|
753
|
+
content: m.text
|
|
754
|
+
}));
|
|
755
|
+
const result = await claudeClientRef.current.sendMessage(text, {
|
|
756
|
+
messages: conversationHistory
|
|
757
|
+
});
|
|
758
|
+
const aiMessage = {
|
|
759
|
+
id: (Date.now() + 1).toString(),
|
|
760
|
+
text: result.message,
|
|
761
|
+
type: result.success ? "ai" : "system",
|
|
762
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
763
|
+
};
|
|
764
|
+
setMessages((prev) => [...prev, aiMessage]);
|
|
765
|
+
} else {
|
|
766
|
+
const result = await aiInterface.findAndExecuteCommand(text);
|
|
767
|
+
const aiMessage = {
|
|
768
|
+
id: (Date.now() + 1).toString(),
|
|
769
|
+
text: result.message,
|
|
770
|
+
type: result.success ? "ai" : "system",
|
|
771
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
772
|
+
};
|
|
773
|
+
setMessages((prev) => [...prev, aiMessage]);
|
|
774
|
+
}
|
|
293
775
|
} catch (error) {
|
|
294
776
|
const errorMessage = {
|
|
295
777
|
id: (Date.now() + 1).toString(),
|
|
@@ -301,16 +783,16 @@ function ChatProvider({
|
|
|
301
783
|
} finally {
|
|
302
784
|
setIsLoading(false);
|
|
303
785
|
}
|
|
304
|
-
}, [aiInterface]);
|
|
305
|
-
const clearMessages =
|
|
786
|
+
}, [aiInterface, messages]);
|
|
787
|
+
const clearMessages = useCallback3(() => {
|
|
306
788
|
setMessages([]);
|
|
307
|
-
localStorage.removeItem(
|
|
789
|
+
localStorage.removeItem(STORAGE_KEY2);
|
|
308
790
|
}, []);
|
|
309
|
-
return /* @__PURE__ */
|
|
791
|
+
return /* @__PURE__ */ jsx3(ChatContext.Provider, { value: { messages, sendMessage, clearMessages, isLoading, isAiMode }, children });
|
|
310
792
|
}
|
|
311
793
|
|
|
312
794
|
// src/components/ChatBubble/constants.ts
|
|
313
|
-
import
|
|
795
|
+
import React4 from "react";
|
|
314
796
|
|
|
315
797
|
// src/names/Components.ts
|
|
316
798
|
var Components = {
|
|
@@ -318,7 +800,20 @@ var Components = {
|
|
|
318
800
|
ChatToggleButton: "chat-toggle-button",
|
|
319
801
|
ChatInput: "chat-message-input",
|
|
320
802
|
ChatSendButton: "chat-send-button",
|
|
321
|
-
ChatClearButton: "chat-clear-button"
|
|
803
|
+
ChatClearButton: "chat-clear-button",
|
|
804
|
+
ChatMoreMenu: "chat-more-menu",
|
|
805
|
+
ChatMoreMenuButton: "chat-more-menu-button",
|
|
806
|
+
// API Key configuration components (BYOK mode)
|
|
807
|
+
ApiKeySection: "api-key-section",
|
|
808
|
+
ApiKeyInput: "api-key-input",
|
|
809
|
+
ApiKeySubmitButton: "api-key-submit-button",
|
|
810
|
+
ApiKeyClearButton: "api-key-clear-button",
|
|
811
|
+
ApiKeyConfigureButton: "api-key-configure-button",
|
|
812
|
+
ApiKeyStatus: "api-key-status",
|
|
813
|
+
ApiKeyMasked: "api-key-masked",
|
|
814
|
+
ApiKeyError: "api-key-error",
|
|
815
|
+
ApiKeyShowToggle: "api-key-show-toggle",
|
|
816
|
+
ApiKeyCancelButton: "api-key-cancel-button"
|
|
322
817
|
};
|
|
323
818
|
var ChatBubbleVariant = {
|
|
324
819
|
full: "full",
|
|
@@ -520,7 +1015,7 @@ var GLASS_INVERTED = {
|
|
|
520
1015
|
var DEFAULT_CONFIG = {
|
|
521
1016
|
title: "Supernal Interface",
|
|
522
1017
|
logo: DEFAULT_LOGO,
|
|
523
|
-
avatar:
|
|
1018
|
+
avatar: React4.createElement("img", { src: DEFAULT_LOGO, alt: "Supernal", className: "w-6 h-6" }),
|
|
524
1019
|
description: "I'm a TOOL system AI can use to control this site",
|
|
525
1020
|
placeholder: "Try: toggle notifications",
|
|
526
1021
|
sendButtonLabel: "Send",
|
|
@@ -543,7 +1038,7 @@ var DEFAULT_CONFIG = {
|
|
|
543
1038
|
};
|
|
544
1039
|
|
|
545
1040
|
// src/components/ChatBubble/InputField.tsx
|
|
546
|
-
import { jsx as
|
|
1041
|
+
import { jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
547
1042
|
var InputField = ({
|
|
548
1043
|
compact = false,
|
|
549
1044
|
inputValue,
|
|
@@ -559,8 +1054,8 @@ var InputField = ({
|
|
|
559
1054
|
onMicClick,
|
|
560
1055
|
modKey = "Ctrl",
|
|
561
1056
|
onKeyDown
|
|
562
|
-
}) => /* @__PURE__ */
|
|
563
|
-
/* @__PURE__ */
|
|
1057
|
+
}) => /* @__PURE__ */ jsx4("form", { onSubmit, className: compact ? "flex space-x-2" : THEME_CLASSES.bg.inputForm + " bg-transparent", children: /* @__PURE__ */ jsxs("div", { className: compact ? "flex space-x-2 flex-1" : "relative", children: [
|
|
1058
|
+
/* @__PURE__ */ jsx4(
|
|
564
1059
|
"input",
|
|
565
1060
|
{
|
|
566
1061
|
ref: compact ? void 0 : inputRef,
|
|
@@ -574,7 +1069,7 @@ var InputField = ({
|
|
|
574
1069
|
"data-testid": ChatNames.input
|
|
575
1070
|
}
|
|
576
1071
|
),
|
|
577
|
-
voiceEnabled && onMicClick && !compact && (!inputValue.trim() || isListening) && /* @__PURE__ */
|
|
1072
|
+
voiceEnabled && onMicClick && !compact && (!inputValue.trim() || isListening) && /* @__PURE__ */ jsx4(
|
|
578
1073
|
"button",
|
|
579
1074
|
{
|
|
580
1075
|
type: "button",
|
|
@@ -582,33 +1077,33 @@ var InputField = ({
|
|
|
582
1077
|
className: `absolute right-2 top-1/2 -translate-y-1/2 p-2 rounded-full transition-all ${isListening ? "bg-red-500 text-white animate-pulse" : "text-gray-500 hover:text-blue-600 hover:bg-gray-100 dark:hover:bg-gray-700"}`,
|
|
583
1078
|
title: isListening ? "Stop recording (ESC)" : `Voice input (click or press ${modKey}+/)`,
|
|
584
1079
|
"data-testid": "voice-input-button",
|
|
585
|
-
children: isListening ? /* @__PURE__ */
|
|
1080
|
+
children: isListening ? /* @__PURE__ */ jsx4("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) }) : /* @__PURE__ */ jsx4("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" }) })
|
|
586
1081
|
}
|
|
587
1082
|
),
|
|
588
|
-
inputValue.trim() && /* @__PURE__ */
|
|
1083
|
+
inputValue.trim() && /* @__PURE__ */ jsx4(
|
|
589
1084
|
"button",
|
|
590
1085
|
{
|
|
591
1086
|
type: "submit",
|
|
592
1087
|
className: compact ? "px-3 py-2 bg-gradient-to-r from-blue-500 to-blue-600 text-white rounded-xl hover:from-blue-600 hover:to-blue-700 disabled:from-gray-300 disabled:to-gray-400 disabled:cursor-not-allowed transition-all text-xs font-medium shadow-md hover:shadow-lg" : THEME_CLASSES.input.sendButton,
|
|
593
1088
|
"data-testid": ChatNames.sendButton,
|
|
594
1089
|
title: sendButtonLabel,
|
|
595
|
-
children: compact ? "\u2192" : /* @__PURE__ */
|
|
1090
|
+
children: compact ? "\u2192" : /* @__PURE__ */ jsx4("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2.5", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13 5l7 7m0 0l-7 7m7-7H3" }) })
|
|
596
1091
|
}
|
|
597
1092
|
)
|
|
598
1093
|
] }) });
|
|
599
1094
|
|
|
600
1095
|
// src/components/ChatBubble/Avatar.tsx
|
|
601
|
-
import { Fragment, jsx as
|
|
1096
|
+
import { Fragment, jsx as jsx5 } from "react/jsx-runtime";
|
|
602
1097
|
var Avatar = ({ avatar, size = "normal" }) => {
|
|
603
1098
|
if (!avatar) return null;
|
|
604
1099
|
if (typeof avatar === "string") {
|
|
605
|
-
return size === "small" ? /* @__PURE__ */
|
|
1100
|
+
return size === "small" ? /* @__PURE__ */ jsx5("span", { className: "text-lg", children: avatar }) : /* @__PURE__ */ jsx5("div", { className: "w-10 h-10 bg-blue-600 rounded-lg flex items-center justify-center shadow-md", children: /* @__PURE__ */ jsx5("span", { className: "text-white text-sm font-bold", children: avatar }) });
|
|
606
1101
|
}
|
|
607
|
-
return /* @__PURE__ */
|
|
1102
|
+
return /* @__PURE__ */ jsx5(Fragment, { children: avatar });
|
|
608
1103
|
};
|
|
609
1104
|
|
|
610
1105
|
// src/components/ChatBubble/ChatBubble.tsx
|
|
611
|
-
import
|
|
1106
|
+
import React9, { useState as useState9, useRef as useRef10, useEffect as useEffect8, useMemo as useMemo4 } from "react";
|
|
612
1107
|
|
|
613
1108
|
// src/components/MessageRenderer.tsx
|
|
614
1109
|
import ReactMarkdown from "react-markdown";
|
|
@@ -618,12 +1113,12 @@ import remarkDirective from "remark-directive";
|
|
|
618
1113
|
import rehypeKatex from "rehype-katex";
|
|
619
1114
|
|
|
620
1115
|
// src/components/CodeBlock.tsx
|
|
621
|
-
import
|
|
1116
|
+
import React5, { useState as useState3 } from "react";
|
|
622
1117
|
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
|
623
|
-
import { vscDarkPlus, vs } from "react-syntax-highlighter/dist/
|
|
624
|
-
import { jsx as
|
|
1118
|
+
import { vscDarkPlus, vs } from "react-syntax-highlighter/dist/esm/styles/prism";
|
|
1119
|
+
import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
625
1120
|
function CodeBlock({ children, className, inline, theme = "dark" }) {
|
|
626
|
-
const [copied, setCopied] =
|
|
1121
|
+
const [copied, setCopied] = useState3(false);
|
|
627
1122
|
const match = /language-(\w+)/.exec(className || "");
|
|
628
1123
|
const language = match ? match[1] : "text";
|
|
629
1124
|
const handleCopy = async () => {
|
|
@@ -632,25 +1127,25 @@ function CodeBlock({ children, className, inline, theme = "dark" }) {
|
|
|
632
1127
|
setTimeout(() => setCopied(false), 2e3);
|
|
633
1128
|
};
|
|
634
1129
|
if (inline) {
|
|
635
|
-
return /* @__PURE__ */
|
|
1130
|
+
return /* @__PURE__ */ jsx6("code", { className: `${className || ""} px-1.5 py-0.5 rounded text-sm font-mono ${theme === "dark" ? "bg-gray-800 text-gray-200" : "bg-gray-100 text-gray-800"}`, children });
|
|
636
1131
|
}
|
|
637
1132
|
return /* @__PURE__ */ jsxs2("div", { className: "relative group my-4", children: [
|
|
638
|
-
/* @__PURE__ */
|
|
1133
|
+
/* @__PURE__ */ jsx6(
|
|
639
1134
|
"button",
|
|
640
1135
|
{
|
|
641
1136
|
onClick: handleCopy,
|
|
642
1137
|
className: `absolute top-2 right-2 px-3 py-1.5 text-xs font-medium rounded transition-all ${theme === "dark" ? "bg-gray-700 hover:bg-gray-600 text-gray-200" : "bg-gray-200 hover:bg-gray-300 text-gray-700"} ${copied ? "opacity-100" : "opacity-0 group-hover:opacity-100"}`,
|
|
643
1138
|
"aria-label": "Copy code",
|
|
644
1139
|
children: copied ? /* @__PURE__ */ jsxs2("span", { className: "flex items-center gap-1", children: [
|
|
645
|
-
/* @__PURE__ */
|
|
1140
|
+
/* @__PURE__ */ jsx6("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
|
|
646
1141
|
"Copied!"
|
|
647
1142
|
] }) : /* @__PURE__ */ jsxs2("span", { className: "flex items-center gap-1", children: [
|
|
648
|
-
/* @__PURE__ */
|
|
1143
|
+
/* @__PURE__ */ jsx6("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
|
|
649
1144
|
"Copy"
|
|
650
1145
|
] })
|
|
651
1146
|
}
|
|
652
1147
|
),
|
|
653
|
-
|
|
1148
|
+
React5.createElement(SyntaxHighlighter, {
|
|
654
1149
|
language,
|
|
655
1150
|
style: theme === "dark" ? vscDarkPlus : vs,
|
|
656
1151
|
customStyle: {
|
|
@@ -667,13 +1162,13 @@ function CodeBlock({ children, className, inline, theme = "dark" }) {
|
|
|
667
1162
|
}
|
|
668
1163
|
|
|
669
1164
|
// src/components/MermaidDiagram.tsx
|
|
670
|
-
import { useEffect as
|
|
671
|
-
import { jsx as
|
|
1165
|
+
import { useEffect as useEffect3, useRef as useRef4, useState as useState4 } from "react";
|
|
1166
|
+
import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
672
1167
|
function MermaidDiagram({ chart, theme = "dark" }) {
|
|
673
|
-
const containerRef =
|
|
674
|
-
const [error, setError] =
|
|
675
|
-
const [isLoading, setIsLoading] =
|
|
676
|
-
|
|
1168
|
+
const containerRef = useRef4(null);
|
|
1169
|
+
const [error, setError] = useState4(null);
|
|
1170
|
+
const [isLoading, setIsLoading] = useState4(true);
|
|
1171
|
+
useEffect3(() => {
|
|
677
1172
|
let mounted = true;
|
|
678
1173
|
const renderDiagram = async () => {
|
|
679
1174
|
if (!containerRef.current) return;
|
|
@@ -708,17 +1203,17 @@ function MermaidDiagram({ chart, theme = "dark" }) {
|
|
|
708
1203
|
}, [chart, theme]);
|
|
709
1204
|
if (error) {
|
|
710
1205
|
return /* @__PURE__ */ jsxs3("div", { className: `my-4 p-4 rounded-lg border ${theme === "dark" ? "bg-red-900/20 border-red-500 text-red-200" : "bg-red-50 border-red-300 text-red-800"}`, children: [
|
|
711
|
-
/* @__PURE__ */
|
|
712
|
-
/* @__PURE__ */
|
|
1206
|
+
/* @__PURE__ */ jsx7("div", { className: "font-semibold mb-1", children: "Mermaid Diagram Error" }),
|
|
1207
|
+
/* @__PURE__ */ jsx7("div", { className: "text-sm opacity-90", children: error }),
|
|
713
1208
|
/* @__PURE__ */ jsxs3("details", { className: "mt-2 text-xs opacity-75", children: [
|
|
714
|
-
/* @__PURE__ */
|
|
715
|
-
/* @__PURE__ */
|
|
1209
|
+
/* @__PURE__ */ jsx7("summary", { className: "cursor-pointer", children: "View diagram source" }),
|
|
1210
|
+
/* @__PURE__ */ jsx7("pre", { className: "mt-2 whitespace-pre-wrap", children: chart })
|
|
716
1211
|
] })
|
|
717
1212
|
] });
|
|
718
1213
|
}
|
|
719
1214
|
return /* @__PURE__ */ jsxs3("div", { className: "my-4 flex justify-center", children: [
|
|
720
|
-
isLoading && /* @__PURE__ */
|
|
721
|
-
/* @__PURE__ */
|
|
1215
|
+
isLoading && /* @__PURE__ */ jsx7("div", { className: `py-8 text-sm ${theme === "dark" ? "text-gray-400" : "text-gray-600"}`, children: "Rendering diagram..." }),
|
|
1216
|
+
/* @__PURE__ */ jsx7(
|
|
722
1217
|
"div",
|
|
723
1218
|
{
|
|
724
1219
|
ref: containerRef,
|
|
@@ -729,7 +1224,7 @@ function MermaidDiagram({ chart, theme = "dark" }) {
|
|
|
729
1224
|
}
|
|
730
1225
|
|
|
731
1226
|
// src/components/MessageRenderer.tsx
|
|
732
|
-
import { jsx as
|
|
1227
|
+
import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
733
1228
|
function MessageRenderer({ content, theme = "dark" }) {
|
|
734
1229
|
const components = {
|
|
735
1230
|
// Code blocks with syntax highlighting
|
|
@@ -740,9 +1235,9 @@ function MessageRenderer({ content, theme = "dark" }) {
|
|
|
740
1235
|
const language = match ? match[1] : "";
|
|
741
1236
|
const inline = !className;
|
|
742
1237
|
if (language === "mermaid") {
|
|
743
|
-
return /* @__PURE__ */
|
|
1238
|
+
return /* @__PURE__ */ jsx8(MermaidDiagram, { chart: value, theme });
|
|
744
1239
|
}
|
|
745
|
-
return /* @__PURE__ */
|
|
1240
|
+
return /* @__PURE__ */ jsx8(
|
|
746
1241
|
CodeBlock,
|
|
747
1242
|
{
|
|
748
1243
|
className,
|
|
@@ -753,13 +1248,13 @@ function MessageRenderer({ content, theme = "dark" }) {
|
|
|
753
1248
|
);
|
|
754
1249
|
},
|
|
755
1250
|
// Headings with better styling
|
|
756
|
-
h1: ({ children }) => /* @__PURE__ */
|
|
757
|
-
h2: ({ children }) => /* @__PURE__ */
|
|
758
|
-
h3: ({ children }) => /* @__PURE__ */
|
|
1251
|
+
h1: ({ children }) => /* @__PURE__ */ jsx8("h1", { className: `text-2xl font-bold mt-6 mb-3 ${theme === "dark" ? "text-gray-100" : "text-gray-900"}`, children }),
|
|
1252
|
+
h2: ({ children }) => /* @__PURE__ */ jsx8("h2", { className: `text-xl font-bold mt-5 mb-2.5 ${theme === "dark" ? "text-gray-100" : "text-gray-900"}`, children }),
|
|
1253
|
+
h3: ({ children }) => /* @__PURE__ */ jsx8("h3", { className: `text-lg font-semibold mt-4 mb-2 ${theme === "dark" ? "text-gray-200" : "text-gray-800"}`, children }),
|
|
759
1254
|
// Paragraphs
|
|
760
|
-
p: ({ children }) => /* @__PURE__ */
|
|
1255
|
+
p: ({ children }) => /* @__PURE__ */ jsx8("p", { className: `mb-3 leading-relaxed ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
|
|
761
1256
|
// Links
|
|
762
|
-
a: ({ href, children }) => /* @__PURE__ */
|
|
1257
|
+
a: ({ href, children }) => /* @__PURE__ */ jsx8(
|
|
763
1258
|
"a",
|
|
764
1259
|
{
|
|
765
1260
|
href,
|
|
@@ -770,17 +1265,17 @@ function MessageRenderer({ content, theme = "dark" }) {
|
|
|
770
1265
|
}
|
|
771
1266
|
),
|
|
772
1267
|
// Lists
|
|
773
|
-
ul: ({ children }) => /* @__PURE__ */
|
|
774
|
-
ol: ({ children }) => /* @__PURE__ */
|
|
1268
|
+
ul: ({ children }) => /* @__PURE__ */ jsx8("ul", { className: `list-disc list-inside mb-3 space-y-1 ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
|
|
1269
|
+
ol: ({ children }) => /* @__PURE__ */ jsx8("ol", { className: `list-decimal list-inside mb-3 space-y-1 ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
|
|
775
1270
|
// Blockquotes
|
|
776
|
-
blockquote: ({ children }) => /* @__PURE__ */
|
|
1271
|
+
blockquote: ({ children }) => /* @__PURE__ */ jsx8("blockquote", { className: `border-l-4 pl-4 my-3 italic ${theme === "dark" ? "border-blue-500 bg-blue-900/20 py-2 pr-2" : "border-blue-400 bg-blue-50 py-2 pr-2"}`, children }),
|
|
777
1272
|
// Tables
|
|
778
|
-
table: ({ children }) => /* @__PURE__ */
|
|
779
|
-
thead: ({ children }) => /* @__PURE__ */
|
|
780
|
-
th: ({ children }) => /* @__PURE__ */
|
|
781
|
-
td: ({ children }) => /* @__PURE__ */
|
|
1273
|
+
table: ({ children }) => /* @__PURE__ */ jsx8("div", { className: "overflow-x-auto my-4", children: /* @__PURE__ */ jsx8("table", { className: `min-w-full border-collapse ${theme === "dark" ? "border-gray-700" : "border-gray-300"}`, children }) }),
|
|
1274
|
+
thead: ({ children }) => /* @__PURE__ */ jsx8("thead", { className: theme === "dark" ? "bg-gray-800" : "bg-gray-100", children }),
|
|
1275
|
+
th: ({ children }) => /* @__PURE__ */ jsx8("th", { className: `px-4 py-2 text-left font-semibold border ${theme === "dark" ? "border-gray-700 text-gray-200" : "border-gray-300 text-gray-800"}`, children }),
|
|
1276
|
+
td: ({ children }) => /* @__PURE__ */ jsx8("td", { className: `px-4 py-2 border ${theme === "dark" ? "border-gray-700 text-gray-300" : "border-gray-300 text-gray-700"}`, children }),
|
|
782
1277
|
// Horizontal rule
|
|
783
|
-
hr: () => /* @__PURE__ */
|
|
1278
|
+
hr: () => /* @__PURE__ */ jsx8("hr", { className: `my-4 border-t ${theme === "dark" ? "border-gray-700" : "border-gray-300"}` }),
|
|
784
1279
|
// Admonitions support (using containerDirective from remark-directive)
|
|
785
1280
|
div: ({ node, className, children, ...props }) => {
|
|
786
1281
|
if (className?.includes("admonition")) {
|
|
@@ -808,15 +1303,15 @@ function MessageRenderer({ content, theme = "dark" }) {
|
|
|
808
1303
|
}
|
|
809
1304
|
};
|
|
810
1305
|
const style = styles[type] || styles.info;
|
|
811
|
-
return /* @__PURE__ */
|
|
812
|
-
/* @__PURE__ */
|
|
813
|
-
/* @__PURE__ */
|
|
1306
|
+
return /* @__PURE__ */ jsx8("div", { className: `my-4 p-4 border-l-4 rounded-r-lg ${style.border} ${style.bg}`, children: /* @__PURE__ */ jsxs4("div", { className: "flex items-start gap-2", children: [
|
|
1307
|
+
/* @__PURE__ */ jsx8("span", { className: "text-lg flex-shrink-0", children: style.icon }),
|
|
1308
|
+
/* @__PURE__ */ jsx8("div", { className: "flex-1", children })
|
|
814
1309
|
] }) });
|
|
815
1310
|
}
|
|
816
|
-
return /* @__PURE__ */
|
|
1311
|
+
return /* @__PURE__ */ jsx8("div", { className, ...props, children });
|
|
817
1312
|
}
|
|
818
1313
|
};
|
|
819
|
-
return /* @__PURE__ */
|
|
1314
|
+
return /* @__PURE__ */ jsx8("div", { className: "markdown-content", children: /* @__PURE__ */ jsx8(
|
|
820
1315
|
ReactMarkdown,
|
|
821
1316
|
{
|
|
822
1317
|
remarkPlugins: [remarkGfm, remarkMath, remarkDirective],
|
|
@@ -828,7 +1323,7 @@ function MessageRenderer({ content, theme = "dark" }) {
|
|
|
828
1323
|
}
|
|
829
1324
|
|
|
830
1325
|
// src/hooks/useTTS.ts
|
|
831
|
-
import { useState as
|
|
1326
|
+
import { useState as useState5, useRef as useRef5, useCallback as useCallback4 } from "react";
|
|
832
1327
|
var Platform = {
|
|
833
1328
|
isNative: typeof window !== "undefined" && "Capacitor" in window,
|
|
834
1329
|
isWeb: typeof window !== "undefined" && !("Capacitor" in window)
|
|
@@ -843,13 +1338,13 @@ function isNativeTTSSupported() {
|
|
|
843
1338
|
return false;
|
|
844
1339
|
}
|
|
845
1340
|
function useTTS() {
|
|
846
|
-
const [isPlaying, setIsPlaying] =
|
|
847
|
-
const [error, setError] =
|
|
848
|
-
const [currentText, setCurrentText] =
|
|
849
|
-
const audioRef =
|
|
850
|
-
const utteranceRef =
|
|
1341
|
+
const [isPlaying, setIsPlaying] = useState5(false);
|
|
1342
|
+
const [error, setError] = useState5(null);
|
|
1343
|
+
const [currentText, setCurrentText] = useState5(null);
|
|
1344
|
+
const audioRef = useRef5(null);
|
|
1345
|
+
const utteranceRef = useRef5(null);
|
|
851
1346
|
const isNativeSupported = isNativeTTSSupported();
|
|
852
|
-
const speakNative =
|
|
1347
|
+
const speakNative = useCallback4(
|
|
853
1348
|
async (text, options = {}) => {
|
|
854
1349
|
if (Platform.isNative) {
|
|
855
1350
|
try {
|
|
@@ -894,7 +1389,7 @@ function useTTS() {
|
|
|
894
1389
|
},
|
|
895
1390
|
[]
|
|
896
1391
|
);
|
|
897
|
-
const speakAPI =
|
|
1392
|
+
const speakAPI = useCallback4(
|
|
898
1393
|
async (text, options = {}) => {
|
|
899
1394
|
const apiUrl = process.env.NEXT_PUBLIC_TTS_API_URL || "https://tts.supernal.ai";
|
|
900
1395
|
const apiKey = process.env.NEXT_PUBLIC_TTS_API_KEY || "";
|
|
@@ -955,7 +1450,7 @@ function useTTS() {
|
|
|
955
1450
|
},
|
|
956
1451
|
[]
|
|
957
1452
|
);
|
|
958
|
-
const speak =
|
|
1453
|
+
const speak = useCallback4(
|
|
959
1454
|
async (options) => {
|
|
960
1455
|
const {
|
|
961
1456
|
text,
|
|
@@ -999,7 +1494,7 @@ function useTTS() {
|
|
|
999
1494
|
},
|
|
1000
1495
|
[speakNative, speakAPI, isNativeSupported]
|
|
1001
1496
|
);
|
|
1002
|
-
const stop =
|
|
1497
|
+
const stop = useCallback4(() => {
|
|
1003
1498
|
if ("speechSynthesis" in window && window.speechSynthesis.speaking) {
|
|
1004
1499
|
window.speechSynthesis.cancel();
|
|
1005
1500
|
utteranceRef.current = null;
|
|
@@ -1032,18 +1527,18 @@ function base64ToBlob(base64, mimeType) {
|
|
|
1032
1527
|
}
|
|
1033
1528
|
|
|
1034
1529
|
// src/hooks/useSTT.ts
|
|
1035
|
-
import { useState as
|
|
1530
|
+
import { useState as useState6, useRef as useRef6, useCallback as useCallback5, useMemo as useMemo2, useEffect as useEffect4 } from "react";
|
|
1036
1531
|
var Platform2 = {
|
|
1037
1532
|
isNative: typeof window !== "undefined" && "Capacitor" in window,
|
|
1038
1533
|
isWeb: typeof window !== "undefined" && !("Capacitor" in window)
|
|
1039
1534
|
};
|
|
1040
1535
|
function useSTT() {
|
|
1041
|
-
const [isListening, setIsListening] =
|
|
1042
|
-
const [transcript, setTranscript] =
|
|
1043
|
-
const [interimTranscript, setInterimTranscript] =
|
|
1044
|
-
const [error, setError] =
|
|
1045
|
-
const recognitionRef =
|
|
1046
|
-
const isSupported =
|
|
1536
|
+
const [isListening, setIsListening] = useState6(false);
|
|
1537
|
+
const [transcript, setTranscript] = useState6("");
|
|
1538
|
+
const [interimTranscript, setInterimTranscript] = useState6("");
|
|
1539
|
+
const [error, setError] = useState6(null);
|
|
1540
|
+
const recognitionRef = useRef6(null);
|
|
1541
|
+
const isSupported = useMemo2(() => {
|
|
1047
1542
|
if (Platform2.isNative) {
|
|
1048
1543
|
return true;
|
|
1049
1544
|
}
|
|
@@ -1052,7 +1547,7 @@ function useSTT() {
|
|
|
1052
1547
|
}
|
|
1053
1548
|
return false;
|
|
1054
1549
|
}, []);
|
|
1055
|
-
|
|
1550
|
+
useEffect4(() => {
|
|
1056
1551
|
if (!isSupported || Platform2.isNative) return;
|
|
1057
1552
|
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
1058
1553
|
if (!SpeechRecognition) return;
|
|
@@ -1090,7 +1585,7 @@ function useSTT() {
|
|
|
1090
1585
|
}
|
|
1091
1586
|
};
|
|
1092
1587
|
}, [isSupported]);
|
|
1093
|
-
const startListening =
|
|
1588
|
+
const startListening = useCallback5(async () => {
|
|
1094
1589
|
setError(null);
|
|
1095
1590
|
setTranscript("");
|
|
1096
1591
|
setInterimTranscript("");
|
|
@@ -1122,7 +1617,7 @@ function useSTT() {
|
|
|
1122
1617
|
setIsListening(false);
|
|
1123
1618
|
}
|
|
1124
1619
|
}, []);
|
|
1125
|
-
const stopListening =
|
|
1620
|
+
const stopListening = useCallback5(() => {
|
|
1126
1621
|
if (Platform2.isNative) {
|
|
1127
1622
|
setIsListening(false);
|
|
1128
1623
|
return;
|
|
@@ -1131,7 +1626,7 @@ function useSTT() {
|
|
|
1131
1626
|
recognitionRef.current.stop();
|
|
1132
1627
|
}
|
|
1133
1628
|
}, []);
|
|
1134
|
-
const resetTranscript =
|
|
1629
|
+
const resetTranscript = useCallback5(() => {
|
|
1135
1630
|
setTranscript("");
|
|
1136
1631
|
setInterimTranscript("");
|
|
1137
1632
|
setError(null);
|
|
@@ -1149,7 +1644,7 @@ function useSTT() {
|
|
|
1149
1644
|
}
|
|
1150
1645
|
|
|
1151
1646
|
// src/components/TTSButton.tsx
|
|
1152
|
-
import { jsx as
|
|
1647
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
1153
1648
|
function TTSButton({
|
|
1154
1649
|
text,
|
|
1155
1650
|
usePremiumVoices = false,
|
|
@@ -1177,7 +1672,7 @@ function TTSButton({
|
|
|
1177
1672
|
const isDark = theme === "dark";
|
|
1178
1673
|
const iconSize = size === "small" ? "w-3 h-3" : "w-4 h-4";
|
|
1179
1674
|
const buttonPadding = size === "small" ? "p-1" : "p-2";
|
|
1180
|
-
return /* @__PURE__ */
|
|
1675
|
+
return /* @__PURE__ */ jsx9(
|
|
1181
1676
|
"button",
|
|
1182
1677
|
{
|
|
1183
1678
|
onClick: handleClick,
|
|
@@ -1187,23 +1682,23 @@ function TTSButton({
|
|
|
1187
1682
|
"aria-label": isPlaying ? "Stop speaking" : "Read aloud",
|
|
1188
1683
|
children: isPlaying ? (
|
|
1189
1684
|
// Stop icon (pulsing square)
|
|
1190
|
-
/* @__PURE__ */
|
|
1685
|
+
/* @__PURE__ */ jsx9("svg", { className: iconSize, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx9("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) })
|
|
1191
1686
|
) : error ? (
|
|
1192
1687
|
// Error icon
|
|
1193
|
-
/* @__PURE__ */
|
|
1688
|
+
/* @__PURE__ */ jsx9("svg", { className: iconSize, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx9("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) })
|
|
1194
1689
|
) : (
|
|
1195
1690
|
// Speaker icon
|
|
1196
|
-
/* @__PURE__ */
|
|
1691
|
+
/* @__PURE__ */ jsx9("svg", { className: iconSize, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx9("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15.536 8.464a5 5 0 010 7.072m2.828-9.9a9 9 0 010 12.728M5.586 15.414a2 2 0 002.828 0l1.768-1.768a2 2 0 00 0-2.828l-1.768-1.768a2 2 0 00-2.828 0V15.414z" }) })
|
|
1197
1692
|
)
|
|
1198
1693
|
}
|
|
1199
1694
|
);
|
|
1200
1695
|
}
|
|
1201
1696
|
|
|
1202
1697
|
// src/components/SubtitleOverlay.tsx
|
|
1203
|
-
import { useState as
|
|
1698
|
+
import { useState as useState7, useEffect as useEffect5, useRef as useRef7 } from "react";
|
|
1204
1699
|
|
|
1205
1700
|
// src/components/TTSPlaylistMenu.tsx
|
|
1206
|
-
import { jsx as
|
|
1701
|
+
import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1207
1702
|
var TTSPlaylistMenu = ({
|
|
1208
1703
|
isOpen,
|
|
1209
1704
|
onClose,
|
|
@@ -1224,7 +1719,7 @@ var TTSPlaylistMenu = ({
|
|
|
1224
1719
|
border: "1px solid rgba(0, 0, 0, 0.1)",
|
|
1225
1720
|
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.2)"
|
|
1226
1721
|
};
|
|
1227
|
-
return /* @__PURE__ */
|
|
1722
|
+
return /* @__PURE__ */ jsx10(
|
|
1228
1723
|
"div",
|
|
1229
1724
|
{
|
|
1230
1725
|
className: "fixed z-50",
|
|
@@ -1250,33 +1745,33 @@ var TTSPlaylistMenu = ({
|
|
|
1250
1745
|
{
|
|
1251
1746
|
className: `p-4 border-b flex items-center justify-between ${theme === "dark" ? "border-white/10" : "border-black/10"}`,
|
|
1252
1747
|
children: [
|
|
1253
|
-
/* @__PURE__ */
|
|
1748
|
+
/* @__PURE__ */ jsx10(
|
|
1254
1749
|
"h3",
|
|
1255
1750
|
{
|
|
1256
1751
|
className: `font-semibold text-sm ${theme === "dark" ? "text-white" : "text-gray-900"}`,
|
|
1257
1752
|
children: "Readable Sections"
|
|
1258
1753
|
}
|
|
1259
1754
|
),
|
|
1260
|
-
/* @__PURE__ */
|
|
1755
|
+
/* @__PURE__ */ jsx10(
|
|
1261
1756
|
"button",
|
|
1262
1757
|
{
|
|
1263
1758
|
onClick: onClose,
|
|
1264
1759
|
className: `p-1.5 rounded-lg transition-all ${theme === "dark" ? "text-gray-400 hover:text-white hover:bg-white/10" : "text-gray-600 hover:text-gray-900 hover:bg-black/5"}`,
|
|
1265
1760
|
title: "Close",
|
|
1266
1761
|
"data-testid": "close-playlist-menu",
|
|
1267
|
-
children: /* @__PURE__ */
|
|
1762
|
+
children: /* @__PURE__ */ jsx10("span", { className: "text-lg font-bold", "aria-hidden": "true", children: "\xD7" })
|
|
1268
1763
|
}
|
|
1269
1764
|
)
|
|
1270
1765
|
]
|
|
1271
1766
|
}
|
|
1272
1767
|
),
|
|
1273
|
-
/* @__PURE__ */
|
|
1768
|
+
/* @__PURE__ */ jsx10("div", { className: "overflow-y-auto max-h-80 p-2", children: widgets.length === 0 ? /* @__PURE__ */ jsx10(
|
|
1274
1769
|
"div",
|
|
1275
1770
|
{
|
|
1276
1771
|
className: `p-6 text-center text-sm ${theme === "dark" ? "text-gray-400" : "text-gray-600"}`,
|
|
1277
1772
|
children: "No readable sections found on this page"
|
|
1278
1773
|
}
|
|
1279
|
-
) : widgets.map((widget) => /* @__PURE__ */
|
|
1774
|
+
) : widgets.map((widget) => /* @__PURE__ */ jsx10(
|
|
1280
1775
|
"button",
|
|
1281
1776
|
{
|
|
1282
1777
|
onClick: () => handleWidgetClick(widget),
|
|
@@ -1291,7 +1786,7 @@ var TTSPlaylistMenu = ({
|
|
|
1291
1786
|
{
|
|
1292
1787
|
className: `font-medium text-sm flex items-center ${theme === "dark" ? "text-white" : "text-gray-900"}`,
|
|
1293
1788
|
children: [
|
|
1294
|
-
/* @__PURE__ */
|
|
1789
|
+
/* @__PURE__ */ jsx10("span", { className: "mr-2", "aria-hidden": "true", children: "\u{1F50A}" }),
|
|
1295
1790
|
widget.label || `TTS Widget ${widget.id}`
|
|
1296
1791
|
]
|
|
1297
1792
|
}
|
|
@@ -1514,7 +2009,7 @@ function extractTTSWidgets() {
|
|
|
1514
2009
|
}
|
|
1515
2010
|
|
|
1516
2011
|
// src/components/SubtitleOverlay.tsx
|
|
1517
|
-
import { Fragment as Fragment2, jsx as
|
|
2012
|
+
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1518
2013
|
var opacityStates = {
|
|
1519
2014
|
mobile: {
|
|
1520
2015
|
idle: 1,
|
|
@@ -1558,47 +2053,47 @@ var SubtitleOverlay = ({
|
|
|
1558
2053
|
resetTranscript,
|
|
1559
2054
|
onSwitchToFullMode
|
|
1560
2055
|
}) => {
|
|
1561
|
-
const [overlayState, setOverlayState] =
|
|
1562
|
-
const [opacity, setOpacity] =
|
|
1563
|
-
const [lastInputMethod, setLastInputMethod] =
|
|
1564
|
-
const [isMobile, setIsMobile] =
|
|
1565
|
-
const [messageOpacity, setMessageOpacity] =
|
|
1566
|
-
const [expansionState, setExpansionState] =
|
|
2056
|
+
const [overlayState, setOverlayState] = useState7("idle");
|
|
2057
|
+
const [opacity, setOpacity] = useState7(1);
|
|
2058
|
+
const [lastInputMethod, setLastInputMethod] = useState7(null);
|
|
2059
|
+
const [isMobile, setIsMobile] = useState7(false);
|
|
2060
|
+
const [messageOpacity, setMessageOpacity] = useState7(1);
|
|
2061
|
+
const [expansionState, setExpansionState] = useState7(() => {
|
|
1567
2062
|
if (typeof window !== "undefined") {
|
|
1568
2063
|
const saved = localStorage.getItem("subtitle-overlay-expanded");
|
|
1569
2064
|
return saved === "true" ? "expanded" : "collapsed";
|
|
1570
2065
|
}
|
|
1571
2066
|
return "collapsed";
|
|
1572
2067
|
});
|
|
1573
|
-
const [touchStartY, setTouchStartY] =
|
|
1574
|
-
const lastInputTimeRef =
|
|
1575
|
-
const autoFadeTimerRef =
|
|
1576
|
-
const messageFadeTimerRef =
|
|
1577
|
-
const inputRef =
|
|
1578
|
-
const [suggestions, setSuggestions] =
|
|
1579
|
-
const [currentSuggestionIndex, setCurrentSuggestionIndex] =
|
|
1580
|
-
const [glassTheme, setGlassTheme] =
|
|
1581
|
-
const [detectedGlassTheme, setDetectedGlassTheme] =
|
|
1582
|
-
const [hasTTSWidgets, setHasTTSWidgets] =
|
|
1583
|
-
const [showPlaylist, setShowPlaylist] =
|
|
1584
|
-
const [ttsWidgets, setTTSWidgets] =
|
|
1585
|
-
const [touchStartYInput, setTouchStartYInput] =
|
|
1586
|
-
const [completedActions, setCompletedActions] =
|
|
1587
|
-
const [showCompletedActions, setShowCompletedActions] =
|
|
1588
|
-
const [shouldShowAiResponse, setShouldShowAiResponse] =
|
|
1589
|
-
const [latestActionOpacity, setLatestActionOpacity] =
|
|
1590
|
-
const latestActionFadeRef =
|
|
1591
|
-
const lastUserMessageRef =
|
|
1592
|
-
const lastShownAiMessageRef =
|
|
1593
|
-
const justExpandedViaSlashRef =
|
|
1594
|
-
const [isDragging, setIsDragging] =
|
|
1595
|
-
const [position, setPosition] =
|
|
1596
|
-
const [dragStart, setDragStart] =
|
|
1597
|
-
const dragRef =
|
|
1598
|
-
const dragDistanceRef =
|
|
1599
|
-
const lastEscapeTimeRef =
|
|
2068
|
+
const [touchStartY, setTouchStartY] = useState7(null);
|
|
2069
|
+
const lastInputTimeRef = useRef7(Date.now());
|
|
2070
|
+
const autoFadeTimerRef = useRef7(null);
|
|
2071
|
+
const messageFadeTimerRef = useRef7(null);
|
|
2072
|
+
const inputRef = useRef7(null);
|
|
2073
|
+
const [suggestions, setSuggestions] = useState7([]);
|
|
2074
|
+
const [currentSuggestionIndex, setCurrentSuggestionIndex] = useState7(0);
|
|
2075
|
+
const [glassTheme, setGlassTheme] = useState7("auto");
|
|
2076
|
+
const [detectedGlassTheme, setDetectedGlassTheme] = useState7("light");
|
|
2077
|
+
const [hasTTSWidgets, setHasTTSWidgets] = useState7(false);
|
|
2078
|
+
const [showPlaylist, setShowPlaylist] = useState7(false);
|
|
2079
|
+
const [ttsWidgets, setTTSWidgets] = useState7([]);
|
|
2080
|
+
const [touchStartYInput, setTouchStartYInput] = useState7(null);
|
|
2081
|
+
const [completedActions, setCompletedActions] = useState7([]);
|
|
2082
|
+
const [showCompletedActions, setShowCompletedActions] = useState7(false);
|
|
2083
|
+
const [shouldShowAiResponse, setShouldShowAiResponse] = useState7(false);
|
|
2084
|
+
const [latestActionOpacity, setLatestActionOpacity] = useState7(0);
|
|
2085
|
+
const latestActionFadeRef = useRef7(null);
|
|
2086
|
+
const lastUserMessageRef = useRef7("");
|
|
2087
|
+
const lastShownAiMessageRef = useRef7("");
|
|
2088
|
+
const justExpandedViaSlashRef = useRef7(false);
|
|
2089
|
+
const [isDragging, setIsDragging] = useState7(false);
|
|
2090
|
+
const [position, setPosition] = useState7({ x: 0, y: 0 });
|
|
2091
|
+
const [dragStart, setDragStart] = useState7({ x: 0, y: 0 });
|
|
2092
|
+
const dragRef = useRef7(null);
|
|
2093
|
+
const dragDistanceRef = useRef7(0);
|
|
2094
|
+
const lastEscapeTimeRef = useRef7(0);
|
|
1600
2095
|
const DOUBLE_ESCAPE_THRESHOLD_MS = 500;
|
|
1601
|
-
|
|
2096
|
+
useEffect5(() => {
|
|
1602
2097
|
const checkMobile = () => {
|
|
1603
2098
|
const mobile = window.innerWidth < 768;
|
|
1604
2099
|
setIsMobile(mobile);
|
|
@@ -1607,7 +2102,7 @@ var SubtitleOverlay = ({
|
|
|
1607
2102
|
window.addEventListener("resize", checkMobile);
|
|
1608
2103
|
return () => window.removeEventListener("resize", checkMobile);
|
|
1609
2104
|
}, []);
|
|
1610
|
-
|
|
2105
|
+
useEffect5(() => {
|
|
1611
2106
|
if (autoFadeTimerRef.current) {
|
|
1612
2107
|
clearTimeout(autoFadeTimerRef.current);
|
|
1613
2108
|
autoFadeTimerRef.current = null;
|
|
@@ -1623,7 +2118,7 @@ var SubtitleOverlay = ({
|
|
|
1623
2118
|
}
|
|
1624
2119
|
};
|
|
1625
2120
|
}, [overlayState, isMobile]);
|
|
1626
|
-
|
|
2121
|
+
useEffect5(() => {
|
|
1627
2122
|
if (messageFadeTimerRef.current) {
|
|
1628
2123
|
clearTimeout(messageFadeTimerRef.current);
|
|
1629
2124
|
messageFadeTimerRef.current = null;
|
|
@@ -1659,7 +2154,7 @@ var SubtitleOverlay = ({
|
|
|
1659
2154
|
}
|
|
1660
2155
|
};
|
|
1661
2156
|
}, [messages.filter((m) => m.type === "ai").slice(-1)[0]?.text, shouldShowAiResponse]);
|
|
1662
|
-
|
|
2157
|
+
useEffect5(() => {
|
|
1663
2158
|
if (sttTranscript && voiceEnabled && resetTranscript) {
|
|
1664
2159
|
onSendMessage(sttTranscript);
|
|
1665
2160
|
resetTranscript();
|
|
@@ -1676,11 +2171,11 @@ var SubtitleOverlay = ({
|
|
|
1676
2171
|
triggerActionFade();
|
|
1677
2172
|
}
|
|
1678
2173
|
}, [sttTranscript, voiceEnabled, resetTranscript, onSendMessage]);
|
|
1679
|
-
|
|
2174
|
+
useEffect5(() => {
|
|
1680
2175
|
const pageSuggestions = extractPageSuggestions();
|
|
1681
2176
|
setSuggestions(pageSuggestions);
|
|
1682
2177
|
}, []);
|
|
1683
|
-
|
|
2178
|
+
useEffect5(() => {
|
|
1684
2179
|
const detectWidgets = async () => {
|
|
1685
2180
|
const detected = await detectTTSWidgets();
|
|
1686
2181
|
setHasTTSWidgets(detected);
|
|
@@ -1715,7 +2210,7 @@ var SubtitleOverlay = ({
|
|
|
1715
2210
|
window.removeEventListener("supernal-tts-ready", handleReady);
|
|
1716
2211
|
};
|
|
1717
2212
|
}, []);
|
|
1718
|
-
|
|
2213
|
+
useEffect5(() => {
|
|
1719
2214
|
if (glassTheme !== "auto") return;
|
|
1720
2215
|
const { glassTheme: detected } = detectBackgroundContext();
|
|
1721
2216
|
setDetectedGlassTheme(detected);
|
|
@@ -1731,7 +2226,7 @@ var SubtitleOverlay = ({
|
|
|
1731
2226
|
window.addEventListener("scroll", handleScroll);
|
|
1732
2227
|
return () => window.removeEventListener("scroll", handleScroll);
|
|
1733
2228
|
}, [glassTheme]);
|
|
1734
|
-
|
|
2229
|
+
useEffect5(() => {
|
|
1735
2230
|
const handleGlobalKeyDown = (e) => {
|
|
1736
2231
|
if (e.key === "Escape") {
|
|
1737
2232
|
const now = Date.now();
|
|
@@ -1778,12 +2273,12 @@ var SubtitleOverlay = ({
|
|
|
1778
2273
|
window.addEventListener("keydown", handleGlobalKeyDown);
|
|
1779
2274
|
return () => window.removeEventListener("keydown", handleGlobalKeyDown);
|
|
1780
2275
|
}, [expansionState, onSwitchToFullMode, voiceEnabled, onMicClick]);
|
|
1781
|
-
|
|
2276
|
+
useEffect5(() => {
|
|
1782
2277
|
if (typeof window !== "undefined") {
|
|
1783
2278
|
localStorage.setItem("subtitle-overlay-expanded", expansionState === "expanded" ? "true" : "false");
|
|
1784
2279
|
}
|
|
1785
2280
|
}, [expansionState]);
|
|
1786
|
-
|
|
2281
|
+
useEffect5(() => {
|
|
1787
2282
|
if (expansionState === "expanded" && inputRef.current) {
|
|
1788
2283
|
setTimeout(() => {
|
|
1789
2284
|
inputRef.current?.focus();
|
|
@@ -1797,7 +2292,7 @@ var SubtitleOverlay = ({
|
|
|
1797
2292
|
}, 100);
|
|
1798
2293
|
}
|
|
1799
2294
|
}, [expansionState]);
|
|
1800
|
-
|
|
2295
|
+
useEffect5(() => {
|
|
1801
2296
|
if (isMobile) return;
|
|
1802
2297
|
const handleMouseMove = (e) => {
|
|
1803
2298
|
if (!isDragging) return;
|
|
@@ -1821,7 +2316,7 @@ var SubtitleOverlay = ({
|
|
|
1821
2316
|
window.removeEventListener("mouseup", handleMouseUp);
|
|
1822
2317
|
};
|
|
1823
2318
|
}, [isDragging, dragStart, isMobile]);
|
|
1824
|
-
|
|
2319
|
+
useEffect5(() => {
|
|
1825
2320
|
const timeSinceLastInput = Date.now() - lastInputTimeRef.current;
|
|
1826
2321
|
const context = {
|
|
1827
2322
|
isListening,
|
|
@@ -1982,7 +2477,7 @@ var SubtitleOverlay = ({
|
|
|
1982
2477
|
};
|
|
1983
2478
|
if (expansionState === "collapsed") {
|
|
1984
2479
|
return /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1985
|
-
hasTTSWidgets && /* @__PURE__ */
|
|
2480
|
+
hasTTSWidgets && /* @__PURE__ */ jsx11(
|
|
1986
2481
|
"button",
|
|
1987
2482
|
{
|
|
1988
2483
|
type: "button",
|
|
@@ -2001,10 +2496,10 @@ var SubtitleOverlay = ({
|
|
|
2001
2496
|
title: ttsWidgets.length === 1 ? "Go to readable section" : "View readable sections",
|
|
2002
2497
|
"data-testid": "tts-playlist-button",
|
|
2003
2498
|
"aria-label": ttsWidgets.length === 1 ? "Go to readable section" : "View readable sections",
|
|
2004
|
-
children: /* @__PURE__ */
|
|
2499
|
+
children: /* @__PURE__ */ jsx11("span", { className: "text-xl font-bold select-none", "aria-hidden": "true", children: "~+" })
|
|
2005
2500
|
}
|
|
2006
2501
|
),
|
|
2007
|
-
/* @__PURE__ */
|
|
2502
|
+
/* @__PURE__ */ jsx11(
|
|
2008
2503
|
TTSPlaylistMenu,
|
|
2009
2504
|
{
|
|
2010
2505
|
isOpen: showPlaylist,
|
|
@@ -2014,7 +2509,7 @@ var SubtitleOverlay = ({
|
|
|
2014
2509
|
onWidgetSelect: handleWidgetSelect
|
|
2015
2510
|
}
|
|
2016
2511
|
),
|
|
2017
|
-
/* @__PURE__ */
|
|
2512
|
+
/* @__PURE__ */ jsx11(
|
|
2018
2513
|
"div",
|
|
2019
2514
|
{
|
|
2020
2515
|
className: "fixed",
|
|
@@ -2024,7 +2519,7 @@ var SubtitleOverlay = ({
|
|
|
2024
2519
|
zIndex: 55
|
|
2025
2520
|
},
|
|
2026
2521
|
"data-testid": "subtitle-overlay-collapsed",
|
|
2027
|
-
children: /* @__PURE__ */
|
|
2522
|
+
children: /* @__PURE__ */ jsx11(
|
|
2028
2523
|
"button",
|
|
2029
2524
|
{
|
|
2030
2525
|
type: "button",
|
|
@@ -2040,7 +2535,7 @@ var SubtitleOverlay = ({
|
|
|
2040
2535
|
title: getIconTitle(),
|
|
2041
2536
|
"data-testid": "voice-input-button",
|
|
2042
2537
|
"aria-label": getIconTitle(),
|
|
2043
|
-
children: /* @__PURE__ */
|
|
2538
|
+
children: /* @__PURE__ */ jsx11("span", { className: "text-xl font-bold select-none", "aria-hidden": "true", children: getIcon() })
|
|
2044
2539
|
}
|
|
2045
2540
|
)
|
|
2046
2541
|
}
|
|
@@ -2073,7 +2568,7 @@ var SubtitleOverlay = ({
|
|
|
2073
2568
|
role: "complementary",
|
|
2074
2569
|
"aria-label": "Chat overlay",
|
|
2075
2570
|
children: [
|
|
2076
|
-
!isMobile && /* @__PURE__ */
|
|
2571
|
+
!isMobile && /* @__PURE__ */ jsx11(
|
|
2077
2572
|
"div",
|
|
2078
2573
|
{
|
|
2079
2574
|
className: "drag-handle absolute -top-3 left-1/2 transform -translate-x-1/2 cursor-grab active:cursor-grabbing opacity-40 hover:opacity-70 transition-opacity",
|
|
@@ -2101,8 +2596,8 @@ var SubtitleOverlay = ({
|
|
|
2101
2596
|
"data-testid": "completed-actions-list",
|
|
2102
2597
|
children: [
|
|
2103
2598
|
/* @__PURE__ */ jsxs6("div", { className: "font-medium opacity-70 mb-2 flex items-center justify-between", children: [
|
|
2104
|
-
/* @__PURE__ */
|
|
2105
|
-
/* @__PURE__ */
|
|
2599
|
+
/* @__PURE__ */ jsx11("span", { children: "Completed Actions" }),
|
|
2600
|
+
/* @__PURE__ */ jsx11(
|
|
2106
2601
|
"button",
|
|
2107
2602
|
{
|
|
2108
2603
|
onClick: () => setShowCompletedActions(false),
|
|
@@ -2112,9 +2607,9 @@ var SubtitleOverlay = ({
|
|
|
2112
2607
|
}
|
|
2113
2608
|
)
|
|
2114
2609
|
] }),
|
|
2115
|
-
/* @__PURE__ */
|
|
2116
|
-
/* @__PURE__ */
|
|
2117
|
-
/* @__PURE__ */
|
|
2610
|
+
/* @__PURE__ */ jsx11("div", { className: "space-y-1", children: completedActions.map((action) => /* @__PURE__ */ jsxs6("div", { className: "text-xs opacity-80 border-l-2 border-green-500 pl-2", children: [
|
|
2611
|
+
/* @__PURE__ */ jsx11("div", { className: "font-medium", children: action.tool }),
|
|
2612
|
+
/* @__PURE__ */ jsx11("div", { className: "opacity-70", children: action.description })
|
|
2118
2613
|
] }, action.id)) })
|
|
2119
2614
|
]
|
|
2120
2615
|
}
|
|
@@ -2141,21 +2636,21 @@ var SubtitleOverlay = ({
|
|
|
2141
2636
|
className: "border-l-2 border-green-500 pl-2 mb-1",
|
|
2142
2637
|
style: { opacity: latestActionOpacity, transition: "opacity 0.6s ease-out" },
|
|
2143
2638
|
children: [
|
|
2144
|
-
/* @__PURE__ */
|
|
2145
|
-
/* @__PURE__ */
|
|
2639
|
+
/* @__PURE__ */ jsx11("span", { className: "font-medium", children: latest.tool }),
|
|
2640
|
+
/* @__PURE__ */ jsx11("span", { className: "opacity-70 ml-1", children: latest.description })
|
|
2146
2641
|
]
|
|
2147
2642
|
}
|
|
2148
2643
|
);
|
|
2149
2644
|
})(),
|
|
2150
2645
|
lastAiMessage && messageOpacity > 0 && /* @__PURE__ */ jsxs6("div", { style: { opacity: messageOpacity, transition: "opacity 0.8s ease-out" }, children: [
|
|
2151
|
-
/* @__PURE__ */
|
|
2646
|
+
/* @__PURE__ */ jsx11("span", { className: "font-medium opacity-70", children: "AI:" }),
|
|
2152
2647
|
" ",
|
|
2153
|
-
/* @__PURE__ */
|
|
2648
|
+
/* @__PURE__ */ jsx11("span", { className: "text-sm", children: lastAiMessage.text })
|
|
2154
2649
|
] })
|
|
2155
2650
|
]
|
|
2156
2651
|
}
|
|
2157
2652
|
),
|
|
2158
|
-
completedActions.length > 0 && !showCompletedActions && /* @__PURE__ */
|
|
2653
|
+
completedActions.length > 0 && !showCompletedActions && /* @__PURE__ */ jsx11("div", { className: "flex justify-center mb-1", children: /* @__PURE__ */ jsx11(
|
|
2159
2654
|
"button",
|
|
2160
2655
|
{
|
|
2161
2656
|
type: "button",
|
|
@@ -2171,11 +2666,11 @@ var SubtitleOverlay = ({
|
|
|
2171
2666
|
title: `${completedActions.length} previous actions`,
|
|
2172
2667
|
"data-testid": "completed-actions-toggle",
|
|
2173
2668
|
"aria-label": `Show ${completedActions.length} completed actions`,
|
|
2174
|
-
children: /* @__PURE__ */
|
|
2669
|
+
children: /* @__PURE__ */ jsx11("svg", { width: "16", height: "8", viewBox: "0 0 16 8", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx11("path", { d: "M2 6L8 2L14 6" }) })
|
|
2175
2670
|
}
|
|
2176
2671
|
) }),
|
|
2177
2672
|
/* @__PURE__ */ jsxs6("div", { className: "flex items-center space-x-2", children: [
|
|
2178
|
-
hasTTSWidgets && /* @__PURE__ */
|
|
2673
|
+
hasTTSWidgets && /* @__PURE__ */ jsx11(
|
|
2179
2674
|
"button",
|
|
2180
2675
|
{
|
|
2181
2676
|
type: "button",
|
|
@@ -2190,7 +2685,7 @@ var SubtitleOverlay = ({
|
|
|
2190
2685
|
title: ttsWidgets.length === 1 ? "Go to readable section" : "View readable sections",
|
|
2191
2686
|
"data-testid": "tts-playlist-button-expanded",
|
|
2192
2687
|
"aria-label": ttsWidgets.length === 1 ? "Go to readable section" : "View readable sections",
|
|
2193
|
-
children: /* @__PURE__ */
|
|
2688
|
+
children: /* @__PURE__ */ jsx11("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: "~+" })
|
|
2194
2689
|
}
|
|
2195
2690
|
),
|
|
2196
2691
|
/* @__PURE__ */ jsxs6(
|
|
@@ -2202,7 +2697,7 @@ var SubtitleOverlay = ({
|
|
|
2202
2697
|
border: effectiveGlassTheme === "dark" ? "1px solid rgba(255, 255, 255, 0.12)" : "1px solid rgba(0, 0, 0, 0.1)"
|
|
2203
2698
|
},
|
|
2204
2699
|
children: [
|
|
2205
|
-
/* @__PURE__ */
|
|
2700
|
+
/* @__PURE__ */ jsx11(
|
|
2206
2701
|
"input",
|
|
2207
2702
|
{
|
|
2208
2703
|
ref: inputRef,
|
|
@@ -2222,7 +2717,7 @@ var SubtitleOverlay = ({
|
|
|
2222
2717
|
"aria-label": "Chat message input"
|
|
2223
2718
|
}
|
|
2224
2719
|
),
|
|
2225
|
-
isListening && /* @__PURE__ */
|
|
2720
|
+
isListening && /* @__PURE__ */ jsx11("div", { className: "flex space-x-1 items-center", "aria-hidden": "true", "data-testid": "subtitle-overlay-waveform", children: [...Array(5)].map((_, i) => /* @__PURE__ */ jsx11(
|
|
2226
2721
|
"div",
|
|
2227
2722
|
{
|
|
2228
2723
|
className: "w-0.5 bg-red-500 rounded-full animate-pulse",
|
|
@@ -2233,7 +2728,7 @@ var SubtitleOverlay = ({
|
|
|
2233
2728
|
},
|
|
2234
2729
|
i
|
|
2235
2730
|
)) }),
|
|
2236
|
-
inputValue.trim() && /* @__PURE__ */
|
|
2731
|
+
inputValue.trim() && /* @__PURE__ */ jsx11(
|
|
2237
2732
|
"button",
|
|
2238
2733
|
{
|
|
2239
2734
|
type: "button",
|
|
@@ -2249,10 +2744,10 @@ var SubtitleOverlay = ({
|
|
|
2249
2744
|
title: "Send message",
|
|
2250
2745
|
"data-testid": "send-button",
|
|
2251
2746
|
"aria-label": "Send message",
|
|
2252
|
-
children: /* @__PURE__ */
|
|
2747
|
+
children: /* @__PURE__ */ jsx11("span", { className: "text-base select-none", "aria-hidden": "true", children: "\u2192" })
|
|
2253
2748
|
}
|
|
2254
2749
|
),
|
|
2255
|
-
voiceEnabled && /* @__PURE__ */
|
|
2750
|
+
voiceEnabled && /* @__PURE__ */ jsx11(
|
|
2256
2751
|
"button",
|
|
2257
2752
|
{
|
|
2258
2753
|
type: "button",
|
|
@@ -2272,10 +2767,10 @@ var SubtitleOverlay = ({
|
|
|
2272
2767
|
title: getIconTitle(),
|
|
2273
2768
|
"data-testid": "voice-input-button",
|
|
2274
2769
|
"aria-label": getIconTitle(),
|
|
2275
|
-
children: /* @__PURE__ */
|
|
2770
|
+
children: /* @__PURE__ */ jsx11("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: getIcon() })
|
|
2276
2771
|
}
|
|
2277
2772
|
),
|
|
2278
|
-
/* @__PURE__ */
|
|
2773
|
+
/* @__PURE__ */ jsx11(
|
|
2279
2774
|
"button",
|
|
2280
2775
|
{
|
|
2281
2776
|
type: "button",
|
|
@@ -2290,7 +2785,7 @@ var SubtitleOverlay = ({
|
|
|
2290
2785
|
title: "Collapse",
|
|
2291
2786
|
"data-testid": "collapse-button",
|
|
2292
2787
|
"aria-label": "Collapse overlay",
|
|
2293
|
-
children: /* @__PURE__ */
|
|
2788
|
+
children: /* @__PURE__ */ jsx11("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: "\xD7" })
|
|
2294
2789
|
}
|
|
2295
2790
|
)
|
|
2296
2791
|
]
|
|
@@ -2303,23 +2798,23 @@ var SubtitleOverlay = ({
|
|
|
2303
2798
|
};
|
|
2304
2799
|
|
|
2305
2800
|
// src/components/SlashCommand/useSlashCommand.ts
|
|
2306
|
-
import { useState as
|
|
2801
|
+
import { useState as useState8, useMemo as useMemo3, useCallback as useCallback6, useRef as useRef8, useEffect as useEffect6 } from "react";
|
|
2307
2802
|
import { ToolRegistry } from "@supernal/interface/browser";
|
|
2308
2803
|
function useSlashCommand(inputValue, onSelect) {
|
|
2309
|
-
const [selectedIndex, setSelectedIndex] =
|
|
2310
|
-
const prevOpenRef =
|
|
2804
|
+
const [selectedIndex, setSelectedIndex] = useState8(0);
|
|
2805
|
+
const prevOpenRef = useRef8(false);
|
|
2311
2806
|
const isOpen = inputValue.startsWith("/");
|
|
2312
2807
|
const query = isOpen ? inputValue.slice(1) : "";
|
|
2313
|
-
|
|
2808
|
+
useEffect6(() => {
|
|
2314
2809
|
if (isOpen && !prevOpenRef.current) {
|
|
2315
2810
|
setSelectedIndex(0);
|
|
2316
2811
|
}
|
|
2317
2812
|
prevOpenRef.current = isOpen;
|
|
2318
2813
|
}, [isOpen]);
|
|
2319
|
-
|
|
2814
|
+
useEffect6(() => {
|
|
2320
2815
|
setSelectedIndex(0);
|
|
2321
2816
|
}, [query]);
|
|
2322
|
-
const filteredTools =
|
|
2817
|
+
const filteredTools = useMemo3(() => {
|
|
2323
2818
|
if (!isOpen) return [];
|
|
2324
2819
|
const locationTools = ToolRegistry.getToolsByLocation();
|
|
2325
2820
|
const aiTools = locationTools.filter((t) => t.aiEnabled);
|
|
@@ -2336,13 +2831,13 @@ function useSlashCommand(inputValue, onSelect) {
|
|
|
2336
2831
|
return fields.some((f) => f.includes(q));
|
|
2337
2832
|
});
|
|
2338
2833
|
}, [isOpen, query]);
|
|
2339
|
-
const close =
|
|
2834
|
+
const close = useCallback6(() => {
|
|
2340
2835
|
}, []);
|
|
2341
|
-
const selectTool =
|
|
2836
|
+
const selectTool = useCallback6((tool) => {
|
|
2342
2837
|
const command = tool.examples?.[0] || tool.name?.toLowerCase() || tool.toolId;
|
|
2343
2838
|
onSelect(command);
|
|
2344
2839
|
}, [onSelect]);
|
|
2345
|
-
const onKeyDown =
|
|
2840
|
+
const onKeyDown = useCallback6((e) => {
|
|
2346
2841
|
if (!isOpen || filteredTools.length === 0) return;
|
|
2347
2842
|
if (e.key === "ArrowDown") {
|
|
2348
2843
|
e.preventDefault();
|
|
@@ -2372,8 +2867,8 @@ function useSlashCommand(inputValue, onSelect) {
|
|
|
2372
2867
|
}
|
|
2373
2868
|
|
|
2374
2869
|
// src/components/SlashCommand/SlashCommandPopup.tsx
|
|
2375
|
-
import { useEffect as
|
|
2376
|
-
import { jsx as
|
|
2870
|
+
import { useEffect as useEffect7, useRef as useRef9 } from "react";
|
|
2871
|
+
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2377
2872
|
var MAX_VISIBLE_ITEMS = 8;
|
|
2378
2873
|
var SlashCommandPopup = ({
|
|
2379
2874
|
tools,
|
|
@@ -2381,12 +2876,12 @@ var SlashCommandPopup = ({
|
|
|
2381
2876
|
onSelect,
|
|
2382
2877
|
onClose
|
|
2383
2878
|
}) => {
|
|
2384
|
-
const listRef =
|
|
2385
|
-
const selectedRef =
|
|
2386
|
-
|
|
2879
|
+
const listRef = useRef9(null);
|
|
2880
|
+
const selectedRef = useRef9(null);
|
|
2881
|
+
useEffect7(() => {
|
|
2387
2882
|
selectedRef.current?.scrollIntoView({ block: "nearest" });
|
|
2388
2883
|
}, [selectedIndex]);
|
|
2389
|
-
|
|
2884
|
+
useEffect7(() => {
|
|
2390
2885
|
const handleClickOutside = (e) => {
|
|
2391
2886
|
if (listRef.current && !listRef.current.contains(e.target)) {
|
|
2392
2887
|
onClose();
|
|
@@ -2461,9 +2956,9 @@ var SlashCommandPopup = ({
|
|
|
2461
2956
|
"/",
|
|
2462
2957
|
tool.toolId
|
|
2463
2958
|
] }),
|
|
2464
|
-
/* @__PURE__ */
|
|
2959
|
+
/* @__PURE__ */ jsx12("span", { style: { color: "rgba(255,255,255,0.7)", fontWeight: 400, marginLeft: 8 }, children: tool.name })
|
|
2465
2960
|
] }),
|
|
2466
|
-
tool.description && /* @__PURE__ */
|
|
2961
|
+
tool.description && /* @__PURE__ */ jsx12("div", { style: {
|
|
2467
2962
|
fontSize: 11,
|
|
2468
2963
|
color: "rgba(255,255,255,0.4)",
|
|
2469
2964
|
marginTop: 2,
|
|
@@ -2483,13 +2978,13 @@ var SlashCommandPopup = ({
|
|
|
2483
2978
|
color: "rgba(255,255,255,0.3)",
|
|
2484
2979
|
fontSize: 10
|
|
2485
2980
|
}, children: [
|
|
2486
|
-
/* @__PURE__ */
|
|
2981
|
+
/* @__PURE__ */ jsx12("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "\u2191\u2193" }),
|
|
2487
2982
|
" navigate",
|
|
2488
2983
|
" ",
|
|
2489
|
-
/* @__PURE__ */
|
|
2984
|
+
/* @__PURE__ */ jsx12("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "Enter" }),
|
|
2490
2985
|
" select",
|
|
2491
2986
|
" ",
|
|
2492
|
-
/* @__PURE__ */
|
|
2987
|
+
/* @__PURE__ */ jsx12("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "Esc" }),
|
|
2493
2988
|
" dismiss"
|
|
2494
2989
|
] })
|
|
2495
2990
|
]
|
|
@@ -2498,7 +2993,7 @@ var SlashCommandPopup = ({
|
|
|
2498
2993
|
};
|
|
2499
2994
|
|
|
2500
2995
|
// src/components/ChatBubble/ChatBubble.tsx
|
|
2501
|
-
import { Fragment as Fragment3, jsx as
|
|
2996
|
+
import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2502
2997
|
var ChatBubble = ({
|
|
2503
2998
|
messages,
|
|
2504
2999
|
onSendMessage,
|
|
@@ -2513,65 +3008,69 @@ var ChatBubble = ({
|
|
|
2513
3008
|
}) => {
|
|
2514
3009
|
const mergedConfig = { ...DEFAULT_CONFIG, ...userConfig };
|
|
2515
3010
|
if (userConfig?.logo && !userConfig?.avatar) {
|
|
2516
|
-
mergedConfig.avatar = /* @__PURE__ */
|
|
3011
|
+
mergedConfig.avatar = /* @__PURE__ */ jsx13("img", { src: userConfig.logo, alt: "Supernal", className: "w-6 h-6" });
|
|
2517
3012
|
}
|
|
2518
3013
|
const config = mergedConfig;
|
|
2519
|
-
const [isExpanded, setIsExpanded] =
|
|
2520
|
-
const [isMinimized, setIsMinimized] =
|
|
2521
|
-
const [inputValue, setInputValue] =
|
|
2522
|
-
const [lastReadMessageCount, setLastReadMessageCount] =
|
|
2523
|
-
const [showWelcome, setShowWelcome] =
|
|
3014
|
+
const [isExpanded, setIsExpanded] = useState9(defaultExpanded);
|
|
3015
|
+
const [isMinimized, setIsMinimized] = useState9(false);
|
|
3016
|
+
const [inputValue, setInputValue] = useState9("");
|
|
3017
|
+
const [lastReadMessageCount, setLastReadMessageCount] = useState9(0);
|
|
3018
|
+
const [showWelcome, setShowWelcome] = useState9(
|
|
2524
3019
|
config.welcome?.enabled && messages.length === 0
|
|
2525
3020
|
);
|
|
2526
|
-
const [isDragging, setIsDragging] =
|
|
2527
|
-
const [dragInitiated, setDragInitiated] =
|
|
2528
|
-
const [isDocked, setIsDocked] =
|
|
2529
|
-
const [dockPosition, setDockPosition] =
|
|
2530
|
-
const [panelPosition, setPanelPosition] =
|
|
2531
|
-
const [theme, setTheme] =
|
|
2532
|
-
const [showMoreMenu, setShowMoreMenu] =
|
|
2533
|
-
const [, setTimestampTick] =
|
|
2534
|
-
const [localGlassMode, setLocalGlassMode] =
|
|
2535
|
-
const [glassOpacity, setGlassOpacity] =
|
|
2536
|
-
const [notifications, setNotifications] =
|
|
2537
|
-
const [voiceEnabled, setVoiceEnabled] =
|
|
2538
|
-
const [usePremiumVoices, setUsePremiumVoices] =
|
|
2539
|
-
const [autoReadResponses, setAutoReadResponses] =
|
|
2540
|
-
const [ttsSpeed, setTtsSpeed] =
|
|
2541
|
-
const [sttAutoRecordTimeout, setSttAutoRecordTimeout] =
|
|
2542
|
-
const [sttAutoExecute, setSttAutoExecute] =
|
|
2543
|
-
const sttAutoRecordTimeoutRef =
|
|
3021
|
+
const [isDragging, setIsDragging] = useState9(false);
|
|
3022
|
+
const [dragInitiated, setDragInitiated] = useState9(false);
|
|
3023
|
+
const [isDocked, setIsDocked] = useState9(true);
|
|
3024
|
+
const [dockPosition, setDockPosition] = useState9(position);
|
|
3025
|
+
const [panelPosition, setPanelPosition] = useState9({ x: 0, y: 0 });
|
|
3026
|
+
const [theme, setTheme] = useState9("light");
|
|
3027
|
+
const [showMoreMenu, setShowMoreMenu] = useState9(false);
|
|
3028
|
+
const [, setTimestampTick] = useState9(0);
|
|
3029
|
+
const [localGlassMode, setLocalGlassMode] = useState9(config.glassMode ?? true);
|
|
3030
|
+
const [glassOpacity, setGlassOpacity] = useState9("medium");
|
|
3031
|
+
const [notifications, setNotifications] = useState9(true);
|
|
3032
|
+
const [voiceEnabled, setVoiceEnabled] = useState9(true);
|
|
3033
|
+
const [usePremiumVoices, setUsePremiumVoices] = useState9(false);
|
|
3034
|
+
const [autoReadResponses, setAutoReadResponses] = useState9(false);
|
|
3035
|
+
const [ttsSpeed, setTtsSpeed] = useState9(1);
|
|
3036
|
+
const [sttAutoRecordTimeout, setSttAutoRecordTimeout] = useState9(5e3);
|
|
3037
|
+
const [sttAutoExecute, setSttAutoExecute] = useState9(true);
|
|
3038
|
+
const sttAutoRecordTimeoutRef = useRef10(null);
|
|
2544
3039
|
const { speak: speakTTS, stop: stopTTS, isPlaying: isTTSPlaying } = useTTS();
|
|
2545
3040
|
const { startListening, stopListening, transcript: sttTranscript, isListening, resetTranscript } = useSTT();
|
|
3041
|
+
const apiKey = useApiKeyOptional();
|
|
3042
|
+
const [showApiKeyInput, setShowApiKeyInput] = useState9(false);
|
|
3043
|
+
const [apiKeyInputValue, setApiKeyInputValue] = useState9("");
|
|
3044
|
+
const [showApiKey, setShowApiKey] = useState9(false);
|
|
2546
3045
|
const slashCommand = useSlashCommand(inputValue, (command) => {
|
|
2547
3046
|
setInputValue(command);
|
|
2548
3047
|
setTimeout(() => inputRef.current?.focus(), 0);
|
|
2549
3048
|
});
|
|
2550
|
-
const [displayMode, setDisplayMode] =
|
|
2551
|
-
const [drawerSide, setDrawerSide] =
|
|
2552
|
-
const displayModeLoadedFromStorage =
|
|
2553
|
-
|
|
3049
|
+
const [displayMode, setDisplayMode] = useState9(propDisplayMode);
|
|
3050
|
+
const [drawerSide, setDrawerSide] = useState9(propDrawerSide);
|
|
3051
|
+
const displayModeLoadedFromStorage = useRef10(false);
|
|
3052
|
+
useEffect8(() => {
|
|
2554
3053
|
if (!displayModeLoadedFromStorage.current) {
|
|
2555
3054
|
setDisplayMode(propDisplayMode);
|
|
2556
3055
|
}
|
|
2557
3056
|
}, [propDisplayMode]);
|
|
2558
|
-
const [drawerOpen, setDrawerOpen] =
|
|
2559
|
-
const [touchStart, setTouchStart] =
|
|
2560
|
-
const [swipeProgress, setSwipeProgress] =
|
|
2561
|
-
const [isMobile, setIsMobile] =
|
|
2562
|
-
const lastEscapeTimeRef =
|
|
3057
|
+
const [drawerOpen, setDrawerOpen] = useState9(false);
|
|
3058
|
+
const [touchStart, setTouchStart] = useState9(null);
|
|
3059
|
+
const [swipeProgress, setSwipeProgress] = useState9(0);
|
|
3060
|
+
const [isMobile, setIsMobile] = useState9(false);
|
|
3061
|
+
const lastEscapeTimeRef = useRef10(0);
|
|
2563
3062
|
const DOUBLE_ESCAPE_THRESHOLD_MS = 500;
|
|
2564
|
-
const [isMac, setIsMac] =
|
|
2565
|
-
const [currentHintIndex, setCurrentHintIndex] =
|
|
2566
|
-
const [isHydrated, setIsHydrated] =
|
|
2567
|
-
|
|
3063
|
+
const [isMac, setIsMac] = useState9(false);
|
|
3064
|
+
const [currentHintIndex, setCurrentHintIndex] = useState9(0);
|
|
3065
|
+
const [isHydrated, setIsHydrated] = useState9(false);
|
|
3066
|
+
useEffect8(() => {
|
|
2568
3067
|
if (typeof window !== "undefined") {
|
|
2569
3068
|
const platform = window.navigator.platform.toLowerCase();
|
|
2570
3069
|
const isMacPlatform = platform.includes("mac");
|
|
2571
3070
|
setIsMac(isMacPlatform);
|
|
2572
3071
|
}
|
|
2573
3072
|
}, []);
|
|
2574
|
-
const inputHints =
|
|
3073
|
+
const inputHints = useMemo4(() => {
|
|
2575
3074
|
const modKey = isMac ? "Cmd" : "Ctrl";
|
|
2576
3075
|
return [
|
|
2577
3076
|
`Press ${modKey}+/ to start voice recording`,
|
|
@@ -2580,14 +3079,14 @@ var ChatBubble = ({
|
|
|
2580
3079
|
sttAutoExecute ? `Voice commands execute automatically` : "Voice commands fill this input"
|
|
2581
3080
|
];
|
|
2582
3081
|
}, [isMac, sttAutoExecute]);
|
|
2583
|
-
|
|
3082
|
+
useEffect8(() => {
|
|
2584
3083
|
setCurrentHintIndex((prev) => (prev + 1) % inputHints.length);
|
|
2585
3084
|
}, [messages.length, inputHints.length]);
|
|
2586
|
-
const messagesEndRef =
|
|
2587
|
-
const inputRef =
|
|
2588
|
-
const panelRef =
|
|
2589
|
-
const dragRef =
|
|
2590
|
-
const rafRef =
|
|
3085
|
+
const messagesEndRef = useRef10(null);
|
|
3086
|
+
const inputRef = useRef10(null);
|
|
3087
|
+
const panelRef = useRef10(null);
|
|
3088
|
+
const dragRef = useRef10(null);
|
|
3089
|
+
const rafRef = useRef10(null);
|
|
2591
3090
|
const formatRelativeTime = (timestamp) => {
|
|
2592
3091
|
const now = /* @__PURE__ */ new Date();
|
|
2593
3092
|
const messageTime = new Date(timestamp);
|
|
@@ -2602,7 +3101,7 @@ var ChatBubble = ({
|
|
|
2602
3101
|
if (diffDays < 7) return `${diffDays} ${diffDays === 1 ? "day" : "days"} ago`;
|
|
2603
3102
|
return messageTime.toLocaleDateString();
|
|
2604
3103
|
};
|
|
2605
|
-
|
|
3104
|
+
useEffect8(() => {
|
|
2606
3105
|
if (variant === "floating" && panelPosition.x === 0 && panelPosition.y === 0) {
|
|
2607
3106
|
try {
|
|
2608
3107
|
const stored = localStorage.getItem(storageKey);
|
|
@@ -2624,7 +3123,7 @@ var ChatBubble = ({
|
|
|
2624
3123
|
}
|
|
2625
3124
|
}
|
|
2626
3125
|
}, [variant, storageKey, panelPosition.x, panelPosition.y]);
|
|
2627
|
-
|
|
3126
|
+
useEffect8(() => {
|
|
2628
3127
|
if (variant === "full" || variant === "drawer" || variant === "subtitle") {
|
|
2629
3128
|
try {
|
|
2630
3129
|
const stored = localStorage.getItem(storageKey);
|
|
@@ -2702,12 +3201,12 @@ var ChatBubble = ({
|
|
|
2702
3201
|
}
|
|
2703
3202
|
setIsHydrated(true);
|
|
2704
3203
|
}, [storageKey, variant, defaultExpanded, position]);
|
|
2705
|
-
|
|
3204
|
+
useEffect8(() => {
|
|
2706
3205
|
if (variant !== "full" && variant !== "drawer" && variant !== "subtitle") {
|
|
2707
3206
|
setIsHydrated(true);
|
|
2708
3207
|
}
|
|
2709
3208
|
}, [variant]);
|
|
2710
|
-
|
|
3209
|
+
useEffect8(() => {
|
|
2711
3210
|
if (!isExpanded || isDocked || !panelRef.current) return;
|
|
2712
3211
|
const checkBounds = () => {
|
|
2713
3212
|
const rect = panelRef.current?.getBoundingClientRect();
|
|
@@ -2724,7 +3223,7 @@ var ChatBubble = ({
|
|
|
2724
3223
|
const timeoutId = setTimeout(checkBounds, 100);
|
|
2725
3224
|
return () => clearTimeout(timeoutId);
|
|
2726
3225
|
}, [isExpanded, isDocked]);
|
|
2727
|
-
|
|
3226
|
+
useEffect8(() => {
|
|
2728
3227
|
const isSubtitleMode = displayMode === "subtitle" || displayMode === "auto" && variant === "subtitle";
|
|
2729
3228
|
if (isSubtitleMode) return;
|
|
2730
3229
|
const handleKeyDown = (e) => {
|
|
@@ -2757,13 +3256,13 @@ var ChatBubble = ({
|
|
|
2757
3256
|
window.addEventListener("keydown", handleKeyDown);
|
|
2758
3257
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
2759
3258
|
}, [isExpanded, isDocked, position, variant, displayMode, isMobile]);
|
|
2760
|
-
|
|
3259
|
+
useEffect8(() => {
|
|
2761
3260
|
if (typeof window !== "undefined") {
|
|
2762
3261
|
const isDark = document.documentElement.getAttribute("data-theme") === "dark";
|
|
2763
3262
|
setTheme(isDark ? "dark" : "light");
|
|
2764
3263
|
}
|
|
2765
3264
|
}, []);
|
|
2766
|
-
|
|
3265
|
+
useEffect8(() => {
|
|
2767
3266
|
if (typeof window === "undefined") return;
|
|
2768
3267
|
const mediaQuery = window.matchMedia("(max-width: 767px)");
|
|
2769
3268
|
const handleChange = (e) => {
|
|
@@ -2773,26 +3272,26 @@ var ChatBubble = ({
|
|
|
2773
3272
|
mediaQuery.addEventListener("change", handleChange);
|
|
2774
3273
|
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
2775
3274
|
}, []);
|
|
2776
|
-
const currentVariant =
|
|
3275
|
+
const currentVariant = React9.useMemo(() => {
|
|
2777
3276
|
if (displayMode !== "auto") {
|
|
2778
3277
|
return displayMode;
|
|
2779
3278
|
}
|
|
2780
3279
|
return isMobile && variant === "full" ? "subtitle" : variant;
|
|
2781
3280
|
}, [displayMode, isMobile, variant]);
|
|
2782
|
-
const prevVariantRef =
|
|
2783
|
-
|
|
3281
|
+
const prevVariantRef = React9.useRef(variant);
|
|
3282
|
+
useEffect8(() => {
|
|
2784
3283
|
if (prevVariantRef.current !== variant && displayMode !== "auto") {
|
|
2785
3284
|
setDisplayMode("auto");
|
|
2786
3285
|
prevVariantRef.current = variant;
|
|
2787
3286
|
}
|
|
2788
3287
|
}, [variant, displayMode]);
|
|
2789
|
-
|
|
3288
|
+
useEffect8(() => {
|
|
2790
3289
|
const interval = setInterval(() => {
|
|
2791
3290
|
setTimestampTick((tick) => tick + 1);
|
|
2792
3291
|
}, 6e4);
|
|
2793
3292
|
return () => clearInterval(interval);
|
|
2794
3293
|
}, []);
|
|
2795
|
-
|
|
3294
|
+
useEffect8(() => {
|
|
2796
3295
|
if (variant === "full" || variant === "drawer" || variant === "subtitle") {
|
|
2797
3296
|
try {
|
|
2798
3297
|
localStorage.setItem(
|
|
@@ -2824,7 +3323,7 @@ var ChatBubble = ({
|
|
|
2824
3323
|
}
|
|
2825
3324
|
}, [isExpanded, isMinimized, isDocked, dockPosition, panelPosition, theme, localGlassMode, notifications, displayMode, drawerSide, drawerOpen, glassOpacity, voiceEnabled, usePremiumVoices, autoReadResponses, ttsSpeed, sttAutoRecordTimeout, sttAutoExecute, storageKey, variant]);
|
|
2826
3325
|
const { registerInput } = useChatInput();
|
|
2827
|
-
|
|
3326
|
+
useEffect8(() => {
|
|
2828
3327
|
registerInput((text, submit = false) => {
|
|
2829
3328
|
setInputValue(text);
|
|
2830
3329
|
if (!isExpanded && variant === "full") {
|
|
@@ -2841,7 +3340,7 @@ var ChatBubble = ({
|
|
|
2841
3340
|
}, [registerInput, onSendMessage]);
|
|
2842
3341
|
const unreadCount = Math.max(0, messages.length - lastReadMessageCount);
|
|
2843
3342
|
const hasUnread = unreadCount > 0 && !isExpanded && variant === "full";
|
|
2844
|
-
|
|
3343
|
+
useEffect8(() => {
|
|
2845
3344
|
if (isExpanded || variant === "floating") {
|
|
2846
3345
|
messagesEndRef.current?.scrollIntoView({ behavior: "auto" });
|
|
2847
3346
|
setLastReadMessageCount(messages.length);
|
|
@@ -2853,12 +3352,12 @@ var ChatBubble = ({
|
|
|
2853
3352
|
}
|
|
2854
3353
|
}
|
|
2855
3354
|
}, [messages, isExpanded, variant]);
|
|
2856
|
-
|
|
3355
|
+
useEffect8(() => {
|
|
2857
3356
|
if (isExpanded && variant === "full") {
|
|
2858
3357
|
inputRef.current?.focus();
|
|
2859
3358
|
}
|
|
2860
3359
|
}, [isExpanded, variant]);
|
|
2861
|
-
|
|
3360
|
+
useEffect8(() => {
|
|
2862
3361
|
if (!voiceEnabled || !autoReadResponses || messages.length === 0) return;
|
|
2863
3362
|
const lastMessage = messages[messages.length - 1];
|
|
2864
3363
|
if (lastMessage.type === "ai") {
|
|
@@ -2870,7 +3369,7 @@ var ChatBubble = ({
|
|
|
2870
3369
|
});
|
|
2871
3370
|
}
|
|
2872
3371
|
}, [messages, voiceEnabled, autoReadResponses, ttsSpeed, usePremiumVoices, speakTTS]);
|
|
2873
|
-
|
|
3372
|
+
useEffect8(() => {
|
|
2874
3373
|
if (currentVariant === "subtitle") return;
|
|
2875
3374
|
if (sttTranscript && voiceEnabled) {
|
|
2876
3375
|
setInputValue(sttTranscript);
|
|
@@ -2885,7 +3384,7 @@ var ChatBubble = ({
|
|
|
2885
3384
|
}
|
|
2886
3385
|
}
|
|
2887
3386
|
}, [sttTranscript, voiceEnabled, resetTranscript, sttAutoExecute, onSendMessage, currentVariant]);
|
|
2888
|
-
|
|
3387
|
+
useEffect8(() => {
|
|
2889
3388
|
if (currentVariant === "subtitle") return;
|
|
2890
3389
|
const handleKeyDown = (e) => {
|
|
2891
3390
|
if ((e.metaKey || e.ctrlKey) && e.key === "/" && voiceEnabled) {
|
|
@@ -2943,7 +3442,7 @@ var ChatBubble = ({
|
|
|
2943
3442
|
}
|
|
2944
3443
|
};
|
|
2945
3444
|
}, [currentVariant, isExpanded, showMoreMenu, voiceEnabled, isListening, startListening, stopListening, sttAutoRecordTimeout]);
|
|
2946
|
-
|
|
3445
|
+
useEffect8(() => {
|
|
2947
3446
|
if (currentVariant !== "drawer") return;
|
|
2948
3447
|
const handleKeyDown = (e) => {
|
|
2949
3448
|
if (e.key === "Escape" && drawerOpen) {
|
|
@@ -2953,7 +3452,7 @@ var ChatBubble = ({
|
|
|
2953
3452
|
window.addEventListener("keydown", handleKeyDown);
|
|
2954
3453
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
2955
3454
|
}, [currentVariant, drawerOpen]);
|
|
2956
|
-
|
|
3455
|
+
useEffect8(() => {
|
|
2957
3456
|
if (!showMoreMenu) return;
|
|
2958
3457
|
const handleClickOutside = (e) => {
|
|
2959
3458
|
const target = e.target;
|
|
@@ -2964,7 +3463,7 @@ var ChatBubble = ({
|
|
|
2964
3463
|
document.addEventListener("mousedown", handleClickOutside);
|
|
2965
3464
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
2966
3465
|
}, [showMoreMenu]);
|
|
2967
|
-
|
|
3466
|
+
useEffect8(() => {
|
|
2968
3467
|
if (typeof window === "undefined" || currentVariant !== "drawer") return;
|
|
2969
3468
|
const EDGE_ZONE_PX = 20;
|
|
2970
3469
|
const SWIPE_THRESHOLD = 0.4;
|
|
@@ -3049,7 +3548,7 @@ var ChatBubble = ({
|
|
|
3049
3548
|
};
|
|
3050
3549
|
}
|
|
3051
3550
|
};
|
|
3052
|
-
|
|
3551
|
+
useEffect8(() => {
|
|
3053
3552
|
if (!dragInitiated || !dragRef.current) return;
|
|
3054
3553
|
const dragThresholdPx = 5;
|
|
3055
3554
|
const handleMouseMove = (e) => {
|
|
@@ -3212,7 +3711,7 @@ var ChatBubble = ({
|
|
|
3212
3711
|
return null;
|
|
3213
3712
|
}
|
|
3214
3713
|
if (currentVariant === "subtitle") {
|
|
3215
|
-
return /* @__PURE__ */
|
|
3714
|
+
return /* @__PURE__ */ jsx13(
|
|
3216
3715
|
SubtitleOverlay,
|
|
3217
3716
|
{
|
|
3218
3717
|
messages,
|
|
@@ -3245,7 +3744,7 @@ var ChatBubble = ({
|
|
|
3245
3744
|
if (currentVariant === "drawer") {
|
|
3246
3745
|
const drawerWidth = "100vw";
|
|
3247
3746
|
return /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
3248
|
-
(drawerOpen || swipeProgress > 0) && /* @__PURE__ */
|
|
3747
|
+
(drawerOpen || swipeProgress > 0) && /* @__PURE__ */ jsx13(
|
|
3249
3748
|
"div",
|
|
3250
3749
|
{
|
|
3251
3750
|
className: "fixed inset-0 bg-black z-[49998] transition-opacity duration-300",
|
|
@@ -3279,28 +3778,28 @@ var ChatBubble = ({
|
|
|
3279
3778
|
/* @__PURE__ */ jsxs8("div", { className: `${THEME_CLASSES.bg.header} ${glassMode ? THEME_CLASSES.bg.headerGradient : THEME_CLASSES.bg.headerLight}`, children: [
|
|
3280
3779
|
/* @__PURE__ */ jsxs8("div", { className: "flex items-center space-x-3", children: [
|
|
3281
3780
|
config.avatar && /* @__PURE__ */ jsxs8("div", { className: "relative flex-shrink-0", children: [
|
|
3282
|
-
/* @__PURE__ */
|
|
3283
|
-
/* @__PURE__ */
|
|
3781
|
+
/* @__PURE__ */ jsx13(Avatar, { avatar: config.avatar }),
|
|
3782
|
+
/* @__PURE__ */ jsx13("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
|
|
3284
3783
|
] }),
|
|
3285
|
-
config.title && /* @__PURE__ */
|
|
3784
|
+
config.title && /* @__PURE__ */ jsx13("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx13("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
|
|
3286
3785
|
] }),
|
|
3287
|
-
/* @__PURE__ */
|
|
3786
|
+
/* @__PURE__ */ jsx13("button", { onClick: () => setDrawerOpen(false), className: THEME_CLASSES.button.close, title: "Close drawer", children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
|
|
3288
3787
|
] }),
|
|
3289
|
-
/* @__PURE__ */ jsxs8("div", { className: "flex-1 overflow-y-auto p-4 space-y-2", children: [
|
|
3788
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex-1 overflow-y-auto p-4 space-y-2", "data-testid": "chat-messages", children: [
|
|
3290
3789
|
showWelcome && messages.length === 0 && config.welcome?.enabled && /* @__PURE__ */ jsxs8("div", { className: THEME_CLASSES.welcome.container, children: [
|
|
3291
|
-
config.welcome.title && /* @__PURE__ */
|
|
3292
|
-
config.welcome.content && /* @__PURE__ */
|
|
3790
|
+
config.welcome.title && /* @__PURE__ */ jsx13("h4", { className: THEME_CLASSES.welcome.title, style: INLINE_STYLES.welcomeTitle(theme === "dark"), children: config.welcome.title }),
|
|
3791
|
+
config.welcome.content && /* @__PURE__ */ jsx13("p", { className: THEME_CLASSES.welcome.content, style: INLINE_STYLES.welcomeContent(theme === "dark"), children: config.welcome.content })
|
|
3293
3792
|
] }),
|
|
3294
3793
|
messages.map((message) => /* @__PURE__ */ jsxs8("div", { className: `group flex items-center gap-1 mb-2 ${message.type === "user" ? "flex-row-reverse" : "flex-row"}`, children: [
|
|
3295
|
-
/* @__PURE__ */
|
|
3794
|
+
/* @__PURE__ */ jsx13(
|
|
3296
3795
|
"div",
|
|
3297
3796
|
{
|
|
3298
3797
|
className: `inline-block px-4 py-2.5 rounded-2xl max-w-[95%] text-sm shadow-sm transition-all ${message.type === "user" ? THEME_CLASSES.message.user : message.type === "ai" ? THEME_CLASSES.message.ai : THEME_CLASSES.message.system}`,
|
|
3299
3798
|
style: message.type === "user" ? INLINE_STYLES.messageUser() : message.type === "ai" ? INLINE_STYLES.messageAI(theme === "dark") : INLINE_STYLES.messageSystem(theme === "dark"),
|
|
3300
|
-
children: /* @__PURE__ */
|
|
3799
|
+
children: /* @__PURE__ */ jsx13(MessageRenderer, { content: message.text, theme })
|
|
3301
3800
|
}
|
|
3302
3801
|
),
|
|
3303
|
-
message.type === "ai" && voiceEnabled && /* @__PURE__ */
|
|
3802
|
+
message.type === "ai" && voiceEnabled && /* @__PURE__ */ jsx13(
|
|
3304
3803
|
TTSButton,
|
|
3305
3804
|
{
|
|
3306
3805
|
text: message.text,
|
|
@@ -3310,7 +3809,7 @@ var ChatBubble = ({
|
|
|
3310
3809
|
size: "small"
|
|
3311
3810
|
}
|
|
3312
3811
|
),
|
|
3313
|
-
/* @__PURE__ */
|
|
3812
|
+
/* @__PURE__ */ jsx13(
|
|
3314
3813
|
"div",
|
|
3315
3814
|
{
|
|
3316
3815
|
className: `text-xs opacity-0 group-hover:opacity-70 transition-opacity whitespace-nowrap flex-shrink-0 ${message.type === "user" ? "text-gray-400 dark:text-gray-500 text-left" : "text-gray-600 dark:text-gray-400 text-right"}`,
|
|
@@ -3319,10 +3818,10 @@ var ChatBubble = ({
|
|
|
3319
3818
|
}
|
|
3320
3819
|
)
|
|
3321
3820
|
] }, message.id)),
|
|
3322
|
-
/* @__PURE__ */
|
|
3821
|
+
/* @__PURE__ */ jsx13("div", { ref: messagesEndRef })
|
|
3323
3822
|
] }),
|
|
3324
3823
|
/* @__PURE__ */ jsxs8("div", { style: { position: "relative" }, children: [
|
|
3325
|
-
slashCommand.isOpen && /* @__PURE__ */
|
|
3824
|
+
slashCommand.isOpen && /* @__PURE__ */ jsx13(
|
|
3326
3825
|
SlashCommandPopup,
|
|
3327
3826
|
{
|
|
3328
3827
|
tools: slashCommand.filteredTools,
|
|
@@ -3331,7 +3830,7 @@ var ChatBubble = ({
|
|
|
3331
3830
|
onClose: () => setInputValue("")
|
|
3332
3831
|
}
|
|
3333
3832
|
),
|
|
3334
|
-
/* @__PURE__ */
|
|
3833
|
+
/* @__PURE__ */ jsx13(
|
|
3335
3834
|
InputField,
|
|
3336
3835
|
{
|
|
3337
3836
|
inputValue,
|
|
@@ -3353,20 +3852,20 @@ var ChatBubble = ({
|
|
|
3353
3852
|
]
|
|
3354
3853
|
}
|
|
3355
3854
|
),
|
|
3356
|
-
!drawerOpen && /* @__PURE__ */
|
|
3855
|
+
!drawerOpen && /* @__PURE__ */ jsx13(
|
|
3357
3856
|
"div",
|
|
3358
3857
|
{
|
|
3359
3858
|
className: `fixed ${drawerSide === "right" ? "right-0" : "left-0"} bottom-20 opacity-70 hover:opacity-100 transition-opacity duration-300 z-[999999] cursor-pointer`,
|
|
3360
3859
|
style: { zIndex: 999999 },
|
|
3361
3860
|
onClick: () => setDrawerOpen(true),
|
|
3362
|
-
children: /* @__PURE__ */
|
|
3861
|
+
children: /* @__PURE__ */ jsx13("div", { className: `${glassMode ? "backdrop-blur-md bg-white/50 dark:bg-gray-800/50" : "bg-white dark:bg-gray-800"} text-gray-700 dark:text-gray-200 px-3 py-3 ${drawerSide === "right" ? "rounded-l-xl" : "rounded-r-xl"} shadow-md hover:shadow-lg flex items-center justify-center transition-all`, children: voiceEnabled ? /* @__PURE__ */ jsx13("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" }) }) : /* @__PURE__ */ jsx13("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }) })
|
|
3363
3862
|
}
|
|
3364
3863
|
)
|
|
3365
3864
|
] });
|
|
3366
3865
|
}
|
|
3367
3866
|
if (currentVariant === "floating") {
|
|
3368
3867
|
const recentMessage = messages[messages.length - 1];
|
|
3369
|
-
return /* @__PURE__ */
|
|
3868
|
+
return /* @__PURE__ */ jsx13(
|
|
3370
3869
|
"div",
|
|
3371
3870
|
{
|
|
3372
3871
|
className: `fixed z-[999999] ${isDragging ? "cursor-grabbing" : "cursor-grab"}`,
|
|
@@ -3382,29 +3881,29 @@ var ChatBubble = ({
|
|
|
3382
3881
|
children: /* @__PURE__ */ jsxs8("div", { className: `${glassClasses} rounded-2xl shadow-2xl p-3 max-w-xs ${!glassMode && "border-gray-200 border"}`, children: [
|
|
3383
3882
|
/* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between mb-2", children: [
|
|
3384
3883
|
/* @__PURE__ */ jsxs8("div", { className: "flex items-center space-x-2", children: [
|
|
3385
|
-
/* @__PURE__ */
|
|
3386
|
-
config.title && /* @__PURE__ */
|
|
3884
|
+
/* @__PURE__ */ jsx13(Avatar, { avatar: config.avatar, size: "small" }),
|
|
3885
|
+
config.title && /* @__PURE__ */ jsx13("span", { className: THEME_CLASSES.text.floatingTitle, children: config.title })
|
|
3387
3886
|
] }),
|
|
3388
|
-
onClearChat && /* @__PURE__ */
|
|
3887
|
+
onClearChat && /* @__PURE__ */ jsx13(
|
|
3389
3888
|
"button",
|
|
3390
3889
|
{
|
|
3391
3890
|
onClick: onClearChat,
|
|
3392
3891
|
className: THEME_CLASSES.button.floatingClear,
|
|
3393
3892
|
title: "Clear chat",
|
|
3394
3893
|
"data-testid": ChatNames.clearButton,
|
|
3395
|
-
children: /* @__PURE__ */
|
|
3894
|
+
children: /* @__PURE__ */ jsx13("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
3396
3895
|
}
|
|
3397
3896
|
)
|
|
3398
3897
|
] }),
|
|
3399
3898
|
recentMessage && /* @__PURE__ */ jsxs8("div", { className: `mb-2 group flex items-center gap-2 ${recentMessage.type === "user" ? "flex-row-reverse" : "flex-row"}`, children: [
|
|
3400
|
-
/* @__PURE__ */
|
|
3899
|
+
/* @__PURE__ */ jsx13(
|
|
3401
3900
|
"div",
|
|
3402
3901
|
{
|
|
3403
3902
|
className: `text-xs px-3 py-2 rounded-xl transition-all ${recentMessage.type === "user" ? "bg-gradient-to-br from-blue-500 to-blue-600 text-white shadow-lg" : recentMessage.type === "ai" ? "bg-gradient-to-br from-gray-100 to-gray-200 dark:from-gray-700 dark:to-gray-800 text-gray-900 dark:text-white shadow-md" : "bg-gradient-to-br from-yellow-100 to-yellow-200 text-yellow-900 shadow-md"}`,
|
|
3404
3903
|
children: recentMessage.text.length > 60 ? `${recentMessage.text.slice(0, 60)}...` : recentMessage.text
|
|
3405
3904
|
}
|
|
3406
3905
|
),
|
|
3407
|
-
/* @__PURE__ */
|
|
3906
|
+
/* @__PURE__ */ jsx13(
|
|
3408
3907
|
"div",
|
|
3409
3908
|
{
|
|
3410
3909
|
className: `text-xs opacity-0 group-hover:opacity-70 transition-opacity whitespace-nowrap flex-shrink-0 ${recentMessage.type === "user" ? "text-gray-400 dark:text-gray-500 text-left" : "text-gray-600 dark:text-gray-400 text-right"}`,
|
|
@@ -3414,7 +3913,7 @@ var ChatBubble = ({
|
|
|
3414
3913
|
)
|
|
3415
3914
|
] }),
|
|
3416
3915
|
/* @__PURE__ */ jsxs8("div", { style: { position: "relative" }, children: [
|
|
3417
|
-
slashCommand.isOpen && /* @__PURE__ */
|
|
3916
|
+
slashCommand.isOpen && /* @__PURE__ */ jsx13(
|
|
3418
3917
|
SlashCommandPopup,
|
|
3419
3918
|
{
|
|
3420
3919
|
tools: slashCommand.filteredTools,
|
|
@@ -3423,7 +3922,7 @@ var ChatBubble = ({
|
|
|
3423
3922
|
onClose: () => setInputValue("")
|
|
3424
3923
|
}
|
|
3425
3924
|
),
|
|
3426
|
-
/* @__PURE__ */
|
|
3925
|
+
/* @__PURE__ */ jsx13(
|
|
3427
3926
|
InputField,
|
|
3428
3927
|
{
|
|
3429
3928
|
compact: true,
|
|
@@ -3443,7 +3942,7 @@ var ChatBubble = ({
|
|
|
3443
3942
|
}
|
|
3444
3943
|
);
|
|
3445
3944
|
}
|
|
3446
|
-
return /* @__PURE__ */
|
|
3945
|
+
return /* @__PURE__ */ jsx13(Fragment3, { children: /* @__PURE__ */ jsxs8(
|
|
3447
3946
|
"div",
|
|
3448
3947
|
{
|
|
3449
3948
|
className: "fixed",
|
|
@@ -3497,13 +3996,13 @@ var ChatBubble = ({
|
|
|
3497
3996
|
children: [
|
|
3498
3997
|
/* @__PURE__ */ jsxs8("div", { className: "flex items-center space-x-3", children: [
|
|
3499
3998
|
config.avatar && /* @__PURE__ */ jsxs8("div", { className: "relative flex-shrink-0", children: [
|
|
3500
|
-
/* @__PURE__ */
|
|
3501
|
-
/* @__PURE__ */
|
|
3999
|
+
/* @__PURE__ */ jsx13(Avatar, { avatar: config.avatar }),
|
|
4000
|
+
/* @__PURE__ */ jsx13("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
|
|
3502
4001
|
] }),
|
|
3503
|
-
config.title && /* @__PURE__ */
|
|
4002
|
+
config.title && /* @__PURE__ */ jsx13("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx13("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
|
|
3504
4003
|
] }),
|
|
3505
4004
|
/* @__PURE__ */ jsxs8("div", { className: "flex items-center space-x-1 flex-shrink-0", children: [
|
|
3506
|
-
/* @__PURE__ */
|
|
4005
|
+
/* @__PURE__ */ jsx13(
|
|
3507
4006
|
"button",
|
|
3508
4007
|
{
|
|
3509
4008
|
onClick: (e) => {
|
|
@@ -3512,10 +4011,10 @@ var ChatBubble = ({
|
|
|
3512
4011
|
},
|
|
3513
4012
|
className: THEME_CLASSES.button.minimize,
|
|
3514
4013
|
title: "Minimize chat",
|
|
3515
|
-
children: /* @__PURE__ */
|
|
4014
|
+
children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
|
|
3516
4015
|
}
|
|
3517
4016
|
),
|
|
3518
|
-
/* @__PURE__ */
|
|
4017
|
+
/* @__PURE__ */ jsx13(
|
|
3519
4018
|
"button",
|
|
3520
4019
|
{
|
|
3521
4020
|
onClick: (e) => {
|
|
@@ -3524,7 +4023,7 @@ var ChatBubble = ({
|
|
|
3524
4023
|
},
|
|
3525
4024
|
className: THEME_CLASSES.button.close,
|
|
3526
4025
|
title: "Close chat",
|
|
3527
|
-
children: /* @__PURE__ */
|
|
4026
|
+
children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
3528
4027
|
}
|
|
3529
4028
|
)
|
|
3530
4029
|
] })
|
|
@@ -3534,10 +4033,10 @@ var ChatBubble = ({
|
|
|
3534
4033
|
/* @__PURE__ */ jsxs8("div", { className: "p-4", children: [
|
|
3535
4034
|
(() => {
|
|
3536
4035
|
const lastAiMessage = [...messages].reverse().find((m) => m.type === "ai");
|
|
3537
|
-
return lastAiMessage ? /* @__PURE__ */
|
|
4036
|
+
return lastAiMessage ? /* @__PURE__ */ jsx13("div", { className: "mb-3", children: /* @__PURE__ */ jsx13("div", { className: `text-xs px-3 py-2 rounded-xl ${THEME_CLASSES.message.ai}`, style: INLINE_STYLES.messageAI(theme === "dark"), children: lastAiMessage.text.length > 100 ? `${lastAiMessage.text.slice(0, 100)}...` : lastAiMessage.text }) }) : /* @__PURE__ */ jsx13("div", { className: "mb-3", children: /* @__PURE__ */ jsx13("div", { className: THEME_CLASSES.text.minimizedMessage, style: INLINE_STYLES.minimizedMessage(theme === "dark"), children: "No AI responses yet" }) });
|
|
3538
4037
|
})(),
|
|
3539
4038
|
/* @__PURE__ */ jsxs8("div", { style: { position: "relative" }, children: [
|
|
3540
|
-
slashCommand.isOpen && /* @__PURE__ */
|
|
4039
|
+
slashCommand.isOpen && /* @__PURE__ */ jsx13(
|
|
3541
4040
|
SlashCommandPopup,
|
|
3542
4041
|
{
|
|
3543
4042
|
tools: slashCommand.filteredTools,
|
|
@@ -3546,7 +4045,7 @@ var ChatBubble = ({
|
|
|
3546
4045
|
onClose: () => setInputValue("")
|
|
3547
4046
|
}
|
|
3548
4047
|
),
|
|
3549
|
-
/* @__PURE__ */
|
|
4048
|
+
/* @__PURE__ */ jsx13(
|
|
3550
4049
|
InputField,
|
|
3551
4050
|
{
|
|
3552
4051
|
compact: true,
|
|
@@ -3593,13 +4092,13 @@ var ChatBubble = ({
|
|
|
3593
4092
|
children: [
|
|
3594
4093
|
/* @__PURE__ */ jsxs8("div", { className: "flex items-center space-x-3", children: [
|
|
3595
4094
|
config.avatar && /* @__PURE__ */ jsxs8("div", { className: "relative flex-shrink-0", children: [
|
|
3596
|
-
/* @__PURE__ */
|
|
3597
|
-
/* @__PURE__ */
|
|
4095
|
+
/* @__PURE__ */ jsx13(Avatar, { avatar: config.avatar }),
|
|
4096
|
+
/* @__PURE__ */ jsx13("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
|
|
3598
4097
|
] }),
|
|
3599
|
-
config.title && /* @__PURE__ */
|
|
4098
|
+
config.title && /* @__PURE__ */ jsx13("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx13("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
|
|
3600
4099
|
] }),
|
|
3601
4100
|
/* @__PURE__ */ jsxs8("div", { className: "flex items-center space-x-1 flex-shrink-0 relative", "data-more-menu": true, children: [
|
|
3602
|
-
/* @__PURE__ */
|
|
4101
|
+
/* @__PURE__ */ jsx13(
|
|
3603
4102
|
"a",
|
|
3604
4103
|
{
|
|
3605
4104
|
href: "https://www.interface.supernal.ai",
|
|
@@ -3607,30 +4106,160 @@ var ChatBubble = ({
|
|
|
3607
4106
|
rel: "noopener noreferrer",
|
|
3608
4107
|
className: "p-2 text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 transition-colors rounded-lg hover:bg-white/30",
|
|
3609
4108
|
title: "Visit Supernal Interface Documentation",
|
|
3610
|
-
children: /* @__PURE__ */
|
|
4109
|
+
children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" }) })
|
|
3611
4110
|
}
|
|
3612
4111
|
),
|
|
3613
|
-
/* @__PURE__ */
|
|
4112
|
+
/* @__PURE__ */ jsx13(
|
|
3614
4113
|
"button",
|
|
3615
4114
|
{
|
|
3616
4115
|
onClick: () => setShowMoreMenu(!showMoreMenu),
|
|
3617
4116
|
className: THEME_CLASSES.button.more,
|
|
3618
4117
|
title: "More options",
|
|
3619
|
-
|
|
4118
|
+
"data-testid": "chat-more-menu-button",
|
|
4119
|
+
children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 5v.01M12 12v.01M12 19v.01M12 6a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2z" }) })
|
|
3620
4120
|
}
|
|
3621
4121
|
),
|
|
3622
|
-
showMoreMenu && /* @__PURE__ */ jsxs8("div", { className: "absolute right-0 top-10 bg-white dark:bg-gray-800 rounded-lg shadow-xl border border-gray-200 dark:border-gray-600 p-2 min-w-[
|
|
3623
|
-
/* @__PURE__ */
|
|
3624
|
-
/* @__PURE__ */
|
|
4122
|
+
showMoreMenu && /* @__PURE__ */ jsxs8("div", { className: "absolute right-0 top-10 bg-white dark:bg-gray-800 rounded-lg shadow-xl border border-gray-200 dark:border-gray-600 p-2 min-w-[280px] z-50", "data-more-menu": true, "data-testid": "chat-more-menu", children: [
|
|
4123
|
+
apiKey && /* @__PURE__ */ jsxs8("div", { className: "px-3 py-2 border-b border-gray-200 dark:border-gray-600 mb-2", "data-testid": "api-key-section", children: [
|
|
4124
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between mb-2", children: [
|
|
4125
|
+
/* @__PURE__ */ jsxs8("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-200 flex items-center gap-2", children: [
|
|
4126
|
+
/* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" }) }),
|
|
4127
|
+
"API Key"
|
|
4128
|
+
] }),
|
|
4129
|
+
apiKey.status === "valid" && /* @__PURE__ */ jsx13("span", { className: "text-green-500", title: "API key is valid", "data-testid": "api-key-status", "data-status": "valid", children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx13("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z", clipRule: "evenodd" }) }) }),
|
|
4130
|
+
apiKey.status === "invalid" && /* @__PURE__ */ jsx13("span", { className: "text-red-500", title: "API key is invalid", "data-testid": "api-key-status", "data-status": "invalid", children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx13("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z", clipRule: "evenodd" }) }) }),
|
|
4131
|
+
apiKey.status === "validating" && /* @__PURE__ */ jsx13("span", { className: "text-blue-500 animate-spin", title: "Validating...", "data-testid": "api-key-status", "data-status": "validating", children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" }) }) })
|
|
4132
|
+
] }),
|
|
4133
|
+
apiKey.status === "valid" && apiKey.maskedKey ? (
|
|
4134
|
+
// Key is set - show masked key and clear button
|
|
4135
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
|
|
4136
|
+
/* @__PURE__ */ jsx13("code", { className: "flex-1 text-xs bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded text-gray-600 dark:text-gray-300 font-mono", "data-testid": "api-key-masked", children: apiKey.maskedKey }),
|
|
4137
|
+
/* @__PURE__ */ jsx13(
|
|
4138
|
+
"button",
|
|
4139
|
+
{
|
|
4140
|
+
onClick: () => {
|
|
4141
|
+
apiKey.clearApiKey();
|
|
4142
|
+
setApiKeyInputValue("");
|
|
4143
|
+
},
|
|
4144
|
+
className: "text-xs text-red-500 hover:text-red-600 px-2 py-1",
|
|
4145
|
+
title: "Remove API key",
|
|
4146
|
+
"data-testid": "api-key-clear-button",
|
|
4147
|
+
children: "Clear"
|
|
4148
|
+
}
|
|
4149
|
+
)
|
|
4150
|
+
] })
|
|
4151
|
+
) : showApiKeyInput ? (
|
|
4152
|
+
// Input mode - show form
|
|
4153
|
+
/* @__PURE__ */ jsxs8("div", { className: "space-y-2", children: [
|
|
4154
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex gap-1", children: [
|
|
4155
|
+
/* @__PURE__ */ jsx13(
|
|
4156
|
+
"input",
|
|
4157
|
+
{
|
|
4158
|
+
type: showApiKey ? "text" : "password",
|
|
4159
|
+
value: apiKeyInputValue,
|
|
4160
|
+
onChange: (e) => setApiKeyInputValue(e.target.value),
|
|
4161
|
+
placeholder: "sk-ant-...",
|
|
4162
|
+
className: "flex-1 text-sm px-2 py-1.5 border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-1 focus:ring-blue-500",
|
|
4163
|
+
"data-testid": "api-key-input",
|
|
4164
|
+
onKeyDown: (e) => {
|
|
4165
|
+
if (e.key === "Enter") {
|
|
4166
|
+
e.preventDefault();
|
|
4167
|
+
if (apiKeyInputValue.trim()) {
|
|
4168
|
+
apiKey.setApiKey(apiKeyInputValue.trim()).then((success) => {
|
|
4169
|
+
if (success) {
|
|
4170
|
+
setApiKeyInputValue("");
|
|
4171
|
+
setShowApiKeyInput(false);
|
|
4172
|
+
}
|
|
4173
|
+
});
|
|
4174
|
+
}
|
|
4175
|
+
}
|
|
4176
|
+
if (e.key === "Escape") {
|
|
4177
|
+
setShowApiKeyInput(false);
|
|
4178
|
+
setApiKeyInputValue("");
|
|
4179
|
+
}
|
|
4180
|
+
},
|
|
4181
|
+
autoFocus: true
|
|
4182
|
+
}
|
|
4183
|
+
),
|
|
4184
|
+
/* @__PURE__ */ jsx13(
|
|
4185
|
+
"button",
|
|
4186
|
+
{
|
|
4187
|
+
onClick: () => setShowApiKey(!showApiKey),
|
|
4188
|
+
className: "px-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200",
|
|
4189
|
+
title: showApiKey ? "Hide" : "Show",
|
|
4190
|
+
"data-testid": "api-key-show-toggle",
|
|
4191
|
+
children: showApiKey ? "\u{1F648}" : "\u{1F441}\uFE0F"
|
|
4192
|
+
}
|
|
4193
|
+
)
|
|
4194
|
+
] }),
|
|
4195
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex gap-2", children: [
|
|
4196
|
+
/* @__PURE__ */ jsx13(
|
|
4197
|
+
"button",
|
|
4198
|
+
{
|
|
4199
|
+
onClick: async () => {
|
|
4200
|
+
if (apiKeyInputValue.trim()) {
|
|
4201
|
+
const success = await apiKey.setApiKey(apiKeyInputValue.trim());
|
|
4202
|
+
if (success) {
|
|
4203
|
+
setApiKeyInputValue("");
|
|
4204
|
+
setShowApiKeyInput(false);
|
|
4205
|
+
}
|
|
4206
|
+
}
|
|
4207
|
+
},
|
|
4208
|
+
disabled: !apiKeyInputValue.trim() || apiKey.status === "validating",
|
|
4209
|
+
className: "flex-1 text-xs px-3 py-1.5 bg-blue-600 text-white rounded hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed",
|
|
4210
|
+
"data-testid": "api-key-submit-button",
|
|
4211
|
+
children: apiKey.status === "validating" ? "Validating..." : "Save"
|
|
4212
|
+
}
|
|
4213
|
+
),
|
|
4214
|
+
/* @__PURE__ */ jsx13(
|
|
4215
|
+
"button",
|
|
4216
|
+
{
|
|
4217
|
+
onClick: () => {
|
|
4218
|
+
setShowApiKeyInput(false);
|
|
4219
|
+
setApiKeyInputValue("");
|
|
4220
|
+
},
|
|
4221
|
+
className: "text-xs px-3 py-1.5 text-gray-600 dark:text-gray-300 hover:text-gray-800 dark:hover:text-gray-100",
|
|
4222
|
+
"data-testid": "api-key-cancel-button",
|
|
4223
|
+
children: "Cancel"
|
|
4224
|
+
}
|
|
4225
|
+
)
|
|
4226
|
+
] }),
|
|
4227
|
+
apiKey.error && /* @__PURE__ */ jsx13("p", { className: "text-xs text-red-500", "data-testid": "api-key-error", children: apiKey.error }),
|
|
4228
|
+
/* @__PURE__ */ jsx13(
|
|
4229
|
+
"a",
|
|
4230
|
+
{
|
|
4231
|
+
href: "https://console.anthropic.com/settings/keys",
|
|
4232
|
+
target: "_blank",
|
|
4233
|
+
rel: "noopener noreferrer",
|
|
4234
|
+
className: "block text-xs text-blue-500 hover:underline",
|
|
4235
|
+
children: "Get an API key from Anthropic \u2192"
|
|
4236
|
+
}
|
|
4237
|
+
)
|
|
4238
|
+
] })
|
|
4239
|
+
) : (
|
|
4240
|
+
// No key - show configure button
|
|
4241
|
+
/* @__PURE__ */ jsx13(
|
|
4242
|
+
"button",
|
|
4243
|
+
{
|
|
4244
|
+
onClick: () => setShowApiKeyInput(true),
|
|
4245
|
+
className: "w-full text-sm px-3 py-2 bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200 rounded hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors",
|
|
4246
|
+
"data-testid": "api-key-configure-button",
|
|
4247
|
+
children: "Configure API Key"
|
|
4248
|
+
}
|
|
4249
|
+
)
|
|
4250
|
+
)
|
|
4251
|
+
] }),
|
|
4252
|
+
/* @__PURE__ */ jsx13("div", { className: "px-3 py-2 border-b border-gray-200 dark:border-gray-600 mb-2", children: /* @__PURE__ */ jsxs8("div", { className: "grid grid-cols-4 gap-1", children: [
|
|
4253
|
+
/* @__PURE__ */ jsx13(
|
|
3625
4254
|
"button",
|
|
3626
4255
|
{
|
|
3627
4256
|
onClick: () => setLocalGlassMode(false),
|
|
3628
4257
|
className: `flex items-center justify-center p-2 rounded transition-all ${!localGlassMode ? "bg-blue-600 text-white shadow-sm" : "bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-600"}`,
|
|
3629
4258
|
title: "Glass Off",
|
|
3630
|
-
children: /* @__PURE__ */
|
|
4259
|
+
children: /* @__PURE__ */ jsx13("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("rect", { x: "8", y: "8", width: "8", height: "8", rx: "1" }) })
|
|
3631
4260
|
}
|
|
3632
4261
|
),
|
|
3633
|
-
/* @__PURE__ */
|
|
4262
|
+
/* @__PURE__ */ jsx13(
|
|
3634
4263
|
"button",
|
|
3635
4264
|
{
|
|
3636
4265
|
onClick: () => {
|
|
@@ -3639,10 +4268,10 @@ var ChatBubble = ({
|
|
|
3639
4268
|
},
|
|
3640
4269
|
className: `flex items-center justify-center p-2 rounded transition-all ${localGlassMode && glassOpacity === "low" ? "bg-blue-600 text-white shadow-sm" : "bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-600"}`,
|
|
3641
4270
|
title: "Glass Low",
|
|
3642
|
-
children: /* @__PURE__ */
|
|
4271
|
+
children: /* @__PURE__ */ jsx13("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("rect", { x: "9", y: "9", width: "6", height: "6", rx: "1", strokeWidth: "2" }) })
|
|
3643
4272
|
}
|
|
3644
4273
|
),
|
|
3645
|
-
/* @__PURE__ */
|
|
4274
|
+
/* @__PURE__ */ jsx13(
|
|
3646
4275
|
"button",
|
|
3647
4276
|
{
|
|
3648
4277
|
onClick: () => {
|
|
@@ -3652,12 +4281,12 @@ var ChatBubble = ({
|
|
|
3652
4281
|
className: `flex items-center justify-center p-2 rounded transition-all ${localGlassMode && glassOpacity === "medium" ? "bg-blue-600 text-white shadow-sm" : "bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-600"}`,
|
|
3653
4282
|
title: "Glass Medium",
|
|
3654
4283
|
children: /* @__PURE__ */ jsxs8("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [
|
|
3655
|
-
/* @__PURE__ */
|
|
3656
|
-
/* @__PURE__ */
|
|
4284
|
+
/* @__PURE__ */ jsx13("rect", { x: "8", y: "8", width: "8", height: "8", rx: "1", strokeWidth: "2" }),
|
|
4285
|
+
/* @__PURE__ */ jsx13("rect", { x: "10", y: "10", width: "4", height: "4", rx: "0.5", strokeWidth: "1.5" })
|
|
3657
4286
|
] })
|
|
3658
4287
|
}
|
|
3659
4288
|
),
|
|
3660
|
-
/* @__PURE__ */
|
|
4289
|
+
/* @__PURE__ */ jsx13(
|
|
3661
4290
|
"button",
|
|
3662
4291
|
{
|
|
3663
4292
|
onClick: () => {
|
|
@@ -3667,9 +4296,9 @@ var ChatBubble = ({
|
|
|
3667
4296
|
className: `flex items-center justify-center p-2 rounded transition-all ${localGlassMode && glassOpacity === "high" ? "bg-blue-600 text-white shadow-sm" : "bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-600"}`,
|
|
3668
4297
|
title: "Glass High",
|
|
3669
4298
|
children: /* @__PURE__ */ jsxs8("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [
|
|
3670
|
-
/* @__PURE__ */
|
|
3671
|
-
/* @__PURE__ */
|
|
3672
|
-
/* @__PURE__ */
|
|
4299
|
+
/* @__PURE__ */ jsx13("rect", { x: "7", y: "7", width: "10", height: "10", rx: "1", strokeWidth: "2" }),
|
|
4300
|
+
/* @__PURE__ */ jsx13("rect", { x: "9", y: "9", width: "6", height: "6", rx: "0.5", strokeWidth: "1.5" }),
|
|
4301
|
+
/* @__PURE__ */ jsx13("rect", { x: "11", y: "11", width: "2", height: "2", rx: "0.5", strokeWidth: "1" })
|
|
3673
4302
|
] })
|
|
3674
4303
|
}
|
|
3675
4304
|
)
|
|
@@ -3686,7 +4315,7 @@ var ChatBubble = ({
|
|
|
3686
4315
|
},
|
|
3687
4316
|
className: "w-full flex items-center space-x-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
3688
4317
|
children: [
|
|
3689
|
-
/* @__PURE__ */
|
|
4318
|
+
/* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) }),
|
|
3690
4319
|
/* @__PURE__ */ jsxs8("span", { children: [
|
|
3691
4320
|
theme === "light" ? "Dark" : "Light",
|
|
3692
4321
|
" Mode"
|
|
@@ -3705,7 +4334,7 @@ var ChatBubble = ({
|
|
|
3705
4334
|
},
|
|
3706
4335
|
className: "w-full flex items-center space-x-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
3707
4336
|
children: [
|
|
3708
|
-
/* @__PURE__ */
|
|
4337
|
+
/* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" }) }),
|
|
3709
4338
|
/* @__PURE__ */ jsxs8("span", { children: [
|
|
3710
4339
|
voiceEnabled ? "Disable" : "Enable",
|
|
3711
4340
|
" Voice"
|
|
@@ -3722,8 +4351,8 @@ var ChatBubble = ({
|
|
|
3722
4351
|
},
|
|
3723
4352
|
className: "w-full flex items-center space-x-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
3724
4353
|
children: [
|
|
3725
|
-
/* @__PURE__ */
|
|
3726
|
-
/* @__PURE__ */
|
|
4354
|
+
/* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }),
|
|
4355
|
+
/* @__PURE__ */ jsx13("span", { children: "Reset position" })
|
|
3727
4356
|
]
|
|
3728
4357
|
}
|
|
3729
4358
|
),
|
|
@@ -3743,8 +4372,8 @@ var ChatBubble = ({
|
|
|
3743
4372
|
},
|
|
3744
4373
|
className: "w-full flex items-center space-x-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
3745
4374
|
children: [
|
|
3746
|
-
/* @__PURE__ */
|
|
3747
|
-
/* @__PURE__ */
|
|
4375
|
+
/* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
|
|
4376
|
+
/* @__PURE__ */ jsx13("span", { children: "How to use" })
|
|
3748
4377
|
]
|
|
3749
4378
|
}
|
|
3750
4379
|
),
|
|
@@ -3757,41 +4386,41 @@ var ChatBubble = ({
|
|
|
3757
4386
|
},
|
|
3758
4387
|
className: "w-full flex items-center space-x-2 px-3 py-2 text-sm text-red-600 dark:text-red-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors",
|
|
3759
4388
|
children: [
|
|
3760
|
-
/* @__PURE__ */
|
|
3761
|
-
/* @__PURE__ */
|
|
4389
|
+
/* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
|
|
4390
|
+
/* @__PURE__ */ jsx13("span", { children: "Clear chat" })
|
|
3762
4391
|
]
|
|
3763
4392
|
}
|
|
3764
4393
|
)
|
|
3765
4394
|
] }),
|
|
3766
|
-
/* @__PURE__ */
|
|
4395
|
+
/* @__PURE__ */ jsx13(
|
|
3767
4396
|
"button",
|
|
3768
4397
|
{
|
|
3769
4398
|
onClick: () => setIsMinimized(true),
|
|
3770
4399
|
className: THEME_CLASSES.button.minimize,
|
|
3771
4400
|
title: "Minimize",
|
|
3772
|
-
children: /* @__PURE__ */
|
|
4401
|
+
children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20 12H4" }) })
|
|
3773
4402
|
}
|
|
3774
4403
|
),
|
|
3775
|
-
/* @__PURE__ */
|
|
4404
|
+
/* @__PURE__ */ jsx13(
|
|
3776
4405
|
"button",
|
|
3777
4406
|
{
|
|
3778
4407
|
onClick: handleToggle,
|
|
3779
4408
|
className: THEME_CLASSES.button.close,
|
|
3780
4409
|
title: "Close",
|
|
3781
|
-
children: /* @__PURE__ */
|
|
4410
|
+
children: /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
3782
4411
|
}
|
|
3783
4412
|
)
|
|
3784
4413
|
] })
|
|
3785
4414
|
]
|
|
3786
4415
|
}
|
|
3787
4416
|
),
|
|
3788
|
-
/* @__PURE__ */ jsxs8("div", { className: "flex-1 overflow-y-auto p-4 space-y-2", children: [
|
|
4417
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex-1 overflow-y-auto p-4 space-y-2", "data-testid": "chat-messages", children: [
|
|
3789
4418
|
showWelcome && messages.length === 0 && config.welcome?.enabled && /* @__PURE__ */ jsxs8("div", { className: THEME_CLASSES.welcome.container, children: [
|
|
3790
|
-
config.welcome.title && /* @__PURE__ */
|
|
3791
|
-
config.welcome.content && /* @__PURE__ */
|
|
4419
|
+
config.welcome.title && /* @__PURE__ */ jsx13("h4", { className: THEME_CLASSES.welcome.title, style: INLINE_STYLES.welcomeTitle(theme === "dark"), children: config.welcome.title }),
|
|
4420
|
+
config.welcome.content && /* @__PURE__ */ jsx13("p", { className: THEME_CLASSES.welcome.content, style: INLINE_STYLES.welcomeContent(theme === "dark"), children: config.welcome.content }),
|
|
3792
4421
|
config.welcome.suggestedCommands && config.welcome.suggestedCommands.length > 0 && /* @__PURE__ */ jsxs8("div", { className: THEME_CLASSES.welcome.commandsContainer, children: [
|
|
3793
|
-
/* @__PURE__ */
|
|
3794
|
-
/* @__PURE__ */
|
|
4422
|
+
/* @__PURE__ */ jsx13("p", { className: THEME_CLASSES.welcome.commandsHeader, children: "Try these commands:" }),
|
|
4423
|
+
/* @__PURE__ */ jsx13("div", { className: "space-y-1", children: config.welcome.suggestedCommands.map((cmd, idx) => /* @__PURE__ */ jsxs8(
|
|
3795
4424
|
"button",
|
|
3796
4425
|
{
|
|
3797
4426
|
onClick: () => {
|
|
@@ -3806,7 +4435,7 @@ var ChatBubble = ({
|
|
|
3806
4435
|
cmd.text,
|
|
3807
4436
|
'"'
|
|
3808
4437
|
] }),
|
|
3809
|
-
cmd.desc && /* @__PURE__ */
|
|
4438
|
+
cmd.desc && /* @__PURE__ */ jsx13("div", { className: THEME_CLASSES.welcome.commandDesc, style: INLINE_STYLES.commandDesc(theme === "dark"), children: cmd.desc })
|
|
3810
4439
|
]
|
|
3811
4440
|
},
|
|
3812
4441
|
idx
|
|
@@ -3814,16 +4443,16 @@ var ChatBubble = ({
|
|
|
3814
4443
|
] })
|
|
3815
4444
|
] }),
|
|
3816
4445
|
messages.map((message) => /* @__PURE__ */ jsxs8("div", { className: `group flex items-center gap-2 mb-2 ${message.type === "user" ? "flex-row-reverse" : "flex-row"}`, children: [
|
|
3817
|
-
/* @__PURE__ */
|
|
4446
|
+
/* @__PURE__ */ jsx13(
|
|
3818
4447
|
"div",
|
|
3819
4448
|
{
|
|
3820
4449
|
className: `inline-block px-4 py-2.5 rounded-2xl max-w-[80%] text-sm shadow-sm transition-all ${message.type === "user" ? THEME_CLASSES.message.user : message.type === "ai" ? THEME_CLASSES.message.ai : THEME_CLASSES.message.system}`,
|
|
3821
4450
|
style: message.type === "user" ? INLINE_STYLES.messageUser() : message.type === "ai" ? INLINE_STYLES.messageAI(theme === "dark") : INLINE_STYLES.messageSystem(theme === "dark"),
|
|
3822
4451
|
"data-testid": `chat-message-${message.type}`,
|
|
3823
|
-
children: /* @__PURE__ */
|
|
4452
|
+
children: /* @__PURE__ */ jsx13(MessageRenderer, { content: message.text, theme })
|
|
3824
4453
|
}
|
|
3825
4454
|
),
|
|
3826
|
-
message.type === "ai" && voiceEnabled && /* @__PURE__ */
|
|
4455
|
+
message.type === "ai" && voiceEnabled && /* @__PURE__ */ jsx13(
|
|
3827
4456
|
TTSButton,
|
|
3828
4457
|
{
|
|
3829
4458
|
text: message.text,
|
|
@@ -3833,7 +4462,7 @@ var ChatBubble = ({
|
|
|
3833
4462
|
size: "small"
|
|
3834
4463
|
}
|
|
3835
4464
|
),
|
|
3836
|
-
/* @__PURE__ */
|
|
4465
|
+
/* @__PURE__ */ jsx13(
|
|
3837
4466
|
"div",
|
|
3838
4467
|
{
|
|
3839
4468
|
className: `text-xs opacity-0 group-hover:opacity-70 transition-opacity whitespace-nowrap flex-shrink-0 ${message.type === "user" ? "text-gray-400 dark:text-gray-500 text-left" : "text-gray-600 dark:text-gray-400 text-right"}`,
|
|
@@ -3842,10 +4471,10 @@ var ChatBubble = ({
|
|
|
3842
4471
|
}
|
|
3843
4472
|
)
|
|
3844
4473
|
] }, message.id)),
|
|
3845
|
-
/* @__PURE__ */
|
|
4474
|
+
/* @__PURE__ */ jsx13("div", { ref: messagesEndRef })
|
|
3846
4475
|
] }),
|
|
3847
4476
|
/* @__PURE__ */ jsxs8("div", { style: { position: "relative" }, children: [
|
|
3848
|
-
slashCommand.isOpen && /* @__PURE__ */
|
|
4477
|
+
slashCommand.isOpen && /* @__PURE__ */ jsx13(
|
|
3849
4478
|
SlashCommandPopup,
|
|
3850
4479
|
{
|
|
3851
4480
|
tools: slashCommand.filteredTools,
|
|
@@ -3854,7 +4483,7 @@ var ChatBubble = ({
|
|
|
3854
4483
|
onClose: () => setInputValue("")
|
|
3855
4484
|
}
|
|
3856
4485
|
),
|
|
3857
|
-
/* @__PURE__ */
|
|
4486
|
+
/* @__PURE__ */ jsx13(
|
|
3858
4487
|
InputField,
|
|
3859
4488
|
{
|
|
3860
4489
|
inputValue,
|
|
@@ -3884,8 +4513,8 @@ var ChatBubble = ({
|
|
|
3884
4513
|
"data-testid": ChatNames.bubble,
|
|
3885
4514
|
title: `Open chat (press ${isMac ? "Cmd" : "Ctrl"}+/ for voice recording)`,
|
|
3886
4515
|
children: [
|
|
3887
|
-
/* @__PURE__ */
|
|
3888
|
-
hasUnread && notifications && /* @__PURE__ */
|
|
4516
|
+
/* @__PURE__ */ jsx13("img", { src: config.logo, alt: "Supernal", className: "w-8 h-8" }),
|
|
4517
|
+
hasUnread && notifications && /* @__PURE__ */ jsx13("div", { className: "absolute -top-1 -right-1 w-5 h-5 bg-red-500 rounded-full flex items-center justify-center animate-pulse shadow-lg", "data-testid": "unread-indicator", children: /* @__PURE__ */ jsx13("span", { className: "text-xs text-white font-bold", children: unreadCount > 9 ? "9+" : unreadCount }) })
|
|
3889
4518
|
]
|
|
3890
4519
|
}
|
|
3891
4520
|
)
|
|
@@ -3895,33 +4524,33 @@ var ChatBubble = ({
|
|
|
3895
4524
|
};
|
|
3896
4525
|
|
|
3897
4526
|
// src/components/AutoNavigationContext.tsx
|
|
3898
|
-
import { useEffect as
|
|
4527
|
+
import { useEffect as useEffect10, useState as useState11 } from "react";
|
|
3899
4528
|
|
|
3900
4529
|
// src/hooks/useNavigationGraph.tsx
|
|
3901
|
-
import { useEffect as
|
|
4530
|
+
import { useEffect as useEffect9, useState as useState10, useCallback as useCallback7, createContext as createContext4, useContext as useContext4 } from "react";
|
|
3902
4531
|
import {
|
|
3903
4532
|
NavigationGraph
|
|
3904
4533
|
} from "@supernal/interface/browser";
|
|
3905
|
-
import { jsx as
|
|
3906
|
-
var NavigationContextContext =
|
|
4534
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
4535
|
+
var NavigationContextContext = createContext4("global");
|
|
3907
4536
|
function NavigationContextProvider({
|
|
3908
4537
|
value,
|
|
3909
4538
|
children
|
|
3910
4539
|
}) {
|
|
3911
4540
|
const graph = useNavigationGraph();
|
|
3912
|
-
|
|
4541
|
+
useEffect9(() => {
|
|
3913
4542
|
graph.setCurrentContext(value);
|
|
3914
4543
|
}, [value, graph]);
|
|
3915
|
-
return /* @__PURE__ */
|
|
4544
|
+
return /* @__PURE__ */ jsx14(NavigationContextContext.Provider, { value, children });
|
|
3916
4545
|
}
|
|
3917
4546
|
function useNavigationGraph() {
|
|
3918
4547
|
return NavigationGraph.getInstance();
|
|
3919
4548
|
}
|
|
3920
4549
|
function useCurrentContext() {
|
|
3921
|
-
const contextFromProvider =
|
|
4550
|
+
const contextFromProvider = useContext4(NavigationContextContext);
|
|
3922
4551
|
const graph = useNavigationGraph();
|
|
3923
|
-
const [graphContext, setGraphContext] =
|
|
3924
|
-
|
|
4552
|
+
const [graphContext, setGraphContext] = useState10("");
|
|
4553
|
+
useEffect9(() => {
|
|
3925
4554
|
const interval = setInterval(() => {
|
|
3926
4555
|
const current = graph.getCurrentContext?.() || "";
|
|
3927
4556
|
if (current !== graphContext) {
|
|
@@ -3935,7 +4564,7 @@ function useCurrentContext() {
|
|
|
3935
4564
|
function useRegisterTool(toolId, contextId, metadata) {
|
|
3936
4565
|
const graph = useNavigationGraph();
|
|
3937
4566
|
const currentContext = useCurrentContext();
|
|
3938
|
-
|
|
4567
|
+
useEffect9(() => {
|
|
3939
4568
|
let targetContext = contextId || currentContext;
|
|
3940
4569
|
if (!contextId && metadata) {
|
|
3941
4570
|
const detection = graph.detectToolContext?.(toolId, metadata);
|
|
@@ -3949,10 +4578,10 @@ function useRegisterTool(toolId, contextId, metadata) {
|
|
|
3949
4578
|
function useNavigationPath(targetContextOrToolId, isToolId = false) {
|
|
3950
4579
|
const graph = useNavigationGraph();
|
|
3951
4580
|
const currentContext = useCurrentContext();
|
|
3952
|
-
const [path, setPath] =
|
|
3953
|
-
const [loading, setLoading] =
|
|
3954
|
-
const [error, setError] =
|
|
3955
|
-
|
|
4581
|
+
const [path, setPath] = useState10(null);
|
|
4582
|
+
const [loading, setLoading] = useState10(true);
|
|
4583
|
+
const [error, setError] = useState10();
|
|
4584
|
+
useEffect9(() => {
|
|
3956
4585
|
try {
|
|
3957
4586
|
let targetContext = targetContextOrToolId;
|
|
3958
4587
|
if (isToolId) {
|
|
@@ -3980,9 +4609,9 @@ function useNavigationPath(targetContextOrToolId, isToolId = false) {
|
|
|
3980
4609
|
function useNavigate() {
|
|
3981
4610
|
const graph = useNavigationGraph();
|
|
3982
4611
|
const currentContext = useCurrentContext();
|
|
3983
|
-
const [navigating, setNavigating] =
|
|
3984
|
-
const [error, setError] =
|
|
3985
|
-
const navigateTo =
|
|
4612
|
+
const [navigating, setNavigating] = useState10(false);
|
|
4613
|
+
const [error, setError] = useState10();
|
|
4614
|
+
const navigateTo = useCallback7(async (targetContextOrToolId, isToolId = false, executeNavigation) => {
|
|
3986
4615
|
setNavigating(true);
|
|
3987
4616
|
setError(void 0);
|
|
3988
4617
|
try {
|
|
@@ -4024,8 +4653,8 @@ function useNavigate() {
|
|
|
4024
4653
|
}
|
|
4025
4654
|
function useAllContexts() {
|
|
4026
4655
|
const graph = useNavigationGraph();
|
|
4027
|
-
const [contexts, setContexts] =
|
|
4028
|
-
|
|
4656
|
+
const [contexts, setContexts] = useState10(graph.getAllContexts?.());
|
|
4657
|
+
useEffect9(() => {
|
|
4029
4658
|
const interval = setInterval(() => {
|
|
4030
4659
|
setContexts(graph.getAllContexts?.());
|
|
4031
4660
|
}, 1e3);
|
|
@@ -4035,28 +4664,28 @@ function useAllContexts() {
|
|
|
4035
4664
|
}
|
|
4036
4665
|
|
|
4037
4666
|
// src/components/AutoNavigationContext.tsx
|
|
4038
|
-
import { Fragment as Fragment4, jsx as
|
|
4667
|
+
import { Fragment as Fragment4, jsx as jsx15 } from "react/jsx-runtime";
|
|
4039
4668
|
function AutoNavigationContext({
|
|
4040
4669
|
children,
|
|
4041
4670
|
routes,
|
|
4042
4671
|
onNavigate
|
|
4043
4672
|
}) {
|
|
4044
|
-
const [pathname, setPathname] =
|
|
4045
|
-
|
|
4673
|
+
const [pathname, setPathname] = useState11("/");
|
|
4674
|
+
useEffect10(() => {
|
|
4046
4675
|
if (typeof window !== "undefined") {
|
|
4047
4676
|
setPathname(window.location.pathname);
|
|
4048
4677
|
}
|
|
4049
4678
|
}, []);
|
|
4050
4679
|
const context = routes ? inferContextFromPath(pathname, routes) : null;
|
|
4051
|
-
|
|
4680
|
+
useEffect10(() => {
|
|
4052
4681
|
if (onNavigate && context) {
|
|
4053
4682
|
onNavigate(context);
|
|
4054
4683
|
}
|
|
4055
4684
|
}, [context, onNavigate]);
|
|
4056
4685
|
if (!context) {
|
|
4057
|
-
return /* @__PURE__ */
|
|
4686
|
+
return /* @__PURE__ */ jsx15(Fragment4, { children });
|
|
4058
4687
|
}
|
|
4059
|
-
return /* @__PURE__ */
|
|
4688
|
+
return /* @__PURE__ */ jsx15(NavigationContextProvider, { value: context, children });
|
|
4060
4689
|
}
|
|
4061
4690
|
function inferContextFromPath(path, customRoutes) {
|
|
4062
4691
|
if (customRoutes) {
|
|
@@ -4089,7 +4718,7 @@ function inferContextFromPath(path, customRoutes) {
|
|
|
4089
4718
|
import { ExposureCollector, ToolRegistry as ToolRegistry3 } from "@supernal/interface/browser";
|
|
4090
4719
|
|
|
4091
4720
|
// src/hooks/useLocationTracking.ts
|
|
4092
|
-
import { useEffect as
|
|
4721
|
+
import { useEffect as useEffect11, useRef as useRef11 } from "react";
|
|
4093
4722
|
import { LocationContext } from "@supernal/interface/browser";
|
|
4094
4723
|
var usePathname;
|
|
4095
4724
|
var useSearchParams;
|
|
@@ -4121,8 +4750,8 @@ function getCurrentLocation() {
|
|
|
4121
4750
|
};
|
|
4122
4751
|
}
|
|
4123
4752
|
function useLocationTracking() {
|
|
4124
|
-
const lastLocationRef =
|
|
4125
|
-
const lastElementsRef =
|
|
4753
|
+
const lastLocationRef = useRef11("");
|
|
4754
|
+
const lastElementsRef = useRef11([]);
|
|
4126
4755
|
let pathname = null;
|
|
4127
4756
|
let searchParams = null;
|
|
4128
4757
|
try {
|
|
@@ -4134,7 +4763,7 @@ function useLocationTracking() {
|
|
|
4134
4763
|
}
|
|
4135
4764
|
} catch {
|
|
4136
4765
|
}
|
|
4137
|
-
|
|
4766
|
+
useEffect11(() => {
|
|
4138
4767
|
const updateLocation = () => {
|
|
4139
4768
|
const location = pathname !== null ? { pathname, search: searchParams?.toString() || "", asPath: pathname + (searchParams?.toString() ? `?${searchParams.toString()}` : "") } : getCurrentLocation();
|
|
4140
4769
|
const visibleElements = getVisibleElements();
|
|
@@ -4175,7 +4804,7 @@ function useLocationTracking() {
|
|
|
4175
4804
|
}
|
|
4176
4805
|
|
|
4177
4806
|
// src/hooks/useNavigationGraphSetup.ts
|
|
4178
|
-
import { useEffect as
|
|
4807
|
+
import { useEffect as useEffect12, useState as useState12, useCallback as useCallback8 } from "react";
|
|
4179
4808
|
var useAppRouter;
|
|
4180
4809
|
var usePathname2;
|
|
4181
4810
|
try {
|
|
@@ -4185,7 +4814,7 @@ try {
|
|
|
4185
4814
|
} catch {
|
|
4186
4815
|
}
|
|
4187
4816
|
function useNavigationGraphSetup() {
|
|
4188
|
-
const [isInitialized, setIsInitialized] =
|
|
4817
|
+
const [isInitialized, setIsInitialized] = useState12(false);
|
|
4189
4818
|
let router = null;
|
|
4190
4819
|
let pathname = null;
|
|
4191
4820
|
try {
|
|
@@ -4197,7 +4826,7 @@ function useNavigationGraphSetup() {
|
|
|
4197
4826
|
}
|
|
4198
4827
|
} catch {
|
|
4199
4828
|
}
|
|
4200
|
-
const navigate =
|
|
4829
|
+
const navigate = useCallback8((path) => {
|
|
4201
4830
|
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
4202
4831
|
if (router?.push) {
|
|
4203
4832
|
router.push(normalizedPath);
|
|
@@ -4206,7 +4835,7 @@ function useNavigationGraphSetup() {
|
|
|
4206
4835
|
}
|
|
4207
4836
|
}, [router]);
|
|
4208
4837
|
const currentPath = pathname ?? (typeof window !== "undefined" ? window.location.pathname + window.location.search : "/");
|
|
4209
|
-
|
|
4838
|
+
useEffect12(() => {
|
|
4210
4839
|
import("@supernal/interface/browser").then(({ NavigationGraph: NavigationGraph2 }) => {
|
|
4211
4840
|
const graph = NavigationGraph2.getInstance();
|
|
4212
4841
|
graph.setNavigationHandler(navigate);
|
|
@@ -4222,7 +4851,7 @@ function useNavigationGraphSetup() {
|
|
|
4222
4851
|
console.log("[NavigationGraphSetup] Auto-configured with Next.js router");
|
|
4223
4852
|
});
|
|
4224
4853
|
}, [navigate, currentPath]);
|
|
4225
|
-
|
|
4854
|
+
useEffect12(() => {
|
|
4226
4855
|
if (!isInitialized) return;
|
|
4227
4856
|
import("@supernal/interface/browser").then(({ NavigationGraph: NavigationGraph2 }) => {
|
|
4228
4857
|
const graph = NavigationGraph2.getInstance();
|
|
@@ -4233,8 +4862,8 @@ function useNavigationGraphSetup() {
|
|
|
4233
4862
|
}
|
|
4234
4863
|
|
|
4235
4864
|
// src/components/ToolMenuPopup/ToolMenuPopup.tsx
|
|
4236
|
-
import { useEffect as
|
|
4237
|
-
import { jsx as
|
|
4865
|
+
import { useEffect as useEffect13, useRef as useRef12, useState as useState13 } from "react";
|
|
4866
|
+
import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
4238
4867
|
var ToolMenuPopup = ({
|
|
4239
4868
|
isOpen,
|
|
4240
4869
|
onClose,
|
|
@@ -4242,16 +4871,16 @@ var ToolMenuPopup = ({
|
|
|
4242
4871
|
totalTools,
|
|
4243
4872
|
contextLabel
|
|
4244
4873
|
}) => {
|
|
4245
|
-
const [collapsedCategories, setCollapsedCategories] =
|
|
4246
|
-
const [isHydrated, setIsHydrated] =
|
|
4247
|
-
const [isMobile, setIsMobile] =
|
|
4248
|
-
const popupRef =
|
|
4874
|
+
const [collapsedCategories, setCollapsedCategories] = useState13(/* @__PURE__ */ new Set());
|
|
4875
|
+
const [isHydrated, setIsHydrated] = useState13(false);
|
|
4876
|
+
const [isMobile, setIsMobile] = useState13(false);
|
|
4877
|
+
const popupRef = useRef12(null);
|
|
4249
4878
|
const { insertText } = useChatInput();
|
|
4250
|
-
|
|
4879
|
+
useEffect13(() => {
|
|
4251
4880
|
setIsHydrated(true);
|
|
4252
4881
|
setIsMobile(window.matchMedia("(max-width: 767px)").matches);
|
|
4253
4882
|
}, []);
|
|
4254
|
-
|
|
4883
|
+
useEffect13(() => {
|
|
4255
4884
|
if (!isOpen) return;
|
|
4256
4885
|
const handleClickOutside = (e) => {
|
|
4257
4886
|
const target = e.target;
|
|
@@ -4262,7 +4891,7 @@ var ToolMenuPopup = ({
|
|
|
4262
4891
|
document.addEventListener("mousedown", handleClickOutside);
|
|
4263
4892
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
4264
4893
|
}, [isOpen, onClose]);
|
|
4265
|
-
|
|
4894
|
+
useEffect13(() => {
|
|
4266
4895
|
if (!isOpen) return;
|
|
4267
4896
|
const handleKey = (e) => {
|
|
4268
4897
|
if (e.key === "Escape") {
|
|
@@ -4325,7 +4954,7 @@ var ToolMenuPopup = ({
|
|
|
4325
4954
|
alignItems: "center"
|
|
4326
4955
|
}, children: [
|
|
4327
4956
|
/* @__PURE__ */ jsxs9("div", { children: [
|
|
4328
|
-
/* @__PURE__ */
|
|
4957
|
+
/* @__PURE__ */ jsx16("h3", { style: { margin: 0, color: "#fff", fontSize: 16, fontWeight: 600 }, children: "Available Actions" }),
|
|
4329
4958
|
/* @__PURE__ */ jsxs9("p", { style: { margin: "4px 0 0", color: "rgba(255,255,255,0.6)", fontSize: 12 }, children: [
|
|
4330
4959
|
contextLabel,
|
|
4331
4960
|
" \xB7 ",
|
|
@@ -4334,7 +4963,7 @@ var ToolMenuPopup = ({
|
|
|
4334
4963
|
totalTools !== 1 ? "s" : ""
|
|
4335
4964
|
] })
|
|
4336
4965
|
] }),
|
|
4337
|
-
/* @__PURE__ */
|
|
4966
|
+
/* @__PURE__ */ jsx16(
|
|
4338
4967
|
"button",
|
|
4339
4968
|
{
|
|
4340
4969
|
onClick: onClose,
|
|
@@ -4353,7 +4982,7 @@ var ToolMenuPopup = ({
|
|
|
4353
4982
|
)
|
|
4354
4983
|
] }),
|
|
4355
4984
|
/* @__PURE__ */ jsxs9("div", { style: { padding: "8px 12px 16px" }, children: [
|
|
4356
|
-
categories.length === 0 && /* @__PURE__ */
|
|
4985
|
+
categories.length === 0 && /* @__PURE__ */ jsx16("p", { style: { color: "rgba(255,255,255,0.5)", textAlign: "center", padding: "24px 0", fontSize: 14 }, children: "No tools available on this page." }),
|
|
4357
4986
|
categories.map((category) => {
|
|
4358
4987
|
const isCollapsed = collapsedCategories.has(category.key);
|
|
4359
4988
|
return /* @__PURE__ */ jsxs9("div", { style: { marginBottom: 4 }, children: [
|
|
@@ -4383,13 +5012,13 @@ var ToolMenuPopup = ({
|
|
|
4383
5012
|
children: [
|
|
4384
5013
|
/* @__PURE__ */ jsxs9("span", { style: { fontSize: 14, fontWeight: 500 }, children: [
|
|
4385
5014
|
category.displayName,
|
|
4386
|
-
/* @__PURE__ */
|
|
5015
|
+
/* @__PURE__ */ jsx16("span", { style: { color: "rgba(255,255,255,0.4)", fontWeight: 400, marginLeft: 8, fontSize: 12 }, children: category.tools.length })
|
|
4387
5016
|
] }),
|
|
4388
|
-
/* @__PURE__ */
|
|
5017
|
+
/* @__PURE__ */ jsx16("span", { style: { color: "rgba(255,255,255,0.4)", fontSize: 12 }, children: isCollapsed ? "\u25B6" : "\u25BC" })
|
|
4389
5018
|
]
|
|
4390
5019
|
}
|
|
4391
5020
|
),
|
|
4392
|
-
!isCollapsed && /* @__PURE__ */
|
|
5021
|
+
!isCollapsed && /* @__PURE__ */ jsx16("div", { style: { paddingLeft: 8, paddingRight: 8 }, children: category.tools.map((tool, idx) => /* @__PURE__ */ jsxs9(
|
|
4393
5022
|
"button",
|
|
4394
5023
|
{
|
|
4395
5024
|
onClick: () => handleToolClick(tool),
|
|
@@ -4412,8 +5041,8 @@ var ToolMenuPopup = ({
|
|
|
4412
5041
|
e.currentTarget.style.background = "none";
|
|
4413
5042
|
},
|
|
4414
5043
|
children: [
|
|
4415
|
-
/* @__PURE__ */
|
|
4416
|
-
tool.description && /* @__PURE__ */
|
|
5044
|
+
/* @__PURE__ */ jsx16("div", { style: { fontSize: 13, fontWeight: 500 }, children: tool.name }),
|
|
5045
|
+
tool.description && /* @__PURE__ */ jsx16("div", { style: {
|
|
4417
5046
|
fontSize: 11,
|
|
4418
5047
|
color: "rgba(255,255,255,0.5)",
|
|
4419
5048
|
marginTop: 2,
|
|
@@ -4437,14 +5066,14 @@ var ToolMenuPopup = ({
|
|
|
4437
5066
|
fontSize: 11
|
|
4438
5067
|
}, children: [
|
|
4439
5068
|
"Click a tool to insert its command \xB7 Type ",
|
|
4440
|
-
/* @__PURE__ */
|
|
5069
|
+
/* @__PURE__ */ jsx16("kbd", { style: {
|
|
4441
5070
|
padding: "1px 4px",
|
|
4442
5071
|
borderRadius: 3,
|
|
4443
5072
|
border: "1px solid rgba(255,255,255,0.2)",
|
|
4444
5073
|
fontSize: 10
|
|
4445
5074
|
}, children: "/" }),
|
|
4446
5075
|
" in chat for quick commands \xB7 ",
|
|
4447
|
-
/* @__PURE__ */
|
|
5076
|
+
/* @__PURE__ */ jsx16("kbd", { style: {
|
|
4448
5077
|
padding: "1px 4px",
|
|
4449
5078
|
borderRadius: 3,
|
|
4450
5079
|
border: "1px solid rgba(255,255,255,0.2)",
|
|
@@ -4458,10 +5087,10 @@ var ToolMenuPopup = ({
|
|
|
4458
5087
|
};
|
|
4459
5088
|
|
|
4460
5089
|
// src/components/ToolMenuPopup/ToolMenuPopupTrigger.tsx
|
|
4461
|
-
import { useEffect as
|
|
5090
|
+
import { useEffect as useEffect14 } from "react";
|
|
4462
5091
|
|
|
4463
5092
|
// src/components/ToolMenuPopup/useToolMenu.ts
|
|
4464
|
-
import { useState as
|
|
5093
|
+
import { useState as useState14, useMemo as useMemo5, useCallback as useCallback9 } from "react";
|
|
4465
5094
|
import { ToolRegistry as ToolRegistry2 } from "@supernal/interface/browser";
|
|
4466
5095
|
var CATEGORY_DISPLAY = {
|
|
4467
5096
|
navigation: "Navigation",
|
|
@@ -4482,11 +5111,11 @@ var CATEGORY_DISPLAY = {
|
|
|
4482
5111
|
workflow: "Workflow"
|
|
4483
5112
|
};
|
|
4484
5113
|
function useToolMenu() {
|
|
4485
|
-
const [isOpen, setIsOpen] =
|
|
4486
|
-
const open =
|
|
4487
|
-
const close =
|
|
4488
|
-
const toggle =
|
|
4489
|
-
const { categories, totalTools, contextLabel } =
|
|
5114
|
+
const [isOpen, setIsOpen] = useState14(false);
|
|
5115
|
+
const open = useCallback9(() => setIsOpen(true), []);
|
|
5116
|
+
const close = useCallback9(() => setIsOpen(false), []);
|
|
5117
|
+
const toggle = useCallback9(() => setIsOpen((prev) => !prev), []);
|
|
5118
|
+
const { categories, totalTools, contextLabel } = useMemo5(() => {
|
|
4490
5119
|
if (!isOpen) {
|
|
4491
5120
|
return { categories: [], totalTools: 0, contextLabel: "" };
|
|
4492
5121
|
}
|
|
@@ -4518,10 +5147,10 @@ function useToolMenu() {
|
|
|
4518
5147
|
}
|
|
4519
5148
|
|
|
4520
5149
|
// src/components/ToolMenuPopup/ToolMenuPopupTrigger.tsx
|
|
4521
|
-
import { jsx as
|
|
5150
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
4522
5151
|
var ToolMenuPopupTrigger = () => {
|
|
4523
5152
|
const toolMenu = useToolMenu();
|
|
4524
|
-
|
|
5153
|
+
useEffect14(() => {
|
|
4525
5154
|
const handleKeyDown = (e) => {
|
|
4526
5155
|
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key === "/") {
|
|
4527
5156
|
e.preventDefault();
|
|
@@ -4560,7 +5189,7 @@ var ToolMenuPopupTrigger = () => {
|
|
|
4560
5189
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
4561
5190
|
}, [toolMenu]);
|
|
4562
5191
|
if (!toolMenu.isOpen) return null;
|
|
4563
|
-
return /* @__PURE__ */
|
|
5192
|
+
return /* @__PURE__ */ jsx17(
|
|
4564
5193
|
ToolMenuPopup,
|
|
4565
5194
|
{
|
|
4566
5195
|
isOpen: toolMenu.isOpen,
|
|
@@ -4573,7 +5202,7 @@ var ToolMenuPopupTrigger = () => {
|
|
|
4573
5202
|
};
|
|
4574
5203
|
|
|
4575
5204
|
// src/components/SupernalProvider.tsx
|
|
4576
|
-
import { jsx as
|
|
5205
|
+
import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
4577
5206
|
function ChatBubbleConnector({
|
|
4578
5207
|
theme,
|
|
4579
5208
|
position,
|
|
@@ -4590,7 +5219,7 @@ function ChatBubbleConnector({
|
|
|
4590
5219
|
glassMode,
|
|
4591
5220
|
...logo ? { logo } : {}
|
|
4592
5221
|
};
|
|
4593
|
-
return /* @__PURE__ */
|
|
5222
|
+
return /* @__PURE__ */ jsx18(
|
|
4594
5223
|
ChatBubble,
|
|
4595
5224
|
{
|
|
4596
5225
|
messages,
|
|
@@ -4629,7 +5258,7 @@ function SupernalProvider({
|
|
|
4629
5258
|
console.log("[SupernalProvider] variant:", variant, "effectiveDisplayMode:", effectiveDisplayMode);
|
|
4630
5259
|
useLocationTracking();
|
|
4631
5260
|
useNavigationGraphSetup();
|
|
4632
|
-
|
|
5261
|
+
useEffect15(() => {
|
|
4633
5262
|
if (typeof window === "undefined") return;
|
|
4634
5263
|
const collector = ExposureCollector.getInstance();
|
|
4635
5264
|
const registeredToolIds = /* @__PURE__ */ new Set();
|
|
@@ -4661,9 +5290,9 @@ function SupernalProvider({
|
|
|
4661
5290
|
collector.destroy();
|
|
4662
5291
|
};
|
|
4663
5292
|
}, []);
|
|
4664
|
-
return /* @__PURE__ */
|
|
4665
|
-
/* @__PURE__ */
|
|
4666
|
-
shouldRenderChatBubble ? /* @__PURE__ */
|
|
5293
|
+
return /* @__PURE__ */ jsx18(ApiKeyProvider, { initialApiKey: apiKey, children: /* @__PURE__ */ jsx18(ChatInputProvider, { children: /* @__PURE__ */ jsxs10(ChatProvider, { mode, apiKey, onToolExecute, children: [
|
|
5294
|
+
/* @__PURE__ */ jsx18(AutoNavigationContext, { routes, onNavigate, children }),
|
|
5295
|
+
shouldRenderChatBubble ? /* @__PURE__ */ jsx18(
|
|
4667
5296
|
ChatBubbleConnector,
|
|
4668
5297
|
{
|
|
4669
5298
|
theme,
|
|
@@ -4676,26 +5305,26 @@ function SupernalProvider({
|
|
|
4676
5305
|
drawerSide
|
|
4677
5306
|
}
|
|
4678
5307
|
) : null,
|
|
4679
|
-
!disabled && /* @__PURE__ */
|
|
4680
|
-
] }) });
|
|
5308
|
+
!disabled && /* @__PURE__ */ jsx18(ToolMenuPopupTrigger, {})
|
|
5309
|
+
] }) }) });
|
|
4681
5310
|
}
|
|
4682
5311
|
|
|
4683
5312
|
// src/components/ChatBubbleSettingsModal.tsx
|
|
4684
|
-
import
|
|
4685
|
-
import { Fragment as Fragment5, jsx as
|
|
5313
|
+
import React15, { useEffect as useEffect16 } from "react";
|
|
5314
|
+
import { Fragment as Fragment5, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
4686
5315
|
function ChatBubbleSettingsModal({
|
|
4687
5316
|
isOpen,
|
|
4688
5317
|
onClose,
|
|
4689
5318
|
settings,
|
|
4690
5319
|
onSettingsChange
|
|
4691
5320
|
}) {
|
|
4692
|
-
const [localSettings, setLocalSettings] =
|
|
4693
|
-
|
|
5321
|
+
const [localSettings, setLocalSettings] = React15.useState(settings);
|
|
5322
|
+
useEffect16(() => {
|
|
4694
5323
|
if (isOpen) {
|
|
4695
5324
|
setLocalSettings(settings);
|
|
4696
5325
|
}
|
|
4697
5326
|
}, [isOpen, settings]);
|
|
4698
|
-
|
|
5327
|
+
useEffect16(() => {
|
|
4699
5328
|
const handleEscape = (e) => {
|
|
4700
5329
|
if (e.key === "Escape" && isOpen) {
|
|
4701
5330
|
onClose();
|
|
@@ -4717,7 +5346,7 @@ function ChatBubbleSettingsModal({
|
|
|
4717
5346
|
};
|
|
4718
5347
|
const isDark = localSettings.theme === "dark";
|
|
4719
5348
|
return /* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
4720
|
-
/* @__PURE__ */
|
|
5349
|
+
/* @__PURE__ */ jsx19(
|
|
4721
5350
|
"div",
|
|
4722
5351
|
{
|
|
4723
5352
|
className: "fixed inset-0 bg-black bg-opacity-50 z-[60] backdrop-blur-sm",
|
|
@@ -4725,7 +5354,7 @@ function ChatBubbleSettingsModal({
|
|
|
4725
5354
|
"aria-hidden": "true"
|
|
4726
5355
|
}
|
|
4727
5356
|
),
|
|
4728
|
-
/* @__PURE__ */
|
|
5357
|
+
/* @__PURE__ */ jsx19(
|
|
4729
5358
|
"div",
|
|
4730
5359
|
{
|
|
4731
5360
|
className: "fixed inset-0 z-[70] flex items-center justify-center p-4",
|
|
@@ -4740,7 +5369,7 @@ function ChatBubbleSettingsModal({
|
|
|
4740
5369
|
onClick: (e) => e.stopPropagation(),
|
|
4741
5370
|
children: [
|
|
4742
5371
|
/* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between mb-6", children: [
|
|
4743
|
-
/* @__PURE__ */
|
|
5372
|
+
/* @__PURE__ */ jsx19(
|
|
4744
5373
|
"h2",
|
|
4745
5374
|
{
|
|
4746
5375
|
id: "settings-modal-title",
|
|
@@ -4748,56 +5377,56 @@ function ChatBubbleSettingsModal({
|
|
|
4748
5377
|
children: "Chat Settings"
|
|
4749
5378
|
}
|
|
4750
5379
|
),
|
|
4751
|
-
/* @__PURE__ */
|
|
5380
|
+
/* @__PURE__ */ jsx19(
|
|
4752
5381
|
"button",
|
|
4753
5382
|
{
|
|
4754
5383
|
onClick: handleCancel,
|
|
4755
5384
|
className: `${isDark ? "text-gray-400 hover:text-gray-200" : "text-gray-400 hover:text-gray-600"} transition-colors p-1 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700`,
|
|
4756
5385
|
"aria-label": "Close modal",
|
|
4757
|
-
children: /* @__PURE__ */
|
|
5386
|
+
children: /* @__PURE__ */ jsx19("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx19("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
4758
5387
|
}
|
|
4759
5388
|
)
|
|
4760
5389
|
] }),
|
|
4761
5390
|
/* @__PURE__ */ jsxs11("div", { className: "space-y-5 mb-6", children: [
|
|
4762
5391
|
/* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
|
|
4763
5392
|
/* @__PURE__ */ jsxs11("div", { children: [
|
|
4764
|
-
/* @__PURE__ */
|
|
4765
|
-
/* @__PURE__ */
|
|
5393
|
+
/* @__PURE__ */ jsx19("label", { className: "block text-base font-medium mb-1", children: "Theme" }),
|
|
5394
|
+
/* @__PURE__ */ jsx19("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Switch between light and dark modes" })
|
|
4766
5395
|
] }),
|
|
4767
5396
|
/* @__PURE__ */ jsxs11("div", { className: "flex items-center space-x-2", children: [
|
|
4768
|
-
/* @__PURE__ */
|
|
5397
|
+
/* @__PURE__ */ jsx19(
|
|
4769
5398
|
"button",
|
|
4770
5399
|
{
|
|
4771
5400
|
onClick: () => setLocalSettings({ ...localSettings, theme: "light" }),
|
|
4772
5401
|
className: `p-2 rounded-lg transition-all ${localSettings.theme === "light" ? "bg-blue-600 text-white shadow-lg" : isDark ? "bg-gray-700 text-gray-300 hover:bg-gray-600" : "bg-gray-100 text-gray-600 hover:bg-gray-200"}`,
|
|
4773
5402
|
title: "Light mode",
|
|
4774
|
-
children: /* @__PURE__ */
|
|
5403
|
+
children: /* @__PURE__ */ jsx19("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx19("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" }) })
|
|
4775
5404
|
}
|
|
4776
5405
|
),
|
|
4777
|
-
/* @__PURE__ */
|
|
5406
|
+
/* @__PURE__ */ jsx19(
|
|
4778
5407
|
"button",
|
|
4779
5408
|
{
|
|
4780
5409
|
onClick: () => setLocalSettings({ ...localSettings, theme: "dark" }),
|
|
4781
5410
|
className: `p-2 rounded-lg transition-all ${localSettings.theme === "dark" ? "bg-blue-600 text-white shadow-lg" : isDark ? "bg-gray-700 text-gray-300 hover:bg-gray-600" : "bg-gray-100 text-gray-600 hover:bg-gray-200"}`,
|
|
4782
5411
|
title: "Dark mode",
|
|
4783
|
-
children: /* @__PURE__ */
|
|
5412
|
+
children: /* @__PURE__ */ jsx19("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx19("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" }) })
|
|
4784
5413
|
}
|
|
4785
5414
|
)
|
|
4786
5415
|
] })
|
|
4787
5416
|
] }),
|
|
4788
5417
|
/* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
|
|
4789
5418
|
/* @__PURE__ */ jsxs11("div", { children: [
|
|
4790
|
-
/* @__PURE__ */
|
|
4791
|
-
/* @__PURE__ */
|
|
5419
|
+
/* @__PURE__ */ jsx19("label", { className: "block text-base font-medium mb-1", children: "Glass Mode" }),
|
|
5420
|
+
/* @__PURE__ */ jsx19("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable glassmorphism transparency effect" })
|
|
4792
5421
|
] }),
|
|
4793
|
-
/* @__PURE__ */
|
|
5422
|
+
/* @__PURE__ */ jsx19(
|
|
4794
5423
|
"button",
|
|
4795
5424
|
{
|
|
4796
5425
|
onClick: () => setLocalSettings({ ...localSettings, glassMode: !localSettings.glassMode }),
|
|
4797
5426
|
className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${localSettings.glassMode ? "bg-blue-600" : isDark ? "bg-gray-700" : "bg-gray-300"}`,
|
|
4798
5427
|
role: "switch",
|
|
4799
5428
|
"aria-checked": localSettings.glassMode,
|
|
4800
|
-
children: /* @__PURE__ */
|
|
5429
|
+
children: /* @__PURE__ */ jsx19(
|
|
4801
5430
|
"span",
|
|
4802
5431
|
{
|
|
4803
5432
|
className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.glassMode ? "translate-x-6" : "translate-x-1"}`
|
|
@@ -4808,17 +5437,17 @@ function ChatBubbleSettingsModal({
|
|
|
4808
5437
|
] }),
|
|
4809
5438
|
/* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
|
|
4810
5439
|
/* @__PURE__ */ jsxs11("div", { children: [
|
|
4811
|
-
/* @__PURE__ */
|
|
4812
|
-
/* @__PURE__ */
|
|
5440
|
+
/* @__PURE__ */ jsx19("label", { className: "block text-base font-medium mb-1", children: "Notifications" }),
|
|
5441
|
+
/* @__PURE__ */ jsx19("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Show unread message indicators" })
|
|
4813
5442
|
] }),
|
|
4814
|
-
/* @__PURE__ */
|
|
5443
|
+
/* @__PURE__ */ jsx19(
|
|
4815
5444
|
"button",
|
|
4816
5445
|
{
|
|
4817
5446
|
onClick: () => setLocalSettings({ ...localSettings, notifications: !localSettings.notifications }),
|
|
4818
5447
|
className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${localSettings.notifications ? "bg-blue-600" : isDark ? "bg-gray-700" : "bg-gray-300"}`,
|
|
4819
5448
|
role: "switch",
|
|
4820
5449
|
"aria-checked": localSettings.notifications,
|
|
4821
|
-
children: /* @__PURE__ */
|
|
5450
|
+
children: /* @__PURE__ */ jsx19(
|
|
4822
5451
|
"span",
|
|
4823
5452
|
{
|
|
4824
5453
|
className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.notifications ? "translate-x-6" : "translate-x-1"}`
|
|
@@ -4827,16 +5456,16 @@ function ChatBubbleSettingsModal({
|
|
|
4827
5456
|
}
|
|
4828
5457
|
)
|
|
4829
5458
|
] }),
|
|
4830
|
-
/* @__PURE__ */
|
|
5459
|
+
/* @__PURE__ */ jsx19("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
|
|
4831
5460
|
/* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
|
|
4832
5461
|
/* @__PURE__ */ jsxs11("div", { children: [
|
|
4833
5462
|
/* @__PURE__ */ jsxs11("label", { className: "block text-base font-medium mb-1 flex items-center space-x-2", children: [
|
|
4834
|
-
/* @__PURE__ */
|
|
4835
|
-
/* @__PURE__ */
|
|
5463
|
+
/* @__PURE__ */ jsx19("span", { children: "Subtitle Overlay" }),
|
|
5464
|
+
/* @__PURE__ */ jsx19("span", { className: "inline-block px-2 py-0.5 text-xs font-semibold rounded-full bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200", children: "BETA" })
|
|
4836
5465
|
] }),
|
|
4837
|
-
/* @__PURE__ */
|
|
5466
|
+
/* @__PURE__ */ jsx19("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Minimalist voice-first overlay with @/ icon" })
|
|
4838
5467
|
] }),
|
|
4839
|
-
/* @__PURE__ */
|
|
5468
|
+
/* @__PURE__ */ jsx19(
|
|
4840
5469
|
"button",
|
|
4841
5470
|
{
|
|
4842
5471
|
onClick: () => setLocalSettings({
|
|
@@ -4848,7 +5477,7 @@ function ChatBubbleSettingsModal({
|
|
|
4848
5477
|
className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${localSettings.subtitleOverlayEnabled ? "bg-blue-600" : isDark ? "bg-gray-700" : "bg-gray-300"}`,
|
|
4849
5478
|
role: "switch",
|
|
4850
5479
|
"aria-checked": localSettings.subtitleOverlayEnabled,
|
|
4851
|
-
children: /* @__PURE__ */
|
|
5480
|
+
children: /* @__PURE__ */ jsx19(
|
|
4852
5481
|
"span",
|
|
4853
5482
|
{
|
|
4854
5483
|
className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.subtitleOverlayEnabled ? "translate-x-6" : "translate-x-1"}`
|
|
@@ -4859,8 +5488,8 @@ function ChatBubbleSettingsModal({
|
|
|
4859
5488
|
] }),
|
|
4860
5489
|
/* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
|
|
4861
5490
|
/* @__PURE__ */ jsxs11("div", { children: [
|
|
4862
|
-
/* @__PURE__ */
|
|
4863
|
-
/* @__PURE__ */
|
|
5491
|
+
/* @__PURE__ */ jsx19("label", { className: "block text-base font-medium mb-1", children: "Display Mode" }),
|
|
5492
|
+
/* @__PURE__ */ jsx19("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Auto switches drawer on mobile, panel on desktop" })
|
|
4864
5493
|
] }),
|
|
4865
5494
|
/* @__PURE__ */ jsxs11(
|
|
4866
5495
|
"select",
|
|
@@ -4872,22 +5501,22 @@ function ChatBubbleSettingsModal({
|
|
|
4872
5501
|
}),
|
|
4873
5502
|
className: `px-3 py-2 rounded-lg border ${isDark ? "bg-gray-700 border-gray-600 text-white" : "bg-white border-gray-300 text-gray-900"} focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all`,
|
|
4874
5503
|
children: [
|
|
4875
|
-
/* @__PURE__ */
|
|
4876
|
-
/* @__PURE__ */
|
|
4877
|
-
/* @__PURE__ */
|
|
4878
|
-
/* @__PURE__ */
|
|
4879
|
-
/* @__PURE__ */
|
|
5504
|
+
/* @__PURE__ */ jsx19("option", { value: "auto", children: "Auto (Recommended)" }),
|
|
5505
|
+
/* @__PURE__ */ jsx19("option", { value: "drawer", children: "Always Drawer" }),
|
|
5506
|
+
/* @__PURE__ */ jsx19("option", { value: "full", children: "Always Panel" }),
|
|
5507
|
+
/* @__PURE__ */ jsx19("option", { value: "floating", children: "Always Floating" }),
|
|
5508
|
+
/* @__PURE__ */ jsx19("option", { value: "subtitle", children: "Subtitle Overlay (Beta)" })
|
|
4880
5509
|
]
|
|
4881
5510
|
}
|
|
4882
5511
|
)
|
|
4883
5512
|
] }),
|
|
4884
5513
|
(localSettings.displayMode === "auto" || localSettings.displayMode === "drawer") && /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
|
|
4885
5514
|
/* @__PURE__ */ jsxs11("div", { children: [
|
|
4886
|
-
/* @__PURE__ */
|
|
4887
|
-
/* @__PURE__ */
|
|
5515
|
+
/* @__PURE__ */ jsx19("label", { className: "block text-base font-medium mb-1", children: "Drawer Side" }),
|
|
5516
|
+
/* @__PURE__ */ jsx19("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Which edge drawer slides from" })
|
|
4888
5517
|
] }),
|
|
4889
5518
|
/* @__PURE__ */ jsxs11("div", { className: "flex items-center space-x-2", children: [
|
|
4890
|
-
/* @__PURE__ */
|
|
5519
|
+
/* @__PURE__ */ jsx19(
|
|
4891
5520
|
"button",
|
|
4892
5521
|
{
|
|
4893
5522
|
onClick: () => setLocalSettings({ ...localSettings, drawerSide: "left" }),
|
|
@@ -4895,7 +5524,7 @@ function ChatBubbleSettingsModal({
|
|
|
4895
5524
|
children: "Left"
|
|
4896
5525
|
}
|
|
4897
5526
|
),
|
|
4898
|
-
/* @__PURE__ */
|
|
5527
|
+
/* @__PURE__ */ jsx19(
|
|
4899
5528
|
"button",
|
|
4900
5529
|
{
|
|
4901
5530
|
onClick: () => setLocalSettings({ ...localSettings, drawerSide: "right" }),
|
|
@@ -4905,24 +5534,24 @@ function ChatBubbleSettingsModal({
|
|
|
4905
5534
|
)
|
|
4906
5535
|
] })
|
|
4907
5536
|
] }),
|
|
4908
|
-
/* @__PURE__ */
|
|
5537
|
+
/* @__PURE__ */ jsx19("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
|
|
4909
5538
|
/* @__PURE__ */ jsxs11("div", { className: "mb-3", children: [
|
|
4910
|
-
/* @__PURE__ */
|
|
4911
|
-
/* @__PURE__ */
|
|
5539
|
+
/* @__PURE__ */ jsx19("h3", { className: "text-lg font-semibold mb-1", children: "Voice Control" }),
|
|
5540
|
+
/* @__PURE__ */ jsx19("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable voice input and audio feedback" })
|
|
4912
5541
|
] }),
|
|
4913
5542
|
/* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
|
|
4914
5543
|
/* @__PURE__ */ jsxs11("div", { children: [
|
|
4915
|
-
/* @__PURE__ */
|
|
4916
|
-
/* @__PURE__ */
|
|
5544
|
+
/* @__PURE__ */ jsx19("label", { className: "block text-base font-medium mb-1", children: "Voice Control" }),
|
|
5545
|
+
/* @__PURE__ */ jsx19("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable voice input and TTS responses" })
|
|
4917
5546
|
] }),
|
|
4918
|
-
/* @__PURE__ */
|
|
5547
|
+
/* @__PURE__ */ jsx19(
|
|
4919
5548
|
"button",
|
|
4920
5549
|
{
|
|
4921
5550
|
onClick: () => setLocalSettings({ ...localSettings, voiceEnabled: !localSettings.voiceEnabled }),
|
|
4922
5551
|
className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${localSettings.voiceEnabled ? "bg-blue-600" : isDark ? "bg-gray-700" : "bg-gray-300"}`,
|
|
4923
5552
|
role: "switch",
|
|
4924
5553
|
"aria-checked": localSettings.voiceEnabled,
|
|
4925
|
-
children: /* @__PURE__ */
|
|
5554
|
+
children: /* @__PURE__ */ jsx19(
|
|
4926
5555
|
"span",
|
|
4927
5556
|
{
|
|
4928
5557
|
className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.voiceEnabled ? "translate-x-6" : "translate-x-1"}`
|
|
@@ -4934,17 +5563,17 @@ function ChatBubbleSettingsModal({
|
|
|
4934
5563
|
localSettings.voiceEnabled && /* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
4935
5564
|
/* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between pl-4 border-l-2 border-blue-500/30", children: [
|
|
4936
5565
|
/* @__PURE__ */ jsxs11("div", { children: [
|
|
4937
|
-
/* @__PURE__ */
|
|
4938
|
-
/* @__PURE__ */
|
|
5566
|
+
/* @__PURE__ */ jsx19("label", { className: "block text-sm font-medium mb-1", children: "Auto-read AI Responses" }),
|
|
5567
|
+
/* @__PURE__ */ jsx19("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Automatically read AI messages aloud" })
|
|
4939
5568
|
] }),
|
|
4940
|
-
/* @__PURE__ */
|
|
5569
|
+
/* @__PURE__ */ jsx19(
|
|
4941
5570
|
"button",
|
|
4942
5571
|
{
|
|
4943
5572
|
onClick: () => setLocalSettings({ ...localSettings, autoReadResponses: !localSettings.autoReadResponses }),
|
|
4944
5573
|
className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${localSettings.autoReadResponses ? "bg-blue-600" : isDark ? "bg-gray-700" : "bg-gray-300"}`,
|
|
4945
5574
|
role: "switch",
|
|
4946
5575
|
"aria-checked": localSettings.autoReadResponses,
|
|
4947
|
-
children: /* @__PURE__ */
|
|
5576
|
+
children: /* @__PURE__ */ jsx19(
|
|
4948
5577
|
"span",
|
|
4949
5578
|
{
|
|
4950
5579
|
className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.autoReadResponses ? "translate-x-6" : "translate-x-1"}`
|
|
@@ -4955,17 +5584,17 @@ function ChatBubbleSettingsModal({
|
|
|
4955
5584
|
] }),
|
|
4956
5585
|
/* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between pl-4 border-l-2 border-blue-500/30", children: [
|
|
4957
5586
|
/* @__PURE__ */ jsxs11("div", { children: [
|
|
4958
|
-
/* @__PURE__ */
|
|
4959
|
-
/* @__PURE__ */
|
|
5587
|
+
/* @__PURE__ */ jsx19("label", { className: "block text-sm font-medium mb-1", children: "Premium Voices \u{1F48E}" }),
|
|
5588
|
+
/* @__PURE__ */ jsx19("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Use high-quality OpenAI voices (requires network)" })
|
|
4960
5589
|
] }),
|
|
4961
|
-
/* @__PURE__ */
|
|
5590
|
+
/* @__PURE__ */ jsx19(
|
|
4962
5591
|
"button",
|
|
4963
5592
|
{
|
|
4964
5593
|
onClick: () => setLocalSettings({ ...localSettings, usePremiumVoices: !localSettings.usePremiumVoices }),
|
|
4965
5594
|
className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${localSettings.usePremiumVoices ? "bg-blue-600" : isDark ? "bg-gray-700" : "bg-gray-300"}`,
|
|
4966
5595
|
role: "switch",
|
|
4967
5596
|
"aria-checked": localSettings.usePremiumVoices,
|
|
4968
|
-
children: /* @__PURE__ */
|
|
5597
|
+
children: /* @__PURE__ */ jsx19(
|
|
4969
5598
|
"span",
|
|
4970
5599
|
{
|
|
4971
5600
|
className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.usePremiumVoices ? "translate-x-6" : "translate-x-1"}`
|
|
@@ -4980,7 +5609,7 @@ function ChatBubbleSettingsModal({
|
|
|
4980
5609
|
localSettings.ttsSpeed.toFixed(1),
|
|
4981
5610
|
"x"
|
|
4982
5611
|
] }),
|
|
4983
|
-
/* @__PURE__ */
|
|
5612
|
+
/* @__PURE__ */ jsx19(
|
|
4984
5613
|
"input",
|
|
4985
5614
|
{
|
|
4986
5615
|
type: "range",
|
|
@@ -4993,29 +5622,29 @@ function ChatBubbleSettingsModal({
|
|
|
4993
5622
|
}
|
|
4994
5623
|
),
|
|
4995
5624
|
/* @__PURE__ */ jsxs11("div", { className: "flex justify-between text-xs text-gray-400 mt-1", children: [
|
|
4996
|
-
/* @__PURE__ */
|
|
4997
|
-
/* @__PURE__ */
|
|
4998
|
-
/* @__PURE__ */
|
|
5625
|
+
/* @__PURE__ */ jsx19("span", { children: "0.5x (Slow)" }),
|
|
5626
|
+
/* @__PURE__ */ jsx19("span", { children: "1.0x (Normal)" }),
|
|
5627
|
+
/* @__PURE__ */ jsx19("span", { children: "2.0x (Fast)" })
|
|
4999
5628
|
] })
|
|
5000
5629
|
] }),
|
|
5001
|
-
/* @__PURE__ */
|
|
5630
|
+
/* @__PURE__ */ jsx19("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
|
|
5002
5631
|
/* @__PURE__ */ jsxs11("div", { className: "mb-3", children: [
|
|
5003
|
-
/* @__PURE__ */
|
|
5004
|
-
/* @__PURE__ */
|
|
5632
|
+
/* @__PURE__ */ jsx19("h4", { className: "text-sm font-semibold mb-1", children: "Voice Quick Record (Ctrl+/)" }),
|
|
5633
|
+
/* @__PURE__ */ jsx19("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Press Ctrl+/ (or Cmd+/ on Mac) to auto-record and execute voice commands" })
|
|
5005
5634
|
] }),
|
|
5006
5635
|
/* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between pl-4 border-l-2 border-purple-500/30", children: [
|
|
5007
5636
|
/* @__PURE__ */ jsxs11("div", { children: [
|
|
5008
|
-
/* @__PURE__ */
|
|
5009
|
-
/* @__PURE__ */
|
|
5637
|
+
/* @__PURE__ */ jsx19("label", { className: "block text-sm font-medium mb-1", children: "Auto-Execute Commands" }),
|
|
5638
|
+
/* @__PURE__ */ jsx19("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Automatically run recognized voice commands" })
|
|
5010
5639
|
] }),
|
|
5011
|
-
/* @__PURE__ */
|
|
5640
|
+
/* @__PURE__ */ jsx19(
|
|
5012
5641
|
"button",
|
|
5013
5642
|
{
|
|
5014
5643
|
onClick: () => setLocalSettings({ ...localSettings, sttAutoExecute: !localSettings.sttAutoExecute }),
|
|
5015
5644
|
className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${localSettings.sttAutoExecute ? "bg-purple-600" : isDark ? "bg-gray-700" : "bg-gray-300"}`,
|
|
5016
5645
|
role: "switch",
|
|
5017
5646
|
"aria-checked": localSettings.sttAutoExecute,
|
|
5018
|
-
children: /* @__PURE__ */
|
|
5647
|
+
children: /* @__PURE__ */ jsx19(
|
|
5019
5648
|
"span",
|
|
5020
5649
|
{
|
|
5021
5650
|
className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.sttAutoExecute ? "translate-x-6" : "translate-x-1"}`
|
|
@@ -5030,7 +5659,7 @@ function ChatBubbleSettingsModal({
|
|
|
5030
5659
|
(localSettings.sttAutoRecordTimeout / 1e3).toFixed(1),
|
|
5031
5660
|
"s"
|
|
5032
5661
|
] }),
|
|
5033
|
-
/* @__PURE__ */
|
|
5662
|
+
/* @__PURE__ */ jsx19(
|
|
5034
5663
|
"input",
|
|
5035
5664
|
{
|
|
5036
5665
|
type: "range",
|
|
@@ -5043,21 +5672,21 @@ function ChatBubbleSettingsModal({
|
|
|
5043
5672
|
}
|
|
5044
5673
|
),
|
|
5045
5674
|
/* @__PURE__ */ jsxs11("div", { className: "flex justify-between text-xs text-gray-400 mt-1", children: [
|
|
5046
|
-
/* @__PURE__ */
|
|
5047
|
-
/* @__PURE__ */
|
|
5048
|
-
/* @__PURE__ */
|
|
5675
|
+
/* @__PURE__ */ jsx19("span", { children: "2s" }),
|
|
5676
|
+
/* @__PURE__ */ jsx19("span", { children: "8s" }),
|
|
5677
|
+
/* @__PURE__ */ jsx19("span", { children: "15s" })
|
|
5049
5678
|
] })
|
|
5050
5679
|
] }),
|
|
5051
5680
|
/* @__PURE__ */ jsxs11("div", { className: `p-3 rounded-lg ${isDark ? "bg-purple-900/20 border border-purple-500/30" : "bg-purple-50 border border-purple-200"}`, children: [
|
|
5052
|
-
/* @__PURE__ */
|
|
5053
|
-
/* @__PURE__ */
|
|
5681
|
+
/* @__PURE__ */ jsx19("p", { className: `text-xs ${isDark ? "text-purple-300" : "text-purple-800"} mb-1 font-medium`, children: "\u26A1 Quick Tip: Press Ctrl+/ anywhere (even while typing!)" }),
|
|
5682
|
+
/* @__PURE__ */ jsx19("p", { className: `text-xs ${isDark ? "text-purple-400" : "text-purple-700"}`, children: localSettings.sttAutoExecute ? "Recording auto-stops and executes your command" : "Recording auto-stops and fills the input (press Enter to send)" })
|
|
5054
5683
|
] }),
|
|
5055
|
-
!localSettings.usePremiumVoices && /* @__PURE__ */
|
|
5056
|
-
localSettings.usePremiumVoices && /* @__PURE__ */
|
|
5684
|
+
!localSettings.usePremiumVoices && /* @__PURE__ */ jsx19("div", { className: `p-3 rounded-lg ${isDark ? "bg-green-900/20 border border-green-500/30" : "bg-green-50 border border-green-200"}`, children: /* @__PURE__ */ jsx19("p", { className: `text-xs ${isDark ? "text-green-300" : "text-green-800"}`, children: "\u{1F49A} Using free device voices (works offline, zero cost)" }) }),
|
|
5685
|
+
localSettings.usePremiumVoices && /* @__PURE__ */ jsx19("div", { className: `p-3 rounded-lg ${isDark ? "bg-purple-900/20 border border-purple-500/30" : "bg-purple-50 border border-purple-200"}`, children: /* @__PURE__ */ jsx19("p", { className: `text-xs ${isDark ? "text-purple-300" : "text-purple-800"}`, children: "\u{1F48E} Using premium OpenAI voices (requires internet connection)" }) })
|
|
5057
5686
|
] })
|
|
5058
5687
|
] }),
|
|
5059
5688
|
/* @__PURE__ */ jsxs11("div", { className: "flex justify-end space-x-3 pt-4 border-t border-gray-200 dark:border-gray-700", children: [
|
|
5060
|
-
/* @__PURE__ */
|
|
5689
|
+
/* @__PURE__ */ jsx19(
|
|
5061
5690
|
"button",
|
|
5062
5691
|
{
|
|
5063
5692
|
onClick: handleCancel,
|
|
@@ -5065,7 +5694,7 @@ function ChatBubbleSettingsModal({
|
|
|
5065
5694
|
children: "Cancel"
|
|
5066
5695
|
}
|
|
5067
5696
|
),
|
|
5068
|
-
/* @__PURE__ */
|
|
5697
|
+
/* @__PURE__ */ jsx19(
|
|
5069
5698
|
"button",
|
|
5070
5699
|
{
|
|
5071
5700
|
onClick: handleSave,
|
|
@@ -5201,12 +5830,14 @@ function findBestMatch(query, tools) {
|
|
|
5201
5830
|
};
|
|
5202
5831
|
}
|
|
5203
5832
|
export {
|
|
5833
|
+
ApiKeyProvider,
|
|
5204
5834
|
AutoNavigationContext,
|
|
5205
5835
|
ChatBubble,
|
|
5206
5836
|
ChatBubbleSettingsModal,
|
|
5207
5837
|
ChatBubbleVariant,
|
|
5208
5838
|
ChatInputProvider,
|
|
5209
5839
|
ChatProvider,
|
|
5840
|
+
ClaudeClient,
|
|
5210
5841
|
CodeBlock,
|
|
5211
5842
|
Components,
|
|
5212
5843
|
DemoAIInterface,
|
|
@@ -5220,9 +5851,13 @@ export {
|
|
|
5220
5851
|
ToolManager,
|
|
5221
5852
|
ToolMenuPopup,
|
|
5222
5853
|
ToolMenuPopupTrigger,
|
|
5854
|
+
createClaudeClient,
|
|
5223
5855
|
findBestMatch,
|
|
5224
5856
|
scoreToolMatch,
|
|
5225
5857
|
useAllContexts,
|
|
5858
|
+
useApiKey,
|
|
5859
|
+
useApiKeyOptional,
|
|
5860
|
+
useApiKeyStorage,
|
|
5226
5861
|
useChatContext,
|
|
5227
5862
|
useChatInput,
|
|
5228
5863
|
useCurrentContext,
|