Uma aplicação React moderna construída com TypeScript, focada em acessibilidade e experiência do usuário inclusiva.
- Sobre o Projeto
- Tecnologias
- Instalação
- Scripts Disponíveis
- Estrutura do Projeto
- Acessibilidade
- Testes
- Internacionalização
- Contribuição
- Deployment
Este projeto foi desenvolvido pela Sou Junior como uma aplicação web moderna que prioriza:
- Acessibilidade: Seguindo diretrizes WCAG 2.1 AA
- Performance: Otimizado para carregamento rápido
- Usabilidade: Interface intuitiva e responsiva
- Manutenibilidade: Código limpo e bem estruturado
- React 18.3.1 - Biblioteca para interfaces de usuário
- TypeScript 4.9.5 - Tipagem estática
- React Router DOM 7.6.2 - Roteamento
- Styled Components 6.1.19 - CSS-in-JS
- React i18next 14.1.3 - Internacionalização
- Jest 30.0.2 - Framework de testes
- Cypress 14.5.0 - Testes E2E
- ESLint - Linting de código
- Puppeteer 24.10.2 - Testes visuais
- React GA4 2.1.0 - Google Analytics 4
- Web Vitals 2.1.4 - Métricas de performance
- Node.js (versão 16 ou superior)
- npm ou yarn
# Clone o repositório
git clone [URL_DO_REPOSITORIO]
# Entre no diretório
cd site-webapp-v2
# Instale as dependências
npm install
# Configure as variáveis de ambiente
cp .env.example .env
# Inicie o servidor de desenvolvimento
npm start
# Inicia o servidor de desenvolvimento
npm start
# Acesse http://localhost:3000
# Build para produção
npm run build
# Ejetar configurações (irreversível)
npm run eject
# Executa todos os testes em modo watch
npm test
# Executa apenas testes unitários
npm run test:unit
# Atualiza snapshots dos testes
npm run test:unit:update
# Executa testes de componente com Cypress
npm run cypress:open
# Executa testes E2E
npm run cypress:run
src/
├── components/ # Componentes reutilizáveis
│ ├── .global/ # Componentes globais
│ │ ├── error-boundary/
│ │ ├── link/
│ │ └── loading/
│ └── header/ # Cabeçalho da aplicação
├── hooks/ # Hooks customizados
│ └── useAccessibility.ts
├── i18n/ # Configurações de internacionalização
│ ├── locales/ # Arquivos de tradução
│ │ ├── pt.json
│ │ ├── en.json
│ │ └── es.json
│ └── i18n.ts
├── pages/ # Páginas da aplicação
│ ├── design/ # Sistema de design
│ └── projects/ # Projetos
├── services/ # Serviços e APIs
├── styles/ # Estilos globais
│ └── accessibility.css
├── types/ # Definições de tipos
├── utils/ # Utilitários
│ └── enums/
└── assets/ # Recursos estáticos
Este projeto segue rigorosamente as diretrizes WCAG 2.1 AA, implementando:
- Skip links: "Pular para o conteúdo principal"
- Ordem de foco lógica: Navegação sequencial intuitiva
- Indicadores visuais: Estados de foco bem definidos
- Suporte completo: Enter, Space, Tab, Shift+Tab, Arrow keys
- Razão de contraste: Mínimo 4.5:1 para texto normal
- Alto contraste: Suporte ao modo de alto contraste do sistema
- Cores acessíveis: Paleta otimizada para daltonismo
- ARIA labels: Descrições detalhadas para screen readers
- Live regions: Anúncios dinâmicos acessíveis
- Roles semânticos: banner, main, navigation, button, link
- Screen reader announcer: Hook customizado para anúncios
- Touch targets: Mínimo 44x44px para elementos interativos
- Design fluido: Adaptação para todos os tamanhos de tela
- Zoom até 200%: Sem perda de funcionalidade
// Exemplo de uso
<Link
onClick={handleClick}
ariaLabel="Navegar para página sobre nós"
role="button"
>
Sobre Nós
</Link>
- Navegação principal com
role="navigation"
- Logo com texto alternativo descritivo
- Links com aria-labels específicos
- Tratamento acessível de erros
- Mensagens claras e acionáveis
- Anúncios automáticos para screen readers
// useScreenReaderAnnouncer
const { announce } = useScreenReaderAnnouncer();
announce("Página carregada com sucesso", "polite");
// useFocusManagement
const { focusMainContent, focusFirstError } = useFocusManagement();
// useAssistiveTechnology
const { isScreenReaderActive, prefersReducedMotion } = useAssistiveTechnology();
- ✅ 1.1.1: Imagens com texto alternativo
- ✅ 1.3.1: HTML semântico e estruturado
- ✅ 1.3.2: Ordem de leitura lógica
- ✅ 1.4.3: Contraste mínimo (4.5:1)
- ✅ 1.4.10: Reflow responsivo
- ✅ 1.4.11: Contraste para elementos não-textuais
- ✅ 2.1.1: Funcionalidade por teclado
- ✅ 2.1.2: Sem armadilhas de teclado
- ✅ 2.4.1: Skip links implementados
- ✅ 2.4.3: Ordem de foco lógica
- ✅ 2.4.7: Foco visível
- ✅ 2.5.5: Tamanho mínimo de toque (44px)
- ✅ 3.1.1: Idioma da página definido
- ✅ 3.2.1: Foco sem mudanças inesperadas
- ✅ 3.3.2: Labels e instruções claras
- ✅ 4.1.1: HTML válido
- ✅ 4.1.2: ARIA adequado
- ✅ 4.1.3: Mensagens de status
/* Classes utilitárias incluídas */
.sr-only {
/* Conteúdo apenas para screen readers */
}
.skip-link {
/* Links de pular navegação */
}
/* Media queries de acessibilidade */
@media (prefers-reduced-motion: reduce) {
/* Reduz animações */
}
@media (prefers-contrast: high) {
/* Aumenta contraste */
}
- axe-core: Integrado nos testes E2E
- Lighthouse: Auditoria de acessibilidade
- WAVE: Extensão para análise visual
- Navegação por teclado: Tab, Shift+Tab, Enter, Space, Arrow keys
- Screen readers: NVDA (Windows), VoiceOver (Mac), TalkBack (Android)
- Zoom: Teste até 200% de zoom
- Alto contraste: Modo de alto contraste do sistema
tests/
├── unit/ # Testes unitários
│ ├── components/ # Testes de componentes
│ ├── hooks/ # Testes de hooks
│ ├── pages/ # Testes de páginas
│ └── utils/ # Testes de utilitários
├── component/ # Testes de componente (Cypress)
│ └── src/pages/
└── setup/ # Configurações de teste
├── customMatchers.ts
├── pngSnapshotMatcher.ts
└── visualTestsSetup.ts
# Executar todos os testes unitários
npm run test:unit
# Executar com watch mode
npm test
# Atualizar snapshots
npm run test:unit:update
Exemplo de teste de componente:
describe("Header Component", () => {
it("should render with accessibility attributes", () => {
render(<Header links={mockLinks} />);
const navigation = screen.getByRole("navigation");
expect(navigation).toBeInTheDocument();
expect(navigation).toHaveAttribute("aria-label", "Navegação principal");
});
it("should handle keyboard navigation", async () => {
const mockClick = jest.fn();
render(<Header links={[{ label: "Home", onClick: mockClick }]} />);
const link = screen.getByRole("menuitem");
await user.keyboard("{Tab}{Enter}");
expect(mockClick).toHaveBeenCalled();
});
});
- Screenshot testing: Comparação pixel-perfect
- Cross-browser: Validação em diferentes navegadores
- Responsive: Testes em múltiplas resoluções
// Exemplo de teste visual
it("should match screenshot", async () => {
const image = await page.screenshot();
expect(image).toMatchImageSnapshot({
threshold: 0.2,
customDiffConfig: { threshold: 0.1 },
});
});
# Abrir interface do Cypress
npx cypress open
# Executar testes headless
npx cypress run
Exemplo de teste E2E:
describe("Design Page", () => {
it("should navigate and be accessible", () => {
cy.visit("/design");
cy.checkA11y(); // Verificação de acessibilidade
cy.get('[data-cy="navigation-link"]')
.should("be.visible")
.and("have.attr", "aria-label");
});
});
O projeto inclui matchers personalizados para facilitar os testes:
// setup/customMatchers.ts
expect.extend({
toBeAccessible: element => {
// Verificações de acessibilidade customizadas
},
toHaveCorrectFocusOrder: container => {
// Verificação da ordem de foco
},
});
- 🇧🇷 Português (pt)
- 🇺🇸 Inglês (en)
- 🇪🇸 Espanhol (es)
// i18n/i18n.ts
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
fallbackLng: "pt",
debug: process.env.NODE_ENV === "development",
detection: {
order: ["localStorage", "navigator", "htmlTag"],
caches: ["localStorage"],
},
});
import { useTranslation } from "react-i18next";
const Component = () => {
const { t } = useTranslation();
return <h1>{t("pages.home.title")}</h1>;
};
// locales/pt.json
{
"pages": {
"home": {
"title": "Bem-vindo à Sou Junior"
}
},
"components": {
"header": {
"navigation": "Navegação principal"
}
}
}
- Acessibilidade: Toda nova funcionalidade deve seguir WCAG 2.1 AA
- Testes: Código novo deve ter cobertura de teste adequada
- TypeScript: Use tipagem forte, evite
any
- Commits: Siga o padrão Conventional Commits
# 1. Fork o projeto
# 2. Crie uma branch para sua feature
git checkout -b feature/nova-funcionalidade
# 3. Faça suas alterações
# 4. Execute os testes
npm test
npm run test:unit
# 5. Verifique acessibilidade
npm run test:a11y
# 6. Commit suas mudanças
git commit -m "feat: adiciona nova funcionalidade acessível"
# 7. Push para sua branch
git push origin feature/nova-funcionalidade
# 8. Abra um Pull Request
- Código segue os padrões de acessibilidade
- Testes unitários adicionados/atualizados
- Testes de acessibilidade passando
- Documentação atualizada se necessário
- Sem breaking changes (ou documentados)
- Build está passando
- Screenshots para mudanças visuais
# Gerar build otimizado
npm run build
# O build será criado na pasta 'build/'
# .env
REACT_APP_GA_MEASUREMENT_ID=G-XXXXXXXXXX
REACT_APP_API_URL=https://api.soujunior.org
REACT_APP_ENVIRONMENT=production
- Code splitting: Carregamento sob demanda
- Tree shaking: Remoção de código não utilizado
- Minificação: CSS e JavaScript otimizados
- Service Worker: Cache inteligente (se configurado)
- Bundle analysis: Análise de tamanho dos bundles
- Vercel: Deploy automático via Git
- Netlify: CI/CD integrado
- AWS S3 + CloudFront: Para maior controle
- GitHub Pages: Para projetos open source
- Largest Contentful Paint (LCP): < 2.5s
- First Input Delay (FID): < 100ms
- Cumulative Layout Shift (CLS): < 0.1
- Time to Interactive (TTI): < 3.5s
- Web Vitals: Métricas em tempo real
- Google Analytics 4: Comportamento do usuário
- Lighthouse CI: Auditoria contínua
Este projeto está sob a licença MIT.
Para dúvidas ou problemas:
- Verifique as Issues abertas
- Consulte a documentação de acessibilidade
- Entre em contato com a equipe Sou Junior
Feito com ❤️ pela equipe Sou Junior
Construindo um futuro mais inclusivo, um código por vez.