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:
+23
-14
@@ -12,6 +12,7 @@ from PyQt6.QtWidgets import QApplication, QListWidget, QListWidgetItem
|
||||
|
||||
from app.ui.syntax_highlighter import _KEYWORDS, _TYPES, _FUNCTIONS
|
||||
from app.utils.worker import SchemaWorker
|
||||
from app.config.theme import get_palette
|
||||
|
||||
# Combined, deduplicated keyword list used as the static completion pool.
|
||||
SQL_KEYWORDS: list[str] = list(dict.fromkeys(_KEYWORDS + _TYPES + _FUNCTIONS))
|
||||
@@ -51,24 +52,28 @@ class _CompletionPopup(QListWidget):
|
||||
self.setFont(font)
|
||||
self._row_h = QFontMetrics(font).height() + 6
|
||||
|
||||
self.setStyleSheet("""
|
||||
QListWidget {
|
||||
background: #292c3c;
|
||||
color: #c6d0f5;
|
||||
border: 1px solid #51576d;
|
||||
self._apply_popup_style()
|
||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||
|
||||
def _apply_popup_style(self):
|
||||
p = get_palette()
|
||||
self.setStyleSheet(f"""
|
||||
QListWidget {{
|
||||
background: {p['popup_bg']};
|
||||
color: {p['text']};
|
||||
border: 1px solid {p['popup_border']};
|
||||
border-radius: 4px;
|
||||
padding: 2px;
|
||||
outline: none;
|
||||
}
|
||||
QListWidget::item { padding: 2px 8px; }
|
||||
QListWidget::item:selected {
|
||||
background: #414559;
|
||||
color: #c6d0f5;
|
||||
}
|
||||
QListWidget::item:hover { background: #363a4f; }
|
||||
}}
|
||||
QListWidget::item {{ padding: 2px 8px; }}
|
||||
QListWidget::item:selected {{
|
||||
background: {p['popup_selected']};
|
||||
color: {p['text']};
|
||||
}}
|
||||
QListWidget::item:hover {{ background: {p['popup_hover']}; }}
|
||||
""")
|
||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||
|
||||
self.itemClicked.connect(
|
||||
lambda item: self._editor._completer._accept_completion(item.text())
|
||||
@@ -142,6 +147,10 @@ class SqlCompleter(QObject):
|
||||
|
||||
# ── Public API ────────────────────────────────────────────────────────────
|
||||
|
||||
def update_theme(self) -> None:
|
||||
"""Reapply popup colors after a theme change."""
|
||||
self._popup._apply_popup_style()
|
||||
|
||||
def set_context(self, driver, database: str) -> None:
|
||||
"""Update the active driver/database and refresh schema cache."""
|
||||
self._driver = driver
|
||||
|
||||
Reference in New Issue
Block a user