Frontend
Bootstrap
Framework CSS para desenvolvimento responsivo e mobile-first
O que é Bootstrap?
Bootstrap é o framework CSS mais popular do mundo para desenvolvimento de sites responsivos e mobile-first. Oferece um sistema de grid flexível, componentes pré-construídos e utilitários CSS para acelerar o desenvolvimento.
Por que utilizamos Bootstrap na IngenioLab?
- Desenvolvimento rápido: Componentes prontos para uso
- Responsivo: Mobile-first por padrão
- Customizável: Temas e variáveis SASS
- Compatibilidade: Funciona em todos os browsers
- Comunidade: Vasta documentação e recursos
- Integração React: Funciona perfeitamente com React
Instalação
# Via NPMnpm install bootstrap# Com React Bootstrap (recomendado para React)npm install react-bootstrap bootstrap# Apenas CSS via CDN<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
Configuração IngenioLab
1. Setup básico com Vite:
// src/main.tsximport 'bootstrap/dist/css/bootstrap.min.css'import 'bootstrap/dist/js/bootstrap.bundle.min.js'import './index.css' // Seus estilos customizadosimport { createRoot } from 'react-dom/client'import App from './App'createRoot(document.getElementById('root')!).render(<App />)
2. Com React Bootstrap:
// src/main.tsximport 'bootstrap/dist/css/bootstrap.min.css'import { createRoot } from 'react-dom/client'import App from './App'createRoot(document.getElementById('root')!).render(<App />)
3. Customização SASS:
// src/styles/custom-bootstrap.scss// Importar funções e variáveis do Bootstrap@import "bootstrap/scss/functions";@import "bootstrap/scss/variables";// Customizar variáveis$primary: #007bff;$secondary: #6c757d;$success: #28a745;$danger: #dc3545;// Customizar breakpoints$grid-breakpoints: (xs: 0,sm: 576px,md: 768px,lg: 992px,xl: 1200px,xxl: 1400px);// Importar o resto do Bootstrap@import "bootstrap/scss/bootstrap";// Estilos customizados IngenioLab.ingeniolab-card {border-radius: 12px;box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);}.ingeniolab-btn {border-radius: 8px;font-weight: 600;}
Sistema de Grid
1. Grid básico:
// src/components/GridExample.tsxexport const GridExample = () => {return (<div className="container"><div className="row"><div className="col-12 col-md-6 col-lg-4"><h3>Coluna 1</h3><p>Conteúdo responsivo</p></div><div className="col-12 col-md-6 col-lg-4"><h3>Coluna 2</h3><p>Adapta automaticamente</p></div><div className="col-12 col-md-12 col-lg-4"><h3>Coluna 3</h3><p>Mobile-first design</p></div></div></div>)}
2. Grid avançado com React Bootstrap:
// src/components/Dashboard.tsximport { Container, Row, Col, Card } from 'react-bootstrap'export const Dashboard = () => {return (<Container fluid><Row className="g-4"><Col xs={12} md={6} lg={3}><Card className="h-100"><Card.Body><Card.Title>Total Users</Card.Title><Card.Text className="display-6">1,234</Card.Text></Card.Body></Card></Col><Col xs={12} md={6} lg={3}><Card className="h-100"><Card.Body><Card.Title>Revenue</Card.Title><Card.Text className="display-6">$45,678</Card.Text></Card.Body></Card></Col><Col xs={12} lg={6}><Card className="h-100"><Card.Body><Card.Title>Recent Activity</Card.Title><Card.Text>Lista de atividades...</Card.Text></Card.Body></Card></Col></Row></Container>)}
Componentes com React Bootstrap
1. Navegação:
// src/components/Navigation.tsximport { Navbar, Nav, Container, NavDropdown } from 'react-bootstrap'import { LinkContainer } from 'react-router-bootstrap'export const Navigation = () => {return (<Navbar bg="primary" variant="dark" expand="lg" sticky="top"><Container><LinkContainer to="/"><Navbar.Brand>IngenioLab</Navbar.Brand></LinkContainer><Navbar.Toggle aria-controls="basic-navbar-nav" /><Navbar.Collapse id="basic-navbar-nav"><Nav className="me-auto"><LinkContainer to="/"><Nav.Link>Home</Nav.Link></LinkContainer><LinkContainer to="/users"><Nav.Link>Users</Nav.Link></LinkContainer><NavDropdown title="Dashboard" id="basic-nav-dropdown"><LinkContainer to="/dashboard/analytics"><NavDropdown.Item>Analytics</NavDropdown.Item></LinkContainer><LinkContainer to="/dashboard/reports"><NavDropdown.Item>Reports</NavDropdown.Item></LinkContainer><NavDropdown.Divider /><LinkContainer to="/dashboard/settings"><NavDropdown.Item>Settings</NavDropdown.Item></LinkContainer></NavDropdown></Nav><Nav><Nav.Link href="/profile">Profile</Nav.Link><Nav.Link href="/logout">Logout</Nav.Link></Nav></Navbar.Collapse></Container></Navbar>)}
2. Formulários:
// src/components/UserForm.tsximport { useState } from 'react'import { Form, Button, Alert, Row, Col, Card } from 'react-bootstrap'interface UserFormData {name: stringemail: stringrole: stringisActive: boolean}export const UserForm = () => {const [formData, setFormData] = useState<UserFormData>({name: '',email: '',role: 'user',isActive: true})const [validated, setValidated] = useState(false)const [error, setError] = useState<string | null>(null)const [success, setSuccess] = useState(false)const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {const form = event.currentTargetevent.preventDefault()event.stopPropagation()if (form.checkValidity()) {// Processar formulárioconsole.log('Form data:', formData)setSuccess(true)setError(null)}setValidated(true)}return (<Card><Card.Header><h4>Criar Usuário</h4></Card.Header><Card.Body>{error && <Alert variant="danger">{error}</Alert>}{success && <Alert variant="success">Usuário criado com sucesso!</Alert>}<Form noValidate validated={validated} onSubmit={handleSubmit}><Row><Col md={6}><Form.Group className="mb-3"><Form.Label>Nome *</Form.Label><Form.Controlrequiredtype="text"value={formData.name}onChange={(e) => setFormData(prev => ({ ...prev, name: e.target.value }))}placeholder="Nome completo"/><Form.Control.Feedback type="invalid">Por favor, insira um nome válido.</Form.Control.Feedback></Form.Group></Col><Col md={6}><Form.Group className="mb-3"><Form.Label>Email *</Form.Label><Form.Controlrequiredtype="email"value={formData.email}onChange={(e) => setFormData(prev => ({ ...prev, email: e.target.value }))}placeholder="usuario@exemplo.com"/><Form.Control.Feedback type="invalid">Por favor, insira um email válido.</Form.Control.Feedback></Form.Group></Col></Row><Row><Col md={6}><Form.Group className="mb-3"><Form.Label>Role</Form.Label><Form.Selectvalue={formData.role}onChange={(e) => setFormData(prev => ({ ...prev, role: e.target.value }))}><option value="user">User</option><option value="admin">Admin</option><option value="moderator">Moderator</option></Form.Select></Form.Group></Col><Col md={6}><Form.Group className="mb-3 pt-4"><Form.Checktype="checkbox"id="isActive"label="Usuário ativo"checked={formData.isActive}onChange={(e) => setFormData(prev => ({ ...prev, isActive: e.target.checked }))}/></Form.Group></Col></Row><div className="d-grid gap-2 d-md-flex justify-content-md-end"><Button variant="secondary" type="button">Cancelar</Button><Button variant="primary" type="submit">Criar Usuário</Button></div></Form></Card.Body></Card>)}
3. Tabelas e Listas:
// src/components/UserTable.tsximport { Table, Badge, Button, ButtonGroup } from 'react-bootstrap'interface User {id: stringname: stringemail: stringrole: stringisActive: boolean}interface UserTableProps {users: User[]onEdit: (user: User) => voidonDelete: (userId: string) => void}export const UserTable = ({ users, onEdit, onDelete }: UserTableProps) => {const getRoleBadgeVariant = (role: string) => {switch (role) {case 'admin': return 'danger'case 'moderator': return 'warning'default: return 'primary'}}return (<Table responsive striped hover><thead><tr><th>Nome</th><th>Email</th><th>Role</th><th>Status</th><th width="150">Ações</th></tr></thead><tbody>{users.map(user => (<tr key={user.id}><td>{user.name}</td><td>{user.email}</td><td><Badge bg={getRoleBadgeVariant(user.role)}>{user.role}</Badge></td><td><Badge bg={user.isActive ? 'success' : 'secondary'}>{user.isActive ? 'Ativo' : 'Inativo'}</Badge></td><td><ButtonGroup size="sm"><Buttonvariant="outline-primary"onClick={() => onEdit(user)}>Edit</Button><Buttonvariant="outline-danger"onClick={() => onDelete(user.id)}>Delete</Button></ButtonGroup></td></tr>))}</tbody></Table>)}
4. Modais:
// src/components/DeleteConfirmModal.tsximport { Modal, Button } from 'react-bootstrap'interface DeleteConfirmModalProps {show: booleanonHide: () => voidonConfirm: () => voidtitle: stringmessage: stringloading?: boolean}export const DeleteConfirmModal = ({show,onHide,onConfirm,title,message,loading = false}: DeleteConfirmModalProps) => {return (<Modal show={show} onHide={onHide} centered><Modal.Header closeButton><Modal.Title>{title}</Modal.Title></Modal.Header><Modal.Body><p>{message}</p></Modal.Body><Modal.Footer><Button variant="secondary" onClick={onHide} disabled={loading}>Cancelar</Button><Button variant="danger" onClick={onConfirm} disabled={loading}>{loading ? 'Deletando...' : 'Confirmar'}</Button></Modal.Footer></Modal>)}
Utilitários CSS
1. Spacing e Layout:
// src/components/UtilityExample.tsxexport const UtilityExample = () => {return (<div className="container-fluid">{/* Margin e Padding */}<div className="p-4 m-2 bg-light"><h3 className="mb-3">Título com margin bottom</h3><p className="px-2 py-1">Parágrafo com padding horizontal</p></div>{/* Flexbox */}<div className="d-flex justify-content-between align-items-center p-3 bg-primary text-white"><span>Left</span><span>Center</span><span>Right</span></div>{/* Text utilities */}<div className="text-center p-3"><h4 className="text-primary">Título Azul</h4><p className="text-muted fw-light">Texto secundário</p><small className="text-uppercase fw-bold">Texto em maiúscula</small></div>{/* Display utilities */}<div className="d-none d-md-block">Visível apenas em desktop</div><div className="d-block d-md-none">Visível apenas em mobile</div></div>)}
2. Responsividade:
// src/styles/responsive.scss.ingeniolab-hero {padding: 2rem 1rem;@include media-breakpoint-up(md) {padding: 4rem 2rem;}@include media-breakpoint-up(lg) {padding: 6rem 3rem;}}.ingeniolab-card {margin-bottom: 1rem;@include media-breakpoint-up(lg) {margin-bottom: 2rem;}}
Temas e Customização
1. Dark Theme:
// src/styles/themes.scss[data-bs-theme="dark"] {.ingeniolab-card {background: var(--bs-dark);border-color: var(--bs-gray-700);}.ingeniolab-sidebar {background: var(--bs-gray-900);}}// Componente Reactexport const ThemeToggle = () => {const [theme, setTheme] = useState('light')useEffect(() => {document.documentElement.setAttribute('data-bs-theme', theme)}, [theme])return (<Buttonvariant={theme === 'light' ? 'dark' : 'light'}onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>{theme === 'light' ? '🌙' : '☀️'}</Button>)}
2. Variáveis customizadas:
// src/styles/variables.scss:root {--ingeniolab-primary: #007bff;--ingeniolab-secondary: #6c757d;--ingeniolab-success: #28a745;--ingeniolab-border-radius: 8px;--ingeniolab-box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);}.ingeniolab-btn {border-radius: var(--ingeniolab-border-radius);box-shadow: var(--ingeniolab-box-shadow);}
Performance
1. Import seletivo:
// src/main.tsx - Import apenas componentes necessáriosimport 'bootstrap/scss/functions';import 'bootstrap/scss/variables';import 'bootstrap/scss/mixins';import 'bootstrap/scss/bootstrap-grid';import 'bootstrap/scss/bootstrap-utilities';// Para React Bootstrapimport { Button } from 'react-bootstrap/Button'import { Card } from 'react-bootstrap/Card'// Ao invés de: import { Button, Card } from 'react-bootstrap'
2. Bundle optimization:
// vite.config.tsexport default defineConfig({build: {rollupOptions: {output: {manualChunks: {bootstrap: ['bootstrap', 'react-bootstrap']}}}}})
Acessibilidade
1. ARIA e semântica:
// src/components/AccessibleComponents.tsximport { Button, Alert, Modal } from 'react-bootstrap'export const AccessibleForm = () => {return (<form role="form" aria-label="User registration form"><div className="mb-3"><label htmlFor="username" className="form-label">Username</label><inputid="username"type="text"className="form-control"aria-describedby="username-help"required/><div id="username-help" className="form-text">Choose a unique username</div></div><Button type="submit" aria-label="Submit registration form">Register</Button></form>)}
Integração com Formulários
1. Com React Hook Form:
// src/components/HookFormExample.tsximport { useForm } from 'react-hook-form'import { Form, Button, Alert } from 'react-bootstrap'interface FormData {name: stringemail: string}export const HookFormExample = () => {const { register, handleSubmit, formState: { errors } } = useForm<FormData>()const onSubmit = (data: FormData) => {console.log(data)}return (<Form onSubmit={handleSubmit(onSubmit)}><Form.Group className="mb-3"><Form.Label>Name</Form.Label><Form.Controltype="text"{...register('name', { required: 'Name is required' })}isInvalid={!!errors.name}/><Form.Control.Feedback type="invalid">{errors.name?.message}</Form.Control.Feedback></Form.Group><Form.Group className="mb-3"><Form.Label>Email</Form.Label><Form.Controltype="email"{...register('email', { required: 'Email is required' })}isInvalid={!!errors.email}/><Form.Control.Feedback type="invalid">{errors.email?.message}</Form.Control.Feedback></Form.Group><Button type="submit">Submit</Button></Form>)}