Sistema de temas¶
A Fase 58 (v1.41.0) substituiu o antigo par claro/escuro por um
sistema de seis temas clássicos numa única dimensão
data-theme, mais uma opção auto que segue o sistema operativo. A
Fase 63 (v1.63.0) acrescentou seis presets WCAG AA recomendados,
de forma que o seletor passou a ter no total 12 temas.
Presets recomendados (Fase 63 / v1.63.0)¶
O seletor em Definições → Aparência começa com um sub-separador Recomendado:
- Claro:
catppuccin-latte,supabase,graphite - Escuro:
catppuccin-mocha,soft-pop,amethyst-haze
Foram gerados a partir de presets tweakcn por
scripts/generate_preset_themes.py como temas completos de
44 tokens, com WCAG AA imposto por cálculo (contrast.test.ts
em todos os 12 temas). Os seis clássicos (light, dark, ocean,
forest, high-contrast, sepia) permanecem inalterados.
Funcionamento¶
- Os tokens de cor canónicos ficam em
frontend/src/styles/themes/theme-<id>.css, um bloco por valor dedata-theme(light,dark,ocean,forest,high-contrast,sepia). Cada ficheiro define o conjunto semântico completo de tokens - não há fallback para claro. - Os tokens independentes do tema (espaçamentos, raio, tipos de
letra, a paleta de métodos da marca) e os aliases legados
(
--bg,--surface,--fg,--danger, ...) ficam emstyles/global.css :root. Os aliases resolvem através dos tokens canónicos e seguem assim automaticamente o tema ativo. - Os ficheiros de tema são importados em
main.tsx, claro primeiro, para que o tema ativo ganhe o empate de especificidade contra:root. frontend/src/lib/themes.tsé o registo:THEMES, os tiposThemeId/ThemeChoice,resolveTheme(choice, prefersDark)para o mapeamentoautoe as amostras de cor para pré-visualização.frontend/src/hooks/useTheme.tspossui o atributodata-themeaplicado e guarda a escolha emadaptive-learner.theme(migra a antiga chaveadaptive-learner-themeuma única vez).index.htmlcontém um pequeno script inline que aplica o tema guardado antes do primeiro paint (sem flicker). Espelha a resolução do hook; mantém ambos sincronizados.- Os gráficos (Recharts) não conseguem ler variáveis CSS em
atributos SVG, por isso
lib/chartTheme.ts+useChartThemeleem os valores de tokens calculados e voltam a ler em cada mudança dedata-theme.
Conjunto de tokens (definido por cada tema)¶
Fundos (--bg-primary/secondary/surface/elevated/overlay),
texto (--fg-primary/secondary/muted/inverse), bordas
(--border-primary/subtle/accent), interativo
(--interactive-bg/hover/active/disabled), acento
(--accent, -hover, -fg, -subtle, -rgb), pares de status
(--success/-bg, --error/-bg, --warning/-bg, --info/-bg),
feedback de exercícios (--exercise-correct/-wrong/-selected/-matched),
--star, séries de gráficos (--chart-1..6) e sombras
(--shadow-card/-elevated/-md).
styles/themes/themes.test.ts falha se um tema não tiver um destes
tokens ou tiver um adicional; styles/contrast.test.ts verifica
WCAG 2.1 AA em todos os 12 temas. A referência completa de tokens
está em
Arquitetura de design tokens.
Adicionar um novo tema¶
- Copia um ficheiro existente, p. ex.
cp theme-dark.css theme-midnight.css, e muda o seletor para[data-theme="midnight"]. Mantém cada token - muda apenas os valores. Sem estilos de componentes aqui. - Regista-o em
lib/themes.ts: adiciona aTHEMESuma entradaThemeMeta(id,labelem inglês,familylight|dark e umswatchpara a pré-visualização nas Definições) e acrescenta o id na uniãoThemeId. - Importa-o em
main.tsxapóstheme-light.css(a ordem só conta em relação a claro). - Permite-o no guard de pré-paint: acrescenta o id ao array
validno<script>inline emindex.html. - i18n: adiciona
ui.themes.midnightem todos os oito catálogos sobbackend/config/i18n/*.yamle executamake sync-i18n. - Verifica:
npx vitest run src/styles/themes src/styles/contrast- os pins de completude e de contraste têm de permanecer verdes (ajusta os valores até o contraste no novo tema cumprir AA).
É tudo - o ThemePicker, o script de pré-paint, os gráficos e cada componente adotam o novo tema automaticamente, porque todos leem os tokens canónicos.
Regras¶
- Sem cores fixas no código em componentes.
styles/no-hardcoded-colors.test.tsimpõe isto para os estilos.tsx(uma allowlist documentada cobre resolvers de gráficos, confetti decorativo e cores de dados). - Cada tema define cada token. Sem lacunas com herança de claro - esse foi o erro da auditoria F1 (tokens indefinidos que mostravam hex claro no modo escuro).
- A mudança de tema é instantânea - uma troca de
data-theme, nunca um recarregamento.