"""VivoKey Supra Theme plugin for Dangerous Pi. Registers the Supra theme (Material Design 3 with VivoKey blue, rounded corners, elevation shadows) via the theme_register hook so it appears in Settings > Appearance when this plugin is enabled. """ import shutil import sys from pathlib import Path _plugin_manager_module = ( sys.modules.get('app.backend.managers.plugin_manager') or sys.modules.get('backend.managers.plugin_manager') ) if _plugin_manager_module: PluginBase = _plugin_manager_module.PluginBase PluginMetadata = _plugin_manager_module.PluginMetadata else: from pathlib import Path as _P app_path = _P(__file__).parent.parent.parent if str(app_path) not in sys.path: sys.path.insert(0, str(app_path)) from backend.managers.plugin_manager import PluginBase, PluginMetadata # Paths _PLUGIN_DIR = Path(__file__).parent _STATIC_CSS = _PLUGIN_DIR / "static" / "tokens.css" # Where the frontend serves themes from _THEMES_DIR = _PLUGIN_DIR.parent.parent / "frontend" / "themes" / "supra" class SupraThemePlugin(PluginBase): """Provides the VivoKey Supra theme to Dangerous Pi.""" async def on_load(self): pass async def on_enable(self): # Copy CSS to the themes directory so it's served by the /themes mount _THEMES_DIR.mkdir(parents=True, exist_ok=True) shutil.copy2(_STATIC_CSS, _THEMES_DIR / "tokens.css") # Register the theme via the theme_register hook. # MUST be synchronous — the theme scanner skips async callbacks. def supra_theme_register(): return { "id": "supra", "name": "VivoKey Supra", "description": "Material Design 3 with VivoKey blue, rounded corners, elevation shadows", "supportsModes": ["dark", "light", "auto"], "defaultMode": "dark", "author": "Dangerous Things", "css_url": "/themes/supra/tokens.css", } self.register_hook("theme_register", supra_theme_register) async def on_disable(self): # Clean up the copied theme files if _THEMES_DIR.exists(): shutil.rmtree(_THEMES_DIR, ignore_errors=True) async def on_unload(self): pass def get_metadata(self) -> PluginMetadata: return self.metadata