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.
@@ -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
- const isApiKeyValid = Boolean(apiKey && apiKey.length > 20);
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
- ...msg,
505
- attachmentType: 'podcast',
506
- attachmentName: 'Podcast - ' + content.substring(0, 30) + '...',
507
- audioUrl: 'data:audio/mpeg;base64,//uQx...' // Mock
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>