diff --git a/modules/cybercore-ui/src/main/resources/styles/no-effects.css b/modules/cybercore-ui/src/main/resources/styles/no-effects.css index f2c3415..7afaea7 100644 --- a/modules/cybercore-ui/src/main/resources/styles/no-effects.css +++ b/modules/cybercore-ui/src/main/resources/styles/no-effects.css @@ -3,14 +3,11 @@ .cyber-action-card, .cyber-side-card, .cyber-header-bar, -.theme-toggle-btn, .cyber-status-badge { -fx-effect: null !important; } -.theme-light .cyber-action-card:hover, -.theme-dark .cyber-action-card:hover, -.cyber-side-card:hover, -.theme-toggle-btn:hover { +.cyber-action-card:hover, +.cyber-side-card:hover { -fx-effect: null !important; } diff --git a/modules/cybercore-ui/src/main/resources/styles/theme.css b/modules/cybercore-ui/src/main/resources/styles/theme.css index fbb5cd3..bd9d078 100644 --- a/modules/cybercore-ui/src/main/resources/styles/theme.css +++ b/modules/cybercore-ui/src/main/resources/styles/theme.css @@ -10,15 +10,7 @@ .root { -fx-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; -fx-font-size: 13px; - -fx-text-primary: -fx-color-text; - -fx-text-secondary: -fx-color-text-muted; - -fx-bg-primary: -fx-color-surface; - -fx-border-light: -fx-color-border; - -fx-accent: -fx-color-primary; -} -/* --- Tema Claro (Light Theme) --- */ -.theme-light { /* Superfícies & Fundos */ -fx-color-background: #f1f5f9; -fx-color-surface: #ffffff; @@ -73,7 +65,7 @@ -fx-control-inner-background: -fx-color-surface; -fx-text-fill: -fx-color-text; - /* Tokens semânticos complementares e aliases de compatibilidade */ + /* Tokens semânticos essenciais usados pelo Java */ -fx-text-primary: -fx-color-text; -fx-text-secondary: -fx-color-text-muted; -fx-bg-primary: -fx-color-surface; @@ -81,70 +73,6 @@ -fx-accent: -fx-color-primary; } -/* --- Tema Escuro (Dark Theme) --- */ -.theme-dark { - /* Superfícies & Fundos */ - -fx-color-background: #090d16; - -fx-color-surface: #111827; - -fx-color-surface-hover: #1e293b; - -fx-color-surface-active: #334155; - -fx-color-surface-subtle: #0f172a; - - /* Bordas */ - -fx-color-border: #334155; - -fx-color-border-subtle: #1e293b; - -fx-color-border-hover: #475569; - - /* Tipografia (WCAG AA: contraste >= 4.5:1) */ - -fx-color-text: #f8fafc; - -fx-color-text-muted: #94a3b8; - -fx-color-text-inverse: #0f172a; - - /* Primária (Azul da Marca CyberCore Dark) */ - -fx-color-primary: #38bdf8; - -fx-color-primary-hover: #0284c7; - -fx-color-primary-active: #0369a1; - -fx-color-primary-subtle: rgba(56, 189, 248, 0.15); - - /* Sucesso */ - -fx-color-success: #34d399; - -fx-color-success-hover: #10b981; - -fx-color-success-subtle: rgba(52, 211, 153, 0.15); - -fx-color-success-border: rgba(52, 211, 153, 0.4); - - /* Aviso */ - -fx-color-warning: #fbbf24; - -fx-color-warning-hover: #f59e0b; - -fx-color-warning-subtle: rgba(251, 191, 36, 0.15); - -fx-color-warning-border: rgba(251, 191, 36, 0.4); - - /* Erro */ - -fx-color-error: #f87171; - -fx-color-error-hover: #ef4444; - -fx-color-error-subtle: rgba(248, 113, 113, 0.15); - -fx-color-error-border: rgba(248, 113, 113, 0.4); - - /* Foco & Realce */ - -fx-color-focus: #38bdf8; - - /* Sombras & Efeitos */ - -fx-color-shadow: rgba(0, 0, 0, 0.4); - -fx-color-shadow-hover: rgba(0, 0, 0, 0.6); - - /* Lookups nativos do JavaFX */ - -fx-base: -fx-color-background; - -fx-background: -fx-color-background; - -fx-control-inner-background: -fx-color-surface; - -fx-text-fill: -fx-color-text; - - /* Tokens semânticos complementares e aliases de compatibilidade */ - -fx-text-primary: -fx-color-text; - -fx-text-secondary: -fx-color-text-muted; - -fx-bg-primary: -fx-color-surface; - -fx-border-light: -fx-color-border; - -fx-accent: -fx-color-primary; -} - /* ========================================================================== 2. REGRAS GERAIS DE ESTRUTURA E CONTAINERS ========================================================================== */ @@ -213,27 +141,6 @@ -fx-font-weight: bold; } -/* Botão de Alternância de Tema */ -.theme-toggle-btn { - -fx-background-color: -fx-color-surface; - -fx-border-color: -fx-color-border; - -fx-border-radius: 18px; - -fx-border-width: 1px; - -fx-background-radius: 18px; - -fx-text-fill: -fx-color-text; - -fx-padding: 4px 12px; - -fx-font-size: 11px; - -fx-font-weight: bold; - -fx-cursor: hand; - -fx-effect: dropshadow(three-pass-box, -fx-color-shadow, 4, 0, 0, 1); -} - -.theme-toggle-btn:hover { - -fx-background-color: -fx-color-surface-hover; - -fx-border-color: -fx-color-primary; - -fx-text-fill: -fx-color-primary; -} - /* ========================================================================== 3. HUB DE AÇÕES E PAINEL LATERAL ========================================================================== */ diff --git a/modules/cybercore-ui/src/test/java/br/com/cybercore/signer/ui/theme/DesignTokenGuardrailTest.java b/modules/cybercore-ui/src/test/java/br/com/cybercore/signer/ui/theme/DesignTokenGuardrailTest.java index e37e5fb..76d6c74 100644 --- a/modules/cybercore-ui/src/test/java/br/com/cybercore/signer/ui/theme/DesignTokenGuardrailTest.java +++ b/modules/cybercore-ui/src/test/java/br/com/cybercore/signer/ui/theme/DesignTokenGuardrailTest.java @@ -46,8 +46,8 @@ class DesignTokenGuardrailTest { continue; } - // Detecta entrada nos blocos de tokens .theme-light e .theme-dark - if (trimmed.contains(".theme-light") || trimmed.contains(".theme-dark")) { + // Detecta entrada no bloco canônico de tokens .root + if (trimmed.startsWith(".root") || trimmed.contains(".root ")) { insideTokenBlock = true; } @@ -248,8 +248,8 @@ class DesignTokenGuardrailTest { } @Test - @DisplayName("(c) Relação de contraste WCAG 2.1 deve ser >= 4.5:1 para texto normal nos temas claro e escuro") - void shouldMeetWcagContrastRequirementsInBothThemes() throws Exception { + @DisplayName("(c) Relação de contraste WCAG 2.1 deve ser >= 4.5:1 para texto normal no tema único (.root)") + void shouldMeetWcagContrastRequirementsInTheme() throws Exception { InputStream stream = getClass().getResourceAsStream("/styles/theme.css"); assertThat(stream).isNotNull(); @@ -258,14 +258,11 @@ class DesignTokenGuardrailTest { content = new String(stream.readAllBytes(), StandardCharsets.UTF_8); } - // Extrai mapa de tokens por tema (.theme-light e .theme-dark) - java.util.Map lightTokens = extractTokensFromBlock(content, ".theme-light"); - java.util.Map darkTokens = extractTokensFromBlock(content, ".theme-dark"); + // Extrai mapa de tokens definidos no bloco .root + java.util.Map tokens = extractTokensFromBlock(content, ".root"); + assertThat(tokens).isNotEmpty(); - assertThat(lightTokens).isNotEmpty(); - assertThat(darkTokens).isNotEmpty(); - - // Pares a validar em cada tema: (texto, fundo) + // Pares a validar: (texto, fundo) String[][] pairs = { {"-fx-color-text", "-fx-color-background"}, {"-fx-color-text", "-fx-color-surface"}, @@ -281,24 +278,12 @@ class DesignTokenGuardrailTest { String textToken = pair[0]; String bgToken = pair[1]; - // Tema Claro - if (lightTokens.containsKey(textToken) && lightTokens.containsKey(bgToken)) { - String textColor = lightTokens.get(textToken); - String bgColor = lightTokens.get(bgToken); + if (tokens.containsKey(textToken) && tokens.containsKey(bgToken)) { + String textColor = tokens.get(textToken); + String bgColor = tokens.get(bgToken); double ratio = calculateContrastRatio(textColor, bgColor); if (ratio < 4.5) { - contrastFailures.add(String.format("Tema Claro: %s (%s) sobre %s (%s) = %.2f:1 (mínimo 4.5:1)", - textToken, textColor, bgToken, bgColor, ratio)); - } - } - - // Tema Escuro - if (darkTokens.containsKey(textToken) && darkTokens.containsKey(bgToken)) { - String textColor = darkTokens.get(textToken); - String bgColor = darkTokens.get(bgToken); - double ratio = calculateContrastRatio(textColor, bgColor); - if (ratio < 4.5) { - contrastFailures.add(String.format("Tema Escuro: %s (%s) sobre %s (%s) = %.2f:1 (mínimo 4.5:1)", + contrastFailures.add(String.format("%s (%s) sobre %s (%s) = %.2f:1 (mínimo 4.5:1)", textToken, textColor, bgToken, bgColor, ratio)); } }