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,330 @@
1
+ import React, { useState } from 'react';
2
+ import { Map } from '../ui/map';
3
+ import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '../ui/card';
4
+ import { Button } from '../ui/button';
5
+ import { Badge } from '../ui/badge';
6
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from '../ui/tabs';
7
+ import { MapPin, Store, Home, Building2, Navigation } from 'lucide-react';
8
+
9
+ /**
10
+ * LocationPickerExample
11
+ *
12
+ * Exemplo avançado que demonstra:
13
+ * - Seleção de localização em um mapa
14
+ * - Múltiplas categorias de locais
15
+ * - Estado interativo
16
+ * - Integração com outros componentes UI
17
+ */
18
+
19
+ interface Location {
20
+ id: string;
21
+ name: string;
22
+ address: string;
23
+ category: 'store' | 'office' | 'home';
24
+ coords: { lat: number; lng: number };
25
+ description: string;
26
+ isOpen?: boolean;
27
+ phone?: string;
28
+ }
29
+
30
+ const mockLocations: Location[] = [
31
+ {
32
+ id: '1',
33
+ name: 'Loja Centro',
34
+ address: 'Av. Paulista, 1000 - Bela Vista, São Paulo',
35
+ category: 'store',
36
+ coords: { lat: -23.5505, lng: -46.6333 },
37
+ description: 'Nossa loja principal no centro da cidade',
38
+ isOpen: true,
39
+ phone: '(11) 3456-7890'
40
+ },
41
+ {
42
+ id: '2',
43
+ name: 'Loja Shopping',
44
+ address: 'Shopping Ibirapuera - Vila Clementino, São Paulo',
45
+ category: 'store',
46
+ coords: { lat: -23.5965, lng: -46.6520 },
47
+ description: 'Loja no Shopping Ibirapuera',
48
+ isOpen: true,
49
+ phone: '(11) 3456-7891'
50
+ },
51
+ {
52
+ id: '3',
53
+ name: 'Escritório Administrativo',
54
+ address: 'Rua Augusta, 2000 - Consolação, São Paulo',
55
+ category: 'office',
56
+ coords: { lat: -23.5558, lng: -46.6600 },
57
+ description: 'Sede administrativa da empresa',
58
+ isOpen: false,
59
+ phone: '(11) 3456-7892'
60
+ },
61
+ {
62
+ id: '4',
63
+ name: 'Centro de Distribuição',
64
+ address: 'Rodovia dos Bandeirantes, km 24',
65
+ category: 'office',
66
+ coords: { lat: -23.4850, lng: -46.6850 },
67
+ description: 'Centro de logística e distribuição',
68
+ isOpen: true,
69
+ phone: '(11) 3456-7893'
70
+ }
71
+ ];
72
+
73
+ export function LocationPickerExample() {
74
+ const [selectedLocation, setSelectedLocation] = useState<Location | null>(mockLocations[0]);
75
+ const [activeCategory, setActiveCategory] = useState<string>('all');
76
+
77
+ // Filtrar localizações por categoria
78
+ const filteredLocations = activeCategory === 'all'
79
+ ? mockLocations
80
+ : mockLocations.filter(loc => loc.category === activeCategory);
81
+
82
+ // Criar marcadores para o mapa
83
+ const markers = filteredLocations.map(loc => ({
84
+ position: loc.coords,
85
+ title: loc.name,
86
+ info: loc.address,
87
+ label: loc.category === 'store' ? '🏪' : loc.category === 'office' ? '🏢' : '🏠'
88
+ }));
89
+
90
+ // Calcular centro do mapa baseado nos locais filtrados
91
+ const mapCenter = selectedLocation?.coords || { lat: -23.5505, lng: -46.6333 };
92
+
93
+ const getCategoryIcon = (category: string) => {
94
+ switch (category) {
95
+ case 'store': return <Store className="w-4 h-4" />;
96
+ case 'office': return <Building2 className="w-4 h-4" />;
97
+ case 'home': return <Home className="w-4 h-4" />;
98
+ default: return <MapPin className="w-4 h-4" />;
99
+ }
100
+ };
101
+
102
+ const getCategoryLabel = (category: string) => {
103
+ switch (category) {
104
+ case 'store': return 'Loja';
105
+ case 'office': return 'Escritório';
106
+ case 'home': return 'Residência';
107
+ default: return 'Local';
108
+ }
109
+ };
110
+
111
+ return (
112
+ <div className="space-y-6 max-w-6xl mx-auto">
113
+ <div className="space-y-2">
114
+ <h2 className="text-2xl">Encontre uma Localização</h2>
115
+ <p className="text-muted-foreground">
116
+ Selecione um local para ver mais informações e como chegar
117
+ </p>
118
+ </div>
119
+
120
+ <Tabs defaultValue="all" onValueChange={setActiveCategory}>
121
+ <TabsList className="w-full grid grid-cols-4">
122
+ <TabsTrigger value="all">
123
+ <MapPin className="w-4 h-4 mr-2" />
124
+ Todos ({mockLocations.length})
125
+ </TabsTrigger>
126
+ <TabsTrigger value="store">
127
+ <Store className="w-4 h-4 mr-2" />
128
+ Lojas ({mockLocations.filter(l => l.category === 'store').length})
129
+ </TabsTrigger>
130
+ <TabsTrigger value="office">
131
+ <Building2 className="w-4 h-4 mr-2" />
132
+ Escritórios ({mockLocations.filter(l => l.category === 'office').length})
133
+ </TabsTrigger>
134
+ <TabsTrigger value="home">
135
+ <Home className="w-4 h-4 mr-2" />
136
+ Outros ({mockLocations.filter(l => l.category === 'home').length})
137
+ </TabsTrigger>
138
+ </TabsList>
139
+
140
+ <TabsContent value={activeCategory} className="mt-6">
141
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
142
+ {/* Lista de Locais */}
143
+ <div className="lg:col-span-1 space-y-3">
144
+ <h3 className="text-sm font-medium text-muted-foreground">
145
+ {filteredLocations.length} {filteredLocations.length === 1 ? 'local' : 'locais'} encontrado{filteredLocations.length !== 1 ? 's' : ''}
146
+ </h3>
147
+
148
+ <div className="space-y-2 max-h-[600px] overflow-y-auto pr-2">
149
+ {filteredLocations.map((location) => (
150
+ <Card
151
+ key={location.id}
152
+ className={`cursor-pointer transition-all hover:shadow-md ${
153
+ selectedLocation?.id === location.id
154
+ ? 'ring-2 ring-primary bg-primary/5'
155
+ : ''
156
+ }`}
157
+ onClick={() => setSelectedLocation(location)}
158
+ >
159
+ <CardHeader className="p-4">
160
+ <div className="flex items-start justify-between gap-2">
161
+ <div className="flex-1">
162
+ <CardTitle className="text-base flex items-center gap-2">
163
+ {getCategoryIcon(location.category)}
164
+ {location.name}
165
+ </CardTitle>
166
+ <CardDescription className="text-xs mt-1">
167
+ {location.address}
168
+ </CardDescription>
169
+ </div>
170
+ {location.isOpen !== undefined && (
171
+ <Badge
172
+ variant={location.isOpen ? 'success' : 'secondary'}
173
+ className="text-xs"
174
+ >
175
+ {location.isOpen ? 'Aberto' : 'Fechado'}
176
+ </Badge>
177
+ )}
178
+ </div>
179
+ </CardHeader>
180
+ </Card>
181
+ ))}
182
+ </div>
183
+ </div>
184
+
185
+ {/* Mapa e Detalhes */}
186
+ <div className="lg:col-span-2 space-y-4">
187
+ {/* Mapa */}
188
+ <Card>
189
+ <CardContent className="p-4">
190
+ <Map
191
+ center={mapCenter}
192
+ zoom={selectedLocation ? 15 : 12}
193
+ markers={markers}
194
+ height="400px"
195
+ zoomControl={true}
196
+ fullscreenControl={true}
197
+ />
198
+ </CardContent>
199
+ </Card>
200
+
201
+ {/* Informações do Local Selecionado */}
202
+ {selectedLocation && (
203
+ <Card>
204
+ <CardHeader>
205
+ <div className="flex items-start justify-between">
206
+ <div className="space-y-1">
207
+ <div className="flex items-center gap-2">
208
+ {getCategoryIcon(selectedLocation.category)}
209
+ <CardTitle>{selectedLocation.name}</CardTitle>
210
+ </div>
211
+ <CardDescription>
212
+ {getCategoryLabel(selectedLocation.category)}
213
+ </CardDescription>
214
+ </div>
215
+ {selectedLocation.isOpen !== undefined && (
216
+ <Badge
217
+ variant={selectedLocation.isOpen ? 'success' : 'secondary'}
218
+ >
219
+ {selectedLocation.isOpen ? 'Aberto agora' : 'Fechado'}
220
+ </Badge>
221
+ )}
222
+ </div>
223
+ </CardHeader>
224
+ <CardContent className="space-y-4">
225
+ <div className="space-y-2">
226
+ <div className="flex items-start gap-2 text-sm">
227
+ <MapPin className="w-4 h-4 text-muted-foreground mt-0.5 shrink-0" />
228
+ <span>{selectedLocation.address}</span>
229
+ </div>
230
+ {selectedLocation.phone && (
231
+ <div className="flex items-center gap-2 text-sm">
232
+ <span className="text-muted-foreground">📞</span>
233
+ <span>{selectedLocation.phone}</span>
234
+ </div>
235
+ )}
236
+ </div>
237
+
238
+ <p className="text-sm text-muted-foreground">
239
+ {selectedLocation.description}
240
+ </p>
241
+ </CardContent>
242
+ <CardFooter className="flex gap-2">
243
+ <Button className="flex-1">
244
+ <Navigation className="w-4 h-4 mr-2" />
245
+ Como Chegar
246
+ </Button>
247
+ <Button variant="outline" className="flex-1">
248
+ Mais Informações
249
+ </Button>
250
+ </CardFooter>
251
+ </Card>
252
+ )}
253
+ </div>
254
+ </div>
255
+ </TabsContent>
256
+ </Tabs>
257
+ </div>
258
+ );
259
+ }
260
+
261
+ /**
262
+ * VARIAÇÃO: Seletor de Endereço de Entrega
263
+ */
264
+ export function DeliveryAddressSelector() {
265
+ const [selectedAddress, setSelectedAddress] = useState<string | null>(null);
266
+
267
+ const addresses = [
268
+ { id: '1', label: 'Casa', address: 'Rua das Flores, 123', coords: { lat: -23.5505, lng: -46.6333 } },
269
+ { id: '2', label: 'Trabalho', address: 'Av. Paulista, 1000', coords: { lat: -23.5615, lng: -46.6560 } },
270
+ { id: '3', label: 'Outro', address: 'Rua Augusta, 2000', coords: { lat: -23.5558, lng: -46.6600 } }
271
+ ];
272
+
273
+ const selectedCoords = addresses.find(a => a.id === selectedAddress)?.coords || addresses[0].coords;
274
+
275
+ return (
276
+ <Card className="max-w-2xl">
277
+ <CardHeader>
278
+ <CardTitle>Selecione o Endereço de Entrega</CardTitle>
279
+ <CardDescription>
280
+ Escolha onde deseja receber seu pedido
281
+ </CardDescription>
282
+ </CardHeader>
283
+ <CardContent className="space-y-4">
284
+ <div className="space-y-2">
285
+ {addresses.map((addr) => (
286
+ <button
287
+ key={addr.id}
288
+ onClick={() => setSelectedAddress(addr.id)}
289
+ className={`w-full p-4 rounded-lg border-2 text-left transition-all ${
290
+ selectedAddress === addr.id
291
+ ? 'border-primary bg-primary/5'
292
+ : 'border-border hover:border-primary/50'
293
+ }`}
294
+ >
295
+ <div className="flex items-start gap-3">
296
+ <Home className="w-5 h-5 text-muted-foreground mt-0.5" />
297
+ <div className="flex-1">
298
+ <p className="font-medium">{addr.label}</p>
299
+ <p className="text-sm text-muted-foreground">{addr.address}</p>
300
+ </div>
301
+ {selectedAddress === addr.id && (
302
+ <div className="w-5 h-5 rounded-full bg-primary flex items-center justify-center">
303
+ <span className="text-xs text-primary-foreground">✓</span>
304
+ </div>
305
+ )}
306
+ </div>
307
+ </button>
308
+ ))}
309
+ </div>
310
+
311
+ <Map
312
+ center={selectedCoords}
313
+ zoom={15}
314
+ markers={[
315
+ {
316
+ position: selectedCoords,
317
+ title: "Endereço de Entrega"
318
+ }
319
+ ]}
320
+ height="300px"
321
+ />
322
+ </CardContent>
323
+ <CardFooter>
324
+ <Button className="w-full" disabled={!selectedAddress}>
325
+ Confirmar Endereço
326
+ </Button>
327
+ </CardFooter>
328
+ </Card>
329
+ );
330
+ }
@@ -0,0 +1,280 @@
1
+ import React from 'react';
2
+ import { Map } from '../ui/map';
3
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../ui/card';
4
+ import { Badge } from '../ui/badge';
5
+ import { Button } from '../ui/button';
6
+ import { MapPin, Navigation, Store, Heart } from 'lucide-react';
7
+
8
+ /**
9
+ * Exemplos práticos de uso do componente Map
10
+ * Demonstra diferentes casos de uso do mundo real
11
+ */
12
+
13
+ // 1. Mapa de Loja com Raio de Entrega
14
+ export function StoreDeliveryMap() {
15
+ const storeLocation = { lat: -23.5505, lng: -46.6333 };
16
+
17
+ return (
18
+ <Card>
19
+ <CardHeader>
20
+ <div className="flex items-center gap-2">
21
+ <Store className="w-5 h-5 text-primary" />
22
+ <CardTitle>Área de Entrega</CardTitle>
23
+ </div>
24
+ <CardDescription>
25
+ Realizamos entregas em um raio de 5km da nossa loja
26
+ </CardDescription>
27
+ </CardHeader>
28
+ <CardContent>
29
+ <Map
30
+ center={storeLocation}
31
+ zoom={13}
32
+ markers={[
33
+ {
34
+ position: storeLocation,
35
+ title: "Nossa Loja",
36
+ info: "Avenida Paulista, 1000"
37
+ }
38
+ ]}
39
+ circle={{
40
+ center: storeLocation,
41
+ radius: 5000,
42
+ fillColor: "#10B981",
43
+ strokeColor: "#059669"
44
+ }}
45
+ height="400px"
46
+ />
47
+ <div className="mt-4 flex items-center justify-between">
48
+ <div className="flex items-center gap-2">
49
+ <MapPin className="w-4 h-4 text-muted-foreground" />
50
+ <span className="text-sm text-muted-foreground">
51
+ Cobertura de 5km
52
+ </span>
53
+ </div>
54
+ <Button size="sm">
55
+ <Navigation className="w-4 h-4 mr-2" />
56
+ Como Chegar
57
+ </Button>
58
+ </div>
59
+ </CardContent>
60
+ </Card>
61
+ );
62
+ }
63
+
64
+ // 2. Mapa de Locais Favoritos
65
+ export function FavoritePlacesMap() {
66
+ const favorites = [
67
+ {
68
+ position: { lat: -23.5505, lng: -46.6333 },
69
+ label: "⭐",
70
+ title: "Restaurante Favorito",
71
+ info: "Melhor pizza da cidade!"
72
+ },
73
+ {
74
+ position: { lat: -23.5475, lng: -46.6361 },
75
+ label: "☕",
76
+ title: "Cafeteria",
77
+ info: "Café artesanal"
78
+ },
79
+ {
80
+ position: { lat: -23.5613, lng: -46.6563 },
81
+ label: "🏃",
82
+ title: "Parque",
83
+ info: "Local de corrida matinal"
84
+ },
85
+ {
86
+ position: { lat: -23.5558, lng: -46.6396 },
87
+ label: "🎬",
88
+ title: "Cinema",
89
+ info: "Cinema independente"
90
+ }
91
+ ];
92
+
93
+ return (
94
+ <Card>
95
+ <CardHeader>
96
+ <div className="flex items-center justify-between">
97
+ <div className="flex items-center gap-2">
98
+ <Heart className="w-5 h-5 text-destructive" />
99
+ <CardTitle>Meus Lugares Favoritos</CardTitle>
100
+ </div>
101
+ <Badge variant="secondary">{favorites.length} locais</Badge>
102
+ </div>
103
+ <CardDescription>
104
+ Lugares que você marcou como favoritos
105
+ </CardDescription>
106
+ </CardHeader>
107
+ <CardContent>
108
+ <Map
109
+ center={{ lat: -23.5505, lng: -46.6333 }}
110
+ zoom={13}
111
+ markers={favorites}
112
+ height="450px"
113
+ />
114
+ </CardContent>
115
+ </Card>
116
+ );
117
+ }
118
+
119
+ // 3. Mapa de Escritórios da Empresa
120
+ export function CompanyOfficesMap() {
121
+ const offices = [
122
+ {
123
+ position: { lat: -23.5505, lng: -46.6333 },
124
+ label: "HQ",
125
+ title: "Sede - São Paulo",
126
+ info: "Matriz da empresa - 200 funcionários"
127
+ },
128
+ {
129
+ position: { lat: -22.9068, lng: -43.1729 },
130
+ label: "RJ",
131
+ title: "Filial - Rio de Janeiro",
132
+ info: "Escritório regional - 80 funcionários"
133
+ },
134
+ {
135
+ position: { lat: -19.9167, lng: -43.9345 },
136
+ label: "BH",
137
+ title: "Filial - Belo Horizonte",
138
+ info: "Centro de distribuição - 50 funcionários"
139
+ },
140
+ {
141
+ position: { lat: -25.4284, lng: -49.2733 },
142
+ label: "CWB",
143
+ title: "Filial - Curitiba",
144
+ info: "Centro de tecnologia - 120 funcionários"
145
+ }
146
+ ];
147
+
148
+ return (
149
+ <Card>
150
+ <CardHeader>
151
+ <CardTitle>Nossos Escritórios</CardTitle>
152
+ <CardDescription>
153
+ Presença em 4 estados brasileiros
154
+ </CardDescription>
155
+ </CardHeader>
156
+ <CardContent>
157
+ <Map
158
+ center={{ lat: -22.5, lng: -45.0 }}
159
+ zoom={6}
160
+ markers={offices}
161
+ height="500px"
162
+ zoomControl={true}
163
+ fullscreenControl={true}
164
+ />
165
+ <div className="mt-4 grid grid-cols-2 md:grid-cols-4 gap-2">
166
+ {offices.map((office, index) => (
167
+ <div key={index} className="text-center p-3 bg-muted rounded-lg">
168
+ <div className="text-2xl mb-1">{office.label}</div>
169
+ <p className="text-xs text-muted-foreground line-clamp-1">
170
+ {office.title}
171
+ </p>
172
+ </div>
173
+ ))}
174
+ </div>
175
+ </CardContent>
176
+ </Card>
177
+ );
178
+ }
179
+
180
+ // 4. Mapa de Zona de Serviço com Polígono
181
+ export function ServiceZoneMap() {
182
+ const serviceZone = {
183
+ paths: [
184
+ { lat: -23.540, lng: -46.620 },
185
+ { lat: -23.540, lng: -46.660 },
186
+ { lat: -23.565, lng: -46.660 },
187
+ { lat: -23.565, lng: -46.620 }
188
+ ],
189
+ fillColor: "#3B82F6",
190
+ strokeColor: "#2563EB"
191
+ };
192
+
193
+ return (
194
+ <Card>
195
+ <CardHeader>
196
+ <CardTitle>Área de Atendimento</CardTitle>
197
+ <CardDescription>
198
+ Zona azul indica nossa área de serviço prioritária
199
+ </CardDescription>
200
+ </CardHeader>
201
+ <CardContent>
202
+ <Map
203
+ center={{ lat: -23.5525, lng: -46.640 }}
204
+ zoom={13}
205
+ polygon={serviceZone}
206
+ markers={[
207
+ {
208
+ position: { lat: -23.5525, lng: -46.640 },
209
+ title: "Central de Operações",
210
+ info: "Base de atendimento"
211
+ }
212
+ ]}
213
+ height="450px"
214
+ />
215
+ <div className="mt-4 p-4 bg-blue-50 dark:bg-blue-950/20 rounded-lg border border-blue-200 dark:border-blue-800">
216
+ <p className="text-sm text-blue-900 dark:text-blue-100">
217
+ <strong>Atendimento prioritário:</strong> Clientes dentro da zona azul
218
+ recebem atendimento em até 2 horas.
219
+ </p>
220
+ </div>
221
+ </CardContent>
222
+ </Card>
223
+ );
224
+ }
225
+
226
+ // 5. Grid de Mapas Compactos (Comparação)
227
+ export function CompactMapsGrid() {
228
+ const cities = [
229
+ {
230
+ name: "São Paulo",
231
+ center: { lat: -23.5505, lng: -46.6333 },
232
+ description: "Maior cidade do Brasil"
233
+ },
234
+ {
235
+ name: "Rio de Janeiro",
236
+ center: { lat: -22.9068, lng: -43.1729 },
237
+ description: "Cidade maravilhosa"
238
+ },
239
+ {
240
+ name: "Brasília",
241
+ center: { lat: -15.7942, lng: -47.8822 },
242
+ description: "Capital federal"
243
+ },
244
+ {
245
+ name: "Salvador",
246
+ center: { lat: -12.9714, lng: -38.5014 },
247
+ description: "Primeira capital"
248
+ }
249
+ ];
250
+
251
+ return (
252
+ <Card>
253
+ <CardHeader>
254
+ <CardTitle>Principais Cidades</CardTitle>
255
+ <CardDescription>
256
+ Visão rápida das principais metrópoles brasileiras
257
+ </CardDescription>
258
+ </CardHeader>
259
+ <CardContent>
260
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
261
+ {cities.map((city, index) => (
262
+ <div key={index} className="space-y-2">
263
+ <div className="flex items-center justify-between">
264
+ <h4 className="font-medium">{city.name}</h4>
265
+ <Badge variant="outline">{city.description}</Badge>
266
+ </div>
267
+ <Map
268
+ center={city.center}
269
+ zoom={11}
270
+ height="200px"
271
+ disableDefaultUI={true}
272
+ gestureHandling="none"
273
+ />
274
+ </div>
275
+ ))}
276
+ </div>
277
+ </CardContent>
278
+ </Card>
279
+ );
280
+ }