Portfólio pessoal de Gustavo Oliveira (Engenheiro de Software Full Stack), construído com React, TypeScript e Vite.
Acesse: https://portfolio-dgzd.onrender.com
- Framework: React 19 + TypeScript
- Build: Vite 7 (+ SWC)
- Estilo: Tailwind CSS 4 + tw-animate-css
- UI primitivos: Radix UI + componentes locais (shadcn-style)
- Roteamento: React Router 7 (com lazy loading)
- Ícones: Lucide
- Testes: Vitest + Testing Library + jsdom
- Lint/Format: ESLint 9 (typescript-eslint, react-hooks, react-refresh) + Prettier
npm run dev # ambiente de desenvolvimento
npm run build # type-check + build de produção
npm run preview # preview do build
npm run lint # eslint
npm test # vitest (uma execução)
npm run test:watch # vitest em modo watch
npm run test:coverage # vitest com cobertura V8src/
├── assets/ # imagens estáticas
├── components/
│ ├── consent/ # gate de consentimento + carregamento condicional de fontes
│ ├── sections/ # seções da home (Hero, Sobre, Carreira, Projetos, Contato)
│ ├── shared/ # componentes reutilizáveis (Header, SectionHeader, ScrollReveal, ErrorBoundary, TechBadge, ExternalLink)
│ ├── theme/ # ThemeProvider + ModeToggle
│ └── ui/ # primitivos (Button, Card, DropdownMenu)
├── data/ # dados estáticos (experiências, projetos, navegação, contatos)
├── hooks/ # hooks reutilizáveis (useScrollReveal)
├── layout/ # Layout raiz + Page
├── lib/ # utilitários (cn)
├── pages/ # páginas roteáveis (Home, NotFound)
├── routes/ # configuração de rotas
└── test/ # setup do Vitest + mocks
- Clean Code & SOLID — componentes pequenos, com responsabilidade única; dados separados de visualização (
/data); composição via primitivos (Card,SectionHeader,TechBadge,ExternalLink). - Acessibilidade —
aria-*em diálogo de consentimento, navegação e botões; alt em imagens; roles semânticos. - Privacidade-first — nenhum recurso de terceiros (Google Fonts) é carregado antes do consentimento. Nada de cookies de rastreamento.
- Performance — code-splitting por rota com
React.lazy+Suspense; imagens comloading="lazy". - Resiliência —
ErrorBoundaryglobal e fallback de 404.
Decisões importantes estão documentadas em docs/adr/:
| ADR | Tópico |
|---|---|
| 001 | Organização de componentes (shared, sections, ui, etc) |
Antes de qualquer conteúdo ser renderizado, um aviso solicita aceite. Após aceite, são utilizados apenas estes itens no próprio navegador do usuário:
| Chave | Finalidade |
|---|---|
portfolio-consent-v1 |
Registra o aceite |
portfolio-theme |
Preferência de tema (light/dark/system) |
Nenhum dado pessoal é coletado ou transmitido.
main # produção (estável, apenas releases)
└── develop # integração contínua
└── feature/* # branches de funcionalidades/refatorações
Toda mudança nasce em feature/* a partir de develop, é integrada via Pull Request em develop, e periodicamente develop é promovido para main.
Projeto pessoal — sem licença pública definida.