Appearance tab was local-state-only — light mode did nothing. Wire it up: - index.css: theme color tokens are now CSS variables on :root (dark default) with a [data-theme="light"] override using a soft GRAY page background (#E4E6EB), not white. The @theme tokens + html/body + select reference the vars, so the app shell and any component using bg-page/text-text-primary/etc. themes automatically. - New src/lib/theme.ts: localStorage-backed appearance prefs (theme/fontSize/ radius/animations) + applyAppearance() toggling data-theme on <html>, mirroring the terminalPrefs pattern. - main.tsx applies saved theme before first render (no flash). - Settings AppearanceSection persists + applies on change; theme/fontSize/radius/ animations are live. Dropped the non-functional "Sidebar Expanded by default" toggle. (accent color is still cosmetic-only — full token migration of hardcoded-hex pages is a separate task, noted in ROADMAP.) Also adds the Remote Desktop GNOME & KDE support work to ROADMAP as an add-on (XFCE confirmed working; GNOME needs a FreeRDP-3 guacd image, KDE via xrdp + startplasma-x11). Full detail in docs/rdp-debug-handoff.md. Co-authored-by: Samuel James <ssamjame@amazon.com> Co-authored-by: Kiro <noreply@kiro.dev>
48 lines
1.9 KiB
TypeScript
48 lines
1.9 KiB
TypeScript
// App appearance prefs (theme + a few visual knobs), persisted to localStorage
|
|
// and applied by toggling attributes / CSS variables on <html>. Kept out of a
|
|
// component module so it can be imported anywhere (and called once at boot in
|
|
// main.tsx before React renders, to avoid a dark→light flash).
|
|
|
|
export type ThemeMode = 'dark' | 'light'
|
|
|
|
export interface AppearancePrefs {
|
|
theme: ThemeMode
|
|
fontSize: number // base font-size in px
|
|
radius: number // card border-radius in px
|
|
animations: boolean
|
|
}
|
|
|
|
const PREFS_KEY = 'archnest-appearance-prefs'
|
|
|
|
export function defaultAppearance(): AppearancePrefs {
|
|
return { theme: 'dark', fontSize: 14, radius: 12, animations: true }
|
|
}
|
|
|
|
export function loadAppearance(): AppearancePrefs {
|
|
try {
|
|
const raw = localStorage.getItem(PREFS_KEY)
|
|
if (raw) return { ...defaultAppearance(), ...JSON.parse(raw) }
|
|
} catch {
|
|
/* ignore malformed local storage */
|
|
}
|
|
return defaultAppearance()
|
|
}
|
|
|
|
export function saveAppearance(prefs: AppearancePrefs) {
|
|
localStorage.setItem(PREFS_KEY, JSON.stringify(prefs))
|
|
}
|
|
|
|
// Apply prefs to the document. Light mode flips data-theme="light" (which the
|
|
// CSS variable overrides in index.css key off of); dark removes the attribute.
|
|
// ponytail: only theme is wired to real CSS right now; fontSize/radius/animations
|
|
// are persisted and exposed as CSS vars for components to opt into later — the
|
|
// app still mostly hardcodes hex, so a full token migration is a separate task
|
|
// (tracked in ROADMAP "Appearance section").
|
|
export function applyAppearance(prefs: AppearancePrefs) {
|
|
const root = document.documentElement
|
|
if (prefs.theme === 'light') root.setAttribute('data-theme', 'light')
|
|
else root.removeAttribute('data-theme')
|
|
root.style.setProperty('--app-font-size', `${prefs.fontSize}px`)
|
|
root.style.setProperty('--card-radius', `${prefs.radius}px`)
|
|
root.style.setProperty('--app-animations', prefs.animations ? '1' : '0')
|
|
}
|