Theming
RedactedWorld ships with three built-in visual themes. Users can switch themes at any time, and their preference is persisted both locally and server-side.
Available Themes
| Theme | Background | Accent | Font | Description |
|---|---|---|---|---|
| Dark Hacker | #0a0a0a | #00ff41 | JetBrains Mono | Terminal-inspired dark theme with green-on-black aesthetics. Designed for users who prefer a classic hacker terminal look. This is the default theme. |
| Clean Professional | #fafafa | #2563eb | Inter | Light theme with blue accents. Optimized for readability in bright environments and professional presentations. |
| Hybrid | #121212 | #a855f7 | Inter | Dark theme with purple accents. A modern dark mode that blends the readability of the professional theme with a dark background. |
Theme Preview
Dark Hacker
Background: #0a0a0a (near black)
Surface: #1a1a1a (dark gray)
Border: #2a2a2a (subtle gray)
Text: #e0e0e0 (light gray)
Accent: #00ff41 (terminal green)
Error: #ff4444 (red)
Warning: #ffaa00 (amber)
Font: JetBrains Mono, monospace
Clean Professional
Background: #fafafa (off-white)
Surface: #ffffff (white)
Border: #e2e8f0 (light slate)
Text: #1e293b (dark slate)
Accent: #2563eb (blue-600)
Error: #dc2626 (red-600)
Warning: #d97706 (amber-600)
Font: Inter, system-ui, sans-serif
Hybrid
Background: #121212 (dark)
Surface: #1e1e1e (dark gray)
Border: #333333 (medium gray)
Text: #e0e0e0 (light gray)
Accent: #a855f7 (purple-500)
Error: #ef4444 (red-500)
Warning: #f59e0b (amber-500)
Font: Inter, system-ui, sans-serif
Implementation
CSS Custom Properties
Themes are implemented using CSS custom properties (variables) defined at the :root level. Each theme overrides these variables through a class applied to the <body> element.
/* Base variables (Dark Hacker - default) */
:root {
--rw-bg: #0a0a0a;
--rw-surface: #1a1a1a;
--rw-border: #2a2a2a;
--rw-text: #e0e0e0;
--rw-text-muted: #888888;
--rw-accent: #00ff41;
--rw-accent-hover: #00cc33;
--rw-error: #ff4444;
--rw-warning: #ffaa00;
--rw-font-body: 'JetBrains Mono', monospace;
--rw-font-heading: 'JetBrains Mono', monospace;
--rw-radius: 4px;
}
/* Clean Professional theme */
body.theme-professional {
--rw-bg: #fafafa;
--rw-surface: #ffffff;
--rw-border: #e2e8f0;
--rw-text: #1e293b;
--rw-text-muted: #64748b;
--rw-accent: #2563eb;
--rw-accent-hover: #1d4ed8;
--rw-error: #dc2626;
--rw-warning: #d97706;
--rw-font-body: 'Inter', system-ui, sans-serif;
--rw-font-heading: 'Inter', system-ui, sans-serif;
--rw-radius: 8px;
}
/* Hybrid theme */
body.theme-hybrid {
--rw-bg: #121212;
--rw-surface: #1e1e1e;
--rw-border: #333333;
--rw-text: #e0e0e0;
--rw-text-muted: #999999;
--rw-accent: #a855f7;
--rw-accent-hover: #9333ea;
--rw-error: #ef4444;
--rw-warning: #f59e0b;
--rw-font-body: 'Inter', system-ui, sans-serif;
--rw-font-heading: 'Inter', system-ui, sans-serif;
--rw-radius: 8px;
}
Theme Switching
The Angular frontend applies theme classes to the <body> element:
// theme.service.ts
@Injectable({ providedIn: 'root' })
export class ThemeService {
private readonly STORAGE_KEY = 'rw-theme';
private readonly DEFAULT_THEME = 'dark-hacker';
setTheme(theme: 'dark-hacker' | 'professional' | 'hybrid'): void {
// Remove existing theme classes
document.body.classList.remove(
'theme-dark-hacker',
'theme-professional',
'theme-hybrid'
);
// Apply new theme class (dark-hacker is the default, no class needed)
if (theme !== 'dark-hacker') {
document.body.classList.add(`theme-${theme}`);
}
// Persist locally
localStorage.setItem(this.STORAGE_KEY, theme);
// Persist to server
this.userService.updatePreferences({ theme }).subscribe();
}
}
Persistence Strategy
Theme preference is stored in two locations for optimal UX:
-
localStorage -- Provides instant theme application on page load, before any API call completes. This prevents the "flash of wrong theme" problem.
-
PostgreSQL (via user-service) -- Ensures the preference follows the user across devices. When a user logs in on a new device, the API response includes their theme preference, which is then written to localStorage.
On page load, the resolution order is:
- Check
localStoragefor a saved theme. - If not found, use the API response from the user profile.
- If neither exists, fall back to
dark-hacker.