235 lines
9.4 KiB
Python
235 lines
9.4 KiB
Python
"""Jetons de couleur et fragments de feuille de style partagés.
|
|
|
|
Les couleurs étaient écrites en dur au fil des widgets : vingt-quatre valeurs
|
|
distinctes dans le seul panneau d'administration, cinq bandeaux d'onglets sans
|
|
rapport de teinte entre eux, et des blocs de résultat dont le fond ne
|
|
correspondait ni à celui de la page ni à celui de leurs voisins. Tout passe
|
|
désormais par ce module — une couleur ne se choisit plus au cas par cas.
|
|
"""
|
|
|
|
# ── Fonds ────────────────────────────────────────────────────────────────────
|
|
BG = "#1c2833" # fond de l'application et de toutes les pages
|
|
BG_SUNKEN = "#17202a" # zones en creux : configurations, blocs de code
|
|
BG_RAISED = "#253545" # éléments posés sur le fond : listes, en-têtes secondaires
|
|
BORDER = "rgba(255,255,255,0.18)"
|
|
BORDER_SOFT = "rgba(255,255,255,0.10)"
|
|
INPUT_BG = "rgba(255,255,255,0.10)" # fond des champs de saisie et listes
|
|
|
|
# ── Textes ───────────────────────────────────────────────────────────────────
|
|
TEXT = "white"
|
|
TEXT_MUTED = "rgba(255,255,255,0.70)"
|
|
TEXT_FAINT = "rgba(255,255,255,0.50)"
|
|
TEXT_CODE = "#a8d8ea" # texte à chasse fixe (aperçus de config, rapports)
|
|
|
|
# ── Accent ───────────────────────────────────────────────────────────────────
|
|
ACCENT = "#2471a3"
|
|
ACCENT_HOVER = "#1a5276"
|
|
ACCENT_ACTIVE = "#154360"
|
|
ACCENT_LIGHT = "#5dade2"
|
|
|
|
# ── États ────────────────────────────────────────────────────────────────────
|
|
# Chaque état porte un trio : teinte du texte, fond translucide, bouton plein.
|
|
OK_TEXT, OK_BG, OK_SOLID = "#a9dfbf", "rgba(39,174,96,0.18)", "#1e8449"
|
|
WARN_TEXT, WARN_BG, WARN_SOLID = "#f7dc6f", "rgba(241,196,15,0.15)", "#b7950b"
|
|
FAIL_TEXT, FAIL_BG, FAIL_SOLID = "#f1948a", "rgba(231,76,60,0.18)", "#c0392b"
|
|
SKIP_TEXT, SKIP_BG = "rgba(255,255,255,0.45)", "rgba(255,255,255,0.05)"
|
|
|
|
# Teintes de survol des boutons pleins ok/fail — reprises telles quelles à
|
|
# plusieurs endroits (panneau admin, fenêtre principale) : un seul nom leur
|
|
# évite de dériver l'une de l'autre au fil des modifications.
|
|
OK_HOVER = "#27ae60"
|
|
FAIL_HOVER = "#e74c3c"
|
|
|
|
_STATE = {
|
|
"ok": (OK_TEXT, OK_BG),
|
|
"warn": (WARN_TEXT, WARN_BG),
|
|
"fail": (FAIL_TEXT, FAIL_BG),
|
|
"skip": (SKIP_TEXT, SKIP_BG),
|
|
"idle": (TEXT_MUTED, "transparent"),
|
|
}
|
|
|
|
# ── Badge de ping (fenêtre principale) ──────────────────────────────────────
|
|
PING_CSS = {
|
|
"good": "background:#1e8449; color:white;",
|
|
"medium": "background:#d4ac0d; color:black;",
|
|
"bad": "background:#922b21; color:white;",
|
|
"offline": f"background:{BG_RAISED}; color:{TEXT_FAINT};",
|
|
}
|
|
|
|
# ── Entrées de journal (fenêtre principale) ─────────────────────────────────
|
|
LOG_COLORS = {
|
|
"success": OK_TEXT,
|
|
"error": FAIL_TEXT,
|
|
"warning": WARN_TEXT,
|
|
"info": ACCENT_LIGHT,
|
|
}
|
|
|
|
# ── Bandeaux d'onglets ───────────────────────────────────────────────────────
|
|
# Cinq teintes calées sur la même luminosité et la même saturation : les
|
|
# onglets restent distinguables sans que l'un paraisse plus clair ou plus
|
|
# saturé que les autres, ce qui était le cas des valeurs choisies à la main.
|
|
BANNER = {
|
|
"wireguard": "#1a5276",
|
|
"keys": "#1a4a6e",
|
|
"mfa": "#4a2a6e",
|
|
"test": "#1a4a7a",
|
|
"settings": "#155e52",
|
|
"security": "#7a3b1a",
|
|
"about": "#243b53",
|
|
}
|
|
|
|
|
|
def result_style(state: str, font_size: int = 11) -> str:
|
|
"""Feuille de style d'un bloc de résultat, selon son état.
|
|
|
|
Les blocs affichaient chacun leur propre fond rgba, recopié à la main :
|
|
même état, teintes différentes d'un widget à l'autre.
|
|
"""
|
|
color, bg = _STATE.get(state, _STATE["idle"])
|
|
return (f"padding: 8px; border-radius: 6px; font-size: {font_size}px;"
|
|
f" background: {bg}; color: {color};")
|
|
|
|
|
|
def result_view_style(state: str = "idle", font_size: int = 12) -> str:
|
|
"""Même chose pour un QTextEdit en lecture seule (rapport défilant)."""
|
|
color, bg = _STATE.get(state, _STATE["idle"])
|
|
return (
|
|
f"QTextEdit {{ background: {bg}; color: {color};"
|
|
f" border: 1px solid {BORDER_SOFT}; border-radius: 6px;"
|
|
f" padding: 8px; font-size: {font_size}px; }}"
|
|
f"QScrollBar:vertical {{ background: transparent; width: 8px;"
|
|
f" border: none; }}"
|
|
f"QScrollBar::handle:vertical {{ background: {BG_RAISED};"
|
|
f" border-radius: 4px; }}"
|
|
"QScrollBar::add-line:vertical,"
|
|
"QScrollBar::sub-line:vertical { height: 0; }"
|
|
)
|
|
|
|
|
|
def scrollarea_style() -> str:
|
|
return (
|
|
f"QScrollArea {{ border: none; background: {BG}; }}"
|
|
f"QScrollBar:vertical {{ background: {BG}; width: 8px; border: none; }}"
|
|
f"QScrollBar::handle:vertical {{ background: {BG_RAISED};"
|
|
f" border-radius: 4px; }}"
|
|
"QScrollBar::add-line:vertical,"
|
|
"QScrollBar::sub-line:vertical { height: 0; }"
|
|
)
|
|
|
|
|
|
def banner_style(color: str) -> str:
|
|
return (f"background: {color}; color: {TEXT}; font-size: 13px;"
|
|
" font-weight: bold; padding-left: 8px;")
|
|
|
|
|
|
#: CSS sombre commun à toutes les pages.
|
|
TAB_CSS = f"""
|
|
QWidget {{ background-color: {BG}; color: {TEXT}; }}
|
|
QLabel {{ color: {TEXT}; background: transparent; }}
|
|
QCheckBox {{ color: {TEXT}; background: transparent; }}
|
|
QGroupBox {{
|
|
color: {TEXT};
|
|
background: transparent;
|
|
border: 1px solid {BORDER};
|
|
border-radius: 5px;
|
|
margin-top: 10px;
|
|
font-weight: bold;
|
|
}}
|
|
QGroupBox::title {{
|
|
subcontrol-origin: margin;
|
|
left: 10px;
|
|
padding: 0 4px;
|
|
color: {TEXT};
|
|
}}
|
|
QLineEdit {{
|
|
background: {INPUT_BG};
|
|
color: {TEXT};
|
|
border: 1px solid {BORDER};
|
|
border-radius: 4px;
|
|
padding: 4px 6px;
|
|
}}
|
|
QLineEdit:read-only {{ background: rgba(255,255,255,0.06); }}
|
|
QLineEdit:disabled {{ background: rgba(255,255,255,0.04);
|
|
color: {TEXT_FAINT}; }}
|
|
QSpinBox {{
|
|
background: {INPUT_BG};
|
|
color: {TEXT};
|
|
border: 1px solid {BORDER};
|
|
border-radius: 4px;
|
|
padding: 3px 6px;
|
|
}}
|
|
QSpinBox::up-button, QSpinBox::down-button {{
|
|
background: rgba(255,255,255,0.15);
|
|
}}
|
|
QComboBox {{
|
|
background: {INPUT_BG};
|
|
color: {TEXT};
|
|
border: 1px solid {BORDER};
|
|
border-radius: 4px;
|
|
padding: 3px 8px;
|
|
}}
|
|
QComboBox::drop-down {{ border: none; }}
|
|
QComboBox QAbstractItemView {{
|
|
background: {BG_RAISED};
|
|
color: {TEXT};
|
|
selection-background-color: {ACCENT};
|
|
}}
|
|
QTextEdit {{
|
|
background: {BG_SUNKEN};
|
|
color: {TEXT_CODE};
|
|
border: 1px solid {BORDER};
|
|
border-radius: 4px;
|
|
}}
|
|
QPushButton {{
|
|
background: {ACCENT};
|
|
color: {TEXT};
|
|
border-radius: 5px;
|
|
padding: 7px 12px;
|
|
border: none;
|
|
}}
|
|
QPushButton:hover {{ background: {ACCENT_HOVER}; }}
|
|
QPushButton:checked {{ background: {ACCENT_ACTIVE}; }}
|
|
QPushButton:disabled {{ background: rgba(255,255,255,0.08);
|
|
color: {TEXT_FAINT}; }}
|
|
"""
|
|
|
|
#: Barre d'onglets, utilisée par le panneau principal et les sous-onglets.
|
|
TABBAR_CSS = f"""
|
|
QTabWidget::pane {{ border: none; background: {BG}; }}
|
|
QTabBar::tab {{
|
|
background: {BG_RAISED};
|
|
color: {TEXT_MUTED};
|
|
padding: 6px 14px;
|
|
border: none;
|
|
}}
|
|
QTabBar::tab:selected {{ background: {ACCENT}; color: {TEXT}; }}
|
|
QTabBar::tab:hover:!selected {{ background: {ACCENT_HOVER};
|
|
color: {TEXT}; }}
|
|
"""
|
|
|
|
|
|
def primary_button_style(solid: str = OK_SOLID, hover: str = OK_HOVER) -> str:
|
|
"""Bouton d'action principale d'une page (lancer un test, par exemple)."""
|
|
return (f"QPushButton {{ padding: 9px; background: {solid}; color: {TEXT};"
|
|
f" border-radius: 5px; font-weight: bold; border: none; }}"
|
|
f"QPushButton:hover {{ background: {hover}; }}")
|
|
|
|
|
|
def secondary_button_style() -> str:
|
|
"""Bouton d'action secondaire d'une page (à côté d'une action principale)."""
|
|
return (f"QPushButton {{ padding: 9px; background: {BG_RAISED}; color: {TEXT};"
|
|
f" border-radius: 5px; border: none; }}"
|
|
f"QPushButton:hover {{ background: {ACCENT_HOVER}; }}")
|
|
|
|
|
|
def hint_style() -> str:
|
|
"""Encart d'introduction posé en tête de chaque onglet.
|
|
|
|
Assez contrasté pour se détacher du fond de page, assez sobre pour ne pas
|
|
concurrencer le contenu : un liseré d'accent à gauche, pas de cadre plein.
|
|
"""
|
|
return (f"background: rgba(36,113,163,0.16);"
|
|
f" border-left: 3px solid {ACCENT_LIGHT};"
|
|
f" border-radius: 4px; padding: 9px 11px;"
|
|
f" color: {TEXT_MUTED}; font-size: 11px;")
|