fix: theme consistency across login, setup, and dashboard

- Fixed localStorage key mismatch ('dark-mode' vs 'darkMode')
- Added theme selector to setup screen (System/Light/Dark)
- Login and setup screens now respect saved theme preference
- Theme persists correctly across logout/login cycles

addresses #332
This commit is contained in:
Pulse Monitor
2025-08-19 10:43:04 +00:00
parent 86824cd059
commit 2be275f644
2 changed files with 104 additions and 4 deletions
@@ -1,6 +1,7 @@
import { Component, createSignal, Show, onMount } from 'solid-js';
import { showSuccess, showError } from '@/utils/toast';
import { copyToClipboard } from '@/utils/clipboard';
import { STORAGE_KEYS } from '@/constants';
export const FirstRunSetup: Component = () => {
const [username, setUsername] = createSignal('admin');
@@ -15,10 +16,44 @@ export const FirstRunSetup: Component = () => {
const [savedPassword, setSavedPassword] = createSignal('');
const [savedToken, setSavedToken] = createSignal('');
const [copied, setCopied] = createSignal<'password' | 'token' | null>(null);
const [themeMode, setThemeMode] = createSignal<'system' | 'light' | 'dark'>('system');
const applyTheme = (mode: 'system' | 'light' | 'dark') => {
if (mode === 'light') {
document.documentElement.classList.remove('dark');
localStorage.setItem(STORAGE_KEYS.DARK_MODE, 'false');
} else if (mode === 'dark') {
document.documentElement.classList.add('dark');
localStorage.setItem(STORAGE_KEYS.DARK_MODE, 'true');
} else {
// System preference
localStorage.removeItem(STORAGE_KEYS.DARK_MODE);
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}
};
onMount(() => {
// Force dark mode for setup screen
document.documentElement.classList.add('dark');
// Check for saved theme preference
const savedTheme = localStorage.getItem(STORAGE_KEYS.DARK_MODE);
if (savedTheme === 'false') {
setThemeMode('light');
document.documentElement.classList.remove('dark');
} else if (savedTheme === 'true') {
setThemeMode('dark');
document.documentElement.classList.add('dark');
} else {
// No saved preference - use system preference
setThemeMode('system');
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}
});
const generatePassword = () => {
@@ -253,6 +288,58 @@ IMPORTANT: Keep these credentials secure!
</Show>
</div>
{/* Theme Selection */}
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Theme Preference
</label>
<div class="grid grid-cols-3 gap-2">
<button
onClick={() => {
setThemeMode('system');
applyTheme('system');
}}
class={`py-2 px-4 rounded-lg text-sm font-medium transition-colors ${
themeMode() === 'system'
? 'bg-blue-600 text-white'
: 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600'
}`}
>
System
</button>
<button
onClick={() => {
setThemeMode('light');
applyTheme('light');
}}
class={`py-2 px-4 rounded-lg text-sm font-medium transition-colors ${
themeMode() === 'light'
? 'bg-blue-600 text-white'
: 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600'
}`}
>
Light
</button>
<button
onClick={() => {
setThemeMode('dark');
applyTheme('dark');
}}
class={`py-2 px-4 rounded-lg text-sm font-medium transition-colors ${
themeMode() === 'dark'
? 'bg-blue-600 text-white'
: 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600'
}`}
>
Dark
</button>
</div>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-2">
{themeMode() === 'system'
? 'Using your operating system theme preference'
: `Using ${themeMode()} mode`}
</p>
</div>
{/* Info Box */}
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 space-y-2">
+15 -2
View File
@@ -1,5 +1,6 @@
import { Component, createSignal, Show, onMount, lazy, Suspense } from 'solid-js';
import { setBasicAuth } from '@/utils/apiClient';
import { STORAGE_KEYS } from '@/constants';
// Force include FirstRunSetup with lazy loading
const FirstRunSetup = lazy(() => import('./FirstRunSetup').then(m => ({ default: m.FirstRunSetup })));
@@ -17,8 +18,20 @@ export const Login: Component<LoginProps> = (props) => {
const [loadingAuth, setLoadingAuth] = createSignal(true);
onMount(async () => {
// Force dark mode for login screen
document.documentElement.classList.add('dark');
// Apply saved theme preference from localStorage
const savedTheme = localStorage.getItem(STORAGE_KEYS.DARK_MODE);
if (savedTheme === 'false') {
document.documentElement.classList.remove('dark');
} else if (savedTheme === 'true') {
document.documentElement.classList.add('dark');
} else {
// No saved preference - use system preference
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}
console.log('[Login] Starting auth check...');
try {