Pular para o conteúdo
Voltar ao portfólio
Código · Front-end

Sports Widget

Réplica em React do widget de esportes da nova aba do Firefox (recurso New Tab Widgets). Reconstruí o componente por engenharia reversa do DOM real — layout, interações e formatação de dados de um torneio de 48 seleções — e o integrei ao design system do portfólio.

Next.js 15React 19TypeScriptCSS ModulesIntl APIa11y

Demonstração ao vivo

Interaja: troque entre Resultados e Seguintes, use Ver tudo para a lista completa e abra o menu (•••).

Sobre o projeto

O Firefox 151 introduziu widgets na nova aba, entre eles um de esportes que acompanha um torneio de seleções. O objetivo aqui foi recriá-lo de forma fiel — visual e funcionalmente — como um componente React reutilizável, sem depender das APIs internas do navegador (os custom elements moz-button e panel-list viraram elementos HTML comuns).

Capturei o DOM real do widget e transcrevi a estrutura, as classes e os dados das partidas. A partir daí, reconstruí a hierarquia de componentes, repliquei o sistema de abas e a lista agrupada, e recriei o estilo lendo as variáveis de tema do portfólio — de modo que o widget responde a light/dark automaticamente.

Funcionalidades

  • Abas Resultados / Seguintes com troca acessível (role=tablist).
  • Lista de partidas agrupada por grupo e fase do torneio.
  • Expandir/colapsar: destaque + “Ver tudo” ⇄ lista completa + “Mostrar menos”.
  • Pílula de placar nos resultados e horário + data nos próximos jogos.
  • Bandeiras via CDN, com estado “a definir” para confrontos de mata-mata.
  • Menu de contexto (popover) com ações reais: trocar de aba e ocultar widget.
  • Datas e horários localizados em pt-BR e determinísticos (seguros para SSR).
  • Adaptação automática a tema claro/escuro do portfólio.

Registros técnicos

Arquitetura em 3 camadas

Dados (src/data/sports.ts), apresentação (componente client) e estilo (CSS Module) ficam separados, facilitando manutenção e a troca da fonte de dados.

Estilo theme-aware

CSS Module consumindo as CSS vars do tema (--card, --foreground, --border, --radius…), o que torna o widget independente de classes utilitárias e fiel ao visual do Firefox em light e dark.

SSR sem hydration mismatch

A formatação de data/hora usa Intl com fuso fixo (America/Sao_Paulo), garantindo que o HTML do servidor case com o do cliente e reproduza os horários originais.

Acessibilidade

role=tablist/tab, aria-selected, aria-label por partida, navegação por teclado e foco visível — espelhando os atributos do widget nativo.

Engenharia reversa

48 seleções e 83 partidas (grupos A–L + mata-mata) extraídas do DOM real capturado do Firefox, preservando códigos, bandeiras e timestamps epoch.

Modelagem de dados

Tipos Match/Team, fábricas para partidas agendadas e encerradas, e formatadores de data reutilizáveis — tudo tipado em TypeScript estrito.