- app/config/theme.py: palette definitions for both themes + apply_qss() helper used by both main.py (startup) and MainWindow (live toggle) - resources/style_light.qss: complete Catppuccin Latte QSS - View menu: ☀️/🌙 Switch Theme action (Ctrl+Shift+T) toggles live - Preferences → Appearance: Color theme dropdown persists choice - SQLHighlighter: _build_rules() reads get_palette(); update_theme() rebuilds rules and rehighlights all open editors on switch - SqlCompleter: popup stylesheet reads get_palette() via _apply_popup_style(); update_theme() called on switch - EditableTableModel: dirty/delete cell colors read get_palette() live - ResultTableModel: NULL_COLOR property reads get_palette() live - TableViewer: apply_settings() refreshes frozen-view border + repaints Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
122 lines
3.6 KiB
Python
122 lines
3.6 KiB
Python
"""
|
|
Theme palettes — Catppuccin Frappé (dark) and Catppuccin Latte (light).
|
|
|
|
Usage:
|
|
from app.config.theme import get_palette, apply_qss, is_dark
|
|
"""
|
|
from pathlib import Path
|
|
|
|
|
|
# ── Catppuccin Frappé ─────────────────────────────────────────────────────────
|
|
DARK = {
|
|
"base": "#303446",
|
|
"mantle": "#292c3c",
|
|
"crust": "#232634",
|
|
"surface0": "#414559",
|
|
"surface1": "#51576d",
|
|
"surface2": "#626880",
|
|
"overlay": "#737994",
|
|
"subtext": "#a5adce",
|
|
"text": "#c6d0f5",
|
|
"blue": "#8caaee",
|
|
"lavender": "#babbf1",
|
|
"green": "#a6d189",
|
|
"teal": "#81c8be",
|
|
"sky": "#99d1db",
|
|
"red": "#e78284",
|
|
"peach": "#ef9f76",
|
|
"yellow": "#e5c890",
|
|
"mauve": "#ca9ee6",
|
|
# derived UI tokens
|
|
"gutter_bg": "#2a2d3e",
|
|
"dirty_bg": "#3a2f25",
|
|
"dirty_fg": "#ef9f76",
|
|
"delete_bg": "#3a2530",
|
|
"delete_fg": "#e78284",
|
|
# syntax
|
|
"syn_keyword": "#8caaee",
|
|
"syn_type": "#ef9f76",
|
|
"syn_function": "#a6d189",
|
|
"syn_string": "#a6d189",
|
|
"syn_number": "#ef9f76",
|
|
"syn_comment": "#737994",
|
|
"syn_operator": "#ca9ee6",
|
|
"syn_ident": "#99d1db",
|
|
# completer popup
|
|
"popup_bg": "#292c3c",
|
|
"popup_border": "#51576d",
|
|
"popup_selected": "#414559",
|
|
"popup_hover": "#363a4f",
|
|
}
|
|
|
|
# ── Catppuccin Latte ──────────────────────────────────────────────────────────
|
|
LIGHT = {
|
|
"base": "#eff1f5",
|
|
"mantle": "#e6e9ef",
|
|
"crust": "#dce0e8",
|
|
"surface0": "#ccd0da",
|
|
"surface1": "#bcc0cc",
|
|
"surface2": "#acb0be",
|
|
"overlay": "#9ca0b0",
|
|
"subtext": "#6c6f85",
|
|
"text": "#4c4f69",
|
|
"blue": "#1e66f5",
|
|
"lavender": "#7287fd",
|
|
"green": "#40a02b",
|
|
"teal": "#179299",
|
|
"sky": "#04a5e5",
|
|
"red": "#d20f39",
|
|
"peach": "#fe640b",
|
|
"yellow": "#df8e1d",
|
|
"mauve": "#8839ef",
|
|
# derived UI tokens
|
|
"gutter_bg": "#dce0e8",
|
|
"dirty_bg": "#fff3e6",
|
|
"dirty_fg": "#fe640b",
|
|
"delete_bg": "#ffe8ed",
|
|
"delete_fg": "#d20f39",
|
|
# syntax
|
|
"syn_keyword": "#1e66f5",
|
|
"syn_type": "#fe640b",
|
|
"syn_function": "#40a02b",
|
|
"syn_string": "#40a02b",
|
|
"syn_number": "#fe640b",
|
|
"syn_comment": "#9ca0b0",
|
|
"syn_operator": "#8839ef",
|
|
"syn_ident": "#04a5e5",
|
|
# completer popup
|
|
"popup_bg": "#e6e9ef",
|
|
"popup_border": "#bcc0cc",
|
|
"popup_selected": "#ccd0da",
|
|
"popup_hover": "#d8dce8",
|
|
}
|
|
|
|
_QSS_DIR = Path(__file__).parent.parent.parent / "resources"
|
|
|
|
|
|
def get_palette() -> dict:
|
|
"""Return the color dict for the currently active theme."""
|
|
from app.config.settings import get_settings
|
|
name = get_settings().get("theme", "dark")
|
|
return DARK if name == "dark" else LIGHT
|
|
|
|
|
|
def is_dark() -> bool:
|
|
from app.config.settings import get_settings
|
|
return get_settings().get("theme", "dark") == "dark"
|
|
|
|
|
|
def qss_path(theme: str) -> Path:
|
|
name = "style" if theme == "dark" else "style_light"
|
|
return _QSS_DIR / f"{name}.qss"
|
|
|
|
|
|
def apply_qss(app, theme: str = None) -> None:
|
|
"""Load and apply the QSS for *theme* (defaults to current setting)."""
|
|
from app.config.settings import get_settings
|
|
if theme is None:
|
|
theme = get_settings().get("theme", "dark")
|
|
path = qss_path(theme)
|
|
if path.exists():
|
|
app.setStyleSheet(path.read_text(encoding="utf-8"))
|