xertica-ui 1.0.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.
Files changed (141) hide show
  1. package/App.tsx +182 -0
  2. package/README.md +330 -0
  3. package/assets/xertica-logo.svg +38 -0
  4. package/assets/xertica-x-logo.svg +21 -0
  5. package/bin/cli.ts +193 -0
  6. package/components/AssistenteXertica.tsx +2003 -0
  7. package/components/AudioPlayer.tsx +203 -0
  8. package/components/CodeBlock.tsx +242 -0
  9. package/components/DocumentEditor.tsx +504 -0
  10. package/components/ForgotPasswordPage.tsx +170 -0
  11. package/components/FormattedDocument.tsx +87 -0
  12. package/components/HomeContent.tsx +123 -0
  13. package/components/HomePage.tsx +70 -0
  14. package/components/LanguageSelector.tsx +54 -0
  15. package/components/LoginPage.tsx +199 -0
  16. package/components/MarkdownMessage.tsx +62 -0
  17. package/components/ModernChatInput.tsx +502 -0
  18. package/components/PodcastPlayer.tsx +409 -0
  19. package/components/ResetPasswordPage.tsx +234 -0
  20. package/components/Sidebar.tsx +489 -0
  21. package/components/TemplateContent.tsx +629 -0
  22. package/components/TemplatePage.tsx +70 -0
  23. package/components/ThemeToggle.tsx +65 -0
  24. package/components/VerifyEmailPage.tsx +187 -0
  25. package/components/XerticaLogo.tsx +69 -0
  26. package/components/XerticaOrbe.tsx +1339 -0
  27. package/components/XerticaXLogo.tsx +53 -0
  28. package/components/examples/DrawingMapExample.tsx +530 -0
  29. package/components/examples/FilterableMapExample.tsx +380 -0
  30. package/components/examples/LocationPickerExample.tsx +330 -0
  31. package/components/examples/MapExamples.tsx +280 -0
  32. package/components/examples/MapShowcase.tsx +446 -0
  33. package/components/examples/RouteMapExamples.tsx +329 -0
  34. package/components/examples/SimpleFilterableMap.tsx +192 -0
  35. package/components/examples/index.ts +52 -0
  36. package/components/figma/ImageWithFallback.tsx +27 -0
  37. package/components/index.ts +44 -0
  38. package/components/media/AudioPlayer.tsx +278 -0
  39. package/components/media/FloatingMediaWrapper.tsx +166 -0
  40. package/components/media/VideoPlayer.tsx +285 -0
  41. package/components/ui/accordion.tsx +66 -0
  42. package/components/ui/alert-dialog.tsx +159 -0
  43. package/components/ui/alert.tsx +91 -0
  44. package/components/ui/aspect-ratio.tsx +11 -0
  45. package/components/ui/avatar.tsx +65 -0
  46. package/components/ui/badge.tsx +55 -0
  47. package/components/ui/breadcrumb.tsx +109 -0
  48. package/components/ui/button.tsx +78 -0
  49. package/components/ui/calendar.tsx +235 -0
  50. package/components/ui/card.tsx +92 -0
  51. package/components/ui/carousel.tsx +241 -0
  52. package/components/ui/chart.tsx +353 -0
  53. package/components/ui/checkbox.tsx +32 -0
  54. package/components/ui/collapsible.tsx +33 -0
  55. package/components/ui/command.tsx +177 -0
  56. package/components/ui/context-menu.tsx +252 -0
  57. package/components/ui/dialog.tsx +138 -0
  58. package/components/ui/drawer.tsx +134 -0
  59. package/components/ui/dropdown-menu.tsx +257 -0
  60. package/components/ui/empty.tsx +90 -0
  61. package/components/ui/file-upload.tsx +152 -0
  62. package/components/ui/form.tsx +195 -0
  63. package/components/ui/google-maps-loader.tsx +379 -0
  64. package/components/ui/hover-card.tsx +44 -0
  65. package/components/ui/index.ts +242 -0
  66. package/components/ui/input-otp.tsx +77 -0
  67. package/components/ui/input.tsx +38 -0
  68. package/components/ui/label.tsx +24 -0
  69. package/components/ui/map-config.ts +12 -0
  70. package/components/ui/map-layers.tsx +129 -0
  71. package/components/ui/map.exports.ts +31 -0
  72. package/components/ui/map.tsx +412 -0
  73. package/components/ui/menubar.tsx +276 -0
  74. package/components/ui/navigation-menu.tsx +162 -0
  75. package/components/ui/notification-badge.tsx +61 -0
  76. package/components/ui/page-header.tsx +229 -0
  77. package/components/ui/pagination.tsx +127 -0
  78. package/components/ui/popover.tsx +48 -0
  79. package/components/ui/progress.tsx +31 -0
  80. package/components/ui/radio-group.tsx +56 -0
  81. package/components/ui/rating.tsx +102 -0
  82. package/components/ui/resizable.tsx +405 -0
  83. package/components/ui/route-map.tsx +246 -0
  84. package/components/ui/scroll-area.tsx +58 -0
  85. package/components/ui/search.tsx +70 -0
  86. package/components/ui/select.tsx +176 -0
  87. package/components/ui/separator.tsx +28 -0
  88. package/components/ui/sheet.tsx +138 -0
  89. package/components/ui/sidebar.tsx +726 -0
  90. package/components/ui/simple-map.tsx +92 -0
  91. package/components/ui/skeleton.tsx +13 -0
  92. package/components/ui/slider.tsx +58 -0
  93. package/components/ui/sonner.tsx +77 -0
  94. package/components/ui/stats-card.tsx +84 -0
  95. package/components/ui/stepper.tsx +126 -0
  96. package/components/ui/switch.tsx +34 -0
  97. package/components/ui/table.tsx +116 -0
  98. package/components/ui/tabs.tsx +66 -0
  99. package/components/ui/textarea.tsx +26 -0
  100. package/components/ui/timeline.tsx +140 -0
  101. package/components/ui/toggle-group.tsx +71 -0
  102. package/components/ui/toggle.tsx +46 -0
  103. package/components/ui/tooltip.tsx +61 -0
  104. package/components/ui/tree-view.tsx +123 -0
  105. package/components/ui/use-mobile.ts +24 -0
  106. package/components/ui/utils.ts +6 -0
  107. package/components/ui/xertica-assistant.tsx +1420 -0
  108. package/contexts/ApiKeyContext.tsx +123 -0
  109. package/contexts/AssistenteContext.tsx +118 -0
  110. package/contexts/BrandColorsContext.tsx +551 -0
  111. package/contexts/LanguageContext.tsx +36 -0
  112. package/contexts/ThemeContext.tsx +85 -0
  113. package/dist/cli.js +20922 -0
  114. package/eslint.config.js +41 -0
  115. package/guidelines/Guidelines.md +61 -0
  116. package/hooks/useTheme.ts +4 -0
  117. package/imports/Podcast.tsx +389 -0
  118. package/imports/XerticaAi.tsx +46 -0
  119. package/imports/XerticaX.tsx +20 -0
  120. package/imports/svg-aueiaqngck.ts +11 -0
  121. package/imports/svg-v9krss1ozd.ts +16 -0
  122. package/imports/svg-vhrdofe3qe.ts +5 -0
  123. package/index.css +4448 -0
  124. package/index.html +14 -0
  125. package/main.tsx +10 -0
  126. package/package.json +119 -0
  127. package/postcss.config.js +6 -0
  128. package/routes.tsx +33 -0
  129. package/styles/globals.css +15 -0
  130. package/styles/xertica/app-overrides/chat.css +61 -0
  131. package/styles/xertica/app-overrides/scrollbar.css +33 -0
  132. package/styles/xertica/base.css +70 -0
  133. package/styles/xertica/integrations/google-maps.css +76 -0
  134. package/styles/xertica/integrations/sonner.css +73 -0
  135. package/styles/xertica/theme-map.css +88 -0
  136. package/styles/xertica/tokens.css +190 -0
  137. package/tsconfig.json +31 -0
  138. package/tsconfig.node.json +10 -0
  139. package/utils/gemini.ts +140 -0
  140. package/vite-env.d.ts +12 -0
  141. package/vite.config.ts +36 -0
