## Copyright © 2026 Olaf Kolkman ## SPDX-License-Identifier: GPL-3.0-or-later import json from backend.app.database import get_connection THEMES = { 'plain-day': {'label': 'Plain Day', 'description': 'A bright, neutral daytime theme.'}, 'plain-night': {'label': 'Plain Night', 'description': 'A neutral dark nighttime theme.'}, 'latte': {'label': 'Catppuccin Latte', 'description': 'Catppuccin light theme.'}, 'frappe': {'label': 'Catppuccin Frappe', 'description': 'Catppuccin soft dark theme.'}, 'macchiato': {'label': 'Catppuccin Macchiato', 'description': 'Catppuccin medium dark theme.'}, 'mocha': {'label': 'Catppuccin Mocha', 'description': 'Catppuccin deep dark theme.'}, 'dracula': {'label': 'Dracula', 'description': 'A vivid dark theme with high-contrast accents.'}, 'nord': {'label': 'Nord', 'description': 'A cool, muted blue-gray theme.'}, 'solarized': {'label': 'Solarized', 'description': 'A balanced theme available in a light style.'}, } DEFAULT_ENABLED_THEMES = tuple(THEMES) def get_enabled_themes() -> list[str]: with get_connection() as conn: row = conn.execute('SELECT value FROM app_settings WHERE name = ?', ('enabled_themes',)).fetchone() if row is None: return list(DEFAULT_ENABLED_THEMES) try: configured = json.loads(row['value']) except (TypeError, json.JSONDecodeError): return list(DEFAULT_ENABLED_THEMES) return [theme for theme in configured if theme in THEMES] or ['mocha'] def save_enabled_themes(themes: list[str]) -> list[str]: selected = list(dict.fromkeys(theme for theme in themes if theme in THEMES)) if not selected: raise ValueError('At least one theme must be enabled') with get_connection() as conn: conn.execute( '''INSERT INTO app_settings (name, value, updated_at) VALUES (?, ?, CURRENT_TIMESTAMP) ON CONFLICT(name) DO UPDATE SET value = excluded.value, updated_at = CURRENT_TIMESTAMP''', ('enabled_themes', json.dumps(selected)), ) conn.commit() return selected