Stage 7 polish (round 2): layout/zoom/tab-bar/hint/check fixes
Tests · UI / test (push) Successful in 12s
Tests · Go / test (pull_request) Successful in 6s
Tests · Integration / integration (pull_request) Successful in 11s
Tests · UI / test (pull_request) Successful in 11s

- nav bar grows ONLY in game (other screens: minimal nav, content fills); tab bar always bottom
- tab bar: tighter icon/label spacing, bigger icons, hint badge on the icon corner
- board zoom reworked to width-based (real native scroll, fixes Safari/Chrome) + constant cqw labels; pinch & swipe-to-history dropped (conflict), double-tap kept, history via menu
- beginner bonus labels shrunk to fit cells
- Draw opens exchange directly (no confirm); confirm popovers restyled like the hamburger dropdown (vertical); removed the floating direction toggle
- pending tiles darker bg (no outline); last-word dark-tile highlight (static / 1s flash)
- check button disabled for <2/>15 chars, already-checked, or 5s cooldown
- global user-select:none (inputs exempt); docs updated; TODO-4 alphabet-on-wire
This commit is contained in:
Ilia Denisov
2026-06-03 14:54:41 +02:00
parent 92a4de3bf4
commit 52a0e3160d
8 changed files with 161 additions and 182 deletions
+9 -5
View File
@@ -2,10 +2,11 @@
import type { Snippet } from 'svelte';
import { navigate } from '../lib/router.svelte';
let { title, back, menu }: { title: string; back?: string; menu?: Snippet } = $props();
let { title, back, menu, grow = false }: { title: string; back?: string; menu?: Snippet; grow?: boolean } =
$props();
</script>
<header class="nav">
<header class="nav" class:grow>
<div class="bar">
{#if back}
<button class="icon back" onclick={() => back && navigate(back)} aria-label="Back">
@@ -20,10 +21,10 @@
</header>
<style>
/* The nav bar grows to fill the spare vertical space (buttons stay at the top), so
the rest of the screen pins to the bottom — a mobile-app layout. */
/* By default the nav bar is minimal and the content fills the screen. In the game
it grows (class `grow`) to push the board and controls to the bottom. */
.nav {
flex: 1 1 auto;
flex: 0 0 auto;
min-height: 52px;
background: var(--bg-elev);
border-bottom: 1px solid var(--border);
@@ -32,6 +33,9 @@
user-select: none;
-webkit-user-select: none;
}
.nav.grow {
flex: 1 1 auto;
}
.bar {
display: flex;
align-items: center;
+8 -1
View File
@@ -96,7 +96,14 @@
transform: translateX(-50%);
z-index: 19;
display: flex;
gap: 4px;
flex-direction: column;
gap: 2px;
white-space: nowrap;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
box-shadow: var(--shadow);
padding: 4px;
min-width: 132px;
}
</style>
+7 -2
View File
@@ -13,6 +13,7 @@
tabbar,
children,
scroll = true,
growNav = false,
}: {
title: string;
back?: string;
@@ -20,13 +21,14 @@
tabbar?: Snippet;
children?: Snippet;
scroll?: boolean;
growNav?: boolean;
} = $props();
</script>
<div class="screen">
<Header {title} {back} {menu} />
<Header {title} {back} {menu} grow={growNav} />
<AdBanner />
<main class="content" class:scroll>{@render children?.()}</main>
<main class="content" class:scroll class:fill={!growNav}>{@render children?.()}</main>
{#if tabbar}
<nav class="tabbar">{@render tabbar()}</nav>
{/if}
@@ -42,6 +44,9 @@
flex: 0 1 auto;
min-height: 0;
}
.content.fill {
flex: 1 1 auto;
}
.content.scroll {
overflow-y: auto;
}