Theme System
This guide documents how dark/light theme switching is implemented in Waldur HomePort.
Architecture Overview
The app uses two separate compiled stylesheets that are dynamically loaded based on the selected theme:
src/metronic/sass/style.scss- Light theme ($mode: default)src/metronic/sass/style.dark.scss- Dark theme ($mode: dark)
SCSS variables use the isDarkMode() function to return different values at compile time:
1 2 3 4 | |
Key Files
| File | Purpose |
|---|---|
src/theme/ThemeProvider.tsx |
React context provider for theme state |
src/theme/useTheme.ts |
Hook to access current theme |
src/theme/ThemeStorage.ts |
localStorage persistence |
src/theme/utils.ts |
Dynamic CSS loading, initial theme detection |
src/theme/ThemeSwitcher.tsx |
UI toggle component |
src/metronic/sass/_tokens.scss |
Semantic design tokens |
src/metronic/sass/_colors.scss |
Theme-aware color definitions |
src/metronic/sass/core/base/functions/_mode.scss |
isDarkMode() SCSS function |
Theme Initialization Flow
Application.tsxwraps the app withThemeProviderThemeProvidercallsgetInitialTheme()which checks:- localStorage for saved preference
- OS
prefers-color-schemesetting - Falls back to 'light'
loadTheme()dynamically imports the appropriate stylesheet- User toggles update localStorage and reload the CSS
Usage Patterns
Pattern 1: Bootstrap Utility Classes (Recommended)
For simple styling, use Bootstrap utility classes that automatically adapt to the theme:
1 2 3 4 5 6 7 8 | |
Common theme-aware classes:
| Class | Light Mode | Dark Mode |
|---|---|---|
bg-primary |
White | Dark gray |
bg-secondary |
Light gray (#f9fafb) | Dark gray (#161b26) |
text-primary |
Dark text | Light text |
text-secondary |
Gray text | Lighter gray text |
text-muted |
Muted gray | Muted light gray |
border-primary |
Light border | Dark border |
Pattern 2: useTheme() Hook
For third-party libraries that need explicit theme values:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Pattern 3: SCSS Design Tokens
When writing custom SCSS, use the semantic design tokens:
1 2 3 4 5 | |
Available tokens (from _tokens.scss):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Pattern 4: CSS Custom Properties
For runtime theming needs, use CSS custom properties:
1 2 3 4 5 6 7 8 9 10 | |
Common Pitfalls
Bootstrap Alert Components
Bootstrap Alert components (<Alert variant="info">) may not properly adapt text colors in dark mode. Instead, use custom styled divs:
1 2 3 4 5 6 7 8 9 10 11 | |
Hardcoded Colors
Avoid hardcoding colors that won't adapt:
1 2 3 4 5 | |
Third-Party Components
Components like react-select, Monaco Editor, and ECharts need explicit theme configuration via the useTheme() hook. Check existing implementations for examples:
src/form/themed-select.tsx- react-select themingsrc/form/MonacoField.tsx- Monaco Editor themingsrc/core/EChart.tsx- ECharts theming
Testing Dark Mode
- Toggle theme using the switcher in the user dropdown menu
- Check that:
- Text is readable against backgrounds
- Borders are visible but not harsh
- Interactive elements have visible hover states
- Third-party components match the overall theme