feat: Add floating sidebar navigation and dark theme support

- Add floating pill-shaped sidebar with navigation icons
- Implement dark/light theme toggle with localStorage persistence
- Update all figure factories for transparent backgrounds
- Use carto-darkmatter map style for choropleths
- Add methodology link button to Toronto dashboard header
- Add back to dashboard button on methodology page
- Remove social links from home page (now in sidebar)
- Update CLAUDE.md to Sprint 7

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-15 11:53:13 -05:00
parent 1e0ea9cca2
commit b3fb94c7cb
13 changed files with 475 additions and 49 deletions

View File

@@ -0,0 +1,179 @@
"""Floating sidebar navigation component."""
import dash_mantine_components as dmc
from dash import dcc, html
from dash_iconify import DashIconify
# Navigation items configuration
NAV_ITEMS = [
{"path": "/", "icon": "tabler:home", "label": "Home"},
{"path": "/toronto", "icon": "tabler:map-2", "label": "Toronto Housing"},
]
# External links configuration
EXTERNAL_LINKS = [
{
"url": "https://github.com/leomiranda",
"icon": "tabler:brand-github",
"label": "GitHub",
},
{
"url": "https://linkedin.com/in/leobmiranda",
"icon": "tabler:brand-linkedin",
"label": "LinkedIn",
},
]
def create_brand_logo() -> html.Div:
"""Create the brand initials logo."""
return html.Div(
dcc.Link(
"LM",
href="/",
className="sidebar-brand-link",
),
className="sidebar-brand",
)
def create_nav_icon(
icon: str,
label: str,
path: str,
current_path: str,
) -> dmc.Tooltip:
"""Create a navigation icon with tooltip.
Args:
icon: Iconify icon string.
label: Tooltip label.
path: Navigation path.
current_path: Current page path for active state.
Returns:
Tooltip-wrapped navigation icon.
"""
is_active = current_path == path or (path != "/" and current_path.startswith(path))
return dmc.Tooltip(
dcc.Link(
dmc.ActionIcon(
DashIconify(icon=icon, width=20),
variant="subtle" if not is_active else "filled",
size="lg",
radius="xl",
color="blue" if is_active else "gray",
className="nav-icon-active" if is_active else "",
),
href=path,
),
label=label,
position="right",
withArrow=True,
)
def create_theme_toggle(current_theme: str = "dark") -> dmc.Tooltip:
"""Create the theme toggle button.
Args:
current_theme: Current theme ('dark' or 'light').
Returns:
Tooltip-wrapped theme toggle icon.
"""
icon = "tabler:sun" if current_theme == "dark" else "tabler:moon"
label = "Switch to light mode" if current_theme == "dark" else "Switch to dark mode"
return dmc.Tooltip(
dmc.ActionIcon(
DashIconify(icon=icon, width=20, id="theme-toggle-icon"),
id="theme-toggle",
variant="subtle",
size="lg",
radius="xl",
color="gray",
),
label=label,
position="right",
withArrow=True,
)
def create_external_link(url: str, icon: str, label: str) -> dmc.Tooltip:
"""Create an external link icon with tooltip.
Args:
url: External URL.
icon: Iconify icon string.
label: Tooltip label.
Returns:
Tooltip-wrapped external link icon.
"""
return dmc.Tooltip(
dmc.Anchor(
dmc.ActionIcon(
DashIconify(icon=icon, width=20),
variant="subtle",
size="lg",
radius="xl",
color="gray",
),
href=url,
target="_blank",
),
label=label,
position="right",
withArrow=True,
)
def create_sidebar_divider() -> html.Div:
"""Create a horizontal divider for the sidebar."""
return html.Div(className="sidebar-divider")
def create_sidebar(current_path: str = "/", current_theme: str = "dark") -> html.Div:
"""Create the floating sidebar navigation.
Args:
current_path: Current page path for active state highlighting.
current_theme: Current theme for toggle icon state.
Returns:
Complete sidebar component.
"""
return html.Div(
[
# Brand logo
create_brand_logo(),
create_sidebar_divider(),
# Navigation icons
*[
create_nav_icon(
icon=item["icon"],
label=item["label"],
path=item["path"],
current_path=current_path,
)
for item in NAV_ITEMS
],
create_sidebar_divider(),
# Theme toggle
create_theme_toggle(current_theme),
create_sidebar_divider(),
# External links
*[
create_external_link(
url=link["url"],
icon=link["icon"],
label=link["label"],
)
for link in EXTERNAL_LINKS
],
],
className="floating-sidebar",
id="floating-sidebar",
)