# Sistema de Estilização e Componentes UI ## Visão Geral O aplicativo utiliza um sistema de estilização híbrido, combinando StyleSheet nativo do React Native com Tailwind CSS para componentes web, além de uma biblioteca completa de componentes UI baseados no shadcn/ui. ## Sistema de Cores e Tema ### Paleta de Cores Principal **Arquivo**: `src/constants/theme.ts` ```typescript export const COLORS = { primary: "#0A1E63", // Azul escuro principal secondary: "#F5F5F5", // Cinza claro background: "#FFFFFF", // Branco de fundo text: "#333333", // Cinza escuro para texto textLight: "#777777", // Cinza médio para texto secundário success: "#4CAF50", // Verde para sucesso warning: "#FFC107", // Amarelo para avisos danger: "#F44336", // Vermelho para erros info: "#2196F3", // Azul para informações border: "#E0E0E0", // Cinza claro para bordas card: "#FFFFFF", // Branco para cards shadow: "#000000", // Preto para sombras error: "#FF3B30", // Vermelho para erros } ``` ### Sistema de Tamanhos ```typescript export const SIZES = { base: 8, // Unidade base (8px) small: 12, // Pequeno font: 14, // Tamanho de fonte padrão medium: 16, // Médio large: 18, // Grande extraLarge: 24, // Extra grande } ``` ### Tipografia ```typescript export const FONTS = { regular: "Roboto-Regular", medium: "Roboto-Medium", bold: "Roboto-Bold", } ``` ### Sistema de Sombras ```typescript export const SHADOWS = { small: { shadowColor: COLORS.shadow, shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, shadowRadius: 3.84, elevation: 2, }, medium: { shadowColor: COLORS.shadow, shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, shadowRadius: 5.84, elevation: 5, }, } ``` ## Configuração Tailwind CSS ### Arquivo de Configuração **Arquivo**: `tailwind.config.ts` ```typescript const config: Config = { darkMode: ["class"], content: [ "./pages/**/*.{js,ts,jsx,tsx,mdx}", "./components/**/*.{js,ts,jsx,tsx,mdx}", "./app/**/*.{js,ts,jsx,tsx,mdx}", "*.{js,ts,jsx,tsx,mdx}" ], theme: { extend: { colors: { background: 'hsl(var(--background))', foreground: 'hsl(var(--foreground))', primary: { DEFAULT: 'hsl(var(--primary))', foreground: 'hsl(var(--primary-foreground))' }, // ... outras cores }, borderRadius: { lg: 'var(--radius)', md: 'calc(var(--radius) - 2px)', sm: 'calc(var(--radius) - 4px)' }, keyframes: { 'accordion-down': { from: { height: '0' }, to: { height: 'var(--radix-accordion-content-height)' } }, 'accordion-up': { from: { height: 'var(--radix-accordion-content-height)' }, to: { height: '0' } } }, animation: { 'accordion-down': 'accordion-down 0.2s ease-out', 'accordion-up': 'accordion-up 0.2s ease-out' } } }, plugins: [require("tailwindcss-animate")], }; ``` ## Componentes UI Principais ### 1. Componente Icon **Arquivo**: `components/Icon.tsx` ```typescript interface IconProps { type: 'material' | 'font-awesome' | 'ionicons'; name: string; size?: number; color?: string; style?: any; } const Icon: React.FC = ({ type, name, size = 24, color, style }) => { switch (type) { case 'material': return ; case 'font-awesome': return ; case 'ionicons': return ; default: return ; } }; ``` **Uso**: ```typescript ``` ### 2. Componente FloatingPanicButton **Arquivo**: `components/FloatingPanicButton.tsx` ```typescript interface FloatingPanicButtonProps { onPanic: (location?: { latitude: number; longitude: number } | null) => void; } const FloatingPanicButton: React.FC = ({ onPanic }) => { const [location, setLocation] = useState(null); const handlePanic = async () => { try { const { status } = await Location.requestForegroundPermissionsAsync(); if (status === 'granted') { const location = await Location.getCurrentPositionAsync({}); setLocation(location.coords); onPanic(location.coords); } else { onPanic(null); } } catch (error) { onPanic(null); } }; return ( ); }; ``` ### 3. Componente DeliveryMap **Arquivo**: `src/components/DeliveryMap.tsx` ```typescript interface DeliveryMapProps { deliveries: Delivery[]; onRouteCalculated?: (optimizedDeliveries: Delivery[]) => void; showRoute?: boolean; } const DeliveryMap: React.FC = ({ deliveries, onRouteCalculated, showRoute = true }) => { const [mapRef, setMapRef] = useState(null); const [routeCoordinates, setRouteCoordinates] = useState([]); // Implementação do mapa com marcadores e rotas return ( {/* Marcadores das entregas */} {deliveries.map((delivery, index) => ( ))} {/* Polilinha da rota */} {showRoute && routeCoordinates.length > 0 && ( )} ); }; ``` ### 4. Componente MobileSignalIndicator **Arquivo**: `src/components/MobileSignalIndicator.tsx` ```typescript interface MobileSignalIndicatorProps { signalInfo: MobileSignalInfo; onOfflineModeChange?: (isOffline: boolean) => void; } const MobileSignalIndicator: React.FC = ({ signalInfo, onOfflineModeChange }) => { const getSignalColor = (strength: number) => { if (strength >= 70) return COLORS.success; if (strength >= 40) return COLORS.warning; return COLORS.danger; }; const getSignalIcon = (strength: number) => { if (strength >= 70) return 'signal-cellular-4-bar'; if (strength >= 40) return 'signal-cellular-2-bar'; return 'signal-cellular-0-bar'; }; return ( {signalInfo.signalStrength}% - {signalInfo.connectionType} {signalInfo.shouldUseOffline && ( OFFLINE )} ); }; ``` ## Componentes shadcn/ui ### Estrutura dos Componentes **Pasta**: `components/ui/` Os componentes seguem o padrão shadcn/ui com adaptações para React Native: #### 1. Button Component **Arquivo**: `components/ui/button.tsx` ```typescript interface ButtonProps { variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'; size?: 'default' | 'sm' | 'lg' | 'icon'; children: React.ReactNode; onPress?: () => void; disabled?: boolean; } const Button: React.FC = ({ variant = 'default', size = 'default', children, onPress, disabled = false }) => { const buttonStyles = [ styles.base, styles[variant], styles[size], disabled && styles.disabled ]; return ( {children} ); }; ``` #### 2. Card Component **Arquivo**: `components/ui/card.tsx` ```typescript interface CardProps { children: React.ReactNode; style?: any; } const Card: React.FC = ({ children, style }) => ( {children} ); const CardHeader: React.FC = ({ children, style }) => ( {children} ); const CardContent: React.FC = ({ children, style }) => ( {children} ); ``` #### 3. Input Component **Arquivo**: `components/ui/input.tsx` ```typescript interface InputProps { placeholder?: string; value?: string; onChangeText?: (text: string) => void; secureTextEntry?: boolean; keyboardType?: KeyboardTypeOptions; style?: any; } const Input: React.FC = ({ placeholder, value, onChangeText, secureTextEntry = false, keyboardType = 'default', style }) => ( ); ``` ## Estilos das Telas Principais ### 1. LoginScreen Styles ```typescript const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: COLORS.background, }, scrollContent: { flexGrow: 1, justifyContent: "center", padding: 20, }, logoContainer: { alignItems: "center", marginBottom: 20, }, headerContainer: { alignItems: "center", marginBottom: 30, }, headerTitle: { fontSize: 28, fontWeight: "bold", color: COLORS.text, marginBottom: 8, }, formContainer: { width: "100%", maxWidth: 400, alignSelf: "center", }, input: { backgroundColor: COLORS.secondary, borderRadius: 12, padding: 15, fontSize: 16, color: COLORS.text, width: "100%", }, loginButton: { backgroundColor: COLORS.primary, borderRadius: 12, padding: 16, alignItems: "center", marginBottom: 24, }, loginButtonText: { color: "#FFFFFF", fontSize: 16, fontWeight: "bold", }, }); ``` ### 2. HomeScreen Styles ```typescript const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: COLORS.background, }, headerGradient: { paddingBottom: 16, }, header: { flexDirection: "row", alignItems: "flex-start", justifyContent: "space-between", paddingHorizontal: 20, paddingVertical: 16, }, statsContainer: { flexDirection: "row", backgroundColor: COLORS.card, paddingVertical: 20, paddingHorizontal: 20, marginHorizontal: 16, marginTop: -8, borderRadius: 16, ...SHADOWS.medium, }, statCard: { flex: 1, alignItems: "center", }, statNumber: { fontSize: 24, fontWeight: "bold", color: COLORS.primary, marginBottom: 4, }, nextDeliveryCard: { backgroundColor: COLORS.card, borderRadius: 20, padding: 20, marginHorizontal: 16, marginBottom: 16, ...SHADOWS.medium, borderWidth: 2, borderColor: COLORS.primary + "20", }, }); ``` ### 3. RoutesScreen Styles ```typescript const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: COLORS.background, }, mapContainer: { flex: 1, borderRadius: 16, overflow: 'hidden', margin: 16, ...SHADOWS.medium, }, map: { flex: 1, }, controlsContainer: { position: 'absolute', top: 20, right: 20, flexDirection: 'row', gap: 10, }, controlButton: { backgroundColor: COLORS.card, borderRadius: 8, padding: 12, ...SHADOWS.small, }, statsContainer: { position: 'absolute', bottom: 20, left: 20, right: 20, backgroundColor: COLORS.card, borderRadius: 16, padding: 16, ...SHADOWS.medium, }, }); ``` ## Sistema de Gradientes ### LinearGradient Usage ```typescript import { LinearGradient } from 'expo-linear-gradient'; // Header gradient {/* Header content */} // Button gradient Entrar // Card gradient {/* Success content */} ``` ## Animações e Transições ### Animated Components ```typescript import { Animated } from 'react-native'; // Fade animation const fadeAnim = useRef(new Animated.Value(0)).current; useEffect(() => { Animated.timing(fadeAnim, { toValue: 1, duration: 300, useNativeDriver: true, }).start(); }, []); {/* Animated content */} // Scale animation const scaleAnim = useRef(new Animated.Value(0)).current; const animatePress = () => { Animated.sequence([ Animated.timing(scaleAnim, { toValue: 0.95, duration: 100, useNativeDriver: true, }), Animated.timing(scaleAnim, { toValue: 1, duration: 100, useNativeDriver: true, }), ]).start(); }; ``` ## Responsividade e Adaptação ### Dimensions Usage ```typescript import { Dimensions } from 'react-native'; const { width, height } = Dimensions.get('window'); // Responsive styles const styles = StyleSheet.create({ container: { width: width * 0.9, height: height * 0.8, }, card: { width: width > 768 ? width * 0.3 : width * 0.9, }, }); ``` ### Platform-specific Styles ```typescript import { Platform } from 'react-native'; const styles = StyleSheet.create({ header: { paddingTop: Platform.OS === 'ios' ? 44 : 24, }, button: { borderRadius: Platform.OS === 'ios' ? 8 : 4, }, }); ``` ## Temas e Modo Escuro ### Theme Provider ```typescript // components/theme-provider.tsx interface ThemeContextType { theme: 'light' | 'dark'; toggleTheme: () => void; } const ThemeContext = createContext({ theme: 'light', toggleTheme: () => {}, }); export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [theme, setTheme] = useState<'light' | 'dark'>('light'); const toggleTheme = () => { setTheme(prev => prev === 'light' ? 'dark' : 'light'); }; return ( {children} ); }; ``` ### Dark Mode Colors ```typescript export const DARK_COLORS = { primary: "#1E40AF", secondary: "#1F2937", background: "#111827", text: "#F9FAFB", textLight: "#9CA3AF", card: "#1F2937", border: "#374151", // ... outras cores }; ``` ## Componentes de Formulário ### Form Components ```typescript // components/ui/form.tsx interface FormFieldProps { label: string; error?: string; children: React.ReactNode; } const FormField: React.FC = ({ label, error, children }) => ( {label} {children} {error && {error}} ); // Usage ``` ## Componentes de Feedback ### Toast Component ```typescript // components/ui/toast.tsx interface ToastProps { message: string; type: 'success' | 'error' | 'warning' | 'info'; visible: boolean; onHide: () => void; } const Toast: React.FC = ({ message, type, visible, onHide }) => { useEffect(() => { if (visible) { const timer = setTimeout(onHide, 3000); return () => clearTimeout(timer); } }, [visible, onHide]); if (!visible) return null; return ( {message} ); }; ``` ### Loading Component ```typescript // components/ui/loading.tsx interface LoadingProps { visible: boolean; message?: string; } const Loading: React.FC = ({ visible, message = "Carregando..." }) => { if (!visible) return null; return ( {message} ); }; ``` ## Considerações para Sincronização Offline ### 1. Indicadores de Status ```typescript // Componente para mostrar status de sincronização const SyncStatusIndicator: React.FC<{ status: 'synced' | 'pending' | 'error' }> = ({ status }) => { const getStatusColor = (status: string) => { switch (status) { case 'synced': return COLORS.success; case 'pending': return COLORS.warning; case 'error': return COLORS.danger; default: return COLORS.textLight; } }; const getStatusIcon = (status: string) => { switch (status) { case 'synced': return 'checkmark-circle'; case 'pending': return 'time'; case 'error': return 'close-circle'; default: return 'help-circle'; } }; return ( {status.toUpperCase()} ); }; ``` ### 2. Componentes Offline ```typescript // Componente para modo offline const OfflineBanner: React.FC<{ visible: boolean }> = ({ visible }) => { if (!visible) return null; return ( Modo Offline Ativo ); }; ``` Esta documentação fornece uma visão completa do sistema de estilização e componentes UI do aplicativo, incluindo padrões de design, componentes reutilizáveis e considerações para implementação de funcionalidades offline.