@supernal/interface-nextjs 1.0.25 → 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.js
CHANGED
|
@@ -31,12 +31,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
// src/index.ts
|
|
32
32
|
var index_exports = {};
|
|
33
33
|
__export(index_exports, {
|
|
34
|
+
ApiKeyProvider: () => ApiKeyProvider,
|
|
34
35
|
AutoNavigationContext: () => AutoNavigationContext,
|
|
35
36
|
ChatBubble: () => ChatBubble,
|
|
36
37
|
ChatBubbleSettingsModal: () => ChatBubbleSettingsModal,
|
|
37
38
|
ChatBubbleVariant: () => ChatBubbleVariant,
|
|
38
39
|
ChatInputProvider: () => ChatInputProvider,
|
|
39
40
|
ChatProvider: () => ChatProvider,
|
|
41
|
+
ClaudeClient: () => ClaudeClient,
|
|
40
42
|
CodeBlock: () => CodeBlock,
|
|
41
43
|
Components: () => Components,
|
|
42
44
|
DemoAIInterface: () => DemoAIInterface,
|
|
@@ -50,9 +52,13 @@ __export(index_exports, {
|
|
|
50
52
|
ToolManager: () => ToolManager,
|
|
51
53
|
ToolMenuPopup: () => ToolMenuPopup,
|
|
52
54
|
ToolMenuPopupTrigger: () => ToolMenuPopupTrigger,
|
|
55
|
+
createClaudeClient: () => createClaudeClient,
|
|
53
56
|
findBestMatch: () => findBestMatch,
|
|
54
57
|
scoreToolMatch: () => scoreToolMatch,
|
|
55
58
|
useAllContexts: () => useAllContexts,
|
|
59
|
+
useApiKey: () => useApiKey,
|
|
60
|
+
useApiKeyOptional: () => useApiKeyOptional,
|
|
61
|
+
useApiKeyStorage: () => useApiKeyStorage,
|
|
56
62
|
useChatContext: () => useChatContext,
|
|
57
63
|
useChatInput: () => useChatInput,
|
|
58
64
|
useCurrentContext: () => useCurrentContext,
|
|
@@ -65,7 +71,7 @@ __export(index_exports, {
|
|
|
65
71
|
module.exports = __toCommonJS(index_exports);
|
|
66
72
|
|
|
67
73
|
// src/components/SupernalProvider.tsx
|
|
68
|
-
var
|
|
74
|
+
var import_react21 = require("react");
|
|
69
75
|
|
|
70
76
|
// src/contexts/ChatInputContext.tsx
|
|
71
77
|
var import_react = require("react");
|
|
@@ -92,10 +98,10 @@ function ChatInputProvider({ children }) {
|
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
// src/contexts/ChatProvider.tsx
|
|
95
|
-
var
|
|
101
|
+
var import_react4 = require("react");
|
|
96
102
|
|
|
97
103
|
// src/lib/ChatAIInterface.ts
|
|
98
|
-
var
|
|
104
|
+
var import_browser2 = require("@supernal/interface/browser");
|
|
99
105
|
|
|
100
106
|
// src/lib/ToolManager.ts
|
|
101
107
|
var import_browser = require("@supernal/interface/browser");
|
|
@@ -190,7 +196,7 @@ var ToolManagerClass = class {
|
|
|
190
196
|
var ToolManager = new ToolManagerClass();
|
|
191
197
|
|
|
192
198
|
// src/lib/ChatAIInterface.ts
|
|
193
|
-
var DemoAIInterface = class extends
|
|
199
|
+
var DemoAIInterface = class extends import_browser2.AIInterface {
|
|
194
200
|
constructor() {
|
|
195
201
|
super();
|
|
196
202
|
this.toolExecutionListeners = [];
|
|
@@ -234,17 +240,466 @@ var DemoAIInterface = class extends import_interface.AIInterface {
|
|
|
234
240
|
}
|
|
235
241
|
};
|
|
236
242
|
|
|
237
|
-
// src/
|
|
243
|
+
// src/lib/ClaudeClient.ts
|
|
244
|
+
var COST_PER_1K = {
|
|
245
|
+
"claude-sonnet-4-20250514": { input: 3e-3, output: 0.015 },
|
|
246
|
+
"claude-3-5-sonnet-20241022": { input: 3e-3, output: 0.015 },
|
|
247
|
+
"claude-3-opus-20240229": { input: 0.015, output: 0.075 },
|
|
248
|
+
"claude-3-haiku-20240307": { input: 25e-5, output: 125e-5 }
|
|
249
|
+
};
|
|
250
|
+
var ClaudeClient = class {
|
|
251
|
+
constructor(config) {
|
|
252
|
+
this.apiKey = config.apiKey;
|
|
253
|
+
this.model = config.model || "claude-sonnet-4-20250514";
|
|
254
|
+
this.maxTokens = config.maxTokens || 4096;
|
|
255
|
+
this.systemPrompt = config.systemPrompt || "You are a helpful AI assistant integrated into a web application. Be concise and helpful.";
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Send a message to Claude and get a response
|
|
259
|
+
*/
|
|
260
|
+
async sendMessage(userMessage, options = {}) {
|
|
261
|
+
const messages = [
|
|
262
|
+
...options.messages || [],
|
|
263
|
+
{ role: "user", content: userMessage }
|
|
264
|
+
];
|
|
265
|
+
try {
|
|
266
|
+
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
|
267
|
+
method: "POST",
|
|
268
|
+
headers: {
|
|
269
|
+
"Content-Type": "application/json",
|
|
270
|
+
"x-api-key": this.apiKey,
|
|
271
|
+
"anthropic-version": "2023-06-01",
|
|
272
|
+
"anthropic-dangerous-direct-browser-access": "true"
|
|
273
|
+
},
|
|
274
|
+
body: JSON.stringify({
|
|
275
|
+
model: this.model,
|
|
276
|
+
max_tokens: options.maxTokens || this.maxTokens,
|
|
277
|
+
system: options.systemPrompt || this.systemPrompt,
|
|
278
|
+
messages: messages.map((m) => ({
|
|
279
|
+
role: m.role,
|
|
280
|
+
content: m.content
|
|
281
|
+
})),
|
|
282
|
+
temperature: options.temperature
|
|
283
|
+
})
|
|
284
|
+
});
|
|
285
|
+
if (!response.ok) {
|
|
286
|
+
const errorData = await response.json().catch(() => ({}));
|
|
287
|
+
if (response.status === 401) {
|
|
288
|
+
return {
|
|
289
|
+
success: false,
|
|
290
|
+
message: "Invalid API key. Please check your API key and try again.",
|
|
291
|
+
error: "INVALID_API_KEY"
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
if (response.status === 429) {
|
|
295
|
+
return {
|
|
296
|
+
success: false,
|
|
297
|
+
message: "Rate limit exceeded. Please wait a moment and try again.",
|
|
298
|
+
error: "RATE_LIMITED"
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
if (response.status === 400) {
|
|
302
|
+
return {
|
|
303
|
+
success: false,
|
|
304
|
+
message: errorData.error?.message || "Invalid request",
|
|
305
|
+
error: "BAD_REQUEST"
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
return {
|
|
309
|
+
success: false,
|
|
310
|
+
message: errorData.error?.message || `API error: ${response.status}`,
|
|
311
|
+
error: "API_ERROR"
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
const data = await response.json();
|
|
315
|
+
const textContent = data.content.find((c) => c.type === "text");
|
|
316
|
+
const responseText = textContent?.text || "";
|
|
317
|
+
const modelCosts = COST_PER_1K[this.model] || COST_PER_1K["claude-sonnet-4-20250514"];
|
|
318
|
+
const inputCost = data.usage.input_tokens / 1e3 * modelCosts.input;
|
|
319
|
+
const outputCost = data.usage.output_tokens / 1e3 * modelCosts.output;
|
|
320
|
+
return {
|
|
321
|
+
success: true,
|
|
322
|
+
message: responseText,
|
|
323
|
+
response: data,
|
|
324
|
+
usage: {
|
|
325
|
+
inputTokens: data.usage.input_tokens,
|
|
326
|
+
outputTokens: data.usage.output_tokens,
|
|
327
|
+
estimatedCost: inputCost + outputCost
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
} catch (err) {
|
|
331
|
+
console.error("ClaudeClient error:", err);
|
|
332
|
+
if (err instanceof TypeError && err.message.includes("fetch")) {
|
|
333
|
+
return {
|
|
334
|
+
success: false,
|
|
335
|
+
message: "Network error. Please check your connection.",
|
|
336
|
+
error: "NETWORK_ERROR"
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
success: false,
|
|
341
|
+
message: err instanceof Error ? err.message : "Unknown error occurred",
|
|
342
|
+
error: "UNKNOWN_ERROR"
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Update the API key
|
|
348
|
+
*/
|
|
349
|
+
setApiKey(apiKey) {
|
|
350
|
+
this.apiKey = apiKey;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Update the model
|
|
354
|
+
*/
|
|
355
|
+
setModel(model) {
|
|
356
|
+
this.model = model;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Update the system prompt
|
|
360
|
+
*/
|
|
361
|
+
setSystemPrompt(systemPrompt) {
|
|
362
|
+
this.systemPrompt = systemPrompt;
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
function createClaudeClient(config) {
|
|
366
|
+
return new ClaudeClient(config);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// src/contexts/ApiKeyContext.tsx
|
|
370
|
+
var import_react3 = __toESM(require("react"));
|
|
371
|
+
|
|
372
|
+
// src/hooks/useApiKeyStorage.ts
|
|
373
|
+
var import_react2 = require("react");
|
|
374
|
+
var STORAGE_KEY = "supernal-api-key";
|
|
375
|
+
var ENCRYPTED_STORAGE_KEY = "supernal-vault-v1";
|
|
376
|
+
function validateApiKeyFormat(key) {
|
|
377
|
+
if (!key || key.trim() === "") {
|
|
378
|
+
return { valid: false, error: "API key is required" };
|
|
379
|
+
}
|
|
380
|
+
if (!key.startsWith("sk-ant-")) {
|
|
381
|
+
return { valid: false, error: 'Invalid format. Keys start with "sk-ant-"' };
|
|
382
|
+
}
|
|
383
|
+
if (key.length < 50) {
|
|
384
|
+
return { valid: false, error: "API key appears too short" };
|
|
385
|
+
}
|
|
386
|
+
return { valid: true };
|
|
387
|
+
}
|
|
388
|
+
function maskApiKey(key) {
|
|
389
|
+
if (key.length <= 14) return "\u2022".repeat(key.length);
|
|
390
|
+
return `${key.slice(0, 10)}...${key.slice(-4)}`;
|
|
391
|
+
}
|
|
392
|
+
async function validateApiKeyWithAnthropic(apiKey) {
|
|
393
|
+
try {
|
|
394
|
+
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
|
395
|
+
method: "POST",
|
|
396
|
+
headers: {
|
|
397
|
+
"Content-Type": "application/json",
|
|
398
|
+
"x-api-key": apiKey,
|
|
399
|
+
"anthropic-version": "2023-06-01",
|
|
400
|
+
"anthropic-dangerous-direct-browser-access": "true"
|
|
401
|
+
},
|
|
402
|
+
body: JSON.stringify({
|
|
403
|
+
model: "claude-sonnet-4-20250514",
|
|
404
|
+
max_tokens: 1,
|
|
405
|
+
messages: [{ role: "user", content: "hi" }]
|
|
406
|
+
})
|
|
407
|
+
});
|
|
408
|
+
if (response.ok) {
|
|
409
|
+
return { valid: true };
|
|
410
|
+
}
|
|
411
|
+
const data = await response.json().catch(() => ({}));
|
|
412
|
+
if (response.status === 401) {
|
|
413
|
+
return { valid: false, error: "Invalid API key" };
|
|
414
|
+
}
|
|
415
|
+
if (response.status === 403) {
|
|
416
|
+
return { valid: false, error: "API key does not have permission" };
|
|
417
|
+
}
|
|
418
|
+
if (response.status === 429) {
|
|
419
|
+
return { valid: true };
|
|
420
|
+
}
|
|
421
|
+
return { valid: false, error: data.error?.message || "Validation failed" };
|
|
422
|
+
} catch (err) {
|
|
423
|
+
console.warn("Could not validate API key with Anthropic:", err);
|
|
424
|
+
return validateApiKeyFormat(apiKey);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
var SALT_LENGTH = 32;
|
|
428
|
+
var IV_LENGTH = 12;
|
|
429
|
+
var ITERATIONS = 1e5;
|
|
430
|
+
async function deriveKey(passphrase, salt) {
|
|
431
|
+
const keyMaterial = await crypto.subtle.importKey(
|
|
432
|
+
"raw",
|
|
433
|
+
new TextEncoder().encode(passphrase),
|
|
434
|
+
"PBKDF2",
|
|
435
|
+
false,
|
|
436
|
+
["deriveKey"]
|
|
437
|
+
);
|
|
438
|
+
const saltBuffer = salt.buffer.slice(salt.byteOffset, salt.byteOffset + salt.byteLength);
|
|
439
|
+
return crypto.subtle.deriveKey(
|
|
440
|
+
{ name: "PBKDF2", salt: saltBuffer, iterations: ITERATIONS, hash: "SHA-256" },
|
|
441
|
+
keyMaterial,
|
|
442
|
+
{ name: "AES-GCM", length: 256 },
|
|
443
|
+
false,
|
|
444
|
+
["encrypt", "decrypt"]
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
async function encryptValue(key, plaintext, salt) {
|
|
448
|
+
const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));
|
|
449
|
+
const ivBuffer = iv.buffer.slice(iv.byteOffset, iv.byteOffset + iv.byteLength);
|
|
450
|
+
const ciphertext = await crypto.subtle.encrypt(
|
|
451
|
+
{ name: "AES-GCM", iv: ivBuffer },
|
|
452
|
+
key,
|
|
453
|
+
new TextEncoder().encode(plaintext)
|
|
454
|
+
);
|
|
455
|
+
return {
|
|
456
|
+
version: 1,
|
|
457
|
+
ciphertext: arrayBufferToBase64(ciphertext),
|
|
458
|
+
salt: uint8ArrayToBase64(salt),
|
|
459
|
+
iv: uint8ArrayToBase64(iv),
|
|
460
|
+
encryptedAt: Date.now()
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
async function decryptValue(key, entry) {
|
|
464
|
+
const ciphertext = base64ToArrayBuffer(entry.ciphertext);
|
|
465
|
+
const iv = base64ToUint8Array(entry.iv);
|
|
466
|
+
const ivBuffer = iv.buffer.slice(iv.byteOffset, iv.byteOffset + iv.byteLength);
|
|
467
|
+
const plaintext = await crypto.subtle.decrypt(
|
|
468
|
+
{ name: "AES-GCM", iv: ivBuffer },
|
|
469
|
+
key,
|
|
470
|
+
ciphertext
|
|
471
|
+
);
|
|
472
|
+
return new TextDecoder().decode(plaintext);
|
|
473
|
+
}
|
|
474
|
+
function arrayBufferToBase64(buffer) {
|
|
475
|
+
const bytes = new Uint8Array(buffer);
|
|
476
|
+
let binary = "";
|
|
477
|
+
for (let i = 0; i < bytes.byteLength; i++) {
|
|
478
|
+
binary += String.fromCharCode(bytes[i]);
|
|
479
|
+
}
|
|
480
|
+
return btoa(binary);
|
|
481
|
+
}
|
|
482
|
+
function base64ToArrayBuffer(base64) {
|
|
483
|
+
const binary = atob(base64);
|
|
484
|
+
const bytes = new Uint8Array(binary.length);
|
|
485
|
+
for (let i = 0; i < binary.length; i++) {
|
|
486
|
+
bytes[i] = binary.charCodeAt(i);
|
|
487
|
+
}
|
|
488
|
+
return bytes.buffer;
|
|
489
|
+
}
|
|
490
|
+
function uint8ArrayToBase64(array) {
|
|
491
|
+
const buffer = array.buffer.slice(array.byteOffset, array.byteOffset + array.byteLength);
|
|
492
|
+
return arrayBufferToBase64(buffer);
|
|
493
|
+
}
|
|
494
|
+
function base64ToUint8Array(base64) {
|
|
495
|
+
return new Uint8Array(base64ToArrayBuffer(base64));
|
|
496
|
+
}
|
|
497
|
+
function loadEncryptedEntry() {
|
|
498
|
+
if (typeof window === "undefined") return null;
|
|
499
|
+
try {
|
|
500
|
+
const stored = localStorage.getItem(ENCRYPTED_STORAGE_KEY);
|
|
501
|
+
if (stored) {
|
|
502
|
+
const entry = JSON.parse(stored);
|
|
503
|
+
if (entry.version === 1 && entry.ciphertext && entry.salt) {
|
|
504
|
+
return entry;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
} catch {
|
|
508
|
+
}
|
|
509
|
+
return null;
|
|
510
|
+
}
|
|
511
|
+
function useApiKeyStorage(options = {}) {
|
|
512
|
+
const [state, setState] = (0, import_react2.useState)({
|
|
513
|
+
apiKey: null,
|
|
514
|
+
status: options.encrypted ? "locked" : "none",
|
|
515
|
+
error: null,
|
|
516
|
+
maskedKey: null
|
|
517
|
+
});
|
|
518
|
+
const derivedKeyRef = (0, import_react2.useRef)(null);
|
|
519
|
+
const saltRef = (0, import_react2.useRef)(null);
|
|
520
|
+
(0, import_react2.useEffect)(() => {
|
|
521
|
+
if (typeof window === "undefined") return;
|
|
522
|
+
if (options.encrypted) {
|
|
523
|
+
const entry = loadEncryptedEntry();
|
|
524
|
+
if (entry) {
|
|
525
|
+
setState((prev) => ({ ...prev, status: "locked" }));
|
|
526
|
+
} else {
|
|
527
|
+
setState((prev) => ({ ...prev, status: "locked" }));
|
|
528
|
+
}
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
try {
|
|
532
|
+
const saved = localStorage.getItem(STORAGE_KEY);
|
|
533
|
+
if (saved) {
|
|
534
|
+
const validation = validateApiKeyFormat(saved);
|
|
535
|
+
setState({
|
|
536
|
+
apiKey: saved,
|
|
537
|
+
status: validation.valid ? "valid" : "invalid",
|
|
538
|
+
error: validation.error || null,
|
|
539
|
+
maskedKey: maskApiKey(saved)
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
} catch (err) {
|
|
543
|
+
console.error("Failed to load API key from storage:", err);
|
|
544
|
+
}
|
|
545
|
+
}, [options.encrypted]);
|
|
546
|
+
const unlock = (0, import_react2.useCallback)(async (passphrase) => {
|
|
547
|
+
if (!options.encrypted) {
|
|
548
|
+
return true;
|
|
549
|
+
}
|
|
550
|
+
try {
|
|
551
|
+
const entry = loadEncryptedEntry();
|
|
552
|
+
if (entry) {
|
|
553
|
+
const salt = base64ToUint8Array(entry.salt);
|
|
554
|
+
const key = await deriveKey(passphrase, salt);
|
|
555
|
+
try {
|
|
556
|
+
const apiKey = await decryptValue(key, entry);
|
|
557
|
+
derivedKeyRef.current = key;
|
|
558
|
+
saltRef.current = salt;
|
|
559
|
+
const validation = validateApiKeyFormat(apiKey);
|
|
560
|
+
setState({
|
|
561
|
+
apiKey,
|
|
562
|
+
status: validation.valid ? "valid" : "invalid",
|
|
563
|
+
error: validation.error || null,
|
|
564
|
+
maskedKey: maskApiKey(apiKey)
|
|
565
|
+
});
|
|
566
|
+
return true;
|
|
567
|
+
} catch {
|
|
568
|
+
options.onPassphraseInvalid?.();
|
|
569
|
+
return false;
|
|
570
|
+
}
|
|
571
|
+
} else {
|
|
572
|
+
const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));
|
|
573
|
+
const key = await deriveKey(passphrase, salt);
|
|
574
|
+
derivedKeyRef.current = key;
|
|
575
|
+
saltRef.current = salt;
|
|
576
|
+
setState((prev) => ({
|
|
577
|
+
...prev,
|
|
578
|
+
status: "none"
|
|
579
|
+
// Unlocked but no key yet
|
|
580
|
+
}));
|
|
581
|
+
return true;
|
|
582
|
+
}
|
|
583
|
+
} catch (error) {
|
|
584
|
+
console.error("[useApiKeyStorage] Unlock failed:", error);
|
|
585
|
+
return false;
|
|
586
|
+
}
|
|
587
|
+
}, [options.encrypted, options.onPassphraseInvalid]);
|
|
588
|
+
const lock = (0, import_react2.useCallback)(() => {
|
|
589
|
+
if (!options.encrypted) return;
|
|
590
|
+
derivedKeyRef.current = null;
|
|
591
|
+
setState((prev) => ({
|
|
592
|
+
...prev,
|
|
593
|
+
status: "locked",
|
|
594
|
+
apiKey: null,
|
|
595
|
+
maskedKey: null
|
|
596
|
+
}));
|
|
597
|
+
}, [options.encrypted]);
|
|
598
|
+
const setApiKey = (0, import_react2.useCallback)(async (key, validate = true) => {
|
|
599
|
+
const formatValidation = validateApiKeyFormat(key);
|
|
600
|
+
if (!formatValidation.valid) {
|
|
601
|
+
setState({
|
|
602
|
+
apiKey: null,
|
|
603
|
+
status: "invalid",
|
|
604
|
+
error: formatValidation.error || "Invalid API key",
|
|
605
|
+
maskedKey: null
|
|
606
|
+
});
|
|
607
|
+
return false;
|
|
608
|
+
}
|
|
609
|
+
setState({
|
|
610
|
+
apiKey: key,
|
|
611
|
+
status: validate ? "validating" : "valid",
|
|
612
|
+
error: null,
|
|
613
|
+
maskedKey: maskApiKey(key)
|
|
614
|
+
});
|
|
615
|
+
try {
|
|
616
|
+
if (options.encrypted && derivedKeyRef.current && saltRef.current) {
|
|
617
|
+
const entry = await encryptValue(derivedKeyRef.current, key, saltRef.current);
|
|
618
|
+
localStorage.setItem(ENCRYPTED_STORAGE_KEY, JSON.stringify(entry));
|
|
619
|
+
} else {
|
|
620
|
+
localStorage.setItem(STORAGE_KEY, key);
|
|
621
|
+
}
|
|
622
|
+
} catch (err) {
|
|
623
|
+
console.error("Failed to save API key:", err);
|
|
624
|
+
}
|
|
625
|
+
if (validate) {
|
|
626
|
+
const liveValidation = await validateApiKeyWithAnthropic(key);
|
|
627
|
+
setState((prev) => ({
|
|
628
|
+
...prev,
|
|
629
|
+
status: liveValidation.valid ? "valid" : "invalid",
|
|
630
|
+
error: liveValidation.error || null
|
|
631
|
+
}));
|
|
632
|
+
return liveValidation.valid;
|
|
633
|
+
}
|
|
634
|
+
return true;
|
|
635
|
+
}, [options.encrypted]);
|
|
636
|
+
const clearApiKey = (0, import_react2.useCallback)(() => {
|
|
637
|
+
try {
|
|
638
|
+
if (options.encrypted) {
|
|
639
|
+
localStorage.removeItem(ENCRYPTED_STORAGE_KEY);
|
|
640
|
+
} else {
|
|
641
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
642
|
+
}
|
|
643
|
+
} catch (err) {
|
|
644
|
+
console.error("Failed to clear API key:", err);
|
|
645
|
+
}
|
|
646
|
+
setState({
|
|
647
|
+
apiKey: null,
|
|
648
|
+
status: options.encrypted ? "locked" : "none",
|
|
649
|
+
error: null,
|
|
650
|
+
maskedKey: null
|
|
651
|
+
});
|
|
652
|
+
}, [options.encrypted]);
|
|
653
|
+
const revalidate = (0, import_react2.useCallback)(async () => {
|
|
654
|
+
if (!state.apiKey) return false;
|
|
655
|
+
return setApiKey(state.apiKey, true);
|
|
656
|
+
}, [state.apiKey, setApiKey]);
|
|
657
|
+
return {
|
|
658
|
+
...state,
|
|
659
|
+
hasApiKey: !!state.apiKey && state.status === "valid",
|
|
660
|
+
isLocked: state.status === "locked",
|
|
661
|
+
setApiKey,
|
|
662
|
+
clearApiKey,
|
|
663
|
+
revalidate,
|
|
664
|
+
unlock,
|
|
665
|
+
lock
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// src/contexts/ApiKeyContext.tsx
|
|
238
670
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
239
|
-
var
|
|
671
|
+
var ApiKeyContext = (0, import_react3.createContext)(null);
|
|
672
|
+
function ApiKeyProvider({ children, initialApiKey }) {
|
|
673
|
+
const apiKeyStorage = useApiKeyStorage();
|
|
674
|
+
import_react3.default.useEffect(() => {
|
|
675
|
+
if (initialApiKey && !apiKeyStorage.apiKey && apiKeyStorage.status === "none") {
|
|
676
|
+
apiKeyStorage.setApiKey(initialApiKey, false);
|
|
677
|
+
}
|
|
678
|
+
}, [initialApiKey, apiKeyStorage]);
|
|
679
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ApiKeyContext.Provider, { value: apiKeyStorage, children });
|
|
680
|
+
}
|
|
681
|
+
function useApiKey() {
|
|
682
|
+
const context = (0, import_react3.useContext)(ApiKeyContext);
|
|
683
|
+
if (!context) {
|
|
684
|
+
throw new Error("useApiKey must be used within ApiKeyProvider");
|
|
685
|
+
}
|
|
686
|
+
return context;
|
|
687
|
+
}
|
|
688
|
+
function useApiKeyOptional() {
|
|
689
|
+
return (0, import_react3.useContext)(ApiKeyContext);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// src/contexts/ChatProvider.tsx
|
|
693
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
694
|
+
var ChatContext = (0, import_react4.createContext)(null);
|
|
240
695
|
function useChatContext() {
|
|
241
|
-
const context = (0,
|
|
696
|
+
const context = (0, import_react4.useContext)(ChatContext);
|
|
242
697
|
if (!context) {
|
|
243
698
|
throw new Error("useChatContext must be used within ChatProvider");
|
|
244
699
|
}
|
|
245
700
|
return context;
|
|
246
701
|
}
|
|
247
|
-
var
|
|
702
|
+
var STORAGE_KEY2 = "supernal-chat-messages";
|
|
248
703
|
var MAX_MESSAGES = 100;
|
|
249
704
|
function getInitialMessages() {
|
|
250
705
|
return [
|
|
@@ -289,14 +744,30 @@ function getInitialMessages() {
|
|
|
289
744
|
function ChatProvider({
|
|
290
745
|
children,
|
|
291
746
|
mode = "fuzzy",
|
|
292
|
-
apiKey,
|
|
747
|
+
apiKey: propApiKey,
|
|
293
748
|
onToolExecute
|
|
294
749
|
}) {
|
|
295
|
-
const [messages, setMessages] = (0,
|
|
296
|
-
|
|
750
|
+
const [messages, setMessages] = (0, import_react4.useState)([]);
|
|
751
|
+
const apiKeyContext = useApiKeyOptional();
|
|
752
|
+
const activeApiKey = apiKeyContext?.hasApiKey ? apiKeyContext.apiKey : propApiKey;
|
|
753
|
+
const isAiMode = !!activeApiKey;
|
|
754
|
+
const claudeClientRef = (0, import_react4.useRef)(null);
|
|
755
|
+
(0, import_react4.useEffect)(() => {
|
|
756
|
+
if (activeApiKey) {
|
|
757
|
+
claudeClientRef.current = new ClaudeClient({
|
|
758
|
+
apiKey: activeApiKey,
|
|
759
|
+
systemPrompt: `You are a helpful AI assistant integrated into a web application powered by Supernal Interface.
|
|
760
|
+
You can help users navigate the application and perform tasks.
|
|
761
|
+
Be concise, friendly, and helpful. Use markdown formatting when appropriate.`
|
|
762
|
+
});
|
|
763
|
+
} else {
|
|
764
|
+
claudeClientRef.current = null;
|
|
765
|
+
}
|
|
766
|
+
}, [activeApiKey]);
|
|
767
|
+
(0, import_react4.useEffect)(() => {
|
|
297
768
|
if (typeof window === "undefined") return;
|
|
298
769
|
try {
|
|
299
|
-
const saved = localStorage.getItem(
|
|
770
|
+
const saved = localStorage.getItem(STORAGE_KEY2);
|
|
300
771
|
if (saved) {
|
|
301
772
|
const loaded = JSON.parse(saved).map((m) => ({
|
|
302
773
|
...m,
|
|
@@ -311,24 +782,24 @@ function ChatProvider({
|
|
|
311
782
|
setMessages(getInitialMessages());
|
|
312
783
|
}
|
|
313
784
|
}, []);
|
|
314
|
-
const [isLoading, setIsLoading] = (0,
|
|
315
|
-
const [aiInterface] = (0,
|
|
316
|
-
(0,
|
|
785
|
+
const [isLoading, setIsLoading] = (0, import_react4.useState)(false);
|
|
786
|
+
const [aiInterface] = (0, import_react4.useState)(() => new DemoAIInterface());
|
|
787
|
+
(0, import_react4.useEffect)(() => {
|
|
317
788
|
if (onToolExecute) {
|
|
318
789
|
return aiInterface.onToolExecution((result) => {
|
|
319
790
|
onToolExecute(result.toolName, result);
|
|
320
791
|
});
|
|
321
792
|
}
|
|
322
793
|
}, [aiInterface, onToolExecute]);
|
|
323
|
-
(0,
|
|
794
|
+
(0, import_react4.useEffect)(() => {
|
|
324
795
|
try {
|
|
325
796
|
const toSave = messages.slice(-MAX_MESSAGES);
|
|
326
|
-
localStorage.setItem(
|
|
797
|
+
localStorage.setItem(STORAGE_KEY2, JSON.stringify(toSave));
|
|
327
798
|
} catch (error) {
|
|
328
799
|
console.error("Failed to save messages:", error);
|
|
329
800
|
}
|
|
330
801
|
}, [messages]);
|
|
331
|
-
const sendMessage = (0,
|
|
802
|
+
const sendMessage = (0, import_react4.useCallback)(async (text) => {
|
|
332
803
|
const userMessage = {
|
|
333
804
|
id: Date.now().toString(),
|
|
334
805
|
text,
|
|
@@ -338,14 +809,31 @@ function ChatProvider({
|
|
|
338
809
|
setMessages((prev) => [...prev, userMessage]);
|
|
339
810
|
setIsLoading(true);
|
|
340
811
|
try {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
812
|
+
if (claudeClientRef.current) {
|
|
813
|
+
const conversationHistory = messages.slice(-20).filter((m) => m.type === "user" || m.type === "ai").map((m) => ({
|
|
814
|
+
role: m.type === "user" ? "user" : "assistant",
|
|
815
|
+
content: m.text
|
|
816
|
+
}));
|
|
817
|
+
const result = await claudeClientRef.current.sendMessage(text, {
|
|
818
|
+
messages: conversationHistory
|
|
819
|
+
});
|
|
820
|
+
const aiMessage = {
|
|
821
|
+
id: (Date.now() + 1).toString(),
|
|
822
|
+
text: result.message,
|
|
823
|
+
type: result.success ? "ai" : "system",
|
|
824
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
825
|
+
};
|
|
826
|
+
setMessages((prev) => [...prev, aiMessage]);
|
|
827
|
+
} else {
|
|
828
|
+
const result = await aiInterface.findAndExecuteCommand(text);
|
|
829
|
+
const aiMessage = {
|
|
830
|
+
id: (Date.now() + 1).toString(),
|
|
831
|
+
text: result.message,
|
|
832
|
+
type: result.success ? "ai" : "system",
|
|
833
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
834
|
+
};
|
|
835
|
+
setMessages((prev) => [...prev, aiMessage]);
|
|
836
|
+
}
|
|
349
837
|
} catch (error) {
|
|
350
838
|
const errorMessage = {
|
|
351
839
|
id: (Date.now() + 1).toString(),
|
|
@@ -357,16 +845,16 @@ function ChatProvider({
|
|
|
357
845
|
} finally {
|
|
358
846
|
setIsLoading(false);
|
|
359
847
|
}
|
|
360
|
-
}, [aiInterface]);
|
|
361
|
-
const clearMessages = (0,
|
|
848
|
+
}, [aiInterface, messages]);
|
|
849
|
+
const clearMessages = (0, import_react4.useCallback)(() => {
|
|
362
850
|
setMessages([]);
|
|
363
|
-
localStorage.removeItem(
|
|
851
|
+
localStorage.removeItem(STORAGE_KEY2);
|
|
364
852
|
}, []);
|
|
365
|
-
return /* @__PURE__ */ (0,
|
|
853
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChatContext.Provider, { value: { messages, sendMessage, clearMessages, isLoading, isAiMode }, children });
|
|
366
854
|
}
|
|
367
855
|
|
|
368
856
|
// src/components/ChatBubble/constants.ts
|
|
369
|
-
var
|
|
857
|
+
var import_react5 = __toESM(require("react"));
|
|
370
858
|
|
|
371
859
|
// src/names/Components.ts
|
|
372
860
|
var Components = {
|
|
@@ -374,7 +862,20 @@ var Components = {
|
|
|
374
862
|
ChatToggleButton: "chat-toggle-button",
|
|
375
863
|
ChatInput: "chat-message-input",
|
|
376
864
|
ChatSendButton: "chat-send-button",
|
|
377
|
-
ChatClearButton: "chat-clear-button"
|
|
865
|
+
ChatClearButton: "chat-clear-button",
|
|
866
|
+
ChatMoreMenu: "chat-more-menu",
|
|
867
|
+
ChatMoreMenuButton: "chat-more-menu-button",
|
|
868
|
+
// API Key configuration components (BYOK mode)
|
|
869
|
+
ApiKeySection: "api-key-section",
|
|
870
|
+
ApiKeyInput: "api-key-input",
|
|
871
|
+
ApiKeySubmitButton: "api-key-submit-button",
|
|
872
|
+
ApiKeyClearButton: "api-key-clear-button",
|
|
873
|
+
ApiKeyConfigureButton: "api-key-configure-button",
|
|
874
|
+
ApiKeyStatus: "api-key-status",
|
|
875
|
+
ApiKeyMasked: "api-key-masked",
|
|
876
|
+
ApiKeyError: "api-key-error",
|
|
877
|
+
ApiKeyShowToggle: "api-key-show-toggle",
|
|
878
|
+
ApiKeyCancelButton: "api-key-cancel-button"
|
|
378
879
|
};
|
|
379
880
|
var ChatBubbleVariant = {
|
|
380
881
|
full: "full",
|
|
@@ -576,7 +1077,7 @@ var GLASS_INVERTED = {
|
|
|
576
1077
|
var DEFAULT_CONFIG = {
|
|
577
1078
|
title: "Supernal Interface",
|
|
578
1079
|
logo: DEFAULT_LOGO,
|
|
579
|
-
avatar:
|
|
1080
|
+
avatar: import_react5.default.createElement("img", { src: DEFAULT_LOGO, alt: "Supernal", className: "w-6 h-6" }),
|
|
580
1081
|
description: "I'm a TOOL system AI can use to control this site",
|
|
581
1082
|
placeholder: "Try: toggle notifications",
|
|
582
1083
|
sendButtonLabel: "Send",
|
|
@@ -599,7 +1100,7 @@ var DEFAULT_CONFIG = {
|
|
|
599
1100
|
};
|
|
600
1101
|
|
|
601
1102
|
// src/components/ChatBubble/InputField.tsx
|
|
602
|
-
var
|
|
1103
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
603
1104
|
var InputField = ({
|
|
604
1105
|
compact = false,
|
|
605
1106
|
inputValue,
|
|
@@ -615,8 +1116,8 @@ var InputField = ({
|
|
|
615
1116
|
onMicClick,
|
|
616
1117
|
modKey = "Ctrl",
|
|
617
1118
|
onKeyDown
|
|
618
|
-
}) => /* @__PURE__ */ (0,
|
|
619
|
-
/* @__PURE__ */ (0,
|
|
1119
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("form", { onSubmit, className: compact ? "flex space-x-2" : THEME_CLASSES.bg.inputForm + " bg-transparent", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: compact ? "flex space-x-2 flex-1" : "relative", children: [
|
|
1120
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
620
1121
|
"input",
|
|
621
1122
|
{
|
|
622
1123
|
ref: compact ? void 0 : inputRef,
|
|
@@ -630,7 +1131,7 @@ var InputField = ({
|
|
|
630
1131
|
"data-testid": ChatNames.input
|
|
631
1132
|
}
|
|
632
1133
|
),
|
|
633
|
-
voiceEnabled && onMicClick && !compact && (!inputValue.trim() || isListening) && /* @__PURE__ */ (0,
|
|
1134
|
+
voiceEnabled && onMicClick && !compact && (!inputValue.trim() || isListening) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
634
1135
|
"button",
|
|
635
1136
|
{
|
|
636
1137
|
type: "button",
|
|
@@ -638,33 +1139,33 @@ var InputField = ({
|
|
|
638
1139
|
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"}`,
|
|
639
1140
|
title: isListening ? "Stop recording (ESC)" : `Voice input (click or press ${modKey}+/)`,
|
|
640
1141
|
"data-testid": "voice-input-button",
|
|
641
|
-
children: isListening ? /* @__PURE__ */ (0,
|
|
1142
|
+
children: isListening ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("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" }) })
|
|
642
1143
|
}
|
|
643
1144
|
),
|
|
644
|
-
inputValue.trim() && /* @__PURE__ */ (0,
|
|
1145
|
+
inputValue.trim() && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
645
1146
|
"button",
|
|
646
1147
|
{
|
|
647
1148
|
type: "submit",
|
|
648
1149
|
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,
|
|
649
1150
|
"data-testid": ChatNames.sendButton,
|
|
650
1151
|
title: sendButtonLabel,
|
|
651
|
-
children: compact ? "\u2192" : /* @__PURE__ */ (0,
|
|
1152
|
+
children: compact ? "\u2192" : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2.5", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13 5l7 7m0 0l-7 7m7-7H3" }) })
|
|
652
1153
|
}
|
|
653
1154
|
)
|
|
654
1155
|
] }) });
|
|
655
1156
|
|
|
656
1157
|
// src/components/ChatBubble/Avatar.tsx
|
|
657
|
-
var
|
|
1158
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
658
1159
|
var Avatar = ({ avatar, size = "normal" }) => {
|
|
659
1160
|
if (!avatar) return null;
|
|
660
1161
|
if (typeof avatar === "string") {
|
|
661
|
-
return size === "small" ? /* @__PURE__ */ (0,
|
|
1162
|
+
return size === "small" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-lg", children: avatar }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-10 h-10 bg-blue-600 rounded-lg flex items-center justify-center shadow-md", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-white text-sm font-bold", children: avatar }) });
|
|
662
1163
|
}
|
|
663
|
-
return /* @__PURE__ */ (0,
|
|
1164
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children: avatar });
|
|
664
1165
|
};
|
|
665
1166
|
|
|
666
1167
|
// src/components/ChatBubble/ChatBubble.tsx
|
|
667
|
-
var
|
|
1168
|
+
var import_react13 = __toESM(require("react"));
|
|
668
1169
|
|
|
669
1170
|
// src/components/MessageRenderer.tsx
|
|
670
1171
|
var import_react_markdown = __toESM(require("react-markdown"));
|
|
@@ -674,12 +1175,12 @@ var import_remark_directive = __toESM(require("remark-directive"));
|
|
|
674
1175
|
var import_rehype_katex = __toESM(require("rehype-katex"));
|
|
675
1176
|
|
|
676
1177
|
// src/components/CodeBlock.tsx
|
|
677
|
-
var
|
|
1178
|
+
var import_react6 = __toESM(require("react"));
|
|
678
1179
|
var import_react_syntax_highlighter = require("react-syntax-highlighter");
|
|
679
|
-
var import_prism = require("react-syntax-highlighter/dist/
|
|
680
|
-
var
|
|
1180
|
+
var import_prism = require("react-syntax-highlighter/dist/esm/styles/prism");
|
|
1181
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
681
1182
|
function CodeBlock({ children, className, inline, theme = "dark" }) {
|
|
682
|
-
const [copied, setCopied] = (0,
|
|
1183
|
+
const [copied, setCopied] = (0, import_react6.useState)(false);
|
|
683
1184
|
const match = /language-(\w+)/.exec(className || "");
|
|
684
1185
|
const language = match ? match[1] : "text";
|
|
685
1186
|
const handleCopy = async () => {
|
|
@@ -688,25 +1189,25 @@ function CodeBlock({ children, className, inline, theme = "dark" }) {
|
|
|
688
1189
|
setTimeout(() => setCopied(false), 2e3);
|
|
689
1190
|
};
|
|
690
1191
|
if (inline) {
|
|
691
|
-
return /* @__PURE__ */ (0,
|
|
1192
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("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 });
|
|
692
1193
|
}
|
|
693
|
-
return /* @__PURE__ */ (0,
|
|
694
|
-
/* @__PURE__ */ (0,
|
|
1194
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "relative group my-4", children: [
|
|
1195
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
695
1196
|
"button",
|
|
696
1197
|
{
|
|
697
1198
|
onClick: handleCopy,
|
|
698
1199
|
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"}`,
|
|
699
1200
|
"aria-label": "Copy code",
|
|
700
|
-
children: copied ? /* @__PURE__ */ (0,
|
|
701
|
-
/* @__PURE__ */ (0,
|
|
1201
|
+
children: copied ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "flex items-center gap-1", children: [
|
|
1202
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
|
|
702
1203
|
"Copied!"
|
|
703
|
-
] }) : /* @__PURE__ */ (0,
|
|
704
|
-
/* @__PURE__ */ (0,
|
|
1204
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "flex items-center gap-1", children: [
|
|
1205
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("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" }) }),
|
|
705
1206
|
"Copy"
|
|
706
1207
|
] })
|
|
707
1208
|
}
|
|
708
1209
|
),
|
|
709
|
-
|
|
1210
|
+
import_react6.default.createElement(import_react_syntax_highlighter.Prism, {
|
|
710
1211
|
language,
|
|
711
1212
|
style: theme === "dark" ? import_prism.vscDarkPlus : import_prism.vs,
|
|
712
1213
|
customStyle: {
|
|
@@ -723,13 +1224,13 @@ function CodeBlock({ children, className, inline, theme = "dark" }) {
|
|
|
723
1224
|
}
|
|
724
1225
|
|
|
725
1226
|
// src/components/MermaidDiagram.tsx
|
|
726
|
-
var
|
|
727
|
-
var
|
|
1227
|
+
var import_react7 = require("react");
|
|
1228
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
728
1229
|
function MermaidDiagram({ chart, theme = "dark" }) {
|
|
729
|
-
const containerRef = (0,
|
|
730
|
-
const [error, setError] = (0,
|
|
731
|
-
const [isLoading, setIsLoading] = (0,
|
|
732
|
-
(0,
|
|
1230
|
+
const containerRef = (0, import_react7.useRef)(null);
|
|
1231
|
+
const [error, setError] = (0, import_react7.useState)(null);
|
|
1232
|
+
const [isLoading, setIsLoading] = (0, import_react7.useState)(true);
|
|
1233
|
+
(0, import_react7.useEffect)(() => {
|
|
733
1234
|
let mounted = true;
|
|
734
1235
|
const renderDiagram = async () => {
|
|
735
1236
|
if (!containerRef.current) return;
|
|
@@ -763,18 +1264,18 @@ function MermaidDiagram({ chart, theme = "dark" }) {
|
|
|
763
1264
|
};
|
|
764
1265
|
}, [chart, theme]);
|
|
765
1266
|
if (error) {
|
|
766
|
-
return /* @__PURE__ */ (0,
|
|
767
|
-
/* @__PURE__ */ (0,
|
|
768
|
-
/* @__PURE__ */ (0,
|
|
769
|
-
/* @__PURE__ */ (0,
|
|
770
|
-
/* @__PURE__ */ (0,
|
|
771
|
-
/* @__PURE__ */ (0,
|
|
1267
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("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: [
|
|
1268
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "font-semibold mb-1", children: "Mermaid Diagram Error" }),
|
|
1269
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-sm opacity-90", children: error }),
|
|
1270
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("details", { className: "mt-2 text-xs opacity-75", children: [
|
|
1271
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("summary", { className: "cursor-pointer", children: "View diagram source" }),
|
|
1272
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("pre", { className: "mt-2 whitespace-pre-wrap", children: chart })
|
|
772
1273
|
] })
|
|
773
1274
|
] });
|
|
774
1275
|
}
|
|
775
|
-
return /* @__PURE__ */ (0,
|
|
776
|
-
isLoading && /* @__PURE__ */ (0,
|
|
777
|
-
/* @__PURE__ */ (0,
|
|
1276
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "my-4 flex justify-center", children: [
|
|
1277
|
+
isLoading && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: `py-8 text-sm ${theme === "dark" ? "text-gray-400" : "text-gray-600"}`, children: "Rendering diagram..." }),
|
|
1278
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
778
1279
|
"div",
|
|
779
1280
|
{
|
|
780
1281
|
ref: containerRef,
|
|
@@ -785,7 +1286,7 @@ function MermaidDiagram({ chart, theme = "dark" }) {
|
|
|
785
1286
|
}
|
|
786
1287
|
|
|
787
1288
|
// src/components/MessageRenderer.tsx
|
|
788
|
-
var
|
|
1289
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
789
1290
|
function MessageRenderer({ content, theme = "dark" }) {
|
|
790
1291
|
const components = {
|
|
791
1292
|
// Code blocks with syntax highlighting
|
|
@@ -796,9 +1297,9 @@ function MessageRenderer({ content, theme = "dark" }) {
|
|
|
796
1297
|
const language = match ? match[1] : "";
|
|
797
1298
|
const inline = !className;
|
|
798
1299
|
if (language === "mermaid") {
|
|
799
|
-
return /* @__PURE__ */ (0,
|
|
1300
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MermaidDiagram, { chart: value, theme });
|
|
800
1301
|
}
|
|
801
|
-
return /* @__PURE__ */ (0,
|
|
1302
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
802
1303
|
CodeBlock,
|
|
803
1304
|
{
|
|
804
1305
|
className,
|
|
@@ -809,13 +1310,13 @@ function MessageRenderer({ content, theme = "dark" }) {
|
|
|
809
1310
|
);
|
|
810
1311
|
},
|
|
811
1312
|
// Headings with better styling
|
|
812
|
-
h1: ({ children }) => /* @__PURE__ */ (0,
|
|
813
|
-
h2: ({ children }) => /* @__PURE__ */ (0,
|
|
814
|
-
h3: ({ children }) => /* @__PURE__ */ (0,
|
|
1313
|
+
h1: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h1", { className: `text-2xl font-bold mt-6 mb-3 ${theme === "dark" ? "text-gray-100" : "text-gray-900"}`, children }),
|
|
1314
|
+
h2: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h2", { className: `text-xl font-bold mt-5 mb-2.5 ${theme === "dark" ? "text-gray-100" : "text-gray-900"}`, children }),
|
|
1315
|
+
h3: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { className: `text-lg font-semibold mt-4 mb-2 ${theme === "dark" ? "text-gray-200" : "text-gray-800"}`, children }),
|
|
815
1316
|
// Paragraphs
|
|
816
|
-
p: ({ children }) => /* @__PURE__ */ (0,
|
|
1317
|
+
p: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: `mb-3 leading-relaxed ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
|
|
817
1318
|
// Links
|
|
818
|
-
a: ({ href, children }) => /* @__PURE__ */ (0,
|
|
1319
|
+
a: ({ href, children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
819
1320
|
"a",
|
|
820
1321
|
{
|
|
821
1322
|
href,
|
|
@@ -826,17 +1327,17 @@ function MessageRenderer({ content, theme = "dark" }) {
|
|
|
826
1327
|
}
|
|
827
1328
|
),
|
|
828
1329
|
// Lists
|
|
829
|
-
ul: ({ children }) => /* @__PURE__ */ (0,
|
|
830
|
-
ol: ({ children }) => /* @__PURE__ */ (0,
|
|
1330
|
+
ul: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { className: `list-disc list-inside mb-3 space-y-1 ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
|
|
1331
|
+
ol: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ol", { className: `list-decimal list-inside mb-3 space-y-1 ${theme === "dark" ? "text-gray-300" : "text-gray-700"}`, children }),
|
|
831
1332
|
// Blockquotes
|
|
832
|
-
blockquote: ({ children }) => /* @__PURE__ */ (0,
|
|
1333
|
+
blockquote: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("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 }),
|
|
833
1334
|
// Tables
|
|
834
|
-
table: ({ children }) => /* @__PURE__ */ (0,
|
|
835
|
-
thead: ({ children }) => /* @__PURE__ */ (0,
|
|
836
|
-
th: ({ children }) => /* @__PURE__ */ (0,
|
|
837
|
-
td: ({ children }) => /* @__PURE__ */ (0,
|
|
1335
|
+
table: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "overflow-x-auto my-4", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("table", { className: `min-w-full border-collapse ${theme === "dark" ? "border-gray-700" : "border-gray-300"}`, children }) }),
|
|
1336
|
+
thead: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("thead", { className: theme === "dark" ? "bg-gray-800" : "bg-gray-100", children }),
|
|
1337
|
+
th: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("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 }),
|
|
1338
|
+
td: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { className: `px-4 py-2 border ${theme === "dark" ? "border-gray-700 text-gray-300" : "border-gray-300 text-gray-700"}`, children }),
|
|
838
1339
|
// Horizontal rule
|
|
839
|
-
hr: () => /* @__PURE__ */ (0,
|
|
1340
|
+
hr: () => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("hr", { className: `my-4 border-t ${theme === "dark" ? "border-gray-700" : "border-gray-300"}` }),
|
|
840
1341
|
// Admonitions support (using containerDirective from remark-directive)
|
|
841
1342
|
div: ({ node, className, children, ...props }) => {
|
|
842
1343
|
if (className?.includes("admonition")) {
|
|
@@ -864,15 +1365,15 @@ function MessageRenderer({ content, theme = "dark" }) {
|
|
|
864
1365
|
}
|
|
865
1366
|
};
|
|
866
1367
|
const style = styles[type] || styles.info;
|
|
867
|
-
return /* @__PURE__ */ (0,
|
|
868
|
-
/* @__PURE__ */ (0,
|
|
869
|
-
/* @__PURE__ */ (0,
|
|
1368
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: `my-4 p-4 border-l-4 rounded-r-lg ${style.border} ${style.bg}`, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-start gap-2", children: [
|
|
1369
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-lg flex-shrink-0", children: style.icon }),
|
|
1370
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex-1", children })
|
|
870
1371
|
] }) });
|
|
871
1372
|
}
|
|
872
|
-
return /* @__PURE__ */ (0,
|
|
1373
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className, ...props, children });
|
|
873
1374
|
}
|
|
874
1375
|
};
|
|
875
|
-
return /* @__PURE__ */ (0,
|
|
1376
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "markdown-content", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
876
1377
|
import_react_markdown.default,
|
|
877
1378
|
{
|
|
878
1379
|
remarkPlugins: [import_remark_gfm.default, import_remark_math.default, import_remark_directive.default],
|
|
@@ -884,7 +1385,7 @@ function MessageRenderer({ content, theme = "dark" }) {
|
|
|
884
1385
|
}
|
|
885
1386
|
|
|
886
1387
|
// src/hooks/useTTS.ts
|
|
887
|
-
var
|
|
1388
|
+
var import_react8 = require("react");
|
|
888
1389
|
var Platform = {
|
|
889
1390
|
isNative: typeof window !== "undefined" && "Capacitor" in window,
|
|
890
1391
|
isWeb: typeof window !== "undefined" && !("Capacitor" in window)
|
|
@@ -899,13 +1400,13 @@ function isNativeTTSSupported() {
|
|
|
899
1400
|
return false;
|
|
900
1401
|
}
|
|
901
1402
|
function useTTS() {
|
|
902
|
-
const [isPlaying, setIsPlaying] = (0,
|
|
903
|
-
const [error, setError] = (0,
|
|
904
|
-
const [currentText, setCurrentText] = (0,
|
|
905
|
-
const audioRef = (0,
|
|
906
|
-
const utteranceRef = (0,
|
|
1403
|
+
const [isPlaying, setIsPlaying] = (0, import_react8.useState)(false);
|
|
1404
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
1405
|
+
const [currentText, setCurrentText] = (0, import_react8.useState)(null);
|
|
1406
|
+
const audioRef = (0, import_react8.useRef)(null);
|
|
1407
|
+
const utteranceRef = (0, import_react8.useRef)(null);
|
|
907
1408
|
const isNativeSupported = isNativeTTSSupported();
|
|
908
|
-
const speakNative = (0,
|
|
1409
|
+
const speakNative = (0, import_react8.useCallback)(
|
|
909
1410
|
async (text, options = {}) => {
|
|
910
1411
|
if (Platform.isNative) {
|
|
911
1412
|
try {
|
|
@@ -950,7 +1451,7 @@ function useTTS() {
|
|
|
950
1451
|
},
|
|
951
1452
|
[]
|
|
952
1453
|
);
|
|
953
|
-
const speakAPI = (0,
|
|
1454
|
+
const speakAPI = (0, import_react8.useCallback)(
|
|
954
1455
|
async (text, options = {}) => {
|
|
955
1456
|
const apiUrl = process.env.NEXT_PUBLIC_TTS_API_URL || "https://tts.supernal.ai";
|
|
956
1457
|
const apiKey = process.env.NEXT_PUBLIC_TTS_API_KEY || "";
|
|
@@ -1011,7 +1512,7 @@ function useTTS() {
|
|
|
1011
1512
|
},
|
|
1012
1513
|
[]
|
|
1013
1514
|
);
|
|
1014
|
-
const speak = (0,
|
|
1515
|
+
const speak = (0, import_react8.useCallback)(
|
|
1015
1516
|
async (options) => {
|
|
1016
1517
|
const {
|
|
1017
1518
|
text,
|
|
@@ -1055,7 +1556,7 @@ function useTTS() {
|
|
|
1055
1556
|
},
|
|
1056
1557
|
[speakNative, speakAPI, isNativeSupported]
|
|
1057
1558
|
);
|
|
1058
|
-
const stop = (0,
|
|
1559
|
+
const stop = (0, import_react8.useCallback)(() => {
|
|
1059
1560
|
if ("speechSynthesis" in window && window.speechSynthesis.speaking) {
|
|
1060
1561
|
window.speechSynthesis.cancel();
|
|
1061
1562
|
utteranceRef.current = null;
|
|
@@ -1088,18 +1589,18 @@ function base64ToBlob(base64, mimeType) {
|
|
|
1088
1589
|
}
|
|
1089
1590
|
|
|
1090
1591
|
// src/hooks/useSTT.ts
|
|
1091
|
-
var
|
|
1592
|
+
var import_react9 = require("react");
|
|
1092
1593
|
var Platform2 = {
|
|
1093
1594
|
isNative: typeof window !== "undefined" && "Capacitor" in window,
|
|
1094
1595
|
isWeb: typeof window !== "undefined" && !("Capacitor" in window)
|
|
1095
1596
|
};
|
|
1096
1597
|
function useSTT() {
|
|
1097
|
-
const [isListening, setIsListening] = (0,
|
|
1098
|
-
const [transcript, setTranscript] = (0,
|
|
1099
|
-
const [interimTranscript, setInterimTranscript] = (0,
|
|
1100
|
-
const [error, setError] = (0,
|
|
1101
|
-
const recognitionRef = (0,
|
|
1102
|
-
const isSupported = (0,
|
|
1598
|
+
const [isListening, setIsListening] = (0, import_react9.useState)(false);
|
|
1599
|
+
const [transcript, setTranscript] = (0, import_react9.useState)("");
|
|
1600
|
+
const [interimTranscript, setInterimTranscript] = (0, import_react9.useState)("");
|
|
1601
|
+
const [error, setError] = (0, import_react9.useState)(null);
|
|
1602
|
+
const recognitionRef = (0, import_react9.useRef)(null);
|
|
1603
|
+
const isSupported = (0, import_react9.useMemo)(() => {
|
|
1103
1604
|
if (Platform2.isNative) {
|
|
1104
1605
|
return true;
|
|
1105
1606
|
}
|
|
@@ -1108,7 +1609,7 @@ function useSTT() {
|
|
|
1108
1609
|
}
|
|
1109
1610
|
return false;
|
|
1110
1611
|
}, []);
|
|
1111
|
-
(0,
|
|
1612
|
+
(0, import_react9.useEffect)(() => {
|
|
1112
1613
|
if (!isSupported || Platform2.isNative) return;
|
|
1113
1614
|
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
1114
1615
|
if (!SpeechRecognition) return;
|
|
@@ -1146,7 +1647,7 @@ function useSTT() {
|
|
|
1146
1647
|
}
|
|
1147
1648
|
};
|
|
1148
1649
|
}, [isSupported]);
|
|
1149
|
-
const startListening = (0,
|
|
1650
|
+
const startListening = (0, import_react9.useCallback)(async () => {
|
|
1150
1651
|
setError(null);
|
|
1151
1652
|
setTranscript("");
|
|
1152
1653
|
setInterimTranscript("");
|
|
@@ -1178,7 +1679,7 @@ function useSTT() {
|
|
|
1178
1679
|
setIsListening(false);
|
|
1179
1680
|
}
|
|
1180
1681
|
}, []);
|
|
1181
|
-
const stopListening = (0,
|
|
1682
|
+
const stopListening = (0, import_react9.useCallback)(() => {
|
|
1182
1683
|
if (Platform2.isNative) {
|
|
1183
1684
|
setIsListening(false);
|
|
1184
1685
|
return;
|
|
@@ -1187,7 +1688,7 @@ function useSTT() {
|
|
|
1187
1688
|
recognitionRef.current.stop();
|
|
1188
1689
|
}
|
|
1189
1690
|
}, []);
|
|
1190
|
-
const resetTranscript = (0,
|
|
1691
|
+
const resetTranscript = (0, import_react9.useCallback)(() => {
|
|
1191
1692
|
setTranscript("");
|
|
1192
1693
|
setInterimTranscript("");
|
|
1193
1694
|
setError(null);
|
|
@@ -1205,7 +1706,7 @@ function useSTT() {
|
|
|
1205
1706
|
}
|
|
1206
1707
|
|
|
1207
1708
|
// src/components/TTSButton.tsx
|
|
1208
|
-
var
|
|
1709
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1209
1710
|
function TTSButton({
|
|
1210
1711
|
text,
|
|
1211
1712
|
usePremiumVoices = false,
|
|
@@ -1233,7 +1734,7 @@ function TTSButton({
|
|
|
1233
1734
|
const isDark = theme === "dark";
|
|
1234
1735
|
const iconSize = size === "small" ? "w-3 h-3" : "w-4 h-4";
|
|
1235
1736
|
const buttonPadding = size === "small" ? "p-1" : "p-2";
|
|
1236
|
-
return /* @__PURE__ */ (0,
|
|
1737
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1237
1738
|
"button",
|
|
1238
1739
|
{
|
|
1239
1740
|
onClick: handleClick,
|
|
@@ -1243,23 +1744,23 @@ function TTSButton({
|
|
|
1243
1744
|
"aria-label": isPlaying ? "Stop speaking" : "Read aloud",
|
|
1244
1745
|
children: isPlaying ? (
|
|
1245
1746
|
// Stop icon (pulsing square)
|
|
1246
|
-
/* @__PURE__ */ (0,
|
|
1747
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { className: iconSize, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) })
|
|
1247
1748
|
) : error ? (
|
|
1248
1749
|
// Error icon
|
|
1249
|
-
/* @__PURE__ */ (0,
|
|
1750
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { className: iconSize, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) })
|
|
1250
1751
|
) : (
|
|
1251
1752
|
// Speaker icon
|
|
1252
|
-
/* @__PURE__ */ (0,
|
|
1753
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { className: iconSize, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("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" }) })
|
|
1253
1754
|
)
|
|
1254
1755
|
}
|
|
1255
1756
|
);
|
|
1256
1757
|
}
|
|
1257
1758
|
|
|
1258
1759
|
// src/components/SubtitleOverlay.tsx
|
|
1259
|
-
var
|
|
1760
|
+
var import_react10 = require("react");
|
|
1260
1761
|
|
|
1261
1762
|
// src/components/TTSPlaylistMenu.tsx
|
|
1262
|
-
var
|
|
1763
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1263
1764
|
var TTSPlaylistMenu = ({
|
|
1264
1765
|
isOpen,
|
|
1265
1766
|
onClose,
|
|
@@ -1280,7 +1781,7 @@ var TTSPlaylistMenu = ({
|
|
|
1280
1781
|
border: "1px solid rgba(0, 0, 0, 0.1)",
|
|
1281
1782
|
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.2)"
|
|
1282
1783
|
};
|
|
1283
|
-
return /* @__PURE__ */ (0,
|
|
1784
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1284
1785
|
"div",
|
|
1285
1786
|
{
|
|
1286
1787
|
className: "fixed z-50",
|
|
@@ -1291,7 +1792,7 @@ var TTSPlaylistMenu = ({
|
|
|
1291
1792
|
width: "min(90vw, 400px)"
|
|
1292
1793
|
},
|
|
1293
1794
|
"data-testid": "tts-playlist-menu",
|
|
1294
|
-
children: /* @__PURE__ */ (0,
|
|
1795
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1295
1796
|
"div",
|
|
1296
1797
|
{
|
|
1297
1798
|
style: {
|
|
@@ -1301,38 +1802,38 @@ var TTSPlaylistMenu = ({
|
|
|
1301
1802
|
borderRadius: "16px"
|
|
1302
1803
|
},
|
|
1303
1804
|
children: [
|
|
1304
|
-
/* @__PURE__ */ (0,
|
|
1805
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1305
1806
|
"div",
|
|
1306
1807
|
{
|
|
1307
1808
|
className: `p-4 border-b flex items-center justify-between ${theme === "dark" ? "border-white/10" : "border-black/10"}`,
|
|
1308
1809
|
children: [
|
|
1309
|
-
/* @__PURE__ */ (0,
|
|
1810
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1310
1811
|
"h3",
|
|
1311
1812
|
{
|
|
1312
1813
|
className: `font-semibold text-sm ${theme === "dark" ? "text-white" : "text-gray-900"}`,
|
|
1313
1814
|
children: "Readable Sections"
|
|
1314
1815
|
}
|
|
1315
1816
|
),
|
|
1316
|
-
/* @__PURE__ */ (0,
|
|
1817
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1317
1818
|
"button",
|
|
1318
1819
|
{
|
|
1319
1820
|
onClick: onClose,
|
|
1320
1821
|
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"}`,
|
|
1321
1822
|
title: "Close",
|
|
1322
1823
|
"data-testid": "close-playlist-menu",
|
|
1323
|
-
children: /* @__PURE__ */ (0,
|
|
1824
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-lg font-bold", "aria-hidden": "true", children: "\xD7" })
|
|
1324
1825
|
}
|
|
1325
1826
|
)
|
|
1326
1827
|
]
|
|
1327
1828
|
}
|
|
1328
1829
|
),
|
|
1329
|
-
/* @__PURE__ */ (0,
|
|
1830
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "overflow-y-auto max-h-80 p-2", children: widgets.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1330
1831
|
"div",
|
|
1331
1832
|
{
|
|
1332
1833
|
className: `p-6 text-center text-sm ${theme === "dark" ? "text-gray-400" : "text-gray-600"}`,
|
|
1333
1834
|
children: "No readable sections found on this page"
|
|
1334
1835
|
}
|
|
1335
|
-
) : widgets.map((widget) => /* @__PURE__ */ (0,
|
|
1836
|
+
) : widgets.map((widget) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1336
1837
|
"button",
|
|
1337
1838
|
{
|
|
1338
1839
|
onClick: () => handleWidgetClick(widget),
|
|
@@ -1342,12 +1843,12 @@ var TTSPlaylistMenu = ({
|
|
|
1342
1843
|
WebkitBackdropFilter: "blur(8px)"
|
|
1343
1844
|
},
|
|
1344
1845
|
"data-testid": "playlist-widget-item",
|
|
1345
|
-
children: /* @__PURE__ */ (0,
|
|
1846
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1346
1847
|
"div",
|
|
1347
1848
|
{
|
|
1348
1849
|
className: `font-medium text-sm flex items-center ${theme === "dark" ? "text-white" : "text-gray-900"}`,
|
|
1349
1850
|
children: [
|
|
1350
|
-
/* @__PURE__ */ (0,
|
|
1851
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "mr-2", "aria-hidden": "true", children: "\u{1F50A}" }),
|
|
1351
1852
|
widget.label || `TTS Widget ${widget.id}`
|
|
1352
1853
|
]
|
|
1353
1854
|
}
|
|
@@ -1570,7 +2071,7 @@ function extractTTSWidgets() {
|
|
|
1570
2071
|
}
|
|
1571
2072
|
|
|
1572
2073
|
// src/components/SubtitleOverlay.tsx
|
|
1573
|
-
var
|
|
2074
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1574
2075
|
var opacityStates = {
|
|
1575
2076
|
mobile: {
|
|
1576
2077
|
idle: 1,
|
|
@@ -1614,47 +2115,47 @@ var SubtitleOverlay = ({
|
|
|
1614
2115
|
resetTranscript,
|
|
1615
2116
|
onSwitchToFullMode
|
|
1616
2117
|
}) => {
|
|
1617
|
-
const [overlayState, setOverlayState] = (0,
|
|
1618
|
-
const [opacity, setOpacity] = (0,
|
|
1619
|
-
const [lastInputMethod, setLastInputMethod] = (0,
|
|
1620
|
-
const [isMobile, setIsMobile] = (0,
|
|
1621
|
-
const [messageOpacity, setMessageOpacity] = (0,
|
|
1622
|
-
const [expansionState, setExpansionState] = (0,
|
|
2118
|
+
const [overlayState, setOverlayState] = (0, import_react10.useState)("idle");
|
|
2119
|
+
const [opacity, setOpacity] = (0, import_react10.useState)(1);
|
|
2120
|
+
const [lastInputMethod, setLastInputMethod] = (0, import_react10.useState)(null);
|
|
2121
|
+
const [isMobile, setIsMobile] = (0, import_react10.useState)(false);
|
|
2122
|
+
const [messageOpacity, setMessageOpacity] = (0, import_react10.useState)(1);
|
|
2123
|
+
const [expansionState, setExpansionState] = (0, import_react10.useState)(() => {
|
|
1623
2124
|
if (typeof window !== "undefined") {
|
|
1624
2125
|
const saved = localStorage.getItem("subtitle-overlay-expanded");
|
|
1625
2126
|
return saved === "true" ? "expanded" : "collapsed";
|
|
1626
2127
|
}
|
|
1627
2128
|
return "collapsed";
|
|
1628
2129
|
});
|
|
1629
|
-
const [touchStartY, setTouchStartY] = (0,
|
|
1630
|
-
const lastInputTimeRef = (0,
|
|
1631
|
-
const autoFadeTimerRef = (0,
|
|
1632
|
-
const messageFadeTimerRef = (0,
|
|
1633
|
-
const inputRef = (0,
|
|
1634
|
-
const [suggestions, setSuggestions] = (0,
|
|
1635
|
-
const [currentSuggestionIndex, setCurrentSuggestionIndex] = (0,
|
|
1636
|
-
const [glassTheme, setGlassTheme] = (0,
|
|
1637
|
-
const [detectedGlassTheme, setDetectedGlassTheme] = (0,
|
|
1638
|
-
const [hasTTSWidgets, setHasTTSWidgets] = (0,
|
|
1639
|
-
const [showPlaylist, setShowPlaylist] = (0,
|
|
1640
|
-
const [ttsWidgets, setTTSWidgets] = (0,
|
|
1641
|
-
const [touchStartYInput, setTouchStartYInput] = (0,
|
|
1642
|
-
const [completedActions, setCompletedActions] = (0,
|
|
1643
|
-
const [showCompletedActions, setShowCompletedActions] = (0,
|
|
1644
|
-
const [shouldShowAiResponse, setShouldShowAiResponse] = (0,
|
|
1645
|
-
const [latestActionOpacity, setLatestActionOpacity] = (0,
|
|
1646
|
-
const latestActionFadeRef = (0,
|
|
1647
|
-
const lastUserMessageRef = (0,
|
|
1648
|
-
const lastShownAiMessageRef = (0,
|
|
1649
|
-
const justExpandedViaSlashRef = (0,
|
|
1650
|
-
const [isDragging, setIsDragging] = (0,
|
|
1651
|
-
const [position, setPosition] = (0,
|
|
1652
|
-
const [dragStart, setDragStart] = (0,
|
|
1653
|
-
const dragRef = (0,
|
|
1654
|
-
const dragDistanceRef = (0,
|
|
1655
|
-
const lastEscapeTimeRef = (0,
|
|
2130
|
+
const [touchStartY, setTouchStartY] = (0, import_react10.useState)(null);
|
|
2131
|
+
const lastInputTimeRef = (0, import_react10.useRef)(Date.now());
|
|
2132
|
+
const autoFadeTimerRef = (0, import_react10.useRef)(null);
|
|
2133
|
+
const messageFadeTimerRef = (0, import_react10.useRef)(null);
|
|
2134
|
+
const inputRef = (0, import_react10.useRef)(null);
|
|
2135
|
+
const [suggestions, setSuggestions] = (0, import_react10.useState)([]);
|
|
2136
|
+
const [currentSuggestionIndex, setCurrentSuggestionIndex] = (0, import_react10.useState)(0);
|
|
2137
|
+
const [glassTheme, setGlassTheme] = (0, import_react10.useState)("auto");
|
|
2138
|
+
const [detectedGlassTheme, setDetectedGlassTheme] = (0, import_react10.useState)("light");
|
|
2139
|
+
const [hasTTSWidgets, setHasTTSWidgets] = (0, import_react10.useState)(false);
|
|
2140
|
+
const [showPlaylist, setShowPlaylist] = (0, import_react10.useState)(false);
|
|
2141
|
+
const [ttsWidgets, setTTSWidgets] = (0, import_react10.useState)([]);
|
|
2142
|
+
const [touchStartYInput, setTouchStartYInput] = (0, import_react10.useState)(null);
|
|
2143
|
+
const [completedActions, setCompletedActions] = (0, import_react10.useState)([]);
|
|
2144
|
+
const [showCompletedActions, setShowCompletedActions] = (0, import_react10.useState)(false);
|
|
2145
|
+
const [shouldShowAiResponse, setShouldShowAiResponse] = (0, import_react10.useState)(false);
|
|
2146
|
+
const [latestActionOpacity, setLatestActionOpacity] = (0, import_react10.useState)(0);
|
|
2147
|
+
const latestActionFadeRef = (0, import_react10.useRef)(null);
|
|
2148
|
+
const lastUserMessageRef = (0, import_react10.useRef)("");
|
|
2149
|
+
const lastShownAiMessageRef = (0, import_react10.useRef)("");
|
|
2150
|
+
const justExpandedViaSlashRef = (0, import_react10.useRef)(false);
|
|
2151
|
+
const [isDragging, setIsDragging] = (0, import_react10.useState)(false);
|
|
2152
|
+
const [position, setPosition] = (0, import_react10.useState)({ x: 0, y: 0 });
|
|
2153
|
+
const [dragStart, setDragStart] = (0, import_react10.useState)({ x: 0, y: 0 });
|
|
2154
|
+
const dragRef = (0, import_react10.useRef)(null);
|
|
2155
|
+
const dragDistanceRef = (0, import_react10.useRef)(0);
|
|
2156
|
+
const lastEscapeTimeRef = (0, import_react10.useRef)(0);
|
|
1656
2157
|
const DOUBLE_ESCAPE_THRESHOLD_MS = 500;
|
|
1657
|
-
(0,
|
|
2158
|
+
(0, import_react10.useEffect)(() => {
|
|
1658
2159
|
const checkMobile = () => {
|
|
1659
2160
|
const mobile = window.innerWidth < 768;
|
|
1660
2161
|
setIsMobile(mobile);
|
|
@@ -1663,7 +2164,7 @@ var SubtitleOverlay = ({
|
|
|
1663
2164
|
window.addEventListener("resize", checkMobile);
|
|
1664
2165
|
return () => window.removeEventListener("resize", checkMobile);
|
|
1665
2166
|
}, []);
|
|
1666
|
-
(0,
|
|
2167
|
+
(0, import_react10.useEffect)(() => {
|
|
1667
2168
|
if (autoFadeTimerRef.current) {
|
|
1668
2169
|
clearTimeout(autoFadeTimerRef.current);
|
|
1669
2170
|
autoFadeTimerRef.current = null;
|
|
@@ -1679,7 +2180,7 @@ var SubtitleOverlay = ({
|
|
|
1679
2180
|
}
|
|
1680
2181
|
};
|
|
1681
2182
|
}, [overlayState, isMobile]);
|
|
1682
|
-
(0,
|
|
2183
|
+
(0, import_react10.useEffect)(() => {
|
|
1683
2184
|
if (messageFadeTimerRef.current) {
|
|
1684
2185
|
clearTimeout(messageFadeTimerRef.current);
|
|
1685
2186
|
messageFadeTimerRef.current = null;
|
|
@@ -1715,7 +2216,7 @@ var SubtitleOverlay = ({
|
|
|
1715
2216
|
}
|
|
1716
2217
|
};
|
|
1717
2218
|
}, [messages.filter((m) => m.type === "ai").slice(-1)[0]?.text, shouldShowAiResponse]);
|
|
1718
|
-
(0,
|
|
2219
|
+
(0, import_react10.useEffect)(() => {
|
|
1719
2220
|
if (sttTranscript && voiceEnabled && resetTranscript) {
|
|
1720
2221
|
onSendMessage(sttTranscript);
|
|
1721
2222
|
resetTranscript();
|
|
@@ -1732,11 +2233,11 @@ var SubtitleOverlay = ({
|
|
|
1732
2233
|
triggerActionFade();
|
|
1733
2234
|
}
|
|
1734
2235
|
}, [sttTranscript, voiceEnabled, resetTranscript, onSendMessage]);
|
|
1735
|
-
(0,
|
|
2236
|
+
(0, import_react10.useEffect)(() => {
|
|
1736
2237
|
const pageSuggestions = extractPageSuggestions();
|
|
1737
2238
|
setSuggestions(pageSuggestions);
|
|
1738
2239
|
}, []);
|
|
1739
|
-
(0,
|
|
2240
|
+
(0, import_react10.useEffect)(() => {
|
|
1740
2241
|
const detectWidgets = async () => {
|
|
1741
2242
|
const detected = await detectTTSWidgets();
|
|
1742
2243
|
setHasTTSWidgets(detected);
|
|
@@ -1771,7 +2272,7 @@ var SubtitleOverlay = ({
|
|
|
1771
2272
|
window.removeEventListener("supernal-tts-ready", handleReady);
|
|
1772
2273
|
};
|
|
1773
2274
|
}, []);
|
|
1774
|
-
(0,
|
|
2275
|
+
(0, import_react10.useEffect)(() => {
|
|
1775
2276
|
if (glassTheme !== "auto") return;
|
|
1776
2277
|
const { glassTheme: detected } = detectBackgroundContext();
|
|
1777
2278
|
setDetectedGlassTheme(detected);
|
|
@@ -1787,7 +2288,7 @@ var SubtitleOverlay = ({
|
|
|
1787
2288
|
window.addEventListener("scroll", handleScroll);
|
|
1788
2289
|
return () => window.removeEventListener("scroll", handleScroll);
|
|
1789
2290
|
}, [glassTheme]);
|
|
1790
|
-
(0,
|
|
2291
|
+
(0, import_react10.useEffect)(() => {
|
|
1791
2292
|
const handleGlobalKeyDown = (e) => {
|
|
1792
2293
|
if (e.key === "Escape") {
|
|
1793
2294
|
const now = Date.now();
|
|
@@ -1834,12 +2335,12 @@ var SubtitleOverlay = ({
|
|
|
1834
2335
|
window.addEventListener("keydown", handleGlobalKeyDown);
|
|
1835
2336
|
return () => window.removeEventListener("keydown", handleGlobalKeyDown);
|
|
1836
2337
|
}, [expansionState, onSwitchToFullMode, voiceEnabled, onMicClick]);
|
|
1837
|
-
(0,
|
|
2338
|
+
(0, import_react10.useEffect)(() => {
|
|
1838
2339
|
if (typeof window !== "undefined") {
|
|
1839
2340
|
localStorage.setItem("subtitle-overlay-expanded", expansionState === "expanded" ? "true" : "false");
|
|
1840
2341
|
}
|
|
1841
2342
|
}, [expansionState]);
|
|
1842
|
-
(0,
|
|
2343
|
+
(0, import_react10.useEffect)(() => {
|
|
1843
2344
|
if (expansionState === "expanded" && inputRef.current) {
|
|
1844
2345
|
setTimeout(() => {
|
|
1845
2346
|
inputRef.current?.focus();
|
|
@@ -1853,7 +2354,7 @@ var SubtitleOverlay = ({
|
|
|
1853
2354
|
}, 100);
|
|
1854
2355
|
}
|
|
1855
2356
|
}, [expansionState]);
|
|
1856
|
-
(0,
|
|
2357
|
+
(0, import_react10.useEffect)(() => {
|
|
1857
2358
|
if (isMobile) return;
|
|
1858
2359
|
const handleMouseMove = (e) => {
|
|
1859
2360
|
if (!isDragging) return;
|
|
@@ -1877,7 +2378,7 @@ var SubtitleOverlay = ({
|
|
|
1877
2378
|
window.removeEventListener("mouseup", handleMouseUp);
|
|
1878
2379
|
};
|
|
1879
2380
|
}, [isDragging, dragStart, isMobile]);
|
|
1880
|
-
(0,
|
|
2381
|
+
(0, import_react10.useEffect)(() => {
|
|
1881
2382
|
const timeSinceLastInput = Date.now() - lastInputTimeRef.current;
|
|
1882
2383
|
const context = {
|
|
1883
2384
|
isListening,
|
|
@@ -2037,8 +2538,8 @@ var SubtitleOverlay = ({
|
|
|
2037
2538
|
return "Tap to start voice input";
|
|
2038
2539
|
};
|
|
2039
2540
|
if (expansionState === "collapsed") {
|
|
2040
|
-
return /* @__PURE__ */ (0,
|
|
2041
|
-
hasTTSWidgets && /* @__PURE__ */ (0,
|
|
2541
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
2542
|
+
hasTTSWidgets && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2042
2543
|
"button",
|
|
2043
2544
|
{
|
|
2044
2545
|
type: "button",
|
|
@@ -2057,10 +2558,10 @@ var SubtitleOverlay = ({
|
|
|
2057
2558
|
title: ttsWidgets.length === 1 ? "Go to readable section" : "View readable sections",
|
|
2058
2559
|
"data-testid": "tts-playlist-button",
|
|
2059
2560
|
"aria-label": ttsWidgets.length === 1 ? "Go to readable section" : "View readable sections",
|
|
2060
|
-
children: /* @__PURE__ */ (0,
|
|
2561
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-xl font-bold select-none", "aria-hidden": "true", children: "~+" })
|
|
2061
2562
|
}
|
|
2062
2563
|
),
|
|
2063
|
-
/* @__PURE__ */ (0,
|
|
2564
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2064
2565
|
TTSPlaylistMenu,
|
|
2065
2566
|
{
|
|
2066
2567
|
isOpen: showPlaylist,
|
|
@@ -2070,7 +2571,7 @@ var SubtitleOverlay = ({
|
|
|
2070
2571
|
onWidgetSelect: handleWidgetSelect
|
|
2071
2572
|
}
|
|
2072
2573
|
),
|
|
2073
|
-
/* @__PURE__ */ (0,
|
|
2574
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2074
2575
|
"div",
|
|
2075
2576
|
{
|
|
2076
2577
|
className: "fixed",
|
|
@@ -2080,7 +2581,7 @@ var SubtitleOverlay = ({
|
|
|
2080
2581
|
zIndex: 55
|
|
2081
2582
|
},
|
|
2082
2583
|
"data-testid": "subtitle-overlay-collapsed",
|
|
2083
|
-
children: /* @__PURE__ */ (0,
|
|
2584
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2084
2585
|
"button",
|
|
2085
2586
|
{
|
|
2086
2587
|
type: "button",
|
|
@@ -2096,14 +2597,14 @@ var SubtitleOverlay = ({
|
|
|
2096
2597
|
title: getIconTitle(),
|
|
2097
2598
|
"data-testid": "voice-input-button",
|
|
2098
2599
|
"aria-label": getIconTitle(),
|
|
2099
|
-
children: /* @__PURE__ */ (0,
|
|
2600
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-xl font-bold select-none", "aria-hidden": "true", children: getIcon() })
|
|
2100
2601
|
}
|
|
2101
2602
|
)
|
|
2102
2603
|
}
|
|
2103
2604
|
)
|
|
2104
2605
|
] });
|
|
2105
2606
|
}
|
|
2106
|
-
return /* @__PURE__ */ (0,
|
|
2607
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2107
2608
|
"div",
|
|
2108
2609
|
{
|
|
2109
2610
|
ref: dragRef,
|
|
@@ -2129,7 +2630,7 @@ var SubtitleOverlay = ({
|
|
|
2129
2630
|
role: "complementary",
|
|
2130
2631
|
"aria-label": "Chat overlay",
|
|
2131
2632
|
children: [
|
|
2132
|
-
!isMobile && /* @__PURE__ */ (0,
|
|
2633
|
+
!isMobile && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2133
2634
|
"div",
|
|
2134
2635
|
{
|
|
2135
2636
|
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",
|
|
@@ -2143,7 +2644,7 @@ var SubtitleOverlay = ({
|
|
|
2143
2644
|
"data-testid": "subtitle-overlay-drag-handle"
|
|
2144
2645
|
}
|
|
2145
2646
|
),
|
|
2146
|
-
showCompletedActions && completedActions.length > 0 && /* @__PURE__ */ (0,
|
|
2647
|
+
showCompletedActions && completedActions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2147
2648
|
"div",
|
|
2148
2649
|
{
|
|
2149
2650
|
className: `mb-2 px-4 py-3 text-xs rounded-2xl animate-popup-in ${theme === "dark" ? "text-white" : "text-gray-900"}`,
|
|
@@ -2156,9 +2657,9 @@ var SubtitleOverlay = ({
|
|
|
2156
2657
|
"aria-label": "Completed actions",
|
|
2157
2658
|
"data-testid": "completed-actions-list",
|
|
2158
2659
|
children: [
|
|
2159
|
-
/* @__PURE__ */ (0,
|
|
2160
|
-
/* @__PURE__ */ (0,
|
|
2161
|
-
/* @__PURE__ */ (0,
|
|
2660
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "font-medium opacity-70 mb-2 flex items-center justify-between", children: [
|
|
2661
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: "Completed Actions" }),
|
|
2662
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2162
2663
|
"button",
|
|
2163
2664
|
{
|
|
2164
2665
|
onClick: () => setShowCompletedActions(false),
|
|
@@ -2168,14 +2669,14 @@ var SubtitleOverlay = ({
|
|
|
2168
2669
|
}
|
|
2169
2670
|
)
|
|
2170
2671
|
] }),
|
|
2171
|
-
/* @__PURE__ */ (0,
|
|
2172
|
-
/* @__PURE__ */ (0,
|
|
2173
|
-
/* @__PURE__ */ (0,
|
|
2672
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "space-y-1", children: completedActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "text-xs opacity-80 border-l-2 border-green-500 pl-2", children: [
|
|
2673
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "font-medium", children: action.tool }),
|
|
2674
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "opacity-70", children: action.description })
|
|
2174
2675
|
] }, action.id)) })
|
|
2175
2676
|
]
|
|
2176
2677
|
}
|
|
2177
2678
|
),
|
|
2178
|
-
!showCompletedActions && (latestActionOpacity > 0 || lastAiMessage && messageOpacity > 0) && /* @__PURE__ */ (0,
|
|
2679
|
+
!showCompletedActions && (latestActionOpacity > 0 || lastAiMessage && messageOpacity > 0) && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2179
2680
|
"div",
|
|
2180
2681
|
{
|
|
2181
2682
|
className: `mb-2 px-4 py-2 text-xs rounded-2xl ${theme === "dark" ? "text-white" : "text-gray-900"}`,
|
|
@@ -2191,27 +2692,27 @@ var SubtitleOverlay = ({
|
|
|
2191
2692
|
children: [
|
|
2192
2693
|
latestActionOpacity > 0 && completedActions.length > 0 && (() => {
|
|
2193
2694
|
const latest = completedActions[completedActions.length - 1];
|
|
2194
|
-
return /* @__PURE__ */ (0,
|
|
2695
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2195
2696
|
"div",
|
|
2196
2697
|
{
|
|
2197
2698
|
className: "border-l-2 border-green-500 pl-2 mb-1",
|
|
2198
2699
|
style: { opacity: latestActionOpacity, transition: "opacity 0.6s ease-out" },
|
|
2199
2700
|
children: [
|
|
2200
|
-
/* @__PURE__ */ (0,
|
|
2201
|
-
/* @__PURE__ */ (0,
|
|
2701
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-medium", children: latest.tool }),
|
|
2702
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "opacity-70 ml-1", children: latest.description })
|
|
2202
2703
|
]
|
|
2203
2704
|
}
|
|
2204
2705
|
);
|
|
2205
2706
|
})(),
|
|
2206
|
-
lastAiMessage && messageOpacity > 0 && /* @__PURE__ */ (0,
|
|
2207
|
-
/* @__PURE__ */ (0,
|
|
2707
|
+
lastAiMessage && messageOpacity > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { opacity: messageOpacity, transition: "opacity 0.8s ease-out" }, children: [
|
|
2708
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-medium opacity-70", children: "AI:" }),
|
|
2208
2709
|
" ",
|
|
2209
|
-
/* @__PURE__ */ (0,
|
|
2710
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-sm", children: lastAiMessage.text })
|
|
2210
2711
|
] })
|
|
2211
2712
|
]
|
|
2212
2713
|
}
|
|
2213
2714
|
),
|
|
2214
|
-
completedActions.length > 0 && !showCompletedActions && /* @__PURE__ */ (0,
|
|
2715
|
+
completedActions.length > 0 && !showCompletedActions && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex justify-center mb-1", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2215
2716
|
"button",
|
|
2216
2717
|
{
|
|
2217
2718
|
type: "button",
|
|
@@ -2227,11 +2728,11 @@ var SubtitleOverlay = ({
|
|
|
2227
2728
|
title: `${completedActions.length} previous actions`,
|
|
2228
2729
|
"data-testid": "completed-actions-toggle",
|
|
2229
2730
|
"aria-label": `Show ${completedActions.length} completed actions`,
|
|
2230
|
-
children: /* @__PURE__ */ (0,
|
|
2731
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { width: "16", height: "8", viewBox: "0 0 16 8", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M2 6L8 2L14 6" }) })
|
|
2231
2732
|
}
|
|
2232
2733
|
) }),
|
|
2233
|
-
/* @__PURE__ */ (0,
|
|
2234
|
-
hasTTSWidgets && /* @__PURE__ */ (0,
|
|
2734
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center space-x-2", children: [
|
|
2735
|
+
hasTTSWidgets && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2235
2736
|
"button",
|
|
2236
2737
|
{
|
|
2237
2738
|
type: "button",
|
|
@@ -2246,10 +2747,10 @@ var SubtitleOverlay = ({
|
|
|
2246
2747
|
title: ttsWidgets.length === 1 ? "Go to readable section" : "View readable sections",
|
|
2247
2748
|
"data-testid": "tts-playlist-button-expanded",
|
|
2248
2749
|
"aria-label": ttsWidgets.length === 1 ? "Go to readable section" : "View readable sections",
|
|
2249
|
-
children: /* @__PURE__ */ (0,
|
|
2750
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: "~+" })
|
|
2250
2751
|
}
|
|
2251
2752
|
),
|
|
2252
|
-
/* @__PURE__ */ (0,
|
|
2753
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2253
2754
|
"div",
|
|
2254
2755
|
{
|
|
2255
2756
|
className: "flex-1 flex items-center space-x-2 px-4 py-2 rounded-3xl",
|
|
@@ -2258,7 +2759,7 @@ var SubtitleOverlay = ({
|
|
|
2258
2759
|
border: effectiveGlassTheme === "dark" ? "1px solid rgba(255, 255, 255, 0.12)" : "1px solid rgba(0, 0, 0, 0.1)"
|
|
2259
2760
|
},
|
|
2260
2761
|
children: [
|
|
2261
|
-
/* @__PURE__ */ (0,
|
|
2762
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2262
2763
|
"input",
|
|
2263
2764
|
{
|
|
2264
2765
|
ref: inputRef,
|
|
@@ -2278,7 +2779,7 @@ var SubtitleOverlay = ({
|
|
|
2278
2779
|
"aria-label": "Chat message input"
|
|
2279
2780
|
}
|
|
2280
2781
|
),
|
|
2281
|
-
isListening && /* @__PURE__ */ (0,
|
|
2782
|
+
isListening && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex space-x-1 items-center", "aria-hidden": "true", "data-testid": "subtitle-overlay-waveform", children: [...Array(5)].map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2282
2783
|
"div",
|
|
2283
2784
|
{
|
|
2284
2785
|
className: "w-0.5 bg-red-500 rounded-full animate-pulse",
|
|
@@ -2289,7 +2790,7 @@ var SubtitleOverlay = ({
|
|
|
2289
2790
|
},
|
|
2290
2791
|
i
|
|
2291
2792
|
)) }),
|
|
2292
|
-
inputValue.trim() && /* @__PURE__ */ (0,
|
|
2793
|
+
inputValue.trim() && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2293
2794
|
"button",
|
|
2294
2795
|
{
|
|
2295
2796
|
type: "button",
|
|
@@ -2305,10 +2806,10 @@ var SubtitleOverlay = ({
|
|
|
2305
2806
|
title: "Send message",
|
|
2306
2807
|
"data-testid": "send-button",
|
|
2307
2808
|
"aria-label": "Send message",
|
|
2308
|
-
children: /* @__PURE__ */ (0,
|
|
2809
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-base select-none", "aria-hidden": "true", children: "\u2192" })
|
|
2309
2810
|
}
|
|
2310
2811
|
),
|
|
2311
|
-
voiceEnabled && /* @__PURE__ */ (0,
|
|
2812
|
+
voiceEnabled && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2312
2813
|
"button",
|
|
2313
2814
|
{
|
|
2314
2815
|
type: "button",
|
|
@@ -2328,10 +2829,10 @@ var SubtitleOverlay = ({
|
|
|
2328
2829
|
title: getIconTitle(),
|
|
2329
2830
|
"data-testid": "voice-input-button",
|
|
2330
2831
|
"aria-label": getIconTitle(),
|
|
2331
|
-
children: /* @__PURE__ */ (0,
|
|
2832
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: getIcon() })
|
|
2332
2833
|
}
|
|
2333
2834
|
),
|
|
2334
|
-
/* @__PURE__ */ (0,
|
|
2835
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2335
2836
|
"button",
|
|
2336
2837
|
{
|
|
2337
2838
|
type: "button",
|
|
@@ -2346,7 +2847,7 @@ var SubtitleOverlay = ({
|
|
|
2346
2847
|
title: "Collapse",
|
|
2347
2848
|
"data-testid": "collapse-button",
|
|
2348
2849
|
"aria-label": "Collapse overlay",
|
|
2349
|
-
children: /* @__PURE__ */ (0,
|
|
2850
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-lg font-bold select-none", "aria-hidden": "true", children: "\xD7" })
|
|
2350
2851
|
}
|
|
2351
2852
|
)
|
|
2352
2853
|
]
|
|
@@ -2359,25 +2860,25 @@ var SubtitleOverlay = ({
|
|
|
2359
2860
|
};
|
|
2360
2861
|
|
|
2361
2862
|
// src/components/SlashCommand/useSlashCommand.ts
|
|
2362
|
-
var
|
|
2363
|
-
var
|
|
2863
|
+
var import_react11 = require("react");
|
|
2864
|
+
var import_browser3 = require("@supernal/interface/browser");
|
|
2364
2865
|
function useSlashCommand(inputValue, onSelect) {
|
|
2365
|
-
const [selectedIndex, setSelectedIndex] = (0,
|
|
2366
|
-
const prevOpenRef = (0,
|
|
2866
|
+
const [selectedIndex, setSelectedIndex] = (0, import_react11.useState)(0);
|
|
2867
|
+
const prevOpenRef = (0, import_react11.useRef)(false);
|
|
2367
2868
|
const isOpen = inputValue.startsWith("/");
|
|
2368
2869
|
const query = isOpen ? inputValue.slice(1) : "";
|
|
2369
|
-
(0,
|
|
2870
|
+
(0, import_react11.useEffect)(() => {
|
|
2370
2871
|
if (isOpen && !prevOpenRef.current) {
|
|
2371
2872
|
setSelectedIndex(0);
|
|
2372
2873
|
}
|
|
2373
2874
|
prevOpenRef.current = isOpen;
|
|
2374
2875
|
}, [isOpen]);
|
|
2375
|
-
(0,
|
|
2876
|
+
(0, import_react11.useEffect)(() => {
|
|
2376
2877
|
setSelectedIndex(0);
|
|
2377
2878
|
}, [query]);
|
|
2378
|
-
const filteredTools = (0,
|
|
2879
|
+
const filteredTools = (0, import_react11.useMemo)(() => {
|
|
2379
2880
|
if (!isOpen) return [];
|
|
2380
|
-
const locationTools =
|
|
2881
|
+
const locationTools = import_browser3.ToolRegistry.getToolsByLocation();
|
|
2381
2882
|
const aiTools = locationTools.filter((t) => t.aiEnabled);
|
|
2382
2883
|
if (!query) return aiTools;
|
|
2383
2884
|
const q = query.toLowerCase();
|
|
@@ -2392,13 +2893,13 @@ function useSlashCommand(inputValue, onSelect) {
|
|
|
2392
2893
|
return fields.some((f) => f.includes(q));
|
|
2393
2894
|
});
|
|
2394
2895
|
}, [isOpen, query]);
|
|
2395
|
-
const close = (0,
|
|
2896
|
+
const close = (0, import_react11.useCallback)(() => {
|
|
2396
2897
|
}, []);
|
|
2397
|
-
const selectTool = (0,
|
|
2898
|
+
const selectTool = (0, import_react11.useCallback)((tool) => {
|
|
2398
2899
|
const command = tool.examples?.[0] || tool.name?.toLowerCase() || tool.toolId;
|
|
2399
2900
|
onSelect(command);
|
|
2400
2901
|
}, [onSelect]);
|
|
2401
|
-
const onKeyDown = (0,
|
|
2902
|
+
const onKeyDown = (0, import_react11.useCallback)((e) => {
|
|
2402
2903
|
if (!isOpen || filteredTools.length === 0) return;
|
|
2403
2904
|
if (e.key === "ArrowDown") {
|
|
2404
2905
|
e.preventDefault();
|
|
@@ -2428,8 +2929,8 @@ function useSlashCommand(inputValue, onSelect) {
|
|
|
2428
2929
|
}
|
|
2429
2930
|
|
|
2430
2931
|
// src/components/SlashCommand/SlashCommandPopup.tsx
|
|
2431
|
-
var
|
|
2432
|
-
var
|
|
2932
|
+
var import_react12 = require("react");
|
|
2933
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2433
2934
|
var MAX_VISIBLE_ITEMS = 8;
|
|
2434
2935
|
var SlashCommandPopup = ({
|
|
2435
2936
|
tools,
|
|
@@ -2437,12 +2938,12 @@ var SlashCommandPopup = ({
|
|
|
2437
2938
|
onSelect,
|
|
2438
2939
|
onClose
|
|
2439
2940
|
}) => {
|
|
2440
|
-
const listRef = (0,
|
|
2441
|
-
const selectedRef = (0,
|
|
2442
|
-
(0,
|
|
2941
|
+
const listRef = (0, import_react12.useRef)(null);
|
|
2942
|
+
const selectedRef = (0, import_react12.useRef)(null);
|
|
2943
|
+
(0, import_react12.useEffect)(() => {
|
|
2443
2944
|
selectedRef.current?.scrollIntoView({ block: "nearest" });
|
|
2444
2945
|
}, [selectedIndex]);
|
|
2445
|
-
(0,
|
|
2946
|
+
(0, import_react12.useEffect)(() => {
|
|
2446
2947
|
const handleClickOutside = (e) => {
|
|
2447
2948
|
if (listRef.current && !listRef.current.contains(e.target)) {
|
|
2448
2949
|
onClose();
|
|
@@ -2454,7 +2955,7 @@ var SlashCommandPopup = ({
|
|
|
2454
2955
|
if (tools.length === 0) return null;
|
|
2455
2956
|
const itemHeight = 52;
|
|
2456
2957
|
const maxHeight = MAX_VISIBLE_ITEMS * itemHeight;
|
|
2457
|
-
return /* @__PURE__ */ (0,
|
|
2958
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2458
2959
|
"div",
|
|
2459
2960
|
{
|
|
2460
2961
|
ref: listRef,
|
|
@@ -2472,7 +2973,7 @@ var SlashCommandPopup = ({
|
|
|
2472
2973
|
},
|
|
2473
2974
|
"data-slash-command-popup": true,
|
|
2474
2975
|
children: [
|
|
2475
|
-
/* @__PURE__ */ (0,
|
|
2976
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: {
|
|
2476
2977
|
padding: "8px 12px 4px",
|
|
2477
2978
|
color: "rgba(255,255,255,0.45)",
|
|
2478
2979
|
fontSize: 11,
|
|
@@ -2485,7 +2986,7 @@ var SlashCommandPopup = ({
|
|
|
2485
2986
|
] }),
|
|
2486
2987
|
tools.map((tool, index) => {
|
|
2487
2988
|
const isSelected = index === selectedIndex;
|
|
2488
|
-
return /* @__PURE__ */ (0,
|
|
2989
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2489
2990
|
"button",
|
|
2490
2991
|
{
|
|
2491
2992
|
ref: isSelected ? selectedRef : void 0,
|
|
@@ -2512,14 +3013,14 @@ var SlashCommandPopup = ({
|
|
|
2512
3013
|
}
|
|
2513
3014
|
},
|
|
2514
3015
|
children: [
|
|
2515
|
-
/* @__PURE__ */ (0,
|
|
2516
|
-
/* @__PURE__ */ (0,
|
|
3016
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { fontSize: 13, fontWeight: 500 }, children: [
|
|
3017
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { style: { color: "rgba(147, 197, 253, 0.9)" }, children: [
|
|
2517
3018
|
"/",
|
|
2518
3019
|
tool.toolId
|
|
2519
3020
|
] }),
|
|
2520
|
-
/* @__PURE__ */ (0,
|
|
3021
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { color: "rgba(255,255,255,0.7)", fontWeight: 400, marginLeft: 8 }, children: tool.name })
|
|
2521
3022
|
] }),
|
|
2522
|
-
tool.description && /* @__PURE__ */ (0,
|
|
3023
|
+
tool.description && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: {
|
|
2523
3024
|
fontSize: 11,
|
|
2524
3025
|
color: "rgba(255,255,255,0.4)",
|
|
2525
3026
|
marginTop: 2,
|
|
@@ -2533,19 +3034,19 @@ var SlashCommandPopup = ({
|
|
|
2533
3034
|
tool.toolId
|
|
2534
3035
|
);
|
|
2535
3036
|
}),
|
|
2536
|
-
/* @__PURE__ */ (0,
|
|
3037
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: {
|
|
2537
3038
|
padding: "6px 12px",
|
|
2538
3039
|
borderTop: "1px solid rgba(255,255,255,0.06)",
|
|
2539
3040
|
color: "rgba(255,255,255,0.3)",
|
|
2540
3041
|
fontSize: 10
|
|
2541
3042
|
}, children: [
|
|
2542
|
-
/* @__PURE__ */ (0,
|
|
3043
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "\u2191\u2193" }),
|
|
2543
3044
|
" navigate",
|
|
2544
3045
|
" ",
|
|
2545
|
-
/* @__PURE__ */ (0,
|
|
3046
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "Enter" }),
|
|
2546
3047
|
" select",
|
|
2547
3048
|
" ",
|
|
2548
|
-
/* @__PURE__ */ (0,
|
|
3049
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("kbd", { style: { padding: "1px 3px", borderRadius: 3, border: "1px solid rgba(255,255,255,0.15)", fontSize: 9 }, children: "Esc" }),
|
|
2549
3050
|
" dismiss"
|
|
2550
3051
|
] })
|
|
2551
3052
|
]
|
|
@@ -2554,7 +3055,7 @@ var SlashCommandPopup = ({
|
|
|
2554
3055
|
};
|
|
2555
3056
|
|
|
2556
3057
|
// src/components/ChatBubble/ChatBubble.tsx
|
|
2557
|
-
var
|
|
3058
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2558
3059
|
var ChatBubble = ({
|
|
2559
3060
|
messages,
|
|
2560
3061
|
onSendMessage,
|
|
@@ -2569,65 +3070,69 @@ var ChatBubble = ({
|
|
|
2569
3070
|
}) => {
|
|
2570
3071
|
const mergedConfig = { ...DEFAULT_CONFIG, ...userConfig };
|
|
2571
3072
|
if (userConfig?.logo && !userConfig?.avatar) {
|
|
2572
|
-
mergedConfig.avatar = /* @__PURE__ */ (0,
|
|
3073
|
+
mergedConfig.avatar = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: userConfig.logo, alt: "Supernal", className: "w-6 h-6" });
|
|
2573
3074
|
}
|
|
2574
3075
|
const config = mergedConfig;
|
|
2575
|
-
const [isExpanded, setIsExpanded] = (0,
|
|
2576
|
-
const [isMinimized, setIsMinimized] = (0,
|
|
2577
|
-
const [inputValue, setInputValue] = (0,
|
|
2578
|
-
const [lastReadMessageCount, setLastReadMessageCount] = (0,
|
|
2579
|
-
const [showWelcome, setShowWelcome] = (0,
|
|
3076
|
+
const [isExpanded, setIsExpanded] = (0, import_react13.useState)(defaultExpanded);
|
|
3077
|
+
const [isMinimized, setIsMinimized] = (0, import_react13.useState)(false);
|
|
3078
|
+
const [inputValue, setInputValue] = (0, import_react13.useState)("");
|
|
3079
|
+
const [lastReadMessageCount, setLastReadMessageCount] = (0, import_react13.useState)(0);
|
|
3080
|
+
const [showWelcome, setShowWelcome] = (0, import_react13.useState)(
|
|
2580
3081
|
config.welcome?.enabled && messages.length === 0
|
|
2581
3082
|
);
|
|
2582
|
-
const [isDragging, setIsDragging] = (0,
|
|
2583
|
-
const [dragInitiated, setDragInitiated] = (0,
|
|
2584
|
-
const [isDocked, setIsDocked] = (0,
|
|
2585
|
-
const [dockPosition, setDockPosition] = (0,
|
|
2586
|
-
const [panelPosition, setPanelPosition] = (0,
|
|
2587
|
-
const [theme, setTheme] = (0,
|
|
2588
|
-
const [showMoreMenu, setShowMoreMenu] = (0,
|
|
2589
|
-
const [, setTimestampTick] = (0,
|
|
2590
|
-
const [localGlassMode, setLocalGlassMode] = (0,
|
|
2591
|
-
const [glassOpacity, setGlassOpacity] = (0,
|
|
2592
|
-
const [notifications, setNotifications] = (0,
|
|
2593
|
-
const [voiceEnabled, setVoiceEnabled] = (0,
|
|
2594
|
-
const [usePremiumVoices, setUsePremiumVoices] = (0,
|
|
2595
|
-
const [autoReadResponses, setAutoReadResponses] = (0,
|
|
2596
|
-
const [ttsSpeed, setTtsSpeed] = (0,
|
|
2597
|
-
const [sttAutoRecordTimeout, setSttAutoRecordTimeout] = (0,
|
|
2598
|
-
const [sttAutoExecute, setSttAutoExecute] = (0,
|
|
2599
|
-
const sttAutoRecordTimeoutRef = (0,
|
|
3083
|
+
const [isDragging, setIsDragging] = (0, import_react13.useState)(false);
|
|
3084
|
+
const [dragInitiated, setDragInitiated] = (0, import_react13.useState)(false);
|
|
3085
|
+
const [isDocked, setIsDocked] = (0, import_react13.useState)(true);
|
|
3086
|
+
const [dockPosition, setDockPosition] = (0, import_react13.useState)(position);
|
|
3087
|
+
const [panelPosition, setPanelPosition] = (0, import_react13.useState)({ x: 0, y: 0 });
|
|
3088
|
+
const [theme, setTheme] = (0, import_react13.useState)("light");
|
|
3089
|
+
const [showMoreMenu, setShowMoreMenu] = (0, import_react13.useState)(false);
|
|
3090
|
+
const [, setTimestampTick] = (0, import_react13.useState)(0);
|
|
3091
|
+
const [localGlassMode, setLocalGlassMode] = (0, import_react13.useState)(config.glassMode ?? true);
|
|
3092
|
+
const [glassOpacity, setGlassOpacity] = (0, import_react13.useState)("medium");
|
|
3093
|
+
const [notifications, setNotifications] = (0, import_react13.useState)(true);
|
|
3094
|
+
const [voiceEnabled, setVoiceEnabled] = (0, import_react13.useState)(true);
|
|
3095
|
+
const [usePremiumVoices, setUsePremiumVoices] = (0, import_react13.useState)(false);
|
|
3096
|
+
const [autoReadResponses, setAutoReadResponses] = (0, import_react13.useState)(false);
|
|
3097
|
+
const [ttsSpeed, setTtsSpeed] = (0, import_react13.useState)(1);
|
|
3098
|
+
const [sttAutoRecordTimeout, setSttAutoRecordTimeout] = (0, import_react13.useState)(5e3);
|
|
3099
|
+
const [sttAutoExecute, setSttAutoExecute] = (0, import_react13.useState)(true);
|
|
3100
|
+
const sttAutoRecordTimeoutRef = (0, import_react13.useRef)(null);
|
|
2600
3101
|
const { speak: speakTTS, stop: stopTTS, isPlaying: isTTSPlaying } = useTTS();
|
|
2601
3102
|
const { startListening, stopListening, transcript: sttTranscript, isListening, resetTranscript } = useSTT();
|
|
3103
|
+
const apiKey = useApiKeyOptional();
|
|
3104
|
+
const [showApiKeyInput, setShowApiKeyInput] = (0, import_react13.useState)(false);
|
|
3105
|
+
const [apiKeyInputValue, setApiKeyInputValue] = (0, import_react13.useState)("");
|
|
3106
|
+
const [showApiKey, setShowApiKey] = (0, import_react13.useState)(false);
|
|
2602
3107
|
const slashCommand = useSlashCommand(inputValue, (command) => {
|
|
2603
3108
|
setInputValue(command);
|
|
2604
3109
|
setTimeout(() => inputRef.current?.focus(), 0);
|
|
2605
3110
|
});
|
|
2606
|
-
const [displayMode, setDisplayMode] = (0,
|
|
2607
|
-
const [drawerSide, setDrawerSide] = (0,
|
|
2608
|
-
const displayModeLoadedFromStorage = (0,
|
|
2609
|
-
(0,
|
|
3111
|
+
const [displayMode, setDisplayMode] = (0, import_react13.useState)(propDisplayMode);
|
|
3112
|
+
const [drawerSide, setDrawerSide] = (0, import_react13.useState)(propDrawerSide);
|
|
3113
|
+
const displayModeLoadedFromStorage = (0, import_react13.useRef)(false);
|
|
3114
|
+
(0, import_react13.useEffect)(() => {
|
|
2610
3115
|
if (!displayModeLoadedFromStorage.current) {
|
|
2611
3116
|
setDisplayMode(propDisplayMode);
|
|
2612
3117
|
}
|
|
2613
3118
|
}, [propDisplayMode]);
|
|
2614
|
-
const [drawerOpen, setDrawerOpen] = (0,
|
|
2615
|
-
const [touchStart, setTouchStart] = (0,
|
|
2616
|
-
const [swipeProgress, setSwipeProgress] = (0,
|
|
2617
|
-
const [isMobile, setIsMobile] = (0,
|
|
2618
|
-
const lastEscapeTimeRef = (0,
|
|
3119
|
+
const [drawerOpen, setDrawerOpen] = (0, import_react13.useState)(false);
|
|
3120
|
+
const [touchStart, setTouchStart] = (0, import_react13.useState)(null);
|
|
3121
|
+
const [swipeProgress, setSwipeProgress] = (0, import_react13.useState)(0);
|
|
3122
|
+
const [isMobile, setIsMobile] = (0, import_react13.useState)(false);
|
|
3123
|
+
const lastEscapeTimeRef = (0, import_react13.useRef)(0);
|
|
2619
3124
|
const DOUBLE_ESCAPE_THRESHOLD_MS = 500;
|
|
2620
|
-
const [isMac, setIsMac] = (0,
|
|
2621
|
-
const [currentHintIndex, setCurrentHintIndex] = (0,
|
|
2622
|
-
const [isHydrated, setIsHydrated] = (0,
|
|
2623
|
-
(0,
|
|
3125
|
+
const [isMac, setIsMac] = (0, import_react13.useState)(false);
|
|
3126
|
+
const [currentHintIndex, setCurrentHintIndex] = (0, import_react13.useState)(0);
|
|
3127
|
+
const [isHydrated, setIsHydrated] = (0, import_react13.useState)(false);
|
|
3128
|
+
(0, import_react13.useEffect)(() => {
|
|
2624
3129
|
if (typeof window !== "undefined") {
|
|
2625
3130
|
const platform = window.navigator.platform.toLowerCase();
|
|
2626
3131
|
const isMacPlatform = platform.includes("mac");
|
|
2627
3132
|
setIsMac(isMacPlatform);
|
|
2628
3133
|
}
|
|
2629
3134
|
}, []);
|
|
2630
|
-
const inputHints = (0,
|
|
3135
|
+
const inputHints = (0, import_react13.useMemo)(() => {
|
|
2631
3136
|
const modKey = isMac ? "Cmd" : "Ctrl";
|
|
2632
3137
|
return [
|
|
2633
3138
|
`Press ${modKey}+/ to start voice recording`,
|
|
@@ -2636,14 +3141,14 @@ var ChatBubble = ({
|
|
|
2636
3141
|
sttAutoExecute ? `Voice commands execute automatically` : "Voice commands fill this input"
|
|
2637
3142
|
];
|
|
2638
3143
|
}, [isMac, sttAutoExecute]);
|
|
2639
|
-
(0,
|
|
3144
|
+
(0, import_react13.useEffect)(() => {
|
|
2640
3145
|
setCurrentHintIndex((prev) => (prev + 1) % inputHints.length);
|
|
2641
3146
|
}, [messages.length, inputHints.length]);
|
|
2642
|
-
const messagesEndRef = (0,
|
|
2643
|
-
const inputRef = (0,
|
|
2644
|
-
const panelRef = (0,
|
|
2645
|
-
const dragRef = (0,
|
|
2646
|
-
const rafRef = (0,
|
|
3147
|
+
const messagesEndRef = (0, import_react13.useRef)(null);
|
|
3148
|
+
const inputRef = (0, import_react13.useRef)(null);
|
|
3149
|
+
const panelRef = (0, import_react13.useRef)(null);
|
|
3150
|
+
const dragRef = (0, import_react13.useRef)(null);
|
|
3151
|
+
const rafRef = (0, import_react13.useRef)(null);
|
|
2647
3152
|
const formatRelativeTime = (timestamp) => {
|
|
2648
3153
|
const now = /* @__PURE__ */ new Date();
|
|
2649
3154
|
const messageTime = new Date(timestamp);
|
|
@@ -2658,7 +3163,7 @@ var ChatBubble = ({
|
|
|
2658
3163
|
if (diffDays < 7) return `${diffDays} ${diffDays === 1 ? "day" : "days"} ago`;
|
|
2659
3164
|
return messageTime.toLocaleDateString();
|
|
2660
3165
|
};
|
|
2661
|
-
(0,
|
|
3166
|
+
(0, import_react13.useEffect)(() => {
|
|
2662
3167
|
if (variant === "floating" && panelPosition.x === 0 && panelPosition.y === 0) {
|
|
2663
3168
|
try {
|
|
2664
3169
|
const stored = localStorage.getItem(storageKey);
|
|
@@ -2680,7 +3185,7 @@ var ChatBubble = ({
|
|
|
2680
3185
|
}
|
|
2681
3186
|
}
|
|
2682
3187
|
}, [variant, storageKey, panelPosition.x, panelPosition.y]);
|
|
2683
|
-
(0,
|
|
3188
|
+
(0, import_react13.useEffect)(() => {
|
|
2684
3189
|
if (variant === "full" || variant === "drawer" || variant === "subtitle") {
|
|
2685
3190
|
try {
|
|
2686
3191
|
const stored = localStorage.getItem(storageKey);
|
|
@@ -2758,12 +3263,12 @@ var ChatBubble = ({
|
|
|
2758
3263
|
}
|
|
2759
3264
|
setIsHydrated(true);
|
|
2760
3265
|
}, [storageKey, variant, defaultExpanded, position]);
|
|
2761
|
-
(0,
|
|
3266
|
+
(0, import_react13.useEffect)(() => {
|
|
2762
3267
|
if (variant !== "full" && variant !== "drawer" && variant !== "subtitle") {
|
|
2763
3268
|
setIsHydrated(true);
|
|
2764
3269
|
}
|
|
2765
3270
|
}, [variant]);
|
|
2766
|
-
(0,
|
|
3271
|
+
(0, import_react13.useEffect)(() => {
|
|
2767
3272
|
if (!isExpanded || isDocked || !panelRef.current) return;
|
|
2768
3273
|
const checkBounds = () => {
|
|
2769
3274
|
const rect = panelRef.current?.getBoundingClientRect();
|
|
@@ -2780,7 +3285,7 @@ var ChatBubble = ({
|
|
|
2780
3285
|
const timeoutId = setTimeout(checkBounds, 100);
|
|
2781
3286
|
return () => clearTimeout(timeoutId);
|
|
2782
3287
|
}, [isExpanded, isDocked]);
|
|
2783
|
-
(0,
|
|
3288
|
+
(0, import_react13.useEffect)(() => {
|
|
2784
3289
|
const isSubtitleMode = displayMode === "subtitle" || displayMode === "auto" && variant === "subtitle";
|
|
2785
3290
|
if (isSubtitleMode) return;
|
|
2786
3291
|
const handleKeyDown = (e) => {
|
|
@@ -2813,13 +3318,13 @@ var ChatBubble = ({
|
|
|
2813
3318
|
window.addEventListener("keydown", handleKeyDown);
|
|
2814
3319
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
2815
3320
|
}, [isExpanded, isDocked, position, variant, displayMode, isMobile]);
|
|
2816
|
-
(0,
|
|
3321
|
+
(0, import_react13.useEffect)(() => {
|
|
2817
3322
|
if (typeof window !== "undefined") {
|
|
2818
3323
|
const isDark = document.documentElement.getAttribute("data-theme") === "dark";
|
|
2819
3324
|
setTheme(isDark ? "dark" : "light");
|
|
2820
3325
|
}
|
|
2821
3326
|
}, []);
|
|
2822
|
-
(0,
|
|
3327
|
+
(0, import_react13.useEffect)(() => {
|
|
2823
3328
|
if (typeof window === "undefined") return;
|
|
2824
3329
|
const mediaQuery = window.matchMedia("(max-width: 767px)");
|
|
2825
3330
|
const handleChange = (e) => {
|
|
@@ -2829,26 +3334,26 @@ var ChatBubble = ({
|
|
|
2829
3334
|
mediaQuery.addEventListener("change", handleChange);
|
|
2830
3335
|
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
2831
3336
|
}, []);
|
|
2832
|
-
const currentVariant =
|
|
3337
|
+
const currentVariant = import_react13.default.useMemo(() => {
|
|
2833
3338
|
if (displayMode !== "auto") {
|
|
2834
3339
|
return displayMode;
|
|
2835
3340
|
}
|
|
2836
3341
|
return isMobile && variant === "full" ? "subtitle" : variant;
|
|
2837
3342
|
}, [displayMode, isMobile, variant]);
|
|
2838
|
-
const prevVariantRef =
|
|
2839
|
-
(0,
|
|
3343
|
+
const prevVariantRef = import_react13.default.useRef(variant);
|
|
3344
|
+
(0, import_react13.useEffect)(() => {
|
|
2840
3345
|
if (prevVariantRef.current !== variant && displayMode !== "auto") {
|
|
2841
3346
|
setDisplayMode("auto");
|
|
2842
3347
|
prevVariantRef.current = variant;
|
|
2843
3348
|
}
|
|
2844
3349
|
}, [variant, displayMode]);
|
|
2845
|
-
(0,
|
|
3350
|
+
(0, import_react13.useEffect)(() => {
|
|
2846
3351
|
const interval = setInterval(() => {
|
|
2847
3352
|
setTimestampTick((tick) => tick + 1);
|
|
2848
3353
|
}, 6e4);
|
|
2849
3354
|
return () => clearInterval(interval);
|
|
2850
3355
|
}, []);
|
|
2851
|
-
(0,
|
|
3356
|
+
(0, import_react13.useEffect)(() => {
|
|
2852
3357
|
if (variant === "full" || variant === "drawer" || variant === "subtitle") {
|
|
2853
3358
|
try {
|
|
2854
3359
|
localStorage.setItem(
|
|
@@ -2880,7 +3385,7 @@ var ChatBubble = ({
|
|
|
2880
3385
|
}
|
|
2881
3386
|
}, [isExpanded, isMinimized, isDocked, dockPosition, panelPosition, theme, localGlassMode, notifications, displayMode, drawerSide, drawerOpen, glassOpacity, voiceEnabled, usePremiumVoices, autoReadResponses, ttsSpeed, sttAutoRecordTimeout, sttAutoExecute, storageKey, variant]);
|
|
2882
3387
|
const { registerInput } = useChatInput();
|
|
2883
|
-
(0,
|
|
3388
|
+
(0, import_react13.useEffect)(() => {
|
|
2884
3389
|
registerInput((text, submit = false) => {
|
|
2885
3390
|
setInputValue(text);
|
|
2886
3391
|
if (!isExpanded && variant === "full") {
|
|
@@ -2897,7 +3402,7 @@ var ChatBubble = ({
|
|
|
2897
3402
|
}, [registerInput, onSendMessage]);
|
|
2898
3403
|
const unreadCount = Math.max(0, messages.length - lastReadMessageCount);
|
|
2899
3404
|
const hasUnread = unreadCount > 0 && !isExpanded && variant === "full";
|
|
2900
|
-
(0,
|
|
3405
|
+
(0, import_react13.useEffect)(() => {
|
|
2901
3406
|
if (isExpanded || variant === "floating") {
|
|
2902
3407
|
messagesEndRef.current?.scrollIntoView({ behavior: "auto" });
|
|
2903
3408
|
setLastReadMessageCount(messages.length);
|
|
@@ -2909,12 +3414,12 @@ var ChatBubble = ({
|
|
|
2909
3414
|
}
|
|
2910
3415
|
}
|
|
2911
3416
|
}, [messages, isExpanded, variant]);
|
|
2912
|
-
(0,
|
|
3417
|
+
(0, import_react13.useEffect)(() => {
|
|
2913
3418
|
if (isExpanded && variant === "full") {
|
|
2914
3419
|
inputRef.current?.focus();
|
|
2915
3420
|
}
|
|
2916
3421
|
}, [isExpanded, variant]);
|
|
2917
|
-
(0,
|
|
3422
|
+
(0, import_react13.useEffect)(() => {
|
|
2918
3423
|
if (!voiceEnabled || !autoReadResponses || messages.length === 0) return;
|
|
2919
3424
|
const lastMessage = messages[messages.length - 1];
|
|
2920
3425
|
if (lastMessage.type === "ai") {
|
|
@@ -2926,7 +3431,7 @@ var ChatBubble = ({
|
|
|
2926
3431
|
});
|
|
2927
3432
|
}
|
|
2928
3433
|
}, [messages, voiceEnabled, autoReadResponses, ttsSpeed, usePremiumVoices, speakTTS]);
|
|
2929
|
-
(0,
|
|
3434
|
+
(0, import_react13.useEffect)(() => {
|
|
2930
3435
|
if (currentVariant === "subtitle") return;
|
|
2931
3436
|
if (sttTranscript && voiceEnabled) {
|
|
2932
3437
|
setInputValue(sttTranscript);
|
|
@@ -2941,7 +3446,7 @@ var ChatBubble = ({
|
|
|
2941
3446
|
}
|
|
2942
3447
|
}
|
|
2943
3448
|
}, [sttTranscript, voiceEnabled, resetTranscript, sttAutoExecute, onSendMessage, currentVariant]);
|
|
2944
|
-
(0,
|
|
3449
|
+
(0, import_react13.useEffect)(() => {
|
|
2945
3450
|
if (currentVariant === "subtitle") return;
|
|
2946
3451
|
const handleKeyDown = (e) => {
|
|
2947
3452
|
if ((e.metaKey || e.ctrlKey) && e.key === "/" && voiceEnabled) {
|
|
@@ -2999,7 +3504,7 @@ var ChatBubble = ({
|
|
|
2999
3504
|
}
|
|
3000
3505
|
};
|
|
3001
3506
|
}, [currentVariant, isExpanded, showMoreMenu, voiceEnabled, isListening, startListening, stopListening, sttAutoRecordTimeout]);
|
|
3002
|
-
(0,
|
|
3507
|
+
(0, import_react13.useEffect)(() => {
|
|
3003
3508
|
if (currentVariant !== "drawer") return;
|
|
3004
3509
|
const handleKeyDown = (e) => {
|
|
3005
3510
|
if (e.key === "Escape" && drawerOpen) {
|
|
@@ -3009,7 +3514,7 @@ var ChatBubble = ({
|
|
|
3009
3514
|
window.addEventListener("keydown", handleKeyDown);
|
|
3010
3515
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
3011
3516
|
}, [currentVariant, drawerOpen]);
|
|
3012
|
-
(0,
|
|
3517
|
+
(0, import_react13.useEffect)(() => {
|
|
3013
3518
|
if (!showMoreMenu) return;
|
|
3014
3519
|
const handleClickOutside = (e) => {
|
|
3015
3520
|
const target = e.target;
|
|
@@ -3020,7 +3525,7 @@ var ChatBubble = ({
|
|
|
3020
3525
|
document.addEventListener("mousedown", handleClickOutside);
|
|
3021
3526
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
3022
3527
|
}, [showMoreMenu]);
|
|
3023
|
-
(0,
|
|
3528
|
+
(0, import_react13.useEffect)(() => {
|
|
3024
3529
|
if (typeof window === "undefined" || currentVariant !== "drawer") return;
|
|
3025
3530
|
const EDGE_ZONE_PX = 20;
|
|
3026
3531
|
const SWIPE_THRESHOLD = 0.4;
|
|
@@ -3105,7 +3610,7 @@ var ChatBubble = ({
|
|
|
3105
3610
|
};
|
|
3106
3611
|
}
|
|
3107
3612
|
};
|
|
3108
|
-
(0,
|
|
3613
|
+
(0, import_react13.useEffect)(() => {
|
|
3109
3614
|
if (!dragInitiated || !dragRef.current) return;
|
|
3110
3615
|
const dragThresholdPx = 5;
|
|
3111
3616
|
const handleMouseMove = (e) => {
|
|
@@ -3268,7 +3773,7 @@ var ChatBubble = ({
|
|
|
3268
3773
|
return null;
|
|
3269
3774
|
}
|
|
3270
3775
|
if (currentVariant === "subtitle") {
|
|
3271
|
-
return /* @__PURE__ */ (0,
|
|
3776
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3272
3777
|
SubtitleOverlay,
|
|
3273
3778
|
{
|
|
3274
3779
|
messages,
|
|
@@ -3300,8 +3805,8 @@ var ChatBubble = ({
|
|
|
3300
3805
|
}
|
|
3301
3806
|
if (currentVariant === "drawer") {
|
|
3302
3807
|
const drawerWidth = "100vw";
|
|
3303
|
-
return /* @__PURE__ */ (0,
|
|
3304
|
-
(drawerOpen || swipeProgress > 0) && /* @__PURE__ */ (0,
|
|
3808
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
3809
|
+
(drawerOpen || swipeProgress > 0) && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3305
3810
|
"div",
|
|
3306
3811
|
{
|
|
3307
3812
|
className: "fixed inset-0 bg-black z-[49998] transition-opacity duration-300",
|
|
@@ -3313,7 +3818,7 @@ var ChatBubble = ({
|
|
|
3313
3818
|
onClick: () => setDrawerOpen(false)
|
|
3314
3819
|
}
|
|
3315
3820
|
),
|
|
3316
|
-
/* @__PURE__ */ (0,
|
|
3821
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3317
3822
|
"div",
|
|
3318
3823
|
{
|
|
3319
3824
|
className: `fixed ${drawerSide === "right" ? "right-0" : "left-0"} top-0 h-full z-[49999] flex flex-col ${glassClasses} shadow-2xl`,
|
|
@@ -3332,31 +3837,31 @@ var ChatBubble = ({
|
|
|
3332
3837
|
onTouchMove: handleDrawerTouchMove,
|
|
3333
3838
|
onTouchEnd: handleDrawerTouchEnd,
|
|
3334
3839
|
children: [
|
|
3335
|
-
/* @__PURE__ */ (0,
|
|
3336
|
-
/* @__PURE__ */ (0,
|
|
3337
|
-
config.avatar && /* @__PURE__ */ (0,
|
|
3338
|
-
/* @__PURE__ */ (0,
|
|
3339
|
-
/* @__PURE__ */ (0,
|
|
3840
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `${THEME_CLASSES.bg.header} ${glassMode ? THEME_CLASSES.bg.headerGradient : THEME_CLASSES.bg.headerLight}`, children: [
|
|
3841
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center space-x-3", children: [
|
|
3842
|
+
config.avatar && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "relative flex-shrink-0", children: [
|
|
3843
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Avatar, { avatar: config.avatar }),
|
|
3844
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
|
|
3340
3845
|
] }),
|
|
3341
|
-
config.title && /* @__PURE__ */ (0,
|
|
3846
|
+
config.title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
|
|
3342
3847
|
] }),
|
|
3343
|
-
/* @__PURE__ */ (0,
|
|
3848
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setDrawerOpen(false), className: THEME_CLASSES.button.close, title: "Close drawer", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
|
|
3344
3849
|
] }),
|
|
3345
|
-
/* @__PURE__ */ (0,
|
|
3346
|
-
showWelcome && messages.length === 0 && config.welcome?.enabled && /* @__PURE__ */ (0,
|
|
3347
|
-
config.welcome.title && /* @__PURE__ */ (0,
|
|
3348
|
-
config.welcome.content && /* @__PURE__ */ (0,
|
|
3850
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 overflow-y-auto p-4 space-y-2", "data-testid": "chat-messages", children: [
|
|
3851
|
+
showWelcome && messages.length === 0 && config.welcome?.enabled && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: THEME_CLASSES.welcome.container, children: [
|
|
3852
|
+
config.welcome.title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h4", { className: THEME_CLASSES.welcome.title, style: INLINE_STYLES.welcomeTitle(theme === "dark"), children: config.welcome.title }),
|
|
3853
|
+
config.welcome.content && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: THEME_CLASSES.welcome.content, style: INLINE_STYLES.welcomeContent(theme === "dark"), children: config.welcome.content })
|
|
3349
3854
|
] }),
|
|
3350
|
-
messages.map((message) => /* @__PURE__ */ (0,
|
|
3351
|
-
/* @__PURE__ */ (0,
|
|
3855
|
+
messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `group flex items-center gap-1 mb-2 ${message.type === "user" ? "flex-row-reverse" : "flex-row"}`, children: [
|
|
3856
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3352
3857
|
"div",
|
|
3353
3858
|
{
|
|
3354
3859
|
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}`,
|
|
3355
3860
|
style: message.type === "user" ? INLINE_STYLES.messageUser() : message.type === "ai" ? INLINE_STYLES.messageAI(theme === "dark") : INLINE_STYLES.messageSystem(theme === "dark"),
|
|
3356
|
-
children: /* @__PURE__ */ (0,
|
|
3861
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MessageRenderer, { content: message.text, theme })
|
|
3357
3862
|
}
|
|
3358
3863
|
),
|
|
3359
|
-
message.type === "ai" && voiceEnabled && /* @__PURE__ */ (0,
|
|
3864
|
+
message.type === "ai" && voiceEnabled && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3360
3865
|
TTSButton,
|
|
3361
3866
|
{
|
|
3362
3867
|
text: message.text,
|
|
@@ -3366,7 +3871,7 @@ var ChatBubble = ({
|
|
|
3366
3871
|
size: "small"
|
|
3367
3872
|
}
|
|
3368
3873
|
),
|
|
3369
|
-
/* @__PURE__ */ (0,
|
|
3874
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3370
3875
|
"div",
|
|
3371
3876
|
{
|
|
3372
3877
|
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"}`,
|
|
@@ -3375,10 +3880,10 @@ var ChatBubble = ({
|
|
|
3375
3880
|
}
|
|
3376
3881
|
)
|
|
3377
3882
|
] }, message.id)),
|
|
3378
|
-
/* @__PURE__ */ (0,
|
|
3883
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { ref: messagesEndRef })
|
|
3379
3884
|
] }),
|
|
3380
|
-
/* @__PURE__ */ (0,
|
|
3381
|
-
slashCommand.isOpen && /* @__PURE__ */ (0,
|
|
3885
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { position: "relative" }, children: [
|
|
3886
|
+
slashCommand.isOpen && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3382
3887
|
SlashCommandPopup,
|
|
3383
3888
|
{
|
|
3384
3889
|
tools: slashCommand.filteredTools,
|
|
@@ -3387,7 +3892,7 @@ var ChatBubble = ({
|
|
|
3387
3892
|
onClose: () => setInputValue("")
|
|
3388
3893
|
}
|
|
3389
3894
|
),
|
|
3390
|
-
/* @__PURE__ */ (0,
|
|
3895
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3391
3896
|
InputField,
|
|
3392
3897
|
{
|
|
3393
3898
|
inputValue,
|
|
@@ -3409,20 +3914,20 @@ var ChatBubble = ({
|
|
|
3409
3914
|
]
|
|
3410
3915
|
}
|
|
3411
3916
|
),
|
|
3412
|
-
!drawerOpen && /* @__PURE__ */ (0,
|
|
3917
|
+
!drawerOpen && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3413
3918
|
"div",
|
|
3414
3919
|
{
|
|
3415
3920
|
className: `fixed ${drawerSide === "right" ? "right-0" : "left-0"} bottom-20 opacity-70 hover:opacity-100 transition-opacity duration-300 z-[999999] cursor-pointer`,
|
|
3416
3921
|
style: { zIndex: 999999 },
|
|
3417
3922
|
onClick: () => setDrawerOpen(true),
|
|
3418
|
-
children: /* @__PURE__ */ (0,
|
|
3923
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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" }) }) })
|
|
3419
3924
|
}
|
|
3420
3925
|
)
|
|
3421
3926
|
] });
|
|
3422
3927
|
}
|
|
3423
3928
|
if (currentVariant === "floating") {
|
|
3424
3929
|
const recentMessage = messages[messages.length - 1];
|
|
3425
|
-
return /* @__PURE__ */ (0,
|
|
3930
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3426
3931
|
"div",
|
|
3427
3932
|
{
|
|
3428
3933
|
className: `fixed z-[999999] ${isDragging ? "cursor-grabbing" : "cursor-grab"}`,
|
|
@@ -3435,32 +3940,32 @@ var ChatBubble = ({
|
|
|
3435
3940
|
...!isDragging && { transition: "transform 0.3s cubic-bezier(0.4, 0, 0.2, 1)" }
|
|
3436
3941
|
},
|
|
3437
3942
|
onMouseDown: handlePanelMouseDown,
|
|
3438
|
-
children: /* @__PURE__ */ (0,
|
|
3439
|
-
/* @__PURE__ */ (0,
|
|
3440
|
-
/* @__PURE__ */ (0,
|
|
3441
|
-
/* @__PURE__ */ (0,
|
|
3442
|
-
config.title && /* @__PURE__ */ (0,
|
|
3943
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `${glassClasses} rounded-2xl shadow-2xl p-3 max-w-xs ${!glassMode && "border-gray-200 border"}`, children: [
|
|
3944
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
|
|
3945
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center space-x-2", children: [
|
|
3946
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Avatar, { avatar: config.avatar, size: "small" }),
|
|
3947
|
+
config.title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: THEME_CLASSES.text.floatingTitle, children: config.title })
|
|
3443
3948
|
] }),
|
|
3444
|
-
onClearChat && /* @__PURE__ */ (0,
|
|
3949
|
+
onClearChat && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3445
3950
|
"button",
|
|
3446
3951
|
{
|
|
3447
3952
|
onClick: onClearChat,
|
|
3448
3953
|
className: THEME_CLASSES.button.floatingClear,
|
|
3449
3954
|
title: "Clear chat",
|
|
3450
3955
|
"data-testid": ChatNames.clearButton,
|
|
3451
|
-
children: /* @__PURE__ */ (0,
|
|
3956
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
3452
3957
|
}
|
|
3453
3958
|
)
|
|
3454
3959
|
] }),
|
|
3455
|
-
recentMessage && /* @__PURE__ */ (0,
|
|
3456
|
-
/* @__PURE__ */ (0,
|
|
3960
|
+
recentMessage && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `mb-2 group flex items-center gap-2 ${recentMessage.type === "user" ? "flex-row-reverse" : "flex-row"}`, children: [
|
|
3961
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3457
3962
|
"div",
|
|
3458
3963
|
{
|
|
3459
3964
|
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"}`,
|
|
3460
3965
|
children: recentMessage.text.length > 60 ? `${recentMessage.text.slice(0, 60)}...` : recentMessage.text
|
|
3461
3966
|
}
|
|
3462
3967
|
),
|
|
3463
|
-
/* @__PURE__ */ (0,
|
|
3968
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3464
3969
|
"div",
|
|
3465
3970
|
{
|
|
3466
3971
|
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"}`,
|
|
@@ -3469,8 +3974,8 @@ var ChatBubble = ({
|
|
|
3469
3974
|
}
|
|
3470
3975
|
)
|
|
3471
3976
|
] }),
|
|
3472
|
-
/* @__PURE__ */ (0,
|
|
3473
|
-
slashCommand.isOpen && /* @__PURE__ */ (0,
|
|
3977
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { position: "relative" }, children: [
|
|
3978
|
+
slashCommand.isOpen && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3474
3979
|
SlashCommandPopup,
|
|
3475
3980
|
{
|
|
3476
3981
|
tools: slashCommand.filteredTools,
|
|
@@ -3479,7 +3984,7 @@ var ChatBubble = ({
|
|
|
3479
3984
|
onClose: () => setInputValue("")
|
|
3480
3985
|
}
|
|
3481
3986
|
),
|
|
3482
|
-
/* @__PURE__ */ (0,
|
|
3987
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3483
3988
|
InputField,
|
|
3484
3989
|
{
|
|
3485
3990
|
compact: true,
|
|
@@ -3499,7 +4004,7 @@ var ChatBubble = ({
|
|
|
3499
4004
|
}
|
|
3500
4005
|
);
|
|
3501
4006
|
}
|
|
3502
|
-
return /* @__PURE__ */ (0,
|
|
4007
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3503
4008
|
"div",
|
|
3504
4009
|
{
|
|
3505
4010
|
className: "fixed",
|
|
@@ -3517,7 +4022,7 @@ var ChatBubble = ({
|
|
|
3517
4022
|
}
|
|
3518
4023
|
},
|
|
3519
4024
|
children: [
|
|
3520
|
-
isExpanded && isMinimized && /* @__PURE__ */ (0,
|
|
4025
|
+
isExpanded && isMinimized && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3521
4026
|
"div",
|
|
3522
4027
|
{
|
|
3523
4028
|
ref: panelRef,
|
|
@@ -3535,7 +4040,7 @@ var ChatBubble = ({
|
|
|
3535
4040
|
...isDragging && { cursor: "grabbing" }
|
|
3536
4041
|
},
|
|
3537
4042
|
children: [
|
|
3538
|
-
/* @__PURE__ */ (0,
|
|
4043
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3539
4044
|
"div",
|
|
3540
4045
|
{
|
|
3541
4046
|
"data-drag-handle": true,
|
|
@@ -3551,15 +4056,15 @@ var ChatBubble = ({
|
|
|
3551
4056
|
}
|
|
3552
4057
|
},
|
|
3553
4058
|
children: [
|
|
3554
|
-
/* @__PURE__ */ (0,
|
|
3555
|
-
config.avatar && /* @__PURE__ */ (0,
|
|
3556
|
-
/* @__PURE__ */ (0,
|
|
3557
|
-
/* @__PURE__ */ (0,
|
|
4059
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center space-x-3", children: [
|
|
4060
|
+
config.avatar && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "relative flex-shrink-0", children: [
|
|
4061
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Avatar, { avatar: config.avatar }),
|
|
4062
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
|
|
3558
4063
|
] }),
|
|
3559
|
-
config.title && /* @__PURE__ */ (0,
|
|
4064
|
+
config.title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
|
|
3560
4065
|
] }),
|
|
3561
|
-
/* @__PURE__ */ (0,
|
|
3562
|
-
/* @__PURE__ */ (0,
|
|
4066
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center space-x-1 flex-shrink-0", children: [
|
|
4067
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3563
4068
|
"button",
|
|
3564
4069
|
{
|
|
3565
4070
|
onClick: (e) => {
|
|
@@ -3568,10 +4073,10 @@ var ChatBubble = ({
|
|
|
3568
4073
|
},
|
|
3569
4074
|
className: THEME_CLASSES.button.minimize,
|
|
3570
4075
|
title: "Minimize chat",
|
|
3571
|
-
children: /* @__PURE__ */ (0,
|
|
4076
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
|
|
3572
4077
|
}
|
|
3573
4078
|
),
|
|
3574
|
-
/* @__PURE__ */ (0,
|
|
4079
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3575
4080
|
"button",
|
|
3576
4081
|
{
|
|
3577
4082
|
onClick: (e) => {
|
|
@@ -3580,20 +4085,20 @@ var ChatBubble = ({
|
|
|
3580
4085
|
},
|
|
3581
4086
|
className: THEME_CLASSES.button.close,
|
|
3582
4087
|
title: "Close chat",
|
|
3583
|
-
children: /* @__PURE__ */ (0,
|
|
4088
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
3584
4089
|
}
|
|
3585
4090
|
)
|
|
3586
4091
|
] })
|
|
3587
4092
|
]
|
|
3588
4093
|
}
|
|
3589
4094
|
),
|
|
3590
|
-
/* @__PURE__ */ (0,
|
|
4095
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "p-4", children: [
|
|
3591
4096
|
(() => {
|
|
3592
4097
|
const lastAiMessage = [...messages].reverse().find((m) => m.type === "ai");
|
|
3593
|
-
return lastAiMessage ? /* @__PURE__ */ (0,
|
|
4098
|
+
return lastAiMessage ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: THEME_CLASSES.text.minimizedMessage, style: INLINE_STYLES.minimizedMessage(theme === "dark"), children: "No AI responses yet" }) });
|
|
3594
4099
|
})(),
|
|
3595
|
-
/* @__PURE__ */ (0,
|
|
3596
|
-
slashCommand.isOpen && /* @__PURE__ */ (0,
|
|
4100
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { position: "relative" }, children: [
|
|
4101
|
+
slashCommand.isOpen && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3597
4102
|
SlashCommandPopup,
|
|
3598
4103
|
{
|
|
3599
4104
|
tools: slashCommand.filteredTools,
|
|
@@ -3602,7 +4107,7 @@ var ChatBubble = ({
|
|
|
3602
4107
|
onClose: () => setInputValue("")
|
|
3603
4108
|
}
|
|
3604
4109
|
),
|
|
3605
|
-
/* @__PURE__ */ (0,
|
|
4110
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3606
4111
|
InputField,
|
|
3607
4112
|
{
|
|
3608
4113
|
compact: true,
|
|
@@ -3622,7 +4127,7 @@ var ChatBubble = ({
|
|
|
3622
4127
|
]
|
|
3623
4128
|
}
|
|
3624
4129
|
),
|
|
3625
|
-
isExpanded && !isMinimized && /* @__PURE__ */ (0,
|
|
4130
|
+
isExpanded && !isMinimized && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3626
4131
|
"div",
|
|
3627
4132
|
{
|
|
3628
4133
|
ref: panelRef,
|
|
@@ -3640,22 +4145,22 @@ var ChatBubble = ({
|
|
|
3640
4145
|
...isDragging && { cursor: "grabbing" }
|
|
3641
4146
|
},
|
|
3642
4147
|
children: [
|
|
3643
|
-
/* @__PURE__ */ (0,
|
|
4148
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3644
4149
|
"div",
|
|
3645
4150
|
{
|
|
3646
4151
|
"data-drag-handle": true,
|
|
3647
4152
|
className: `${THEME_CLASSES.bg.header} ${glassMode ? THEME_CLASSES.bg.headerGradient : THEME_CLASSES.bg.headerLight} cursor-move`,
|
|
3648
4153
|
onMouseDown: handlePanelMouseDown,
|
|
3649
4154
|
children: [
|
|
3650
|
-
/* @__PURE__ */ (0,
|
|
3651
|
-
config.avatar && /* @__PURE__ */ (0,
|
|
3652
|
-
/* @__PURE__ */ (0,
|
|
3653
|
-
/* @__PURE__ */ (0,
|
|
4155
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center space-x-3", children: [
|
|
4156
|
+
config.avatar && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "relative flex-shrink-0", children: [
|
|
4157
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Avatar, { avatar: config.avatar }),
|
|
4158
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute -bottom-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
|
|
3654
4159
|
] }),
|
|
3655
|
-
config.title && /* @__PURE__ */ (0,
|
|
4160
|
+
config.title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h3", { className: THEME_CLASSES.text.title, children: config.title }) })
|
|
3656
4161
|
] }),
|
|
3657
|
-
/* @__PURE__ */ (0,
|
|
3658
|
-
/* @__PURE__ */ (0,
|
|
4162
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center space-x-1 flex-shrink-0 relative", "data-more-menu": true, children: [
|
|
4163
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3659
4164
|
"a",
|
|
3660
4165
|
{
|
|
3661
4166
|
href: "https://www.interface.supernal.ai",
|
|
@@ -3663,30 +4168,160 @@ var ChatBubble = ({
|
|
|
3663
4168
|
rel: "noopener noreferrer",
|
|
3664
4169
|
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",
|
|
3665
4170
|
title: "Visit Supernal Interface Documentation",
|
|
3666
|
-
children: /* @__PURE__ */ (0,
|
|
4171
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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" }) })
|
|
3667
4172
|
}
|
|
3668
4173
|
),
|
|
3669
|
-
/* @__PURE__ */ (0,
|
|
4174
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3670
4175
|
"button",
|
|
3671
4176
|
{
|
|
3672
4177
|
onClick: () => setShowMoreMenu(!showMoreMenu),
|
|
3673
4178
|
className: THEME_CLASSES.button.more,
|
|
3674
4179
|
title: "More options",
|
|
3675
|
-
|
|
4180
|
+
"data-testid": "chat-more-menu-button",
|
|
4181
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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" }) })
|
|
3676
4182
|
}
|
|
3677
4183
|
),
|
|
3678
|
-
showMoreMenu && /* @__PURE__ */ (0,
|
|
3679
|
-
/* @__PURE__ */ (0,
|
|
3680
|
-
/* @__PURE__ */ (0,
|
|
4184
|
+
showMoreMenu && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("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: [
|
|
4185
|
+
apiKey && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "px-3 py-2 border-b border-gray-200 dark:border-gray-600 mb-2", "data-testid": "api-key-section", children: [
|
|
4186
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
|
|
4187
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-200 flex items-center gap-2", children: [
|
|
4188
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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" }) }),
|
|
4189
|
+
"API Key"
|
|
4190
|
+
] }),
|
|
4191
|
+
apiKey.status === "valid" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-green-500", title: "API key is valid", "data-testid": "api-key-status", "data-status": "valid", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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" }) }) }),
|
|
4192
|
+
apiKey.status === "invalid" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-red-500", title: "API key is invalid", "data-testid": "api-key-status", "data-status": "invalid", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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" }) }) }),
|
|
4193
|
+
apiKey.status === "validating" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-blue-500 animate-spin", title: "Validating...", "data-testid": "api-key-status", "data-status": "validating", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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" }) }) })
|
|
4194
|
+
] }),
|
|
4195
|
+
apiKey.status === "valid" && apiKey.maskedKey ? (
|
|
4196
|
+
// Key is set - show masked key and clear button
|
|
4197
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
4198
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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 }),
|
|
4199
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4200
|
+
"button",
|
|
4201
|
+
{
|
|
4202
|
+
onClick: () => {
|
|
4203
|
+
apiKey.clearApiKey();
|
|
4204
|
+
setApiKeyInputValue("");
|
|
4205
|
+
},
|
|
4206
|
+
className: "text-xs text-red-500 hover:text-red-600 px-2 py-1",
|
|
4207
|
+
title: "Remove API key",
|
|
4208
|
+
"data-testid": "api-key-clear-button",
|
|
4209
|
+
children: "Clear"
|
|
4210
|
+
}
|
|
4211
|
+
)
|
|
4212
|
+
] })
|
|
4213
|
+
) : showApiKeyInput ? (
|
|
4214
|
+
// Input mode - show form
|
|
4215
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-2", children: [
|
|
4216
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex gap-1", children: [
|
|
4217
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4218
|
+
"input",
|
|
4219
|
+
{
|
|
4220
|
+
type: showApiKey ? "text" : "password",
|
|
4221
|
+
value: apiKeyInputValue,
|
|
4222
|
+
onChange: (e) => setApiKeyInputValue(e.target.value),
|
|
4223
|
+
placeholder: "sk-ant-...",
|
|
4224
|
+
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",
|
|
4225
|
+
"data-testid": "api-key-input",
|
|
4226
|
+
onKeyDown: (e) => {
|
|
4227
|
+
if (e.key === "Enter") {
|
|
4228
|
+
e.preventDefault();
|
|
4229
|
+
if (apiKeyInputValue.trim()) {
|
|
4230
|
+
apiKey.setApiKey(apiKeyInputValue.trim()).then((success) => {
|
|
4231
|
+
if (success) {
|
|
4232
|
+
setApiKeyInputValue("");
|
|
4233
|
+
setShowApiKeyInput(false);
|
|
4234
|
+
}
|
|
4235
|
+
});
|
|
4236
|
+
}
|
|
4237
|
+
}
|
|
4238
|
+
if (e.key === "Escape") {
|
|
4239
|
+
setShowApiKeyInput(false);
|
|
4240
|
+
setApiKeyInputValue("");
|
|
4241
|
+
}
|
|
4242
|
+
},
|
|
4243
|
+
autoFocus: true
|
|
4244
|
+
}
|
|
4245
|
+
),
|
|
4246
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4247
|
+
"button",
|
|
4248
|
+
{
|
|
4249
|
+
onClick: () => setShowApiKey(!showApiKey),
|
|
4250
|
+
className: "px-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200",
|
|
4251
|
+
title: showApiKey ? "Hide" : "Show",
|
|
4252
|
+
"data-testid": "api-key-show-toggle",
|
|
4253
|
+
children: showApiKey ? "\u{1F648}" : "\u{1F441}\uFE0F"
|
|
4254
|
+
}
|
|
4255
|
+
)
|
|
4256
|
+
] }),
|
|
4257
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex gap-2", children: [
|
|
4258
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4259
|
+
"button",
|
|
4260
|
+
{
|
|
4261
|
+
onClick: async () => {
|
|
4262
|
+
if (apiKeyInputValue.trim()) {
|
|
4263
|
+
const success = await apiKey.setApiKey(apiKeyInputValue.trim());
|
|
4264
|
+
if (success) {
|
|
4265
|
+
setApiKeyInputValue("");
|
|
4266
|
+
setShowApiKeyInput(false);
|
|
4267
|
+
}
|
|
4268
|
+
}
|
|
4269
|
+
},
|
|
4270
|
+
disabled: !apiKeyInputValue.trim() || apiKey.status === "validating",
|
|
4271
|
+
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",
|
|
4272
|
+
"data-testid": "api-key-submit-button",
|
|
4273
|
+
children: apiKey.status === "validating" ? "Validating..." : "Save"
|
|
4274
|
+
}
|
|
4275
|
+
),
|
|
4276
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4277
|
+
"button",
|
|
4278
|
+
{
|
|
4279
|
+
onClick: () => {
|
|
4280
|
+
setShowApiKeyInput(false);
|
|
4281
|
+
setApiKeyInputValue("");
|
|
4282
|
+
},
|
|
4283
|
+
className: "text-xs px-3 py-1.5 text-gray-600 dark:text-gray-300 hover:text-gray-800 dark:hover:text-gray-100",
|
|
4284
|
+
"data-testid": "api-key-cancel-button",
|
|
4285
|
+
children: "Cancel"
|
|
4286
|
+
}
|
|
4287
|
+
)
|
|
4288
|
+
] }),
|
|
4289
|
+
apiKey.error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-xs text-red-500", "data-testid": "api-key-error", children: apiKey.error }),
|
|
4290
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4291
|
+
"a",
|
|
4292
|
+
{
|
|
4293
|
+
href: "https://console.anthropic.com/settings/keys",
|
|
4294
|
+
target: "_blank",
|
|
4295
|
+
rel: "noopener noreferrer",
|
|
4296
|
+
className: "block text-xs text-blue-500 hover:underline",
|
|
4297
|
+
children: "Get an API key from Anthropic \u2192"
|
|
4298
|
+
}
|
|
4299
|
+
)
|
|
4300
|
+
] })
|
|
4301
|
+
) : (
|
|
4302
|
+
// No key - show configure button
|
|
4303
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4304
|
+
"button",
|
|
4305
|
+
{
|
|
4306
|
+
onClick: () => setShowApiKeyInput(true),
|
|
4307
|
+
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",
|
|
4308
|
+
"data-testid": "api-key-configure-button",
|
|
4309
|
+
children: "Configure API Key"
|
|
4310
|
+
}
|
|
4311
|
+
)
|
|
4312
|
+
)
|
|
4313
|
+
] }),
|
|
4314
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "px-3 py-2 border-b border-gray-200 dark:border-gray-600 mb-2", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "grid grid-cols-4 gap-1", children: [
|
|
4315
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3681
4316
|
"button",
|
|
3682
4317
|
{
|
|
3683
4318
|
onClick: () => setLocalGlassMode(false),
|
|
3684
4319
|
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"}`,
|
|
3685
4320
|
title: "Glass Off",
|
|
3686
|
-
children: /* @__PURE__ */ (0,
|
|
4321
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("rect", { x: "8", y: "8", width: "8", height: "8", rx: "1" }) })
|
|
3687
4322
|
}
|
|
3688
4323
|
),
|
|
3689
|
-
/* @__PURE__ */ (0,
|
|
4324
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3690
4325
|
"button",
|
|
3691
4326
|
{
|
|
3692
4327
|
onClick: () => {
|
|
@@ -3695,10 +4330,10 @@ var ChatBubble = ({
|
|
|
3695
4330
|
},
|
|
3696
4331
|
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"}`,
|
|
3697
4332
|
title: "Glass Low",
|
|
3698
|
-
children: /* @__PURE__ */ (0,
|
|
4333
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("rect", { x: "9", y: "9", width: "6", height: "6", rx: "1", strokeWidth: "2" }) })
|
|
3699
4334
|
}
|
|
3700
4335
|
),
|
|
3701
|
-
/* @__PURE__ */ (0,
|
|
4336
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3702
4337
|
"button",
|
|
3703
4338
|
{
|
|
3704
4339
|
onClick: () => {
|
|
@@ -3707,13 +4342,13 @@ var ChatBubble = ({
|
|
|
3707
4342
|
},
|
|
3708
4343
|
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"}`,
|
|
3709
4344
|
title: "Glass Medium",
|
|
3710
|
-
children: /* @__PURE__ */ (0,
|
|
3711
|
-
/* @__PURE__ */ (0,
|
|
3712
|
-
/* @__PURE__ */ (0,
|
|
4345
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [
|
|
4346
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("rect", { x: "8", y: "8", width: "8", height: "8", rx: "1", strokeWidth: "2" }),
|
|
4347
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("rect", { x: "10", y: "10", width: "4", height: "4", rx: "0.5", strokeWidth: "1.5" })
|
|
3713
4348
|
] })
|
|
3714
4349
|
}
|
|
3715
4350
|
),
|
|
3716
|
-
/* @__PURE__ */ (0,
|
|
4351
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3717
4352
|
"button",
|
|
3718
4353
|
{
|
|
3719
4354
|
onClick: () => {
|
|
@@ -3722,15 +4357,15 @@ var ChatBubble = ({
|
|
|
3722
4357
|
},
|
|
3723
4358
|
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"}`,
|
|
3724
4359
|
title: "Glass High",
|
|
3725
|
-
children: /* @__PURE__ */ (0,
|
|
3726
|
-
/* @__PURE__ */ (0,
|
|
3727
|
-
/* @__PURE__ */ (0,
|
|
3728
|
-
/* @__PURE__ */ (0,
|
|
4360
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [
|
|
4361
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("rect", { x: "7", y: "7", width: "10", height: "10", rx: "1", strokeWidth: "2" }),
|
|
4362
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("rect", { x: "9", y: "9", width: "6", height: "6", rx: "0.5", strokeWidth: "1.5" }),
|
|
4363
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("rect", { x: "11", y: "11", width: "2", height: "2", rx: "0.5", strokeWidth: "1" })
|
|
3729
4364
|
] })
|
|
3730
4365
|
}
|
|
3731
4366
|
)
|
|
3732
4367
|
] }) }),
|
|
3733
|
-
/* @__PURE__ */ (0,
|
|
4368
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3734
4369
|
"button",
|
|
3735
4370
|
{
|
|
3736
4371
|
onClick: () => {
|
|
@@ -3742,15 +4377,15 @@ var ChatBubble = ({
|
|
|
3742
4377
|
},
|
|
3743
4378
|
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",
|
|
3744
4379
|
children: [
|
|
3745
|
-
/* @__PURE__ */ (0,
|
|
3746
|
-
/* @__PURE__ */ (0,
|
|
4380
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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" }) }),
|
|
4381
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { children: [
|
|
3747
4382
|
theme === "light" ? "Dark" : "Light",
|
|
3748
4383
|
" Mode"
|
|
3749
4384
|
] })
|
|
3750
4385
|
]
|
|
3751
4386
|
}
|
|
3752
4387
|
),
|
|
3753
|
-
/* @__PURE__ */ (0,
|
|
4388
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3754
4389
|
"button",
|
|
3755
4390
|
{
|
|
3756
4391
|
onClick: () => {
|
|
@@ -3761,15 +4396,15 @@ var ChatBubble = ({
|
|
|
3761
4396
|
},
|
|
3762
4397
|
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",
|
|
3763
4398
|
children: [
|
|
3764
|
-
/* @__PURE__ */ (0,
|
|
3765
|
-
/* @__PURE__ */ (0,
|
|
4399
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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" }) }),
|
|
4400
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { children: [
|
|
3766
4401
|
voiceEnabled ? "Disable" : "Enable",
|
|
3767
4402
|
" Voice"
|
|
3768
4403
|
] })
|
|
3769
4404
|
]
|
|
3770
4405
|
}
|
|
3771
4406
|
),
|
|
3772
|
-
/* @__PURE__ */ (0,
|
|
4407
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3773
4408
|
"button",
|
|
3774
4409
|
{
|
|
3775
4410
|
onClick: () => {
|
|
@@ -3778,12 +4413,12 @@ var ChatBubble = ({
|
|
|
3778
4413
|
},
|
|
3779
4414
|
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",
|
|
3780
4415
|
children: [
|
|
3781
|
-
/* @__PURE__ */ (0,
|
|
3782
|
-
/* @__PURE__ */ (0,
|
|
4416
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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" }) }),
|
|
4417
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Reset position" })
|
|
3783
4418
|
]
|
|
3784
4419
|
}
|
|
3785
4420
|
),
|
|
3786
|
-
/* @__PURE__ */ (0,
|
|
4421
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3787
4422
|
"button",
|
|
3788
4423
|
{
|
|
3789
4424
|
onClick: () => {
|
|
@@ -3799,12 +4434,12 @@ var ChatBubble = ({
|
|
|
3799
4434
|
},
|
|
3800
4435
|
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",
|
|
3801
4436
|
children: [
|
|
3802
|
-
/* @__PURE__ */ (0,
|
|
3803
|
-
/* @__PURE__ */ (0,
|
|
4437
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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" }) }),
|
|
4438
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "How to use" })
|
|
3804
4439
|
]
|
|
3805
4440
|
}
|
|
3806
4441
|
),
|
|
3807
|
-
onClearChat && /* @__PURE__ */ (0,
|
|
4442
|
+
onClearChat && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3808
4443
|
"button",
|
|
3809
4444
|
{
|
|
3810
4445
|
onClick: () => {
|
|
@@ -3813,41 +4448,41 @@ var ChatBubble = ({
|
|
|
3813
4448
|
},
|
|
3814
4449
|
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",
|
|
3815
4450
|
children: [
|
|
3816
|
-
/* @__PURE__ */ (0,
|
|
3817
|
-
/* @__PURE__ */ (0,
|
|
4451
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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" }) }),
|
|
4452
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Clear chat" })
|
|
3818
4453
|
]
|
|
3819
4454
|
}
|
|
3820
4455
|
)
|
|
3821
4456
|
] }),
|
|
3822
|
-
/* @__PURE__ */ (0,
|
|
4457
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3823
4458
|
"button",
|
|
3824
4459
|
{
|
|
3825
4460
|
onClick: () => setIsMinimized(true),
|
|
3826
4461
|
className: THEME_CLASSES.button.minimize,
|
|
3827
4462
|
title: "Minimize",
|
|
3828
|
-
children: /* @__PURE__ */ (0,
|
|
4463
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20 12H4" }) })
|
|
3829
4464
|
}
|
|
3830
4465
|
),
|
|
3831
|
-
/* @__PURE__ */ (0,
|
|
4466
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3832
4467
|
"button",
|
|
3833
4468
|
{
|
|
3834
4469
|
onClick: handleToggle,
|
|
3835
4470
|
className: THEME_CLASSES.button.close,
|
|
3836
4471
|
title: "Close",
|
|
3837
|
-
children: /* @__PURE__ */ (0,
|
|
4472
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
3838
4473
|
}
|
|
3839
4474
|
)
|
|
3840
4475
|
] })
|
|
3841
4476
|
]
|
|
3842
4477
|
}
|
|
3843
4478
|
),
|
|
3844
|
-
/* @__PURE__ */ (0,
|
|
3845
|
-
showWelcome && messages.length === 0 && config.welcome?.enabled && /* @__PURE__ */ (0,
|
|
3846
|
-
config.welcome.title && /* @__PURE__ */ (0,
|
|
3847
|
-
config.welcome.content && /* @__PURE__ */ (0,
|
|
3848
|
-
config.welcome.suggestedCommands && config.welcome.suggestedCommands.length > 0 && /* @__PURE__ */ (0,
|
|
3849
|
-
/* @__PURE__ */ (0,
|
|
3850
|
-
/* @__PURE__ */ (0,
|
|
4479
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 overflow-y-auto p-4 space-y-2", "data-testid": "chat-messages", children: [
|
|
4480
|
+
showWelcome && messages.length === 0 && config.welcome?.enabled && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: THEME_CLASSES.welcome.container, children: [
|
|
4481
|
+
config.welcome.title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h4", { className: THEME_CLASSES.welcome.title, style: INLINE_STYLES.welcomeTitle(theme === "dark"), children: config.welcome.title }),
|
|
4482
|
+
config.welcome.content && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: THEME_CLASSES.welcome.content, style: INLINE_STYLES.welcomeContent(theme === "dark"), children: config.welcome.content }),
|
|
4483
|
+
config.welcome.suggestedCommands && config.welcome.suggestedCommands.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: THEME_CLASSES.welcome.commandsContainer, children: [
|
|
4484
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: THEME_CLASSES.welcome.commandsHeader, children: "Try these commands:" }),
|
|
4485
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "space-y-1", children: config.welcome.suggestedCommands.map((cmd, idx) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3851
4486
|
"button",
|
|
3852
4487
|
{
|
|
3853
4488
|
onClick: () => {
|
|
@@ -3857,29 +4492,29 @@ var ChatBubble = ({
|
|
|
3857
4492
|
},
|
|
3858
4493
|
className: THEME_CLASSES.welcome.commandButton,
|
|
3859
4494
|
children: [
|
|
3860
|
-
/* @__PURE__ */ (0,
|
|
4495
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: THEME_CLASSES.welcome.commandText, style: INLINE_STYLES.commandText(theme === "dark"), children: [
|
|
3861
4496
|
'"',
|
|
3862
4497
|
cmd.text,
|
|
3863
4498
|
'"'
|
|
3864
4499
|
] }),
|
|
3865
|
-
cmd.desc && /* @__PURE__ */ (0,
|
|
4500
|
+
cmd.desc && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: THEME_CLASSES.welcome.commandDesc, style: INLINE_STYLES.commandDesc(theme === "dark"), children: cmd.desc })
|
|
3866
4501
|
]
|
|
3867
4502
|
},
|
|
3868
4503
|
idx
|
|
3869
4504
|
)) })
|
|
3870
4505
|
] })
|
|
3871
4506
|
] }),
|
|
3872
|
-
messages.map((message) => /* @__PURE__ */ (0,
|
|
3873
|
-
/* @__PURE__ */ (0,
|
|
4507
|
+
messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `group flex items-center gap-2 mb-2 ${message.type === "user" ? "flex-row-reverse" : "flex-row"}`, children: [
|
|
4508
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3874
4509
|
"div",
|
|
3875
4510
|
{
|
|
3876
4511
|
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}`,
|
|
3877
4512
|
style: message.type === "user" ? INLINE_STYLES.messageUser() : message.type === "ai" ? INLINE_STYLES.messageAI(theme === "dark") : INLINE_STYLES.messageSystem(theme === "dark"),
|
|
3878
4513
|
"data-testid": `chat-message-${message.type}`,
|
|
3879
|
-
children: /* @__PURE__ */ (0,
|
|
4514
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MessageRenderer, { content: message.text, theme })
|
|
3880
4515
|
}
|
|
3881
4516
|
),
|
|
3882
|
-
message.type === "ai" && voiceEnabled && /* @__PURE__ */ (0,
|
|
4517
|
+
message.type === "ai" && voiceEnabled && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3883
4518
|
TTSButton,
|
|
3884
4519
|
{
|
|
3885
4520
|
text: message.text,
|
|
@@ -3889,7 +4524,7 @@ var ChatBubble = ({
|
|
|
3889
4524
|
size: "small"
|
|
3890
4525
|
}
|
|
3891
4526
|
),
|
|
3892
|
-
/* @__PURE__ */ (0,
|
|
4527
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3893
4528
|
"div",
|
|
3894
4529
|
{
|
|
3895
4530
|
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"}`,
|
|
@@ -3898,10 +4533,10 @@ var ChatBubble = ({
|
|
|
3898
4533
|
}
|
|
3899
4534
|
)
|
|
3900
4535
|
] }, message.id)),
|
|
3901
|
-
/* @__PURE__ */ (0,
|
|
4536
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { ref: messagesEndRef })
|
|
3902
4537
|
] }),
|
|
3903
|
-
/* @__PURE__ */ (0,
|
|
3904
|
-
slashCommand.isOpen && /* @__PURE__ */ (0,
|
|
4538
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { position: "relative" }, children: [
|
|
4539
|
+
slashCommand.isOpen && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3905
4540
|
SlashCommandPopup,
|
|
3906
4541
|
{
|
|
3907
4542
|
tools: slashCommand.filteredTools,
|
|
@@ -3910,7 +4545,7 @@ var ChatBubble = ({
|
|
|
3910
4545
|
onClose: () => setInputValue("")
|
|
3911
4546
|
}
|
|
3912
4547
|
),
|
|
3913
|
-
/* @__PURE__ */ (0,
|
|
4548
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3914
4549
|
InputField,
|
|
3915
4550
|
{
|
|
3916
4551
|
inputValue,
|
|
@@ -3932,7 +4567,7 @@ var ChatBubble = ({
|
|
|
3932
4567
|
]
|
|
3933
4568
|
}
|
|
3934
4569
|
),
|
|
3935
|
-
!isExpanded && /* @__PURE__ */ (0,
|
|
4570
|
+
!isExpanded && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3936
4571
|
"button",
|
|
3937
4572
|
{
|
|
3938
4573
|
onClick: handleToggle,
|
|
@@ -3940,8 +4575,8 @@ var ChatBubble = ({
|
|
|
3940
4575
|
"data-testid": ChatNames.bubble,
|
|
3941
4576
|
title: `Open chat (press ${isMac ? "Cmd" : "Ctrl"}+/ for voice recording)`,
|
|
3942
4577
|
children: [
|
|
3943
|
-
/* @__PURE__ */ (0,
|
|
3944
|
-
hasUnread && notifications && /* @__PURE__ */ (0,
|
|
4578
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: config.logo, alt: "Supernal", className: "w-8 h-8" }),
|
|
4579
|
+
hasUnread && notifications && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-xs text-white font-bold", children: unreadCount > 9 ? "9+" : unreadCount }) })
|
|
3945
4580
|
]
|
|
3946
4581
|
}
|
|
3947
4582
|
)
|
|
@@ -3951,31 +4586,31 @@ var ChatBubble = ({
|
|
|
3951
4586
|
};
|
|
3952
4587
|
|
|
3953
4588
|
// src/components/AutoNavigationContext.tsx
|
|
3954
|
-
var
|
|
4589
|
+
var import_react15 = require("react");
|
|
3955
4590
|
|
|
3956
4591
|
// src/hooks/useNavigationGraph.tsx
|
|
3957
|
-
var
|
|
3958
|
-
var
|
|
3959
|
-
var
|
|
3960
|
-
var NavigationContextContext = (0,
|
|
4592
|
+
var import_react14 = require("react");
|
|
4593
|
+
var import_browser4 = require("@supernal/interface/browser");
|
|
4594
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
4595
|
+
var NavigationContextContext = (0, import_react14.createContext)("global");
|
|
3961
4596
|
function NavigationContextProvider({
|
|
3962
4597
|
value,
|
|
3963
4598
|
children
|
|
3964
4599
|
}) {
|
|
3965
4600
|
const graph = useNavigationGraph();
|
|
3966
|
-
(0,
|
|
4601
|
+
(0, import_react14.useEffect)(() => {
|
|
3967
4602
|
graph.setCurrentContext(value);
|
|
3968
4603
|
}, [value, graph]);
|
|
3969
|
-
return /* @__PURE__ */ (0,
|
|
4604
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NavigationContextContext.Provider, { value, children });
|
|
3970
4605
|
}
|
|
3971
4606
|
function useNavigationGraph() {
|
|
3972
|
-
return
|
|
4607
|
+
return import_browser4.NavigationGraph.getInstance();
|
|
3973
4608
|
}
|
|
3974
4609
|
function useCurrentContext() {
|
|
3975
|
-
const contextFromProvider = (0,
|
|
4610
|
+
const contextFromProvider = (0, import_react14.useContext)(NavigationContextContext);
|
|
3976
4611
|
const graph = useNavigationGraph();
|
|
3977
|
-
const [graphContext, setGraphContext] = (0,
|
|
3978
|
-
(0,
|
|
4612
|
+
const [graphContext, setGraphContext] = (0, import_react14.useState)("");
|
|
4613
|
+
(0, import_react14.useEffect)(() => {
|
|
3979
4614
|
const interval = setInterval(() => {
|
|
3980
4615
|
const current = graph.getCurrentContext?.() || "";
|
|
3981
4616
|
if (current !== graphContext) {
|
|
@@ -3989,7 +4624,7 @@ function useCurrentContext() {
|
|
|
3989
4624
|
function useRegisterTool(toolId, contextId, metadata) {
|
|
3990
4625
|
const graph = useNavigationGraph();
|
|
3991
4626
|
const currentContext = useCurrentContext();
|
|
3992
|
-
(0,
|
|
4627
|
+
(0, import_react14.useEffect)(() => {
|
|
3993
4628
|
let targetContext = contextId || currentContext;
|
|
3994
4629
|
if (!contextId && metadata) {
|
|
3995
4630
|
const detection = graph.detectToolContext?.(toolId, metadata);
|
|
@@ -4003,10 +4638,10 @@ function useRegisterTool(toolId, contextId, metadata) {
|
|
|
4003
4638
|
function useNavigationPath(targetContextOrToolId, isToolId = false) {
|
|
4004
4639
|
const graph = useNavigationGraph();
|
|
4005
4640
|
const currentContext = useCurrentContext();
|
|
4006
|
-
const [path, setPath] = (0,
|
|
4007
|
-
const [loading, setLoading] = (0,
|
|
4008
|
-
const [error, setError] = (0,
|
|
4009
|
-
(0,
|
|
4641
|
+
const [path, setPath] = (0, import_react14.useState)(null);
|
|
4642
|
+
const [loading, setLoading] = (0, import_react14.useState)(true);
|
|
4643
|
+
const [error, setError] = (0, import_react14.useState)();
|
|
4644
|
+
(0, import_react14.useEffect)(() => {
|
|
4010
4645
|
try {
|
|
4011
4646
|
let targetContext = targetContextOrToolId;
|
|
4012
4647
|
if (isToolId) {
|
|
@@ -4034,9 +4669,9 @@ function useNavigationPath(targetContextOrToolId, isToolId = false) {
|
|
|
4034
4669
|
function useNavigate() {
|
|
4035
4670
|
const graph = useNavigationGraph();
|
|
4036
4671
|
const currentContext = useCurrentContext();
|
|
4037
|
-
const [navigating, setNavigating] = (0,
|
|
4038
|
-
const [error, setError] = (0,
|
|
4039
|
-
const navigateTo = (0,
|
|
4672
|
+
const [navigating, setNavigating] = (0, import_react14.useState)(false);
|
|
4673
|
+
const [error, setError] = (0, import_react14.useState)();
|
|
4674
|
+
const navigateTo = (0, import_react14.useCallback)(async (targetContextOrToolId, isToolId = false, executeNavigation) => {
|
|
4040
4675
|
setNavigating(true);
|
|
4041
4676
|
setError(void 0);
|
|
4042
4677
|
try {
|
|
@@ -4078,8 +4713,8 @@ function useNavigate() {
|
|
|
4078
4713
|
}
|
|
4079
4714
|
function useAllContexts() {
|
|
4080
4715
|
const graph = useNavigationGraph();
|
|
4081
|
-
const [contexts, setContexts] = (0,
|
|
4082
|
-
(0,
|
|
4716
|
+
const [contexts, setContexts] = (0, import_react14.useState)(graph.getAllContexts?.());
|
|
4717
|
+
(0, import_react14.useEffect)(() => {
|
|
4083
4718
|
const interval = setInterval(() => {
|
|
4084
4719
|
setContexts(graph.getAllContexts?.());
|
|
4085
4720
|
}, 1e3);
|
|
@@ -4089,28 +4724,28 @@ function useAllContexts() {
|
|
|
4089
4724
|
}
|
|
4090
4725
|
|
|
4091
4726
|
// src/components/AutoNavigationContext.tsx
|
|
4092
|
-
var
|
|
4727
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
4093
4728
|
function AutoNavigationContext({
|
|
4094
4729
|
children,
|
|
4095
4730
|
routes,
|
|
4096
4731
|
onNavigate
|
|
4097
4732
|
}) {
|
|
4098
|
-
const [pathname, setPathname] = (0,
|
|
4099
|
-
(0,
|
|
4733
|
+
const [pathname, setPathname] = (0, import_react15.useState)("/");
|
|
4734
|
+
(0, import_react15.useEffect)(() => {
|
|
4100
4735
|
if (typeof window !== "undefined") {
|
|
4101
4736
|
setPathname(window.location.pathname);
|
|
4102
4737
|
}
|
|
4103
4738
|
}, []);
|
|
4104
4739
|
const context = routes ? inferContextFromPath(pathname, routes) : null;
|
|
4105
|
-
(0,
|
|
4740
|
+
(0, import_react15.useEffect)(() => {
|
|
4106
4741
|
if (onNavigate && context) {
|
|
4107
4742
|
onNavigate(context);
|
|
4108
4743
|
}
|
|
4109
4744
|
}, [context, onNavigate]);
|
|
4110
4745
|
if (!context) {
|
|
4111
|
-
return /* @__PURE__ */ (0,
|
|
4746
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
|
|
4112
4747
|
}
|
|
4113
|
-
return /* @__PURE__ */ (0,
|
|
4748
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(NavigationContextProvider, { value: context, children });
|
|
4114
4749
|
}
|
|
4115
4750
|
function inferContextFromPath(path, customRoutes) {
|
|
4116
4751
|
if (customRoutes) {
|
|
@@ -4140,11 +4775,11 @@ function inferContextFromPath(path, customRoutes) {
|
|
|
4140
4775
|
}
|
|
4141
4776
|
|
|
4142
4777
|
// src/components/SupernalProvider.tsx
|
|
4143
|
-
var
|
|
4778
|
+
var import_browser7 = require("@supernal/interface/browser");
|
|
4144
4779
|
|
|
4145
4780
|
// src/hooks/useLocationTracking.ts
|
|
4146
|
-
var
|
|
4147
|
-
var
|
|
4781
|
+
var import_react16 = require("react");
|
|
4782
|
+
var import_browser5 = require("@supernal/interface/browser");
|
|
4148
4783
|
var usePathname;
|
|
4149
4784
|
var useSearchParams;
|
|
4150
4785
|
try {
|
|
@@ -4175,8 +4810,8 @@ function getCurrentLocation() {
|
|
|
4175
4810
|
};
|
|
4176
4811
|
}
|
|
4177
4812
|
function useLocationTracking() {
|
|
4178
|
-
const lastLocationRef = (0,
|
|
4179
|
-
const lastElementsRef = (0,
|
|
4813
|
+
const lastLocationRef = (0, import_react16.useRef)("");
|
|
4814
|
+
const lastElementsRef = (0, import_react16.useRef)([]);
|
|
4180
4815
|
let pathname = null;
|
|
4181
4816
|
let searchParams = null;
|
|
4182
4817
|
try {
|
|
@@ -4188,14 +4823,14 @@ function useLocationTracking() {
|
|
|
4188
4823
|
}
|
|
4189
4824
|
} catch {
|
|
4190
4825
|
}
|
|
4191
|
-
(0,
|
|
4826
|
+
(0, import_react16.useEffect)(() => {
|
|
4192
4827
|
const updateLocation = () => {
|
|
4193
4828
|
const location = pathname !== null ? { pathname, search: searchParams?.toString() || "", asPath: pathname + (searchParams?.toString() ? `?${searchParams.toString()}` : "") } : getCurrentLocation();
|
|
4194
4829
|
const visibleElements = getVisibleElements();
|
|
4195
4830
|
const locationChanged = lastLocationRef.current !== location.pathname;
|
|
4196
4831
|
const elementsChanged = !arraysEqual(lastElementsRef.current, visibleElements);
|
|
4197
4832
|
if (locationChanged || elementsChanged) {
|
|
4198
|
-
|
|
4833
|
+
import_browser5.LocationContext.setCurrent({
|
|
4199
4834
|
page: location.pathname,
|
|
4200
4835
|
route: location.pathname,
|
|
4201
4836
|
elements: visibleElements,
|
|
@@ -4229,7 +4864,7 @@ function useLocationTracking() {
|
|
|
4229
4864
|
}
|
|
4230
4865
|
|
|
4231
4866
|
// src/hooks/useNavigationGraphSetup.ts
|
|
4232
|
-
var
|
|
4867
|
+
var import_react17 = require("react");
|
|
4233
4868
|
var useAppRouter;
|
|
4234
4869
|
var usePathname2;
|
|
4235
4870
|
try {
|
|
@@ -4239,7 +4874,7 @@ try {
|
|
|
4239
4874
|
} catch {
|
|
4240
4875
|
}
|
|
4241
4876
|
function useNavigationGraphSetup() {
|
|
4242
|
-
const [isInitialized, setIsInitialized] = (0,
|
|
4877
|
+
const [isInitialized, setIsInitialized] = (0, import_react17.useState)(false);
|
|
4243
4878
|
let router = null;
|
|
4244
4879
|
let pathname = null;
|
|
4245
4880
|
try {
|
|
@@ -4251,7 +4886,7 @@ function useNavigationGraphSetup() {
|
|
|
4251
4886
|
}
|
|
4252
4887
|
} catch {
|
|
4253
4888
|
}
|
|
4254
|
-
const navigate = (0,
|
|
4889
|
+
const navigate = (0, import_react17.useCallback)((path) => {
|
|
4255
4890
|
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
4256
4891
|
if (router?.push) {
|
|
4257
4892
|
router.push(normalizedPath);
|
|
@@ -4260,7 +4895,7 @@ function useNavigationGraphSetup() {
|
|
|
4260
4895
|
}
|
|
4261
4896
|
}, [router]);
|
|
4262
4897
|
const currentPath = pathname ?? (typeof window !== "undefined" ? window.location.pathname + window.location.search : "/");
|
|
4263
|
-
(0,
|
|
4898
|
+
(0, import_react17.useEffect)(() => {
|
|
4264
4899
|
import("@supernal/interface/browser").then(({ NavigationGraph: NavigationGraph2 }) => {
|
|
4265
4900
|
const graph = NavigationGraph2.getInstance();
|
|
4266
4901
|
graph.setNavigationHandler(navigate);
|
|
@@ -4276,7 +4911,7 @@ function useNavigationGraphSetup() {
|
|
|
4276
4911
|
console.log("[NavigationGraphSetup] Auto-configured with Next.js router");
|
|
4277
4912
|
});
|
|
4278
4913
|
}, [navigate, currentPath]);
|
|
4279
|
-
(0,
|
|
4914
|
+
(0, import_react17.useEffect)(() => {
|
|
4280
4915
|
if (!isInitialized) return;
|
|
4281
4916
|
import("@supernal/interface/browser").then(({ NavigationGraph: NavigationGraph2 }) => {
|
|
4282
4917
|
const graph = NavigationGraph2.getInstance();
|
|
@@ -4287,8 +4922,8 @@ function useNavigationGraphSetup() {
|
|
|
4287
4922
|
}
|
|
4288
4923
|
|
|
4289
4924
|
// src/components/ToolMenuPopup/ToolMenuPopup.tsx
|
|
4290
|
-
var
|
|
4291
|
-
var
|
|
4925
|
+
var import_react18 = require("react");
|
|
4926
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
4292
4927
|
var ToolMenuPopup = ({
|
|
4293
4928
|
isOpen,
|
|
4294
4929
|
onClose,
|
|
@@ -4296,16 +4931,16 @@ var ToolMenuPopup = ({
|
|
|
4296
4931
|
totalTools,
|
|
4297
4932
|
contextLabel
|
|
4298
4933
|
}) => {
|
|
4299
|
-
const [collapsedCategories, setCollapsedCategories] = (0,
|
|
4300
|
-
const [isHydrated, setIsHydrated] = (0,
|
|
4301
|
-
const [isMobile, setIsMobile] = (0,
|
|
4302
|
-
const popupRef = (0,
|
|
4934
|
+
const [collapsedCategories, setCollapsedCategories] = (0, import_react18.useState)(/* @__PURE__ */ new Set());
|
|
4935
|
+
const [isHydrated, setIsHydrated] = (0, import_react18.useState)(false);
|
|
4936
|
+
const [isMobile, setIsMobile] = (0, import_react18.useState)(false);
|
|
4937
|
+
const popupRef = (0, import_react18.useRef)(null);
|
|
4303
4938
|
const { insertText } = useChatInput();
|
|
4304
|
-
(0,
|
|
4939
|
+
(0, import_react18.useEffect)(() => {
|
|
4305
4940
|
setIsHydrated(true);
|
|
4306
4941
|
setIsMobile(window.matchMedia("(max-width: 767px)").matches);
|
|
4307
4942
|
}, []);
|
|
4308
|
-
(0,
|
|
4943
|
+
(0, import_react18.useEffect)(() => {
|
|
4309
4944
|
if (!isOpen) return;
|
|
4310
4945
|
const handleClickOutside = (e) => {
|
|
4311
4946
|
const target = e.target;
|
|
@@ -4316,7 +4951,7 @@ var ToolMenuPopup = ({
|
|
|
4316
4951
|
document.addEventListener("mousedown", handleClickOutside);
|
|
4317
4952
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
4318
4953
|
}, [isOpen, onClose]);
|
|
4319
|
-
(0,
|
|
4954
|
+
(0, import_react18.useEffect)(() => {
|
|
4320
4955
|
if (!isOpen) return;
|
|
4321
4956
|
const handleKey = (e) => {
|
|
4322
4957
|
if (e.key === "Escape") {
|
|
@@ -4364,23 +4999,23 @@ var ToolMenuPopup = ({
|
|
|
4364
4999
|
maxHeight: "70vh",
|
|
4365
5000
|
borderRadius: 16
|
|
4366
5001
|
};
|
|
4367
|
-
return /* @__PURE__ */ (0,
|
|
5002
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
4368
5003
|
"div",
|
|
4369
5004
|
{
|
|
4370
5005
|
ref: popupRef,
|
|
4371
5006
|
"data-tool-menu": true,
|
|
4372
5007
|
style: { ...glassStyle, ...positionStyle, overflowY: "auto" },
|
|
4373
5008
|
children: [
|
|
4374
|
-
/* @__PURE__ */ (0,
|
|
5009
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: {
|
|
4375
5010
|
padding: "16px 20px",
|
|
4376
5011
|
borderBottom: "1px solid rgba(255, 255, 255, 0.1)",
|
|
4377
5012
|
display: "flex",
|
|
4378
5013
|
justifyContent: "space-between",
|
|
4379
5014
|
alignItems: "center"
|
|
4380
5015
|
}, children: [
|
|
4381
|
-
/* @__PURE__ */ (0,
|
|
4382
|
-
/* @__PURE__ */ (0,
|
|
4383
|
-
/* @__PURE__ */ (0,
|
|
5016
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
|
|
5017
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h3", { style: { margin: 0, color: "#fff", fontSize: 16, fontWeight: 600 }, children: "Available Actions" }),
|
|
5018
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("p", { style: { margin: "4px 0 0", color: "rgba(255,255,255,0.6)", fontSize: 12 }, children: [
|
|
4384
5019
|
contextLabel,
|
|
4385
5020
|
" \xB7 ",
|
|
4386
5021
|
totalTools,
|
|
@@ -4388,7 +5023,7 @@ var ToolMenuPopup = ({
|
|
|
4388
5023
|
totalTools !== 1 ? "s" : ""
|
|
4389
5024
|
] })
|
|
4390
5025
|
] }),
|
|
4391
|
-
/* @__PURE__ */ (0,
|
|
5026
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4392
5027
|
"button",
|
|
4393
5028
|
{
|
|
4394
5029
|
onClick: onClose,
|
|
@@ -4406,12 +5041,12 @@ var ToolMenuPopup = ({
|
|
|
4406
5041
|
}
|
|
4407
5042
|
)
|
|
4408
5043
|
] }),
|
|
4409
|
-
/* @__PURE__ */ (0,
|
|
4410
|
-
categories.length === 0 && /* @__PURE__ */ (0,
|
|
5044
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { padding: "8px 12px 16px" }, children: [
|
|
5045
|
+
categories.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: { color: "rgba(255,255,255,0.5)", textAlign: "center", padding: "24px 0", fontSize: 14 }, children: "No tools available on this page." }),
|
|
4411
5046
|
categories.map((category) => {
|
|
4412
5047
|
const isCollapsed = collapsedCategories.has(category.key);
|
|
4413
|
-
return /* @__PURE__ */ (0,
|
|
4414
|
-
/* @__PURE__ */ (0,
|
|
5048
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { marginBottom: 4 }, children: [
|
|
5049
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
4415
5050
|
"button",
|
|
4416
5051
|
{
|
|
4417
5052
|
onClick: () => toggleCategory(category.key),
|
|
@@ -4435,15 +5070,15 @@ var ToolMenuPopup = ({
|
|
|
4435
5070
|
e.currentTarget.style.background = "none";
|
|
4436
5071
|
},
|
|
4437
5072
|
children: [
|
|
4438
|
-
/* @__PURE__ */ (0,
|
|
5073
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { style: { fontSize: 14, fontWeight: 500 }, children: [
|
|
4439
5074
|
category.displayName,
|
|
4440
|
-
/* @__PURE__ */ (0,
|
|
5075
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { color: "rgba(255,255,255,0.4)", fontWeight: 400, marginLeft: 8, fontSize: 12 }, children: category.tools.length })
|
|
4441
5076
|
] }),
|
|
4442
|
-
/* @__PURE__ */ (0,
|
|
5077
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { color: "rgba(255,255,255,0.4)", fontSize: 12 }, children: isCollapsed ? "\u25B6" : "\u25BC" })
|
|
4443
5078
|
]
|
|
4444
5079
|
}
|
|
4445
5080
|
),
|
|
4446
|
-
!isCollapsed && /* @__PURE__ */ (0,
|
|
5081
|
+
!isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { paddingLeft: 8, paddingRight: 8 }, children: category.tools.map((tool, idx) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
4447
5082
|
"button",
|
|
4448
5083
|
{
|
|
4449
5084
|
onClick: () => handleToolClick(tool),
|
|
@@ -4466,8 +5101,8 @@ var ToolMenuPopup = ({
|
|
|
4466
5101
|
e.currentTarget.style.background = "none";
|
|
4467
5102
|
},
|
|
4468
5103
|
children: [
|
|
4469
|
-
/* @__PURE__ */ (0,
|
|
4470
|
-
tool.description && /* @__PURE__ */ (0,
|
|
5104
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { fontSize: 13, fontWeight: 500 }, children: tool.name }),
|
|
5105
|
+
tool.description && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: {
|
|
4471
5106
|
fontSize: 11,
|
|
4472
5107
|
color: "rgba(255,255,255,0.5)",
|
|
4473
5108
|
marginTop: 2,
|
|
@@ -4483,7 +5118,7 @@ var ToolMenuPopup = ({
|
|
|
4483
5118
|
] }, category.key);
|
|
4484
5119
|
})
|
|
4485
5120
|
] }),
|
|
4486
|
-
/* @__PURE__ */ (0,
|
|
5121
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: {
|
|
4487
5122
|
padding: "10px 20px",
|
|
4488
5123
|
borderTop: "1px solid rgba(255, 255, 255, 0.08)",
|
|
4489
5124
|
textAlign: "center",
|
|
@@ -4491,14 +5126,14 @@ var ToolMenuPopup = ({
|
|
|
4491
5126
|
fontSize: 11
|
|
4492
5127
|
}, children: [
|
|
4493
5128
|
"Click a tool to insert its command \xB7 Type ",
|
|
4494
|
-
/* @__PURE__ */ (0,
|
|
5129
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("kbd", { style: {
|
|
4495
5130
|
padding: "1px 4px",
|
|
4496
5131
|
borderRadius: 3,
|
|
4497
5132
|
border: "1px solid rgba(255,255,255,0.2)",
|
|
4498
5133
|
fontSize: 10
|
|
4499
5134
|
}, children: "/" }),
|
|
4500
5135
|
" in chat for quick commands \xB7 ",
|
|
4501
|
-
/* @__PURE__ */ (0,
|
|
5136
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("kbd", { style: {
|
|
4502
5137
|
padding: "1px 4px",
|
|
4503
5138
|
borderRadius: 3,
|
|
4504
5139
|
border: "1px solid rgba(255,255,255,0.2)",
|
|
@@ -4512,11 +5147,11 @@ var ToolMenuPopup = ({
|
|
|
4512
5147
|
};
|
|
4513
5148
|
|
|
4514
5149
|
// src/components/ToolMenuPopup/ToolMenuPopupTrigger.tsx
|
|
4515
|
-
var
|
|
5150
|
+
var import_react20 = require("react");
|
|
4516
5151
|
|
|
4517
5152
|
// src/components/ToolMenuPopup/useToolMenu.ts
|
|
4518
|
-
var
|
|
4519
|
-
var
|
|
5153
|
+
var import_react19 = require("react");
|
|
5154
|
+
var import_browser6 = require("@supernal/interface/browser");
|
|
4520
5155
|
var CATEGORY_DISPLAY = {
|
|
4521
5156
|
navigation: "Navigation",
|
|
4522
5157
|
user_interaction: "Controls",
|
|
@@ -4536,15 +5171,15 @@ var CATEGORY_DISPLAY = {
|
|
|
4536
5171
|
workflow: "Workflow"
|
|
4537
5172
|
};
|
|
4538
5173
|
function useToolMenu() {
|
|
4539
|
-
const [isOpen, setIsOpen] = (0,
|
|
4540
|
-
const open = (0,
|
|
4541
|
-
const close = (0,
|
|
4542
|
-
const toggle = (0,
|
|
4543
|
-
const { categories, totalTools, contextLabel } = (0,
|
|
5174
|
+
const [isOpen, setIsOpen] = (0, import_react19.useState)(false);
|
|
5175
|
+
const open = (0, import_react19.useCallback)(() => setIsOpen(true), []);
|
|
5176
|
+
const close = (0, import_react19.useCallback)(() => setIsOpen(false), []);
|
|
5177
|
+
const toggle = (0, import_react19.useCallback)(() => setIsOpen((prev) => !prev), []);
|
|
5178
|
+
const { categories, totalTools, contextLabel } = (0, import_react19.useMemo)(() => {
|
|
4544
5179
|
if (!isOpen) {
|
|
4545
5180
|
return { categories: [], totalTools: 0, contextLabel: "" };
|
|
4546
5181
|
}
|
|
4547
|
-
const tools =
|
|
5182
|
+
const tools = import_browser6.ToolRegistry.getToolsByLocation();
|
|
4548
5183
|
const aiTools = tools.filter((t) => t.aiEnabled);
|
|
4549
5184
|
const grouped = {};
|
|
4550
5185
|
for (const tool of aiTools) {
|
|
@@ -4572,10 +5207,10 @@ function useToolMenu() {
|
|
|
4572
5207
|
}
|
|
4573
5208
|
|
|
4574
5209
|
// src/components/ToolMenuPopup/ToolMenuPopupTrigger.tsx
|
|
4575
|
-
var
|
|
5210
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
4576
5211
|
var ToolMenuPopupTrigger = () => {
|
|
4577
5212
|
const toolMenu = useToolMenu();
|
|
4578
|
-
(0,
|
|
5213
|
+
(0, import_react20.useEffect)(() => {
|
|
4579
5214
|
const handleKeyDown = (e) => {
|
|
4580
5215
|
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key === "/") {
|
|
4581
5216
|
e.preventDefault();
|
|
@@ -4614,7 +5249,7 @@ var ToolMenuPopupTrigger = () => {
|
|
|
4614
5249
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
4615
5250
|
}, [toolMenu]);
|
|
4616
5251
|
if (!toolMenu.isOpen) return null;
|
|
4617
|
-
return /* @__PURE__ */ (0,
|
|
5252
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
4618
5253
|
ToolMenuPopup,
|
|
4619
5254
|
{
|
|
4620
5255
|
isOpen: toolMenu.isOpen,
|
|
@@ -4627,7 +5262,7 @@ var ToolMenuPopupTrigger = () => {
|
|
|
4627
5262
|
};
|
|
4628
5263
|
|
|
4629
5264
|
// src/components/SupernalProvider.tsx
|
|
4630
|
-
var
|
|
5265
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
4631
5266
|
function ChatBubbleConnector({
|
|
4632
5267
|
theme,
|
|
4633
5268
|
position,
|
|
@@ -4644,7 +5279,7 @@ function ChatBubbleConnector({
|
|
|
4644
5279
|
glassMode,
|
|
4645
5280
|
...logo ? { logo } : {}
|
|
4646
5281
|
};
|
|
4647
|
-
return /* @__PURE__ */ (0,
|
|
5282
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4648
5283
|
ChatBubble,
|
|
4649
5284
|
{
|
|
4650
5285
|
messages,
|
|
@@ -4683,12 +5318,12 @@ function SupernalProvider({
|
|
|
4683
5318
|
console.log("[SupernalProvider] variant:", variant, "effectiveDisplayMode:", effectiveDisplayMode);
|
|
4684
5319
|
useLocationTracking();
|
|
4685
5320
|
useNavigationGraphSetup();
|
|
4686
|
-
(0,
|
|
5321
|
+
(0, import_react21.useEffect)(() => {
|
|
4687
5322
|
if (typeof window === "undefined") return;
|
|
4688
|
-
const collector =
|
|
5323
|
+
const collector = import_browser7.ExposureCollector.getInstance();
|
|
4689
5324
|
const registeredToolIds = /* @__PURE__ */ new Set();
|
|
4690
5325
|
const registerTools = () => {
|
|
4691
|
-
const allTools =
|
|
5326
|
+
const allTools = import_browser7.ToolRegistry.getAllTools();
|
|
4692
5327
|
allTools.forEach((tool) => {
|
|
4693
5328
|
if (tool.elementId && !registeredToolIds.has(tool.toolId)) {
|
|
4694
5329
|
const element = document.querySelector(`[data-testid="${tool.elementId}"]`);
|
|
@@ -4715,9 +5350,9 @@ function SupernalProvider({
|
|
|
4715
5350
|
collector.destroy();
|
|
4716
5351
|
};
|
|
4717
5352
|
}, []);
|
|
4718
|
-
return /* @__PURE__ */ (0,
|
|
4719
|
-
/* @__PURE__ */ (0,
|
|
4720
|
-
shouldRenderChatBubble ? /* @__PURE__ */ (0,
|
|
5353
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ApiKeyProvider, { initialApiKey: apiKey, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ChatInputProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(ChatProvider, { mode, apiKey, onToolExecute, children: [
|
|
5354
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AutoNavigationContext, { routes, onNavigate, children }),
|
|
5355
|
+
shouldRenderChatBubble ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4721
5356
|
ChatBubbleConnector,
|
|
4722
5357
|
{
|
|
4723
5358
|
theme,
|
|
@@ -4730,26 +5365,26 @@ function SupernalProvider({
|
|
|
4730
5365
|
drawerSide
|
|
4731
5366
|
}
|
|
4732
5367
|
) : null,
|
|
4733
|
-
!disabled && /* @__PURE__ */ (0,
|
|
4734
|
-
] }) });
|
|
5368
|
+
!disabled && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ToolMenuPopupTrigger, {})
|
|
5369
|
+
] }) }) });
|
|
4735
5370
|
}
|
|
4736
5371
|
|
|
4737
5372
|
// src/components/ChatBubbleSettingsModal.tsx
|
|
4738
|
-
var
|
|
4739
|
-
var
|
|
5373
|
+
var import_react22 = __toESM(require("react"));
|
|
5374
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
4740
5375
|
function ChatBubbleSettingsModal({
|
|
4741
5376
|
isOpen,
|
|
4742
5377
|
onClose,
|
|
4743
5378
|
settings,
|
|
4744
5379
|
onSettingsChange
|
|
4745
5380
|
}) {
|
|
4746
|
-
const [localSettings, setLocalSettings] =
|
|
4747
|
-
(0,
|
|
5381
|
+
const [localSettings, setLocalSettings] = import_react22.default.useState(settings);
|
|
5382
|
+
(0, import_react22.useEffect)(() => {
|
|
4748
5383
|
if (isOpen) {
|
|
4749
5384
|
setLocalSettings(settings);
|
|
4750
5385
|
}
|
|
4751
5386
|
}, [isOpen, settings]);
|
|
4752
|
-
(0,
|
|
5387
|
+
(0, import_react22.useEffect)(() => {
|
|
4753
5388
|
const handleEscape = (e) => {
|
|
4754
5389
|
if (e.key === "Escape" && isOpen) {
|
|
4755
5390
|
onClose();
|
|
@@ -4770,8 +5405,8 @@ function ChatBubbleSettingsModal({
|
|
|
4770
5405
|
onClose();
|
|
4771
5406
|
};
|
|
4772
5407
|
const isDark = localSettings.theme === "dark";
|
|
4773
|
-
return /* @__PURE__ */ (0,
|
|
4774
|
-
/* @__PURE__ */ (0,
|
|
5408
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
5409
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4775
5410
|
"div",
|
|
4776
5411
|
{
|
|
4777
5412
|
className: "fixed inset-0 bg-black bg-opacity-50 z-[60] backdrop-blur-sm",
|
|
@@ -4779,12 +5414,12 @@ function ChatBubbleSettingsModal({
|
|
|
4779
5414
|
"aria-hidden": "true"
|
|
4780
5415
|
}
|
|
4781
5416
|
),
|
|
4782
|
-
/* @__PURE__ */ (0,
|
|
5417
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4783
5418
|
"div",
|
|
4784
5419
|
{
|
|
4785
5420
|
className: "fixed inset-0 z-[70] flex items-center justify-center p-4",
|
|
4786
5421
|
"data-testid": "chat-settings-modal",
|
|
4787
|
-
children: /* @__PURE__ */ (0,
|
|
5422
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
4788
5423
|
"div",
|
|
4789
5424
|
{
|
|
4790
5425
|
className: `${isDark ? "bg-gray-800 text-white" : "bg-white text-gray-900"} rounded-2xl shadow-2xl max-w-md w-full p-6 border ${isDark ? "border-gray-700" : "border-gray-200"}`,
|
|
@@ -4793,8 +5428,8 @@ function ChatBubbleSettingsModal({
|
|
|
4793
5428
|
"aria-labelledby": "settings-modal-title",
|
|
4794
5429
|
onClick: (e) => e.stopPropagation(),
|
|
4795
5430
|
children: [
|
|
4796
|
-
/* @__PURE__ */ (0,
|
|
4797
|
-
/* @__PURE__ */ (0,
|
|
5431
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between mb-6", children: [
|
|
5432
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4798
5433
|
"h2",
|
|
4799
5434
|
{
|
|
4800
5435
|
id: "settings-modal-title",
|
|
@@ -4802,56 +5437,56 @@ function ChatBubbleSettingsModal({
|
|
|
4802
5437
|
children: "Chat Settings"
|
|
4803
5438
|
}
|
|
4804
5439
|
),
|
|
4805
|
-
/* @__PURE__ */ (0,
|
|
5440
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4806
5441
|
"button",
|
|
4807
5442
|
{
|
|
4808
5443
|
onClick: handleCancel,
|
|
4809
5444
|
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`,
|
|
4810
5445
|
"aria-label": "Close modal",
|
|
4811
|
-
children: /* @__PURE__ */ (0,
|
|
5446
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
4812
5447
|
}
|
|
4813
5448
|
)
|
|
4814
5449
|
] }),
|
|
4815
|
-
/* @__PURE__ */ (0,
|
|
4816
|
-
/* @__PURE__ */ (0,
|
|
4817
|
-
/* @__PURE__ */ (0,
|
|
4818
|
-
/* @__PURE__ */ (0,
|
|
4819
|
-
/* @__PURE__ */ (0,
|
|
5450
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "space-y-5 mb-6", children: [
|
|
5451
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
5452
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
5453
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-base font-medium mb-1", children: "Theme" }),
|
|
5454
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Switch between light and dark modes" })
|
|
4820
5455
|
] }),
|
|
4821
|
-
/* @__PURE__ */ (0,
|
|
4822
|
-
/* @__PURE__ */ (0,
|
|
5456
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center space-x-2", children: [
|
|
5457
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4823
5458
|
"button",
|
|
4824
5459
|
{
|
|
4825
5460
|
onClick: () => setLocalSettings({ ...localSettings, theme: "light" }),
|
|
4826
5461
|
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"}`,
|
|
4827
5462
|
title: "Light mode",
|
|
4828
|
-
children: /* @__PURE__ */ (0,
|
|
5463
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("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" }) })
|
|
4829
5464
|
}
|
|
4830
5465
|
),
|
|
4831
|
-
/* @__PURE__ */ (0,
|
|
5466
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4832
5467
|
"button",
|
|
4833
5468
|
{
|
|
4834
5469
|
onClick: () => setLocalSettings({ ...localSettings, theme: "dark" }),
|
|
4835
5470
|
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"}`,
|
|
4836
5471
|
title: "Dark mode",
|
|
4837
|
-
children: /* @__PURE__ */ (0,
|
|
5472
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("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" }) })
|
|
4838
5473
|
}
|
|
4839
5474
|
)
|
|
4840
5475
|
] })
|
|
4841
5476
|
] }),
|
|
4842
|
-
/* @__PURE__ */ (0,
|
|
4843
|
-
/* @__PURE__ */ (0,
|
|
4844
|
-
/* @__PURE__ */ (0,
|
|
4845
|
-
/* @__PURE__ */ (0,
|
|
5477
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
5478
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
5479
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-base font-medium mb-1", children: "Glass Mode" }),
|
|
5480
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable glassmorphism transparency effect" })
|
|
4846
5481
|
] }),
|
|
4847
|
-
/* @__PURE__ */ (0,
|
|
5482
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4848
5483
|
"button",
|
|
4849
5484
|
{
|
|
4850
5485
|
onClick: () => setLocalSettings({ ...localSettings, glassMode: !localSettings.glassMode }),
|
|
4851
5486
|
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"}`,
|
|
4852
5487
|
role: "switch",
|
|
4853
5488
|
"aria-checked": localSettings.glassMode,
|
|
4854
|
-
children: /* @__PURE__ */ (0,
|
|
5489
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4855
5490
|
"span",
|
|
4856
5491
|
{
|
|
4857
5492
|
className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.glassMode ? "translate-x-6" : "translate-x-1"}`
|
|
@@ -4860,19 +5495,19 @@ function ChatBubbleSettingsModal({
|
|
|
4860
5495
|
}
|
|
4861
5496
|
)
|
|
4862
5497
|
] }),
|
|
4863
|
-
/* @__PURE__ */ (0,
|
|
4864
|
-
/* @__PURE__ */ (0,
|
|
4865
|
-
/* @__PURE__ */ (0,
|
|
4866
|
-
/* @__PURE__ */ (0,
|
|
5498
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
5499
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
5500
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-base font-medium mb-1", children: "Notifications" }),
|
|
5501
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Show unread message indicators" })
|
|
4867
5502
|
] }),
|
|
4868
|
-
/* @__PURE__ */ (0,
|
|
5503
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4869
5504
|
"button",
|
|
4870
5505
|
{
|
|
4871
5506
|
onClick: () => setLocalSettings({ ...localSettings, notifications: !localSettings.notifications }),
|
|
4872
5507
|
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"}`,
|
|
4873
5508
|
role: "switch",
|
|
4874
5509
|
"aria-checked": localSettings.notifications,
|
|
4875
|
-
children: /* @__PURE__ */ (0,
|
|
5510
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4876
5511
|
"span",
|
|
4877
5512
|
{
|
|
4878
5513
|
className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.notifications ? "translate-x-6" : "translate-x-1"}`
|
|
@@ -4881,16 +5516,16 @@ function ChatBubbleSettingsModal({
|
|
|
4881
5516
|
}
|
|
4882
5517
|
)
|
|
4883
5518
|
] }),
|
|
4884
|
-
/* @__PURE__ */ (0,
|
|
4885
|
-
/* @__PURE__ */ (0,
|
|
4886
|
-
/* @__PURE__ */ (0,
|
|
4887
|
-
/* @__PURE__ */ (0,
|
|
4888
|
-
/* @__PURE__ */ (0,
|
|
4889
|
-
/* @__PURE__ */ (0,
|
|
5519
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
|
|
5520
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
5521
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
5522
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "block text-base font-medium mb-1 flex items-center space-x-2", children: [
|
|
5523
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "Subtitle Overlay" }),
|
|
5524
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("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" })
|
|
4890
5525
|
] }),
|
|
4891
|
-
/* @__PURE__ */ (0,
|
|
5526
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Minimalist voice-first overlay with @/ icon" })
|
|
4892
5527
|
] }),
|
|
4893
|
-
/* @__PURE__ */ (0,
|
|
5528
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4894
5529
|
"button",
|
|
4895
5530
|
{
|
|
4896
5531
|
onClick: () => setLocalSettings({
|
|
@@ -4902,7 +5537,7 @@ function ChatBubbleSettingsModal({
|
|
|
4902
5537
|
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"}`,
|
|
4903
5538
|
role: "switch",
|
|
4904
5539
|
"aria-checked": localSettings.subtitleOverlayEnabled,
|
|
4905
|
-
children: /* @__PURE__ */ (0,
|
|
5540
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4906
5541
|
"span",
|
|
4907
5542
|
{
|
|
4908
5543
|
className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.subtitleOverlayEnabled ? "translate-x-6" : "translate-x-1"}`
|
|
@@ -4911,12 +5546,12 @@ function ChatBubbleSettingsModal({
|
|
|
4911
5546
|
}
|
|
4912
5547
|
)
|
|
4913
5548
|
] }),
|
|
4914
|
-
/* @__PURE__ */ (0,
|
|
4915
|
-
/* @__PURE__ */ (0,
|
|
4916
|
-
/* @__PURE__ */ (0,
|
|
4917
|
-
/* @__PURE__ */ (0,
|
|
5549
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
5550
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
5551
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-base font-medium mb-1", children: "Display Mode" }),
|
|
5552
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Auto switches drawer on mobile, panel on desktop" })
|
|
4918
5553
|
] }),
|
|
4919
|
-
/* @__PURE__ */ (0,
|
|
5554
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
4920
5555
|
"select",
|
|
4921
5556
|
{
|
|
4922
5557
|
value: localSettings.displayMode || "auto",
|
|
@@ -4926,22 +5561,22 @@ function ChatBubbleSettingsModal({
|
|
|
4926
5561
|
}),
|
|
4927
5562
|
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`,
|
|
4928
5563
|
children: [
|
|
4929
|
-
/* @__PURE__ */ (0,
|
|
4930
|
-
/* @__PURE__ */ (0,
|
|
4931
|
-
/* @__PURE__ */ (0,
|
|
4932
|
-
/* @__PURE__ */ (0,
|
|
4933
|
-
/* @__PURE__ */ (0,
|
|
5564
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "auto", children: "Auto (Recommended)" }),
|
|
5565
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "drawer", children: "Always Drawer" }),
|
|
5566
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "full", children: "Always Panel" }),
|
|
5567
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "floating", children: "Always Floating" }),
|
|
5568
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "subtitle", children: "Subtitle Overlay (Beta)" })
|
|
4934
5569
|
]
|
|
4935
5570
|
}
|
|
4936
5571
|
)
|
|
4937
5572
|
] }),
|
|
4938
|
-
(localSettings.displayMode === "auto" || localSettings.displayMode === "drawer") && /* @__PURE__ */ (0,
|
|
4939
|
-
/* @__PURE__ */ (0,
|
|
4940
|
-
/* @__PURE__ */ (0,
|
|
4941
|
-
/* @__PURE__ */ (0,
|
|
5573
|
+
(localSettings.displayMode === "auto" || localSettings.displayMode === "drawer") && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
5574
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
5575
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-base font-medium mb-1", children: "Drawer Side" }),
|
|
5576
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Which edge drawer slides from" })
|
|
4942
5577
|
] }),
|
|
4943
|
-
/* @__PURE__ */ (0,
|
|
4944
|
-
/* @__PURE__ */ (0,
|
|
5578
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center space-x-2", children: [
|
|
5579
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4945
5580
|
"button",
|
|
4946
5581
|
{
|
|
4947
5582
|
onClick: () => setLocalSettings({ ...localSettings, drawerSide: "left" }),
|
|
@@ -4949,7 +5584,7 @@ function ChatBubbleSettingsModal({
|
|
|
4949
5584
|
children: "Left"
|
|
4950
5585
|
}
|
|
4951
5586
|
),
|
|
4952
|
-
/* @__PURE__ */ (0,
|
|
5587
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4953
5588
|
"button",
|
|
4954
5589
|
{
|
|
4955
5590
|
onClick: () => setLocalSettings({ ...localSettings, drawerSide: "right" }),
|
|
@@ -4959,24 +5594,24 @@ function ChatBubbleSettingsModal({
|
|
|
4959
5594
|
)
|
|
4960
5595
|
] })
|
|
4961
5596
|
] }),
|
|
4962
|
-
/* @__PURE__ */ (0,
|
|
4963
|
-
/* @__PURE__ */ (0,
|
|
4964
|
-
/* @__PURE__ */ (0,
|
|
4965
|
-
/* @__PURE__ */ (0,
|
|
5597
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
|
|
5598
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "mb-3", children: [
|
|
5599
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { className: "text-lg font-semibold mb-1", children: "Voice Control" }),
|
|
5600
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable voice input and audio feedback" })
|
|
4966
5601
|
] }),
|
|
4967
|
-
/* @__PURE__ */ (0,
|
|
4968
|
-
/* @__PURE__ */ (0,
|
|
4969
|
-
/* @__PURE__ */ (0,
|
|
4970
|
-
/* @__PURE__ */ (0,
|
|
5602
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
5603
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
5604
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-base font-medium mb-1", children: "Voice Control" }),
|
|
5605
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Enable voice input and TTS responses" })
|
|
4971
5606
|
] }),
|
|
4972
|
-
/* @__PURE__ */ (0,
|
|
5607
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4973
5608
|
"button",
|
|
4974
5609
|
{
|
|
4975
5610
|
onClick: () => setLocalSettings({ ...localSettings, voiceEnabled: !localSettings.voiceEnabled }),
|
|
4976
5611
|
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"}`,
|
|
4977
5612
|
role: "switch",
|
|
4978
5613
|
"aria-checked": localSettings.voiceEnabled,
|
|
4979
|
-
children: /* @__PURE__ */ (0,
|
|
5614
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4980
5615
|
"span",
|
|
4981
5616
|
{
|
|
4982
5617
|
className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.voiceEnabled ? "translate-x-6" : "translate-x-1"}`
|
|
@@ -4985,20 +5620,20 @@ function ChatBubbleSettingsModal({
|
|
|
4985
5620
|
}
|
|
4986
5621
|
)
|
|
4987
5622
|
] }),
|
|
4988
|
-
localSettings.voiceEnabled && /* @__PURE__ */ (0,
|
|
4989
|
-
/* @__PURE__ */ (0,
|
|
4990
|
-
/* @__PURE__ */ (0,
|
|
4991
|
-
/* @__PURE__ */ (0,
|
|
4992
|
-
/* @__PURE__ */ (0,
|
|
5623
|
+
localSettings.voiceEnabled && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
5624
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between pl-4 border-l-2 border-blue-500/30", children: [
|
|
5625
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
5626
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-sm font-medium mb-1", children: "Auto-read AI Responses" }),
|
|
5627
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Automatically read AI messages aloud" })
|
|
4993
5628
|
] }),
|
|
4994
|
-
/* @__PURE__ */ (0,
|
|
5629
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4995
5630
|
"button",
|
|
4996
5631
|
{
|
|
4997
5632
|
onClick: () => setLocalSettings({ ...localSettings, autoReadResponses: !localSettings.autoReadResponses }),
|
|
4998
5633
|
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"}`,
|
|
4999
5634
|
role: "switch",
|
|
5000
5635
|
"aria-checked": localSettings.autoReadResponses,
|
|
5001
|
-
children: /* @__PURE__ */ (0,
|
|
5636
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5002
5637
|
"span",
|
|
5003
5638
|
{
|
|
5004
5639
|
className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.autoReadResponses ? "translate-x-6" : "translate-x-1"}`
|
|
@@ -5007,19 +5642,19 @@ function ChatBubbleSettingsModal({
|
|
|
5007
5642
|
}
|
|
5008
5643
|
)
|
|
5009
5644
|
] }),
|
|
5010
|
-
/* @__PURE__ */ (0,
|
|
5011
|
-
/* @__PURE__ */ (0,
|
|
5012
|
-
/* @__PURE__ */ (0,
|
|
5013
|
-
/* @__PURE__ */ (0,
|
|
5645
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between pl-4 border-l-2 border-blue-500/30", children: [
|
|
5646
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
5647
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-sm font-medium mb-1", children: "Premium Voices \u{1F48E}" }),
|
|
5648
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Use high-quality OpenAI voices (requires network)" })
|
|
5014
5649
|
] }),
|
|
5015
|
-
/* @__PURE__ */ (0,
|
|
5650
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5016
5651
|
"button",
|
|
5017
5652
|
{
|
|
5018
5653
|
onClick: () => setLocalSettings({ ...localSettings, usePremiumVoices: !localSettings.usePremiumVoices }),
|
|
5019
5654
|
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"}`,
|
|
5020
5655
|
role: "switch",
|
|
5021
5656
|
"aria-checked": localSettings.usePremiumVoices,
|
|
5022
|
-
children: /* @__PURE__ */ (0,
|
|
5657
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5023
5658
|
"span",
|
|
5024
5659
|
{
|
|
5025
5660
|
className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.usePremiumVoices ? "translate-x-6" : "translate-x-1"}`
|
|
@@ -5028,13 +5663,13 @@ function ChatBubbleSettingsModal({
|
|
|
5028
5663
|
}
|
|
5029
5664
|
)
|
|
5030
5665
|
] }),
|
|
5031
|
-
/* @__PURE__ */ (0,
|
|
5032
|
-
/* @__PURE__ */ (0,
|
|
5666
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "pl-4 border-l-2 border-blue-500/30", children: [
|
|
5667
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "block text-sm font-medium mb-2", children: [
|
|
5033
5668
|
"Voice Speed: ",
|
|
5034
5669
|
localSettings.ttsSpeed.toFixed(1),
|
|
5035
5670
|
"x"
|
|
5036
5671
|
] }),
|
|
5037
|
-
/* @__PURE__ */ (0,
|
|
5672
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5038
5673
|
"input",
|
|
5039
5674
|
{
|
|
5040
5675
|
type: "range",
|
|
@@ -5046,30 +5681,30 @@ function ChatBubbleSettingsModal({
|
|
|
5046
5681
|
className: "w-full h-2 bg-gray-200 dark:bg-gray-700 rounded-lg appearance-none cursor-pointer accent-blue-600"
|
|
5047
5682
|
}
|
|
5048
5683
|
),
|
|
5049
|
-
/* @__PURE__ */ (0,
|
|
5050
|
-
/* @__PURE__ */ (0,
|
|
5051
|
-
/* @__PURE__ */ (0,
|
|
5052
|
-
/* @__PURE__ */ (0,
|
|
5684
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex justify-between text-xs text-gray-400 mt-1", children: [
|
|
5685
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "0.5x (Slow)" }),
|
|
5686
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "1.0x (Normal)" }),
|
|
5687
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "2.0x (Fast)" })
|
|
5053
5688
|
] })
|
|
5054
5689
|
] }),
|
|
5055
|
-
/* @__PURE__ */ (0,
|
|
5056
|
-
/* @__PURE__ */ (0,
|
|
5057
|
-
/* @__PURE__ */ (0,
|
|
5058
|
-
/* @__PURE__ */ (0,
|
|
5690
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: `border-t ${isDark ? "border-gray-700" : "border-gray-200"} my-2` }),
|
|
5691
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "mb-3", children: [
|
|
5692
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h4", { className: "text-sm font-semibold mb-1", children: "Voice Quick Record (Ctrl+/)" }),
|
|
5693
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("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" })
|
|
5059
5694
|
] }),
|
|
5060
|
-
/* @__PURE__ */ (0,
|
|
5061
|
-
/* @__PURE__ */ (0,
|
|
5062
|
-
/* @__PURE__ */ (0,
|
|
5063
|
-
/* @__PURE__ */ (0,
|
|
5695
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between pl-4 border-l-2 border-purple-500/30", children: [
|
|
5696
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
5697
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { className: "block text-sm font-medium mb-1", children: "Auto-Execute Commands" }),
|
|
5698
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Automatically run recognized voice commands" })
|
|
5064
5699
|
] }),
|
|
5065
|
-
/* @__PURE__ */ (0,
|
|
5700
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5066
5701
|
"button",
|
|
5067
5702
|
{
|
|
5068
5703
|
onClick: () => setLocalSettings({ ...localSettings, sttAutoExecute: !localSettings.sttAutoExecute }),
|
|
5069
5704
|
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"}`,
|
|
5070
5705
|
role: "switch",
|
|
5071
5706
|
"aria-checked": localSettings.sttAutoExecute,
|
|
5072
|
-
children: /* @__PURE__ */ (0,
|
|
5707
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5073
5708
|
"span",
|
|
5074
5709
|
{
|
|
5075
5710
|
className: `inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSettings.sttAutoExecute ? "translate-x-6" : "translate-x-1"}`
|
|
@@ -5078,13 +5713,13 @@ function ChatBubbleSettingsModal({
|
|
|
5078
5713
|
}
|
|
5079
5714
|
)
|
|
5080
5715
|
] }),
|
|
5081
|
-
/* @__PURE__ */ (0,
|
|
5082
|
-
/* @__PURE__ */ (0,
|
|
5716
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "pl-4 border-l-2 border-purple-500/30", children: [
|
|
5717
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "block text-sm font-medium mb-2", children: [
|
|
5083
5718
|
"Recording Timeout: ",
|
|
5084
5719
|
(localSettings.sttAutoRecordTimeout / 1e3).toFixed(1),
|
|
5085
5720
|
"s"
|
|
5086
5721
|
] }),
|
|
5087
|
-
/* @__PURE__ */ (0,
|
|
5722
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5088
5723
|
"input",
|
|
5089
5724
|
{
|
|
5090
5725
|
type: "range",
|
|
@@ -5096,22 +5731,22 @@ function ChatBubbleSettingsModal({
|
|
|
5096
5731
|
className: "w-full h-2 bg-gray-200 dark:bg-gray-700 rounded-lg appearance-none cursor-pointer accent-purple-600"
|
|
5097
5732
|
}
|
|
5098
5733
|
),
|
|
5099
|
-
/* @__PURE__ */ (0,
|
|
5100
|
-
/* @__PURE__ */ (0,
|
|
5101
|
-
/* @__PURE__ */ (0,
|
|
5102
|
-
/* @__PURE__ */ (0,
|
|
5734
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex justify-between text-xs text-gray-400 mt-1", children: [
|
|
5735
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "2s" }),
|
|
5736
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "8s" }),
|
|
5737
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "15s" })
|
|
5103
5738
|
] })
|
|
5104
5739
|
] }),
|
|
5105
|
-
/* @__PURE__ */ (0,
|
|
5106
|
-
/* @__PURE__ */ (0,
|
|
5107
|
-
/* @__PURE__ */ (0,
|
|
5740
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: `p-3 rounded-lg ${isDark ? "bg-purple-900/20 border border-purple-500/30" : "bg-purple-50 border border-purple-200"}`, children: [
|
|
5741
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("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!)" }),
|
|
5742
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("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)" })
|
|
5108
5743
|
] }),
|
|
5109
|
-
!localSettings.usePremiumVoices && /* @__PURE__ */ (0,
|
|
5110
|
-
localSettings.usePremiumVoices && /* @__PURE__ */ (0,
|
|
5744
|
+
!localSettings.usePremiumVoices && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("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__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-xs ${isDark ? "text-green-300" : "text-green-800"}`, children: "\u{1F49A} Using free device voices (works offline, zero cost)" }) }),
|
|
5745
|
+
localSettings.usePremiumVoices && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("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__ */ (0, import_jsx_runtime19.jsx)("p", { className: `text-xs ${isDark ? "text-purple-300" : "text-purple-800"}`, children: "\u{1F48E} Using premium OpenAI voices (requires internet connection)" }) })
|
|
5111
5746
|
] })
|
|
5112
5747
|
] }),
|
|
5113
|
-
/* @__PURE__ */ (0,
|
|
5114
|
-
/* @__PURE__ */ (0,
|
|
5748
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex justify-end space-x-3 pt-4 border-t border-gray-200 dark:border-gray-700", children: [
|
|
5749
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5115
5750
|
"button",
|
|
5116
5751
|
{
|
|
5117
5752
|
onClick: handleCancel,
|
|
@@ -5119,7 +5754,7 @@ function ChatBubbleSettingsModal({
|
|
|
5119
5754
|
children: "Cancel"
|
|
5120
5755
|
}
|
|
5121
5756
|
),
|
|
5122
|
-
/* @__PURE__ */ (0,
|
|
5757
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5123
5758
|
"button",
|
|
5124
5759
|
{
|
|
5125
5760
|
onClick: handleSave,
|
|
@@ -5256,12 +5891,14 @@ function findBestMatch(query, tools) {
|
|
|
5256
5891
|
}
|
|
5257
5892
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5258
5893
|
0 && (module.exports = {
|
|
5894
|
+
ApiKeyProvider,
|
|
5259
5895
|
AutoNavigationContext,
|
|
5260
5896
|
ChatBubble,
|
|
5261
5897
|
ChatBubbleSettingsModal,
|
|
5262
5898
|
ChatBubbleVariant,
|
|
5263
5899
|
ChatInputProvider,
|
|
5264
5900
|
ChatProvider,
|
|
5901
|
+
ClaudeClient,
|
|
5265
5902
|
CodeBlock,
|
|
5266
5903
|
Components,
|
|
5267
5904
|
DemoAIInterface,
|
|
@@ -5275,9 +5912,13 @@ function findBestMatch(query, tools) {
|
|
|
5275
5912
|
ToolManager,
|
|
5276
5913
|
ToolMenuPopup,
|
|
5277
5914
|
ToolMenuPopupTrigger,
|
|
5915
|
+
createClaudeClient,
|
|
5278
5916
|
findBestMatch,
|
|
5279
5917
|
scoreToolMatch,
|
|
5280
5918
|
useAllContexts,
|
|
5919
|
+
useApiKey,
|
|
5920
|
+
useApiKeyOptional,
|
|
5921
|
+
useApiKeyStorage,
|
|
5281
5922
|
useChatContext,
|
|
5282
5923
|
useChatInput,
|
|
5283
5924
|
useCurrentContext,
|