diff --git a/tame/app.py b/tame/app.py index 87aa5cb..4f3490c 100644 --- a/tame/app.py +++ b/tame/app.py @@ -613,18 +613,22 @@ def action_pause_all(self) -> None: def action_toggle_theme(self) -> None: new_theme = self._theme_manager.cycle() - css_path = self._theme_manager.get_css_path() - if css_path: - self.stylesheet.source.clear() - # Re-add the app's structural layout CSS first - self.stylesheet.add_source(self.CSS, read_from=("TAMEApp", "")) - # Then add the new theme CSS (Screen colors, widget colors) - self.stylesheet.add_source( - css_path.read_text(), read_from=(str(css_path), "") - ) - self.stylesheet.set_variables(self.get_css_variables()) - self.stylesheet.reparse() - self.stylesheet.update(self) + colors = self._theme_manager.get_colors() + bg, fg = colors["screen"] + self.screen.styles.background = bg + self.screen.styles.color = fg + for widget_key, widget_id in ( + ("header", "header-bar"), + ("viewer", "session-viewer"), + ("status", "status-bar"), + ): + wbg, wfg = colors[widget_key] + try: + widget = self.query_one(f"#{widget_id}") + widget.styles.background = wbg + widget.styles.color = wfg + except Exception: + pass log.info("Switched theme to '%s'", new_theme) def action_delete_session(self) -> None: diff --git a/tame/ui/themes/manager.py b/tame/ui/themes/manager.py index 9698d27..7348ebc 100644 --- a/tame/ui/themes/manager.py +++ b/tame/ui/themes/manager.py @@ -18,6 +18,59 @@ "solarized_light", ] +# Colors for widgets that actually exist in the app. +# Each entry: (background, foreground) per widget selector. +THEME_COLORS: dict[str, dict[str, tuple[str, str]]] = { + "dark": { + "screen": ("#1e1e1e", "#d4d4d4"), + "header": ("#007acc", "#ffffff"), + "viewer": ("#1e1e1e", "#d4d4d4"), + "status": ("#007acc", "#ffffff"), + }, + "light": { + "screen": ("#ffffff", "#333333"), + "header": ("#007acc", "#ffffff"), + "viewer": ("#ffffff", "#333333"), + "status": ("#007acc", "#ffffff"), + }, + "dracula": { + "screen": ("#282a36", "#f8f8f2"), + "header": ("#6272a4", "#f8f8f2"), + "viewer": ("#282a36", "#f8f8f2"), + "status": ("#bd93f9", "#282a36"), + }, + "nord": { + "screen": ("#2e3440", "#d8dee9"), + "header": ("#5e81ac", "#eceff4"), + "viewer": ("#2e3440", "#d8dee9"), + "status": ("#5e81ac", "#eceff4"), + }, + "monokai": { + "screen": ("#272822", "#f8f8f2"), + "header": ("#75715e", "#f8f8f2"), + "viewer": ("#272822", "#f8f8f2"), + "status": ("#66d9ef", "#272822"), + }, + "gruvbox": { + "screen": ("#282828", "#ebdbb2"), + "header": ("#458588", "#ebdbb2"), + "viewer": ("#282828", "#ebdbb2"), + "status": ("#458588", "#ebdbb2"), + }, + "solarized_dark": { + "screen": ("#002b36", "#839496"), + "header": ("#268bd2", "#fdf6e3"), + "viewer": ("#002b36", "#839496"), + "status": ("#268bd2", "#fdf6e3"), + }, + "solarized_light": { + "screen": ("#fdf6e3", "#657b83"), + "header": ("#268bd2", "#fdf6e3"), + "viewer": ("#fdf6e3", "#657b83"), + "status": ("#268bd2", "#fdf6e3"), + }, +} + class ThemeManager: def __init__(self, current: str = "dark", custom_css_path: str = "") -> None: @@ -70,6 +123,11 @@ def cycle(self) -> str: self._current = self._available[(idx + 1) % len(self._available)] return self._current + def get_colors(self, theme_name: str | None = None) -> dict[str, tuple[str, str]]: + """Return (background, foreground) pairs for the given theme.""" + name = theme_name or self._current + return THEME_COLORS.get(name, THEME_COLORS["dark"]) + def set_theme(self, name: str) -> bool: if name in self._available: self._current = name