Implement theme toggle system with localStorage persistence #30

Closed
opened 2026-01-15 06:51:02 +00:00 by lmiranda · 0 comments
Owner

Description

Create a theme toggle system using Dash clientside callbacks that persists the user's theme preference in localStorage. Dark theme should be the default.

Files to Create

  • portfolio_app/callbacks/__init__.py
  • portfolio_app/callbacks/theme.py

Technical Design

Theme State Management

  1. dcc.Store for theme state:

    • id="theme-store"
    • storage_type="local" (localStorage persistence)
    • Default data: {"colorScheme": "dark"}
  2. Theme Application: Set data-mantine-color-scheme attribute on document root

Clientside Callbacks

1. Theme Toggle Callback

Triggered when theme toggle button is clicked.

app.clientside_callback(
    """
    function(n_clicks, currentTheme) {
        if (!n_clicks) {
            return window.dash_clientside.no_update;
        }
        const newScheme = currentTheme.colorScheme === 'dark' ? 'light' : 'dark';
        document.documentElement.setAttribute('data-mantine-color-scheme', newScheme);
        return {colorScheme: newScheme};
    }
    """,
    Output("theme-store", "data"),
    Input("theme-toggle-btn", "n_clicks"),
    State("theme-store", "data"),
    prevent_initial_call=True,
)

2. Theme Initialization Callback

Apply theme from localStorage on page load.

app.clientside_callback(
    """
    function(data) {
        const scheme = data?.colorScheme || 'dark';
        document.documentElement.setAttribute('data-mantine-color-scheme', scheme);
        return scheme === 'dark' ? 'tabler:moon' : 'tabler:sun';
    }
    """,
    Output("theme-toggle-icon", "icon"),
    Input("theme-store", "data"),
)

3. Toggle Icon Update

Update the theme toggle button icon based on current theme.

Registration Function

def register_theme_callbacks(app: dash.Dash) -> None:
    """Register all theme-related clientside callbacks."""
    # ... callback definitions

Integration Points

  • Theme toggle button in sidebar: id="theme-toggle-btn"
  • Theme icon in button: id="theme-toggle-icon" (DashIconify component)
  • Store in app layout: id="theme-store"
  • MantineProvider must NOT have forceColorScheme

Acceptance Criteria

  • Dark theme is default on first visit
  • Clicking toggle switches between dark/light
  • Theme persists after page refresh
  • Theme persists across browser sessions
  • Toggle icon updates (moon for dark, sun for light)
  • No flash of wrong theme on page load
  • All Mantine components respect theme

Part of Sprint 7 (#27)

## Description Create a theme toggle system using Dash clientside callbacks that persists the user's theme preference in localStorage. Dark theme should be the default. ## Files to Create - `portfolio_app/callbacks/__init__.py` - `portfolio_app/callbacks/theme.py` ## Technical Design ### Theme State Management 1. **dcc.Store** for theme state: - `id="theme-store"` - `storage_type="local"` (localStorage persistence) - Default data: `{"colorScheme": "dark"}` 2. **Theme Application**: Set `data-mantine-color-scheme` attribute on document root ### Clientside Callbacks #### 1. Theme Toggle Callback Triggered when theme toggle button is clicked. ```python app.clientside_callback( """ function(n_clicks, currentTheme) { if (!n_clicks) { return window.dash_clientside.no_update; } const newScheme = currentTheme.colorScheme === 'dark' ? 'light' : 'dark'; document.documentElement.setAttribute('data-mantine-color-scheme', newScheme); return {colorScheme: newScheme}; } """, Output("theme-store", "data"), Input("theme-toggle-btn", "n_clicks"), State("theme-store", "data"), prevent_initial_call=True, ) ``` #### 2. Theme Initialization Callback Apply theme from localStorage on page load. ```python app.clientside_callback( """ function(data) { const scheme = data?.colorScheme || 'dark'; document.documentElement.setAttribute('data-mantine-color-scheme', scheme); return scheme === 'dark' ? 'tabler:moon' : 'tabler:sun'; } """, Output("theme-toggle-icon", "icon"), Input("theme-store", "data"), ) ``` #### 3. Toggle Icon Update Update the theme toggle button icon based on current theme. ### Registration Function ```python def register_theme_callbacks(app: dash.Dash) -> None: """Register all theme-related clientside callbacks.""" # ... callback definitions ``` ## Integration Points - Theme toggle button in sidebar: `id="theme-toggle-btn"` - Theme icon in button: `id="theme-toggle-icon"` (DashIconify component) - Store in app layout: `id="theme-store"` - MantineProvider must NOT have `forceColorScheme` ## Acceptance Criteria - [ ] Dark theme is default on first visit - [ ] Clicking toggle switches between dark/light - [ ] Theme persists after page refresh - [ ] Theme persists across browser sessions - [ ] Toggle icon updates (moon for dark, sun for light) - [ ] No flash of wrong theme on page load - [ ] All Mantine components respect theme ## Part of Sprint 7 (#27)
lmiranda added this to the Launch: Host, Bio and Toronto House Market Analysis project 2026-01-16 14:51:54 +00:00
lmiranda self-assigned this 2026-01-16 14:51:59 +00:00
lmiranda moved this to Done in Launch: Host, Bio and Toronto House Market Analysis on 2026-01-16 14:52:13 +00:00
Sign in to join this conversation.