/** * Telegram and system theme detection and application. */ /** * Resolve current color scheme (dark/light). * @returns {"dark"|"light"} */ export function getTheme() { if (typeof window === "undefined") return "dark"; const twa = window.Telegram?.WebApp; if (twa?.colorScheme) return twa.colorScheme; let cssScheme = ""; try { cssScheme = getComputedStyle(document.documentElement) .getPropertyValue("--tg-color-scheme") .trim(); } catch (e) { /* ignore */ } if (cssScheme === "light" || cssScheme === "dark") return cssScheme; if (window.matchMedia("(prefers-color-scheme: dark)").matches) return "dark"; return "light"; } /** * Map Telegram themeParams (snake_case) to CSS variables (--tg-theme-*). * Only set when Telegram WebApp and themeParams are available. */ export function applyThemeParamsToCss() { const twa = window.Telegram?.WebApp; const params = twa?.themeParams; if (!params) return; const root = document.documentElement; const map = [ ["bg_color", "bg-color"], ["secondary_bg_color", "secondary-bg-color"], ["text_color", "text-color"], ["hint_color", "hint-color"], ["link_color", "link-color"], ["button_color", "button-color"], ["header_bg_color", "header-bg-color"], ["accent_text_color", "accent-text-color"] ]; map.forEach(([key, cssKey]) => { const value = params[key]; if (value) root.style.setProperty("--tg-theme-" + cssKey, value); }); } /** * Apply current theme: set data-theme and Telegram background/header when in TWA. */ export function applyTheme() { const scheme = getTheme(); document.documentElement.dataset.theme = scheme; const twa = window.Telegram?.WebApp; if (twa) { if (twa.setBackgroundColor) twa.setBackgroundColor("bg_color"); if (twa.setHeaderColor) twa.setHeaderColor("bg_color"); applyThemeParamsToCss(); } } /** * Run initial theme apply and subscribe to theme changes (TWA or prefers-color-scheme). * Call once at load. */ export function initTheme() { applyTheme(); if (typeof window !== "undefined" && window.Telegram?.WebApp) { setTimeout(applyTheme, 0); setTimeout(applyTheme, 100); } else if (window.matchMedia) { window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", applyTheme); } }