@@ -0,0 +1,123 @@
1
+ import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
2
+
3
+ interface ApiKeyContextType {
4
+ geminiApiKey: string;
5
+ setGeminiApiKey: (key: string) => void;
6
+ isApiKeyValid: boolean;
7
+ googleMapsApiKey: string;
8
+ setGoogleMapsApiKey: (key: string) => void;
9
+ isGoogleMapsKeyValid: boolean;
10
+ reloadMapsApi: () => Promise<void>;
11
+ }
12
+
13
+ const ApiKeyContext = createContext<ApiKeyContextType | undefined>(undefined);
14
+
15
+ export function ApiKeyProvider({ children }: { children: ReactNode }) {
16
+ // Lista de chaves conhecidas como vazadas (para limpeza automática)
17
+ const LEAKED_KEYS = [
18
+ 'AIzaSyCMsAMytBeOK0Qd7RDFKyA5IW9eWt2WTJg',
19
+ 'AIzaSyAiYWEIEmx212Up9zfM8kqyMXB4jLs8gq0'
20
+ ];
21
+
22
+ const [geminiApiKey, setGeminiApiKeyState] = useState<string>(() => {
23
+ const saved = localStorage.getItem('xertica-gemini-api-key');
24
+
25
+ // Se a chave salva estiver na lista de vazadas, removê-la
26
+ if (saved && LEAKED_KEYS.includes(saved)) {
27
+ localStorage.removeItem('xertica-gemini-api-key');
28
+ return '';
29
+ }
30
+
31
+ return saved || '';
32
+ });
33
+
34
+ const [googleMapsApiKey, setGoogleMapsApiKeyState] = useState<string>(() => {
35
+ const saved = localStorage.getItem('xertica-googlemaps-api-key');
36
+ return saved || '';
37
+ });
38
+
39
+ const [isApiKeyValid, setIsApiKeyValid] = useState(false);
40
+ const [isGoogleMapsKeyValid, setIsGoogleMapsKeyValid] = useState(false);
41
+
42
+ useEffect(() => {
43
+ if (geminiApiKey) {
44
+ localStorage.setItem('xertica-gemini-api-key', geminiApiKey);
45
+ // Validação básica do formato da chave
46
+ setIsApiKeyValid(geminiApiKey.startsWith('AIzaSy') && geminiApiKey.length > 20);
47
+ } else {
48
+ localStorage.removeItem('xertica-gemini-api-key');
49
+ setIsApiKeyValid(false);
50
+ }
51
+ }, [geminiApiKey]);
52
+
53
+ useEffect(() => {
54
+ if (googleMapsApiKey) {
55
+ localStorage.setItem('xertica-googlemaps-api-key', googleMapsApiKey);
56
+ // Validação básica do formato da chave do Google Maps
57
+ setIsGoogleMapsKeyValid(googleMapsApiKey.startsWith('AIzaSy') && googleMapsApiKey.length > 20);
58
+
59
+ // Recarregar automaticamente o Google Maps quando a chave mudar
60
+ const reloadMaps = async () => {
61
+ if (googleMapsApiKey.length < 10) return;
62
+
63
+ try {
64
+ const { reloadGoogleMaps } = await import('../components/ui/google-maps-loader');
65
+ await reloadGoogleMaps(googleMapsApiKey);
66
+ console.log('[ApiKeyContext] Google Maps recarregado com sucesso');
67
+ } catch (error) {
68
+ console.error('[ApiKeyContext] Erro ao recarregar Google Maps:', error);
69
+ }
70
+ };
71
+
72
+ reloadMaps();
73
+ } else {
74
+ localStorage.removeItem('xertica-googlemaps-api-key');
75
+ setIsGoogleMapsKeyValid(false);
76
+ }
77
+ }, [googleMapsApiKey]);
78
+
79
+ const setGeminiApiKey = (key: string) => {
80
+ setGeminiApiKeyState(key.trim());
81
+ };
82
+
83
+ const setGoogleMapsApiKey = (key: string) => {
84
+ setGoogleMapsApiKeyState(key.trim());
85
+ };
86
+
87
+ const reloadMapsApi = async () => {
88
+ if (!googleMapsApiKey || googleMapsApiKey.length < 10) {
89
+ return;
90
+ }
91
+
92
+ try {
93
+ // Importar dinamicamente a função de reload
94
+ const { reloadGoogleMaps } = await import('../components/ui/google-maps-loader');
95
+ await reloadGoogleMaps(googleMapsApiKey);
96
+ console.log('[ApiKeyContext] Google Maps recarregado manualmente');
97
+ } catch (error) {
98
+ console.error('[ApiKeyContext] Erro ao recarregar Google Maps:', error);
99
+ }
100
+ };
101
+
102
+ return (
103
+ <ApiKeyContext.Provider value={{
104
+ geminiApiKey,
105
+ setGeminiApiKey,
106
+ isApiKeyValid,
107
+ googleMapsApiKey,
108
+ setGoogleMapsApiKey,
109
+ isGoogleMapsKeyValid,
110
+ reloadMapsApi
111
+ }}>
112
+ {children}
113
+ </ApiKeyContext.Provider>
114
+ );
115
+ }
116
+
117
+ export function useApiKey() {
118
+ const context = useContext(ApiKeyContext);
119
+ if (!context) {
120
+ throw new Error('useApiKey must be used within ApiKeyProvider');
121
+ }
122
+ return context;
123
+ }
@@ -0,0 +1,118 @@
1
+ import React, { createContext, useContext, useState, ReactNode } from 'react';
2
+
3
+ export interface Message {
4
+ id: string;
5
+ type: 'user' | 'assistant';
6
+ content: string;
7
+ timestamp: Date;
8
+ isFavorite?: boolean;
9
+ attachmentType?: 'file' | 'audio' | 'image' | 'podcast' | 'document' | 'search';
10
+ attachmentName?: string;
11
+ audioUrl?: string;
12
+ isPodcastGenerating?: boolean;
13
+ documentContent?: string;
14
+ documentTitle?: string;
15
+ searchResults?: SearchResult[];
16
+ searchSources?: SearchSource[];
17
+ searchCommands?: SearchCommand[];
18
+ }
19
+
20
+ export interface Conversa {
21
+ id: string;
22
+ titulo: string;
23
+ mensagens: Message[];
24
+ ultimaMensagem: string;
25
+ timestamp: string;
26
+ favorita?: boolean;
27
+ }
28
+
29
+ export interface SearchResult {
30
+ id: string;
31
+ title: string;
32
+ description: string;
33
+ type: 'document' | 'file' | 'project' | 'conversation' | 'contact';
34
+ path: string;
35
+ relevance: number;
36
+ lastModified?: string;
37
+ }
38
+
39
+ export interface SearchSource {
40
+ name: string;
41
+ count: number;
42
+ }
43
+
44
+ export interface SearchCommand {
45
+ id: string;
46
+ icon: string;
47
+ label: string;
48
+ description: string;
49
+ }
50
+
51
+ interface AssistenteContextType {
52
+ conversaAtual: string;
53
+ setConversaAtual: (id: string) => void;
54
+ conversas: Conversa[];
55
+ setConversas: React.Dispatch<React.SetStateAction<Conversa[]>>;
56
+ isTyping: boolean;
57
+ setIsTyping: (typing: boolean) => void;
58
+ abaSelecionada: 'chat' | 'historico' | 'favoritos';
59
+ setAbaSelecionada: (aba: 'chat' | 'historico' | 'favoritos') => void;
60
+ editingDocument: { content: string; title: string } | null;
61
+ setEditingDocument: (doc: { content: string; title: string } | null) => void;
62
+ searchFilter: 'all' | 'document' | 'project' | 'conversation' | 'file' | 'contact';
63
+ setSearchFilter: (filter: 'all' | 'document' | 'project' | 'conversation' | 'file' | 'contact') => void;
64
+ savedSearches: string[];
65
+ setSavedSearches: React.Dispatch<React.SetStateAction<string[]>>;
66
+ }
67
+
68
+ const AssistenteContext = createContext<AssistenteContextType | undefined>(undefined);
69
+
70
+ export function AssistenteProvider({ children }: { children: ReactNode }) {
71
+ const [conversaAtual, setConversaAtual] = useState<string>('1');
72
+ const [conversas, setConversas] = useState<Conversa[]>([
73
+ {
74
+ id: '1',
75
+ titulo: 'Nova Conversa',
76
+ mensagens: [],
77
+ ultimaMensagem: '',
78
+ timestamp: new Date().toISOString(),
79
+ favorita: false
80
+ }
81
+ ]);
82
+ const [isTyping, setIsTyping] = useState(false);
83
+ const [abaSelecionada, setAbaSelecionada] = useState<'chat' | 'historico' | 'favoritos'>('chat');
84
+ const [editingDocument, setEditingDocument] = useState<{ content: string; title: string } | null>(null);
85
+ const [searchFilter, setSearchFilter] = useState<'all' | 'document' | 'project' | 'conversation' | 'file' | 'contact'>('all');
86
+ const [savedSearches, setSavedSearches] = useState<string[]>([]);
87
+
88
+ return (
89
+ <AssistenteContext.Provider
90
+ value={{
91
+ conversaAtual,
92
+ setConversaAtual,
93
+ conversas,
94
+ setConversas,
95
+ isTyping,
96
+ setIsTyping,
97
+ abaSelecionada,
98
+ setAbaSelecionada,
99
+ editingDocument,
100
+ setEditingDocument,
101
+ searchFilter,
102
+ setSearchFilter,
103
+ savedSearches,
104
+ setSavedSearches,
105
+ }}
106
+ >
107
+ {children}
108
+ </AssistenteContext.Provider>
109
+ );
110
+ }
111
+
112
+ export function useAssistente() {
113
+ const context = useContext(AssistenteContext);
114
+ if (!context) {
115
+ throw new Error('useAssistente must be used within AssistenteProvider');
116
+ }
117
+ return context;
118
+ }