// Per-device UI preferences (theme, motion, language, onboarding seen). Only conveniences live in localStorage; // nothing about projects or accounts. export type Theme = 'system' | 'light' | 'dark'; export type Motion = 'system' | 'reduce'; export type Lang = 'system' | 'en' | 'tr'; /** Tables: comfortable rows, or compact (smaller padding) for wide data on small windows. */ export type Density = 'comfortable' | 'compact'; export interface Prefs { theme: Theme; motion: Motion; lang: Lang; onboarded: boolean; density?: Density } export const DEFAULT_PREFS: Prefs = { theme: 'system', motion: 'system', lang: 'system', onboarded: false }; const KEY = 'storebound.prefs.v1'; export function parsePrefs(raw: string | null): Prefs { try { const v = JSON.parse(raw ?? '{}') as Partial; return { theme: v.theme === 'light' || v.theme === 'dark' ? v.theme : 'system', motion: v.motion === 'reduce' ? 'reduce' : 'system', lang: v.lang === 'en' || v.lang === 'tr' ? v.lang : 'system', onboarded: v.onboarded === true, ...(v.density === 'compact' ? { density: 'compact' as const } : {}), }; } catch { return { ...DEFAULT_PREFS }; } } export function loadPrefs(): Prefs { try { return parsePrefs(localStorage.getItem(KEY)); } catch { return { ...DEFAULT_PREFS }; } } export function savePrefs(p: Prefs): void { try { localStorage.setItem(KEY, JSON.stringify(p)); } catch { /* private mode: keep it for this run only */ } } /** Puts the preferences on : data-theme (light / dark, absent = follow the system), data-motion and lang. */ export function applyPrefs(p: Prefs, root: { dataset: DOMStringMap; lang?: string } = document.documentElement, systemLang = 'en'): void { if (p.theme === 'system') delete root.dataset.theme; else root.dataset.theme = p.theme; if (p.motion === 'reduce') root.dataset.motion = 'reduce'; else delete root.dataset.motion; if (p.density === 'compact') root.dataset.density = 'compact'; else delete root.dataset.density; root.lang = resolveLang(p.lang, systemLang); } /** The language to show: the preference, else the system's when we have it (tr), else English. */ export function resolveLang(l: Lang, systemLang: string): 'en' | 'tr' { if (l !== 'system') return l; return /^tr\b/i.test(systemLang) ? 'tr' : 'en'; }