feat(gui): GUI V6 G4 — alignement visuel sur la maquette v6 (option A)
Refonte de la couche présentation pour reprendre docs/ui_mockup_v6.html, sans changer de techno UI ni la logique G1-G3. - theme.py : 4 thèmes aux tokens EXACTS de la maquette (sombre #1a1a2e/#16213e/ #e94560, clair, médical, neutre), palette complète + status_color. - ui_kit.py (nouveau) : composants stylés (Card titrée, boutons primary/secondary/ success/pilule, StatCard, ToggleRow) appliquant la palette. - app.py : shell étroit, header identité + version + statut licence + liseré accent, barre d'onglets custom (plus de CTkTabview brut), navigation par recréation, changement de thème à chaud. - tab_usage : carte Apparence (sélecteur de thème), dropzone stylée, grille formats, barre d'actions, progression à étapes + journal, résultats en cartes statistiques. - tab_config : sous-navigation Réglages/Masquage/Partage/Règles ; Réglages câblé au ConfigState (profil, moteurs NER, dossier sortie). - tab_about : grille d'informations + bloc licence (logique inchangée). Logique inchangée : engine_bridge, config_state, license_client/store, runner. Tests : +9 (theme). self-test exit 0, 55 tests gui_v6, 202 tests/unit (0 régression). Smoke construction headless (Xvfb) : 3 onglets × 4 thèmes rendus sans erreur. Pas de pywebview, aucun .exe. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
55
tests/unit/test_gui_v6_theme.py
Normal file
55
tests/unit/test_gui_v6_theme.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""Tests de la logique de thème G4 (palettes maquette, status_color) sans display."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from gui_v6 import theme as theme_mod
|
||||
|
||||
_REQUIRED_TOKENS = {
|
||||
"bg", "card", "card_border", "primary", "primary_dim", "accent",
|
||||
"text", "text_dim", "text_muted", "success", "warning", "danger", "blue",
|
||||
"divider", "btn_sec_bg", "btn_sec_border", "appearance",
|
||||
}
|
||||
|
||||
|
||||
def test_four_themes_present():
|
||||
assert set(theme_mod.PALETTES) == {"sombre", "clair", "medical", "neutre"}
|
||||
assert theme_mod.DEFAULT_THEME == "sombre"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", ["sombre", "clair", "medical", "neutre"])
|
||||
def test_palette_has_all_tokens(name):
|
||||
palette = theme_mod.PALETTES[name]
|
||||
assert _REQUIRED_TOKENS <= set(palette)
|
||||
# Couleurs hex valides (sauf appearance).
|
||||
for key, val in palette.items():
|
||||
if key == "appearance":
|
||||
assert val in ("dark", "light")
|
||||
else:
|
||||
assert isinstance(val, str) and val.startswith("#") and len(val) == 7
|
||||
|
||||
|
||||
def test_default_palette_matches_mockup():
|
||||
p = theme_mod.get_palette("sombre")
|
||||
assert p["bg"] == "#1a1a2e"
|
||||
assert p["card"] == "#16213e"
|
||||
assert p["primary"] == "#e94560"
|
||||
assert p["accent"] == "#f5a623"
|
||||
|
||||
|
||||
def test_get_palette_fallback():
|
||||
assert theme_mod.get_palette("inconnu") is theme_mod.PALETTES[theme_mod.DEFAULT_THEME]
|
||||
|
||||
|
||||
def test_status_color_maps_to_tokens():
|
||||
assert theme_mod.status_color("sombre", "active") == theme_mod.PALETTES["sombre"]["success"]
|
||||
assert theme_mod.status_color("sombre", "expired") == theme_mod.PALETTES["sombre"]["danger"]
|
||||
assert theme_mod.status_color("sombre", "grace") == theme_mod.PALETTES["sombre"]["warning"]
|
||||
# statut inconnu → text_muted, sans lever.
|
||||
assert theme_mod.status_color("sombre", "???") == theme_mod.PALETTES["sombre"]["text_muted"]
|
||||
|
||||
|
||||
def test_theme_labels_present():
|
||||
for name in theme_mod.theme_names():
|
||||
assert name in theme_mod.THEME_LABELS
|
||||
Reference in New Issue
Block a user