Stage 7 polish: app shell + nav + lobby + settings (Parts A/B/C)

- Screen.svelte shell: nav bar grows, ad+content+tabbar pinned bottom (mobile feel)
- AdBanner.svelte + banner.ts rotator (params, mock long/short, linkify); Header CSS chevron + grow; Menu (bigger CSS hamburger); TabBar + HoldConfirm shared components; user-select:none
- Lobby: hide-empty sections, tab order New/Tournaments/Stats, place-based result badges (result.ts)
- Settings: Board style > Labels (beginner/classic/none) + prefs plumbing (boardlabels.ts); i18n keys + ru mirror
This commit is contained in:
Ilia Denisov
2026-06-03 13:20:56 +02:00
parent 03347c5a91
commit 38be7fea96
18 changed files with 871 additions and 244 deletions
+36
View File
@@ -0,0 +1,36 @@
// Bonus-square label modes (a client setting, separate from the theme). The board
// renders these locally — premiums are not on the wire. Default is "beginner".
import type { Premium } from './premiums';
import type { Locale } from './i18n/catalog';
export type BoardLabelMode = 'beginner' | 'classic' | 'none';
export type BonusLabel =
| { kind: 'single'; text: string }
| { kind: 'split'; top: string; bottom: string }
| null;
function multiplier(p: Premium): number {
return p === 'TW' || p === 'TL' ? 3 : 2;
}
function isWord(p: Premium): boolean {
return p === 'TW' || p === 'DW';
}
/**
* bonusLabel returns how a premium square is labelled: `classic` "3W"/"3С", `beginner`
* a split "3×" / "word" (localized), or nothing.
*/
export function bonusLabel(mode: BoardLabelMode, p: Premium, locale: Locale): BonusLabel {
if (mode === 'none' || p === '') return null;
const n = multiplier(p);
const word = isWord(p);
if (mode === 'classic') {
const tag = locale === 'ru' ? (word ? 'С' : 'Б') : word ? 'W' : 'L';
return { kind: 'single', text: `${n}${tag}` };
}
const bottom = locale === 'ru' ? (word ? 'слово' : 'буква') : word ? 'word' : 'letter';
return { kind: 'split', top: `${n}×`, bottom };
}