feat: dark/light theme toggle (Catppuccin Frappé ↔ Latte)

- 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>
This commit is contained in:
2026-05-22 09:11:05 -04:00
co-authored by Claude Sonnet 4.6
parent 6cff9557b3
commit 06b951daf7
11 changed files with 857 additions and 76 deletions
+28 -1
View File
@@ -17,6 +17,7 @@ from PyQt6.QtWidgets import (
)
from PyQt6.QtCore import Qt, QTimer, QThread, pyqtSignal
from PyQt6.QtGui import QAction, QColor, QKeySequence
from app.config.theme import apply_qss, is_dark
from app.ui.schema_browser import SchemaBrowser
from app.ui.sql_editor import SQLEditorWidget
@@ -208,6 +209,12 @@ class MainWindow(QMainWindow):
view_menu.addAction(self._act("Toggle Query History", self._toggle_history, "Ctrl+Shift+H"))
view_menu.addAction(self._act("New SQL Tab", self._new_sql_tab, "Ctrl+T"))
view_menu.addAction(self._act("Close Tab", self._close_current_tab, "Ctrl+W"))
view_menu.addSeparator()
self._theme_action = QAction("", self)
self._theme_action.setShortcut(QKeySequence("Ctrl+Shift+T"))
self._theme_action.triggered.connect(self._toggle_theme)
self._update_theme_action_label()
view_menu.addAction(self._theme_action)
# ── Tools ─────────────────────────────────────────────────────────────
tools_menu = mb.addMenu("&Tools")
@@ -662,9 +669,29 @@ class MainWindow(QMainWindow):
def _open_preferences(self):
dlg = PreferencesDialog(parent=self)
dlg.settings_applied.connect(self._apply_settings_to_open_tabs)
dlg.settings_applied.connect(self._on_settings_applied)
dlg.exec()
def _on_settings_applied(self):
apply_qss(QApplication.instance())
self._update_theme_action_label()
self._apply_settings_to_open_tabs()
def _toggle_theme(self):
from app.config.settings import get_settings
new_theme = "light" if is_dark() else "dark"
get_settings().set("theme", new_theme)
get_settings().save()
apply_qss(QApplication.instance(), new_theme)
self._update_theme_action_label()
self._apply_settings_to_open_tabs()
def _update_theme_action_label(self):
if is_dark():
self._theme_action.setText("☀️ Switch to Light Theme")
else:
self._theme_action.setText("🌙 Switch to Dark Theme")
def _apply_settings_to_open_tabs(self):
"""Push updated settings to all currently open workspace tabs."""
for i in range(self._workspace.count()):