feat(theme): add CSS variable tokens and theme classes

- Define semantic color tokens (--color-bg, --color-text, etc.)
- Add .theme-dark, .theme-light, .theme-system CSS classes
- Create theme.ts utility for theme application
- Add early boot theme script to prevent FOUC
- Support system preference with live updates
This commit is contained in:
Gigi
2025-10-14 09:11:38 +02:00
parent 67a4e17055
commit 994d834a0b
11 changed files with 270 additions and 78 deletions

View File

@@ -4,6 +4,7 @@ import { RelayPool } from 'applesauce-relay'
import { UserSettings } from '../services/settingsService'
import IconButton from './IconButton'
import { loadFont } from '../utils/fontLoader'
import ThemeSettings from './Settings/ThemeSettings'
import ReadingDisplaySettings from './Settings/ReadingDisplaySettings'
import LayoutNavigationSettings from './Settings/LayoutNavigationSettings'
import StartupPreferencesSettings from './Settings/StartupPreferencesSettings'
@@ -159,6 +160,7 @@ const Settings: React.FC<SettingsProps> = ({ settings, onSave, onClose, relayPoo
</div>
<div className="settings-content">
<ThemeSettings settings={localSettings} onUpdate={handleUpdate} />
<ReadingDisplaySettings settings={localSettings} onUpdate={handleUpdate} />
<LayoutNavigationSettings settings={localSettings} onUpdate={handleUpdate} />
<StartupPreferencesSettings settings={localSettings} onUpdate={handleUpdate} />

View File

@@ -0,0 +1,49 @@
import React from 'react'
import { faSun, faMoon, faDesktop } from '@fortawesome/free-solid-svg-icons'
import { UserSettings } from '../../services/settingsService'
import IconButton from '../IconButton'
interface ThemeSettingsProps {
settings: UserSettings
onUpdate: (updates: Partial<UserSettings>) => void
}
const ThemeSettings: React.FC<ThemeSettingsProps> = ({ settings, onUpdate }) => {
const currentTheme = settings.theme ?? 'system'
return (
<div className="settings-section">
<h3 className="section-title">Theme</h3>
<div className="setting-group setting-inline">
<label>Appearance</label>
<div className="setting-buttons">
<IconButton
icon={faSun}
onClick={() => onUpdate({ theme: 'light' })}
title="Light theme"
ariaLabel="Light theme"
variant={currentTheme === 'light' ? 'primary' : 'ghost'}
/>
<IconButton
icon={faMoon}
onClick={() => onUpdate({ theme: 'dark' })}
title="Dark theme"
ariaLabel="Dark theme"
variant={currentTheme === 'dark' ? 'primary' : 'ghost'}
/>
<IconButton
icon={faDesktop}
onClick={() => onUpdate({ theme: 'system' })}
title="Use system preference"
ariaLabel="Use system preference"
variant={currentTheme === 'system' ? 'primary' : 'ghost'}
/>
</div>
</div>
</div>
)
}
export default ThemeSettings