Files
scrabble-game/ui/src/lib/theme.ts
T
Ilia Denisov 1d0bafaabb Stage 17: UI defect fixes (russian variant, Telegram theme/nav/banner, reconnect, hint zoom, plaque, history, transitions, per-game cache)
- #6 align the UI variant id to the backend canonical 'russian_scrabble' (type, variants, Lobby, mock, tests) — fixes the New->Russian 400
- #11/#12 inside Telegram force the colour scheme from WebApp.colorScheme (over OS prefers-color-scheme, fixing the Telegram Desktop breakage) and hide the theme switcher
- #14/#15 nav bar takes Telegram's bg; announcement banner gets a dedicated subtle --ad-bg accent token
- #16 suppress the reconnect banner while backgrounded and silently reconnect the live stream on return to the foreground
- #17 hint zoom scrolls to the placement's bounding box, not the top-left
- #19/#20 players plaque: active seat raised with side shadows, others sunk; tap toggles history
- #21/#23 history: scrollbar-gutter:stable (no word jitter); fixed-height drawer pins the bottom shadow to the board
- #3 (UI) disable nudge on the player's own turn
- #18a directional screen slide transitions (forward in from the right, back reveals the lobby)
- #13 per-game in-memory cache: instant render on re-entry + background refresh
- e2e: openGame waits for the slide transition to settle
2026-06-06 10:23:42 +02:00

53 lines
2.0 KiB
TypeScript

// 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');
}