// Theme application. The design tokens are CSS custom properties (app.css); here we // only flip how they resolve: 'auto' follows the OS, 'light'/'dark' force a value via // [data-theme]. A Telegram Mini App can additionally override the token values from // WebApp.themeParams — the mapping lives here so the token system is Telegram-ready, // while the SDK is wired in the Telegram stage. export type ThemePref = 'auto' | 'light' | 'dark'; export function applyTheme(pref: ThemePref): void { if (typeof document === 'undefined') return; const root = document.documentElement; if (pref === 'auto') root.removeAttribute('data-theme'); else root.setAttribute('data-theme', pref); } export function applyReduceMotion(on: boolean): void { if (typeof document === 'undefined') return; document.body.classList.toggle('reduce-motion', on); } /** Subset of Telegram WebApp.themeParams we map onto our tokens. */ export interface TelegramThemeParams { bg_color?: string; text_color?: string; hint_color?: string; link_color?: string; button_color?: string; button_text_color?: string; secondary_bg_color?: string; header_bg_color?: string; } /** applyTelegramTheme overrides token values at runtime from Telegram themeParams. */ export function applyTelegramTheme(p: TelegramThemeParams): void { if (typeof document === 'undefined') return; const root = document.documentElement; const set = (value: string | undefined, name: string) => { if (value) root.style.setProperty(name, value); }; set(p.bg_color, '--bg'); set(p.bg_color, '--surface'); set(p.secondary_bg_color, '--surface-2'); set(p.text_color, '--text'); set(p.hint_color, '--text-muted'); set(p.button_color, '--accent'); set(p.button_text_color, '--accent-text'); set(p.link_color, '--accent'); // The nav bar tracks Telegram's chrome so it doesn't fall out of the design; the // announcement banner takes the secondary surface so it reads as a subtle accent. set(p.header_bg_color ?? p.bg_color, '--bg-elev'); set(p.secondary_bg_color, '--ad-bg'); }