xertica-ui 1.0.0 → 1.1.0
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/bin/cli.ts +81 -0
- package/components/ui/google-maps-loader.tsx +31 -26
- package/components/ui/map.tsx +11 -11
- package/components/ui/route-map.tsx +13 -13
- package/components/ui/xertica-assistant.tsx +127 -124
- package/dist/cli.js +103 -20812
- package/guidelines/Guidelines.md +643 -46
- package/package.json +2 -2
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, { useState, useEffect, useRef } from 'react';
|
|
2
2
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
3
|
-
import {
|
|
4
|
-
MessageSquare,
|
|
5
|
-
Heart,
|
|
6
|
-
History,
|
|
3
|
+
import {
|
|
4
|
+
MessageSquare,
|
|
5
|
+
Heart,
|
|
6
|
+
History,
|
|
7
7
|
MoreHorizontal,
|
|
8
8
|
X,
|
|
9
9
|
ChevronLeft,
|
|
@@ -183,91 +183,91 @@ export interface XerticaAssistantProps {
|
|
|
183
183
|
* @default 'expanded'
|
|
184
184
|
*/
|
|
185
185
|
mode?: AssistantMode;
|
|
186
|
-
|
|
186
|
+
|
|
187
187
|
/**
|
|
188
188
|
* Se o assistente está expandido (apenas para mode='expanded')
|
|
189
189
|
* @default true
|
|
190
190
|
*/
|
|
191
191
|
isExpanded?: boolean;
|
|
192
|
-
|
|
192
|
+
|
|
193
193
|
/**
|
|
194
194
|
* Callback chamado quando o assistente é expandido/colapsado
|
|
195
195
|
*/
|
|
196
196
|
onToggle?: () => void;
|
|
197
|
-
|
|
197
|
+
|
|
198
198
|
/**
|
|
199
199
|
* Aba selecionada inicialmente
|
|
200
200
|
* @default 'chat'
|
|
201
201
|
*/
|
|
202
202
|
defaultTab?: AssistantTab;
|
|
203
|
-
|
|
203
|
+
|
|
204
204
|
/**
|
|
205
205
|
* Se deve mostrar banner de aviso de API key
|
|
206
206
|
* @default true
|
|
207
207
|
*/
|
|
208
208
|
showApiWarning?: boolean;
|
|
209
|
-
|
|
209
|
+
|
|
210
210
|
/**
|
|
211
211
|
* Chave da API do Gemini (se disponível)
|
|
212
212
|
*/
|
|
213
213
|
apiKey?: string;
|
|
214
|
-
|
|
214
|
+
|
|
215
215
|
/**
|
|
216
216
|
* Callback chamado ao navegar para página de configurações
|
|
217
217
|
*/
|
|
218
218
|
onNavigateSettings?: () => void;
|
|
219
|
-
|
|
219
|
+
|
|
220
220
|
/**
|
|
221
221
|
* Callback chamado ao navegar para página full do assistente
|
|
222
222
|
*/
|
|
223
223
|
onNavigateFullPage?: () => void;
|
|
224
|
-
|
|
224
|
+
|
|
225
225
|
/**
|
|
226
226
|
* Nome do usuário logado
|
|
227
227
|
* @default 'Usuário'
|
|
228
228
|
*/
|
|
229
229
|
userName?: string;
|
|
230
|
-
|
|
230
|
+
|
|
231
231
|
/**
|
|
232
232
|
* Mensagens iniciais (para carregar conversa existente)
|
|
233
233
|
*/
|
|
234
234
|
initialMessages?: Message[];
|
|
235
|
-
|
|
235
|
+
|
|
236
236
|
/**
|
|
237
237
|
* Conversas salvas
|
|
238
238
|
*/
|
|
239
239
|
savedConversations?: Conversation[];
|
|
240
|
-
|
|
240
|
+
|
|
241
241
|
/**
|
|
242
242
|
* Sugestões de mensagens
|
|
243
243
|
*/
|
|
244
244
|
suggestions?: Suggestion[];
|
|
245
|
-
|
|
245
|
+
|
|
246
246
|
/**
|
|
247
247
|
* Callback chamado quando uma mensagem é enviada
|
|
248
248
|
*/
|
|
249
249
|
onSendMessage?: (message: string) => void;
|
|
250
|
-
|
|
250
|
+
|
|
251
251
|
/**
|
|
252
252
|
* Callback chamado quando um arquivo é anexado
|
|
253
253
|
*/
|
|
254
254
|
onFileAttach?: (file: File) => void;
|
|
255
|
-
|
|
255
|
+
|
|
256
256
|
/**
|
|
257
257
|
* Se está processando mensagem (mostra typing indicator)
|
|
258
258
|
*/
|
|
259
259
|
isProcessing?: boolean;
|
|
260
|
-
|
|
260
|
+
|
|
261
261
|
/**
|
|
262
262
|
* Largura customizada (apenas para mode='expanded')
|
|
263
263
|
*/
|
|
264
264
|
width?: string;
|
|
265
|
-
|
|
265
|
+
|
|
266
266
|
/**
|
|
267
267
|
* Altura customizada (apenas para mode='fullPage')
|
|
268
268
|
*/
|
|
269
269
|
height?: string;
|
|
270
|
-
|
|
270
|
+
|
|
271
271
|
/**
|
|
272
272
|
* Classes CSS adicionais
|
|
273
273
|
*/
|
|
@@ -334,11 +334,11 @@ export function XerticaAssistant({
|
|
|
334
334
|
// ============================================================================
|
|
335
335
|
// State Management
|
|
336
336
|
// ============================================================================
|
|
337
|
-
|
|
337
|
+
|
|
338
338
|
const isFullPage = mode === 'fullPage';
|
|
339
339
|
const [internalIsExpanded, setInternalIsExpanded] = useState(controlledIsExpanded ?? true);
|
|
340
340
|
const isExpanded = controlledIsExpanded ?? internalIsExpanded;
|
|
341
|
-
|
|
341
|
+
|
|
342
342
|
const [abaSelecionada, setAbaSelecionada] = useState<AssistantTab>(defaultTab);
|
|
343
343
|
const [mensagens, setMensagens] = useState<Message[]>(initialMessages);
|
|
344
344
|
const [mensagem, setMensagem] = useState('');
|
|
@@ -352,56 +352,59 @@ export function XerticaAssistant({
|
|
|
352
352
|
content: string;
|
|
353
353
|
title: string;
|
|
354
354
|
} | null>(null);
|
|
355
|
-
|
|
355
|
+
|
|
356
356
|
// ============================================================================
|
|
357
357
|
// Refs
|
|
358
358
|
// ============================================================================
|
|
359
|
-
|
|
359
|
+
|
|
360
360
|
const messagesEndRef = useRef<HTMLDivElement>(null);
|
|
361
361
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
362
362
|
const audioInputRef = useRef<HTMLInputElement>(null);
|
|
363
|
-
|
|
363
|
+
|
|
364
364
|
// ============================================================================
|
|
365
365
|
// Sugestões padrão
|
|
366
366
|
// ============================================================================
|
|
367
|
-
|
|
367
|
+
|
|
368
368
|
const defaultSuggestions: Suggestion[] = [
|
|
369
369
|
{ id: '1', texto: 'Me ajude a criar um documento profissional' },
|
|
370
370
|
{ id: '2', texto: 'Buscar nos meus arquivos por "relatório"' },
|
|
371
371
|
{ id: '3', texto: 'Resuma as conversas importantes desta semana' },
|
|
372
372
|
{ id: '4', texto: 'Crie um podcast sobre o último projeto' },
|
|
373
373
|
];
|
|
374
|
-
|
|
374
|
+
|
|
375
375
|
const sugestoes = propSuggestions ?? defaultSuggestions;
|
|
376
|
-
|
|
376
|
+
|
|
377
377
|
// ============================================================================
|
|
378
378
|
// API Key Validation
|
|
379
379
|
// ============================================================================
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
380
|
+
|
|
381
|
+
// API Key Resolution
|
|
382
|
+
const effectiveApiKey = apiKey || (typeof import.meta !== 'undefined' && import.meta.env?.VITE_GEMINI_API_KEY);
|
|
383
|
+
|
|
384
|
+
const isApiKeyValid = Boolean(effectiveApiKey && effectiveApiKey.length > 20);
|
|
385
|
+
|
|
383
386
|
// ============================================================================
|
|
384
387
|
// Effects
|
|
385
388
|
// ============================================================================
|
|
386
|
-
|
|
389
|
+
|
|
387
390
|
// Auto-scroll ao adicionar mensagens
|
|
388
391
|
useEffect(() => {
|
|
389
392
|
if (messagesEndRef.current && abaSelecionada === 'chat') {
|
|
390
393
|
messagesEndRef.current.scrollIntoView({ behavior: 'smooth' });
|
|
391
394
|
}
|
|
392
395
|
}, [mensagens, abaSelecionada]);
|
|
393
|
-
|
|
396
|
+
|
|
394
397
|
// Sincronizar mensagens iniciais
|
|
395
398
|
useEffect(() => {
|
|
396
399
|
if (initialMessages.length > 0) {
|
|
397
400
|
setMensagens(initialMessages);
|
|
398
401
|
}
|
|
399
402
|
}, [initialMessages]);
|
|
400
|
-
|
|
403
|
+
|
|
401
404
|
// ============================================================================
|
|
402
405
|
// Handlers
|
|
403
406
|
// ============================================================================
|
|
404
|
-
|
|
407
|
+
|
|
405
408
|
const handleToggle = () => {
|
|
406
409
|
if (onToggle) {
|
|
407
410
|
onToggle();
|
|
@@ -409,7 +412,7 @@ export function XerticaAssistant({
|
|
|
409
412
|
setInternalIsExpanded(!internalIsExpanded);
|
|
410
413
|
}
|
|
411
414
|
};
|
|
412
|
-
|
|
415
|
+
|
|
413
416
|
const handleExpandWithTab = (tab: AssistantTab) => {
|
|
414
417
|
setAbaSelecionada(tab);
|
|
415
418
|
if (onToggle) {
|
|
@@ -418,10 +421,10 @@ export function XerticaAssistant({
|
|
|
418
421
|
setInternalIsExpanded(true);
|
|
419
422
|
}
|
|
420
423
|
};
|
|
421
|
-
|
|
424
|
+
|
|
422
425
|
const handleEnviarMensagem = async () => {
|
|
423
426
|
if (!mensagem.trim() || isProcessing) return;
|
|
424
|
-
|
|
427
|
+
|
|
425
428
|
const novaMensagem: Message = {
|
|
426
429
|
id: `msg-${Date.now()}`,
|
|
427
430
|
type: 'user',
|
|
@@ -429,16 +432,16 @@ export function XerticaAssistant({
|
|
|
429
432
|
timestamp: new Date(),
|
|
430
433
|
isFavorite: false,
|
|
431
434
|
};
|
|
432
|
-
|
|
435
|
+
|
|
433
436
|
setMensagens(prev => [...prev, novaMensagem]);
|
|
434
|
-
|
|
437
|
+
|
|
435
438
|
if (onSendMessage) {
|
|
436
439
|
onSendMessage(mensagem);
|
|
437
440
|
}
|
|
438
|
-
|
|
441
|
+
|
|
439
442
|
setMensagem('');
|
|
440
443
|
};
|
|
441
|
-
|
|
444
|
+
|
|
442
445
|
const handleToggleFavorite = (messageId: string) => {
|
|
443
446
|
setMensagens(prev =>
|
|
444
447
|
prev.map(msg =>
|
|
@@ -446,7 +449,7 @@ export function XerticaAssistant({
|
|
|
446
449
|
)
|
|
447
450
|
);
|
|
448
451
|
};
|
|
449
|
-
|
|
452
|
+
|
|
450
453
|
const handleCopyMessage = async (content: string, messageId: string) => {
|
|
451
454
|
try {
|
|
452
455
|
// Try modern Clipboard API first
|
|
@@ -476,10 +479,10 @@ export function XerticaAssistant({
|
|
|
476
479
|
document.body.appendChild(textArea);
|
|
477
480
|
textArea.focus();
|
|
478
481
|
textArea.select();
|
|
479
|
-
|
|
482
|
+
|
|
480
483
|
const successful = document.execCommand('copy');
|
|
481
484
|
document.body.removeChild(textArea);
|
|
482
|
-
|
|
485
|
+
|
|
483
486
|
if (successful) {
|
|
484
487
|
setCopiedId(messageId);
|
|
485
488
|
setTimeout(() => setCopiedId(null), 2000);
|
|
@@ -491,28 +494,28 @@ export function XerticaAssistant({
|
|
|
491
494
|
}
|
|
492
495
|
}
|
|
493
496
|
};
|
|
494
|
-
|
|
497
|
+
|
|
495
498
|
const handleGeneratePodcast = async (messageId: string, content: string) => {
|
|
496
499
|
setGeneratingPodcastId(messageId);
|
|
497
|
-
|
|
500
|
+
|
|
498
501
|
// Simulação de geração de podcast
|
|
499
502
|
setTimeout(() => {
|
|
500
503
|
setMensagens(prev =>
|
|
501
504
|
prev.map(msg =>
|
|
502
505
|
msg.id === messageId
|
|
503
506
|
? {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
507
|
+
...msg,
|
|
508
|
+
attachmentType: 'podcast',
|
|
509
|
+
attachmentName: 'Podcast - ' + content.substring(0, 30) + '...',
|
|
510
|
+
audioUrl: 'data:audio/mpeg;base64,//uQx...' // Mock
|
|
511
|
+
}
|
|
509
512
|
: msg
|
|
510
513
|
)
|
|
511
514
|
);
|
|
512
515
|
setGeneratingPodcastId(null);
|
|
513
516
|
}, 2000);
|
|
514
517
|
};
|
|
515
|
-
|
|
518
|
+
|
|
516
519
|
const handleDownloadDocument = (content: string, fileName: string) => {
|
|
517
520
|
const blob = new Blob([content], { type: 'text/markdown' });
|
|
518
521
|
const url = URL.createObjectURL(blob);
|
|
@@ -524,7 +527,7 @@ export function XerticaAssistant({
|
|
|
524
527
|
document.body.removeChild(a);
|
|
525
528
|
URL.revokeObjectURL(url);
|
|
526
529
|
};
|
|
527
|
-
|
|
530
|
+
|
|
528
531
|
const handleDownloadPodcast = (audioUrl: string, fileName: string) => {
|
|
529
532
|
const a = document.createElement('a');
|
|
530
533
|
a.href = audioUrl;
|
|
@@ -533,17 +536,17 @@ export function XerticaAssistant({
|
|
|
533
536
|
a.click();
|
|
534
537
|
document.body.removeChild(a);
|
|
535
538
|
};
|
|
536
|
-
|
|
539
|
+
|
|
537
540
|
const handleEditDocument = (content: string, title: string) => {
|
|
538
541
|
setEditingDocument({ content, title });
|
|
539
542
|
};
|
|
540
|
-
|
|
543
|
+
|
|
541
544
|
const handleNovaConversa = () => {
|
|
542
545
|
setMensagens([]);
|
|
543
546
|
setConversaAtual(null);
|
|
544
547
|
setAbaSelecionada('chat');
|
|
545
548
|
};
|
|
546
|
-
|
|
549
|
+
|
|
547
550
|
const handleSelecionarConversa = (conversaId: string) => {
|
|
548
551
|
const conversa = conversas.find(c => c.id === conversaId);
|
|
549
552
|
if (conversa) {
|
|
@@ -552,7 +555,7 @@ export function XerticaAssistant({
|
|
|
552
555
|
setAbaSelecionada('chat');
|
|
553
556
|
}
|
|
554
557
|
};
|
|
555
|
-
|
|
558
|
+
|
|
556
559
|
const handleToggleFavoritaConversa = (conversaId: string) => {
|
|
557
560
|
setConversas(prev =>
|
|
558
561
|
prev.map(conv =>
|
|
@@ -560,12 +563,12 @@ export function XerticaAssistant({
|
|
|
560
563
|
)
|
|
561
564
|
);
|
|
562
565
|
};
|
|
563
|
-
|
|
566
|
+
|
|
564
567
|
const handleOpenSearchResult = (result: SearchResult) => {
|
|
565
568
|
console.log('Abrir resultado:', result);
|
|
566
569
|
// Implementar lógica de navegação ou abertura de resultado
|
|
567
570
|
};
|
|
568
|
-
|
|
571
|
+
|
|
569
572
|
const handleExecuteSearchCommand = async (
|
|
570
573
|
commandId: string,
|
|
571
574
|
searchTerm: string,
|
|
@@ -573,7 +576,7 @@ export function XerticaAssistant({
|
|
|
573
576
|
messageId: string
|
|
574
577
|
) => {
|
|
575
578
|
setExecutingCommand(commandId);
|
|
576
|
-
|
|
579
|
+
|
|
577
580
|
// Simular execução de comando
|
|
578
581
|
setTimeout(() => {
|
|
579
582
|
if (commandId === '5') {
|
|
@@ -582,31 +585,31 @@ export function XerticaAssistant({
|
|
|
582
585
|
setExecutingCommand(null);
|
|
583
586
|
}, 1500);
|
|
584
587
|
};
|
|
585
|
-
|
|
588
|
+
|
|
586
589
|
// ============================================================================
|
|
587
590
|
// Computations
|
|
588
591
|
// ============================================================================
|
|
589
|
-
|
|
592
|
+
|
|
590
593
|
const conversasFiltradas = conversas.filter(conversa => {
|
|
591
594
|
if (abaSelecionada === 'favoritos') {
|
|
592
595
|
return conversa.favorita;
|
|
593
596
|
}
|
|
594
597
|
return true;
|
|
595
598
|
});
|
|
596
|
-
|
|
599
|
+
|
|
597
600
|
// ============================================================================
|
|
598
601
|
// Render
|
|
599
602
|
// ============================================================================
|
|
600
|
-
|
|
603
|
+
|
|
601
604
|
const containerWidth = width ?? (
|
|
602
|
-
isFullPage
|
|
603
|
-
? '100%'
|
|
604
|
-
: isExpanded
|
|
605
|
+
isFullPage
|
|
606
|
+
? '100%'
|
|
607
|
+
: isExpanded
|
|
605
608
|
? (editingDocument ? '420px' : '100%')
|
|
606
609
|
: '64px' // Compacto quando fechado - apenas ícones
|
|
607
610
|
);
|
|
608
611
|
const containerHeight = height ?? 'h-full';
|
|
609
|
-
|
|
612
|
+
|
|
610
613
|
if (mobileFloating && !isExpanded) {
|
|
611
614
|
return (
|
|
612
615
|
<Button
|
|
@@ -651,14 +654,14 @@ export function XerticaAssistant({
|
|
|
651
654
|
}
|
|
652
655
|
}}
|
|
653
656
|
/>
|
|
654
|
-
|
|
657
|
+
|
|
655
658
|
{/* Document Editor */}
|
|
656
659
|
{editingDocument && !isFullPage && (
|
|
657
|
-
<div
|
|
660
|
+
<div
|
|
658
661
|
className="flex-1 border-r border-border overflow-hidden"
|
|
659
662
|
>
|
|
660
663
|
<div className="h-full flex flex-col">
|
|
661
|
-
<div
|
|
664
|
+
<div
|
|
662
665
|
className="px-4 py-3 border-b border-border bg-card flex items-center justify-between"
|
|
663
666
|
>
|
|
664
667
|
<h3 className="text-card-foreground">{editingDocument.title}</h3>
|
|
@@ -671,7 +674,7 @@ export function XerticaAssistant({
|
|
|
671
674
|
</Button>
|
|
672
675
|
</div>
|
|
673
676
|
<div className="flex-1 overflow-auto p-4">
|
|
674
|
-
<div
|
|
677
|
+
<div
|
|
675
678
|
className="p-4 rounded-xl bg-muted"
|
|
676
679
|
>
|
|
677
680
|
<p className="text-muted-foreground">
|
|
@@ -685,9 +688,9 @@ export function XerticaAssistant({
|
|
|
685
688
|
</div>
|
|
686
689
|
</div>
|
|
687
690
|
)}
|
|
688
|
-
|
|
691
|
+
|
|
689
692
|
{/* Main Assistant Container */}
|
|
690
|
-
<div
|
|
693
|
+
<div
|
|
691
694
|
className={`${containerHeight} flex flex-col ${className} bg-background ${!isFullPage ? 'border-l border-border shadow-sm' : ''}`}
|
|
692
695
|
style={{
|
|
693
696
|
width: isFullPage ? '100%' : containerWidth,
|
|
@@ -695,7 +698,7 @@ export function XerticaAssistant({
|
|
|
695
698
|
>
|
|
696
699
|
{/* Header - Toggle Button - Apenas visível quando não está em fullPage */}
|
|
697
700
|
{!isFullPage && (
|
|
698
|
-
<div
|
|
701
|
+
<div
|
|
699
702
|
className="border-b border-border flex items-center justify-between px-[14px] px-[18px] py-[16px]"
|
|
700
703
|
>
|
|
701
704
|
{isExpanded && (
|
|
@@ -709,7 +712,7 @@ export function XerticaAssistant({
|
|
|
709
712
|
<span className="text-foreground">Assistente Xertica</span>
|
|
710
713
|
</motion.div>
|
|
711
714
|
)}
|
|
712
|
-
|
|
715
|
+
|
|
713
716
|
<div className="flex items-center gap-1">
|
|
714
717
|
{isExpanded && onNavigateFullPage && (
|
|
715
718
|
<Button
|
|
@@ -722,7 +725,7 @@ export function XerticaAssistant({
|
|
|
722
725
|
<Maximize2 className="w-4 h-4" />
|
|
723
726
|
</Button>
|
|
724
727
|
)}
|
|
725
|
-
|
|
728
|
+
|
|
726
729
|
<Button
|
|
727
730
|
variant="ghost"
|
|
728
731
|
size="sm"
|
|
@@ -759,7 +762,7 @@ export function XerticaAssistant({
|
|
|
759
762
|
<p>Assistente Xertica</p>
|
|
760
763
|
</AssistantTooltipContent>
|
|
761
764
|
</Tooltip>
|
|
762
|
-
|
|
765
|
+
|
|
763
766
|
<Tooltip>
|
|
764
767
|
<TooltipTrigger asChild>
|
|
765
768
|
<Button
|
|
@@ -778,7 +781,7 @@ export function XerticaAssistant({
|
|
|
778
781
|
<p>Chat</p>
|
|
779
782
|
</AssistantTooltipContent>
|
|
780
783
|
</Tooltip>
|
|
781
|
-
|
|
784
|
+
|
|
782
785
|
<Tooltip>
|
|
783
786
|
<TooltipTrigger asChild>
|
|
784
787
|
<Button
|
|
@@ -797,7 +800,7 @@ export function XerticaAssistant({
|
|
|
797
800
|
<p>Favoritos</p>
|
|
798
801
|
</AssistantTooltipContent>
|
|
799
802
|
</Tooltip>
|
|
800
|
-
|
|
803
|
+
|
|
801
804
|
<Tooltip>
|
|
802
805
|
<TooltipTrigger asChild>
|
|
803
806
|
<Button
|
|
@@ -831,7 +834,7 @@ export function XerticaAssistant({
|
|
|
831
834
|
>
|
|
832
835
|
{/* Navigation Tabs - Oculto em modo fullPage */}
|
|
833
836
|
{!isFullPage && (
|
|
834
|
-
<div
|
|
837
|
+
<div
|
|
835
838
|
className="px-4 py-2 border-b border-border"
|
|
836
839
|
>
|
|
837
840
|
<div className="flex gap-1">
|
|
@@ -897,9 +900,9 @@ export function XerticaAssistant({
|
|
|
897
900
|
Ir para Configurações
|
|
898
901
|
</Button>
|
|
899
902
|
)}
|
|
900
|
-
<a
|
|
901
|
-
href="https://aistudio.google.com/apikey"
|
|
902
|
-
target="_blank"
|
|
903
|
+
<a
|
|
904
|
+
href="https://aistudio.google.com/apikey"
|
|
905
|
+
target="_blank"
|
|
903
906
|
rel="noopener noreferrer"
|
|
904
907
|
className="inline-flex items-center gap-1 underline text-muted-foreground hover:text-foreground"
|
|
905
908
|
>
|
|
@@ -911,7 +914,7 @@ export function XerticaAssistant({
|
|
|
911
914
|
</div>
|
|
912
915
|
</div>
|
|
913
916
|
)}
|
|
914
|
-
|
|
917
|
+
|
|
915
918
|
{mensagens.length === 0 ? (
|
|
916
919
|
<div className="flex-1 overflow-y-auto min-h-0">
|
|
917
920
|
{/* Welcome Message */}
|
|
@@ -938,7 +941,7 @@ export function XerticaAssistant({
|
|
|
938
941
|
{sugestao.texto}
|
|
939
942
|
</button>
|
|
940
943
|
))}
|
|
941
|
-
|
|
944
|
+
|
|
942
945
|
<Button
|
|
943
946
|
variant="ghost"
|
|
944
947
|
size="sm"
|
|
@@ -965,22 +968,22 @@ export function XerticaAssistant({
|
|
|
965
968
|
<XerticaOrbe size={32} />
|
|
966
969
|
</div>
|
|
967
970
|
)}
|
|
968
|
-
|
|
971
|
+
|
|
969
972
|
<div className={cn(
|
|
970
973
|
"flex flex-col max-w-[85%] md:max-w-[70%] min-w-0 w-fit",
|
|
971
974
|
msg.type === 'user' ? "items-end" : "items-start"
|
|
972
975
|
)}>
|
|
973
|
-
<div
|
|
976
|
+
<div
|
|
974
977
|
className={cn(
|
|
975
978
|
"px-4 py-2 break-words overflow-hidden overflow-x-hidden w-full rounded-2xl",
|
|
976
|
-
msg.type === 'user'
|
|
977
|
-
? "bg-primary text-primary-foreground shadow-sm"
|
|
979
|
+
msg.type === 'user'
|
|
980
|
+
? "bg-primary text-primary-foreground shadow-sm"
|
|
978
981
|
: "bg-muted text-foreground"
|
|
979
982
|
)}
|
|
980
983
|
>
|
|
981
984
|
{/* Document Header with Edit and Download Buttons */}
|
|
982
985
|
{msg.attachmentType === 'document' && (
|
|
983
|
-
<div
|
|
986
|
+
<div
|
|
984
987
|
className="flex items-center justify-between mb-2 pb-2 border-b border-border min-w-0 overflow-hidden"
|
|
985
988
|
>
|
|
986
989
|
<div className="flex items-center gap-2 min-w-0 flex-1 overflow-hidden">
|
|
@@ -1012,7 +1015,7 @@ export function XerticaAssistant({
|
|
|
1012
1015
|
|
|
1013
1016
|
{/* Attachments */}
|
|
1014
1017
|
{msg.attachmentType && msg.attachmentType !== 'podcast' && msg.attachmentType !== 'document' && (
|
|
1015
|
-
<div
|
|
1018
|
+
<div
|
|
1016
1019
|
className="flex items-center gap-2 mb-2 pb-2 border-b border-border min-w-0 overflow-hidden"
|
|
1017
1020
|
>
|
|
1018
1021
|
{msg.attachmentType === 'file' && <FileText className="w-4 h-4 flex-shrink-0" />}
|
|
@@ -1021,21 +1024,21 @@ export function XerticaAssistant({
|
|
|
1021
1024
|
<span className="text-small break-words">{msg.attachmentName}</span>
|
|
1022
1025
|
</div>
|
|
1023
1026
|
)}
|
|
1024
|
-
|
|
1027
|
+
|
|
1025
1028
|
{/* Message Content */}
|
|
1026
1029
|
{msg.type === 'user' ? (
|
|
1027
1030
|
<p className="whitespace-pre-wrap break-words">{msg.content}</p>
|
|
1028
1031
|
) : (
|
|
1029
1032
|
<>
|
|
1030
1033
|
{(msg.content.includes('🔐') || msg.content.includes('❌')) && (
|
|
1031
|
-
<div
|
|
1034
|
+
<div
|
|
1032
1035
|
className="mb-3 p-3 border rounded-[var(--radius)] overflow-hidden bg-[var(--toast-error-bg)]/20 border-[var(--toast-error-border)]/30"
|
|
1033
1036
|
>
|
|
1034
1037
|
<div className="flex items-start gap-2 min-w-0">
|
|
1035
1038
|
<AlertCircle className="w-5 h-5 flex-shrink-0 mt-0.5 text-[var(--toast-error-icon)]" />
|
|
1036
1039
|
<div className="flex-1 min-w-0 overflow-hidden">
|
|
1037
|
-
<MarkdownMessage
|
|
1038
|
-
content={msg.content}
|
|
1040
|
+
<MarkdownMessage
|
|
1041
|
+
content={msg.content}
|
|
1039
1042
|
className="text-foreground"
|
|
1040
1043
|
/>
|
|
1041
1044
|
</div>
|
|
@@ -1043,34 +1046,34 @@ export function XerticaAssistant({
|
|
|
1043
1046
|
</div>
|
|
1044
1047
|
)}
|
|
1045
1048
|
{!(msg.content.includes('🔐') || msg.content.includes('❌')) && (
|
|
1046
|
-
<MarkdownMessage
|
|
1047
|
-
content={msg.content}
|
|
1049
|
+
<MarkdownMessage
|
|
1050
|
+
content={msg.content}
|
|
1048
1051
|
className="text-foreground"
|
|
1049
1052
|
/>
|
|
1050
1053
|
)}
|
|
1051
1054
|
</>
|
|
1052
1055
|
)}
|
|
1053
|
-
|
|
1056
|
+
|
|
1054
1057
|
{/* Document Preview */}
|
|
1055
1058
|
{msg.attachmentType === 'document' && msg.documentContent && (
|
|
1056
|
-
<div
|
|
1059
|
+
<div
|
|
1057
1060
|
className="mt-3 pt-3 border-t border-border overflow-hidden"
|
|
1058
1061
|
>
|
|
1059
|
-
<FormattedDocument
|
|
1062
|
+
<FormattedDocument
|
|
1060
1063
|
content={msg.documentContent}
|
|
1061
1064
|
maxPreviewLength={250}
|
|
1062
1065
|
/>
|
|
1063
1066
|
</div>
|
|
1064
1067
|
)}
|
|
1065
|
-
|
|
1068
|
+
|
|
1066
1069
|
{/* Podcast Player */}
|
|
1067
1070
|
{msg.attachmentType === 'podcast' && msg.audioUrl && (
|
|
1068
|
-
<div
|
|
1071
|
+
<div
|
|
1069
1072
|
className="mt-3 pt-3 border-t border-border overflow-hidden"
|
|
1070
1073
|
>
|
|
1071
1074
|
<div className="flex items-center justify-between mb-3 min-w-0 overflow-hidden">
|
|
1072
1075
|
<div className="flex items-center gap-2 min-w-0 flex-1 overflow-hidden">
|
|
1073
|
-
<div
|
|
1076
|
+
<div
|
|
1074
1077
|
className="w-6 h-6 flex items-center justify-center flex-shrink-0 rounded-[var(--radius-button)] bg-gradient-to-br from-[var(--chart-1)] via-[var(--chart-4)] to-[var(--chart-1)]"
|
|
1075
1078
|
>
|
|
1076
1079
|
<Radio className="w-3 h-3 text-white" />
|
|
@@ -1089,11 +1092,11 @@ export function XerticaAssistant({
|
|
|
1089
1092
|
<Download className="w-3 h-3" />
|
|
1090
1093
|
</Button>
|
|
1091
1094
|
</div>
|
|
1092
|
-
<div
|
|
1095
|
+
<div
|
|
1093
1096
|
className="rounded-[var(--radius)] p-2 overflow-hidden bg-gradient-to-r from-[var(--chart-1)]/10 to-[var(--chart-4)]/10"
|
|
1094
1097
|
>
|
|
1095
|
-
<audio
|
|
1096
|
-
controls
|
|
1098
|
+
<audio
|
|
1099
|
+
controls
|
|
1097
1100
|
className="w-full max-w-full h-10 outline-none"
|
|
1098
1101
|
>
|
|
1099
1102
|
<source src={msg.audioUrl} type="audio/mpeg" />
|
|
@@ -1102,10 +1105,10 @@ export function XerticaAssistant({
|
|
|
1102
1105
|
</div>
|
|
1103
1106
|
</div>
|
|
1104
1107
|
)}
|
|
1105
|
-
|
|
1108
|
+
|
|
1106
1109
|
{/* Search Results */}
|
|
1107
1110
|
{msg.attachmentType === 'search' && msg.searchResults && (
|
|
1108
|
-
<div
|
|
1111
|
+
<div
|
|
1109
1112
|
className="mt-3 pt-3 border-t border-border space-y-4 overflow-hidden"
|
|
1110
1113
|
>
|
|
1111
1114
|
<div className="overflow-hidden">
|
|
@@ -1136,7 +1139,7 @@ export function XerticaAssistant({
|
|
|
1136
1139
|
<h5 className="text-sm font-medium break-words flex-1 min-w-0 text-foreground">
|
|
1137
1140
|
{result.title}
|
|
1138
1141
|
</h5>
|
|
1139
|
-
<span
|
|
1142
|
+
<span
|
|
1140
1143
|
className="px-1.5 py-0.5 rounded-sm flex-shrink-0 self-start bg-[var(--chart-4)]/10 text-[var(--chart-4)]"
|
|
1141
1144
|
>
|
|
1142
1145
|
{result.relevance}%
|
|
@@ -1196,7 +1199,7 @@ export function XerticaAssistant({
|
|
|
1196
1199
|
<button
|
|
1197
1200
|
key={command.id}
|
|
1198
1201
|
onClick={() => handleExecuteSearchCommand(
|
|
1199
|
-
command.id,
|
|
1202
|
+
command.id,
|
|
1200
1203
|
msg.content.replace('🔍 Pesquisa realizada com sucesso!', '').split('"')[1] || 'pesquisa',
|
|
1201
1204
|
msg.searchResults!,
|
|
1202
1205
|
msg.id
|
|
@@ -1230,13 +1233,13 @@ export function XerticaAssistant({
|
|
|
1230
1233
|
</div>
|
|
1231
1234
|
)}
|
|
1232
1235
|
</div>
|
|
1233
|
-
|
|
1236
|
+
|
|
1234
1237
|
{/* Message Actions */}
|
|
1235
1238
|
<div className="flex items-center gap-2 mt-1 px-2">
|
|
1236
1239
|
<span className="text-sm text-muted-foreground">
|
|
1237
1240
|
{msg.timestamp.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' })}
|
|
1238
1241
|
</span>
|
|
1239
|
-
|
|
1242
|
+
|
|
1240
1243
|
<Button
|
|
1241
1244
|
variant="ghost"
|
|
1242
1245
|
size="sm"
|
|
@@ -1245,7 +1248,7 @@ export function XerticaAssistant({
|
|
|
1245
1248
|
>
|
|
1246
1249
|
<Heart className={`w-3 h-3 ${msg.isFavorite ? 'fill-current' : ''}`} />
|
|
1247
1250
|
</Button>
|
|
1248
|
-
|
|
1251
|
+
|
|
1249
1252
|
{msg.type === 'assistant' && msg.attachmentType !== 'podcast' && (
|
|
1250
1253
|
<Button
|
|
1251
1254
|
variant="ghost"
|
|
@@ -1262,7 +1265,7 @@ export function XerticaAssistant({
|
|
|
1262
1265
|
)}
|
|
1263
1266
|
</Button>
|
|
1264
1267
|
)}
|
|
1265
|
-
|
|
1268
|
+
|
|
1266
1269
|
<Button
|
|
1267
1270
|
variant="ghost"
|
|
1268
1271
|
size="sm"
|
|
@@ -1279,7 +1282,7 @@ export function XerticaAssistant({
|
|
|
1279
1282
|
</div>
|
|
1280
1283
|
</motion.div>
|
|
1281
1284
|
))}
|
|
1282
|
-
|
|
1285
|
+
|
|
1283
1286
|
{/* Typing Indicator */}
|
|
1284
1287
|
{isProcessing && (
|
|
1285
1288
|
<motion.div
|
|
@@ -1291,8 +1294,8 @@ export function XerticaAssistant({
|
|
|
1291
1294
|
<div className="flex-shrink-0 pt-1">
|
|
1292
1295
|
<XerticaOrbe size={32} />
|
|
1293
1296
|
</div>
|
|
1294
|
-
|
|
1295
|
-
<div
|
|
1297
|
+
|
|
1298
|
+
<div
|
|
1296
1299
|
className="px-4 py-3 bg-muted rounded-2xl"
|
|
1297
1300
|
>
|
|
1298
1301
|
<div className="flex gap-1">
|
|
@@ -1315,7 +1318,7 @@ export function XerticaAssistant({
|
|
|
1315
1318
|
</div>
|
|
1316
1319
|
</motion.div>
|
|
1317
1320
|
)}
|
|
1318
|
-
|
|
1321
|
+
|
|
1319
1322
|
<div ref={messagesEndRef} />
|
|
1320
1323
|
</div>
|
|
1321
1324
|
</ScrollArea>
|
|
@@ -1343,7 +1346,7 @@ export function XerticaAssistant({
|
|
|
1343
1346
|
<div className="text-center py-8">
|
|
1344
1347
|
<Heart className="w-12 h-12 mx-auto text-muted-foreground/50 mb-2" />
|
|
1345
1348
|
<p className="text-muted-foreground">
|
|
1346
|
-
{abaSelecionada === 'favoritos'
|
|
1349
|
+
{abaSelecionada === 'favoritos'
|
|
1347
1350
|
? 'Nenhuma conversa favorita ainda'
|
|
1348
1351
|
: 'Nenhuma conversa no histórico'}
|
|
1349
1352
|
</p>
|
|
@@ -1373,11 +1376,11 @@ export function XerticaAssistant({
|
|
|
1373
1376
|
}}
|
|
1374
1377
|
className="h-6 w-6 p-0 flex-shrink-0 ml-1"
|
|
1375
1378
|
>
|
|
1376
|
-
<Heart
|
|
1379
|
+
<Heart
|
|
1377
1380
|
className={cn(
|
|
1378
1381
|
"w-3 h-3",
|
|
1379
1382
|
conversa.favorita ? "text-destructive fill-current" : "text-muted-foreground"
|
|
1380
|
-
)}
|
|
1383
|
+
)}
|
|
1381
1384
|
/>
|
|
1382
1385
|
</Button>
|
|
1383
1386
|
</div>
|