feat(ui): batch of UI polish tweaks
CI / changes (pull_request) Successful in 1s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 13s
CI / ui (pull_request) Successful in 52s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m19s

- admin dashboard "Users" count excludes robots (CountUsers, humans only)
- lobby finished-game delete reveal: background matches header/tab-bar (--bg-elev)
- mobile: swipe up on the zoom-out board (no staged tiles) shuffles the rack
- lobby: status icons -25%, game-row top/bottom padding halved
- toast: info tier drifts up ~a tab-bar height while fading over 2s and dismisses
  on tap; error tier unchanged
- game: confirm-move button stays pinned at the right edge; rack tiles shrink to
  fit so a full rack never overflows onto it
- telegram: a successful invite-link redeem shows a welcome window pointing at the bot
- settings: remove the grid-lines toggle; the board is always a gapless checkerboard
- settings/comms hubs: the selected tab highlight wraps icon + label as a pill

Docs: UI_DESIGN (toast, board surface, selected tab), PLAN; e2e updated for the
removed grid-lines toggle.
This commit is contained in:
Ilia Denisov
2026-06-19 08:56:29 +02:00
parent 1c87313a78
commit ab1ad998aa
20 changed files with 227 additions and 101 deletions
+18 -33
View File
@@ -18,7 +18,6 @@
landscape,
variant,
labelMode,
lines,
locale,
focus,
recenter,
@@ -41,8 +40,6 @@
landscape: boolean;
variant: Variant;
labelMode: BoardLabelMode;
/** Draw 1px grid lines between cells; when false the board is a gapless checkerboard. */
lines: boolean;
locale: Locale;
focus: { row: number; col: number } | null;
/** A monotonic nonce the parent bumps to request a scroll to `focus` even when the zoom state
@@ -234,7 +231,7 @@
<div class="viewport" class:zoomed class:land={landscape} bind:this={viewport}>
<div class="scaler" class:land={landscape} style="--z: {z};">
<div class="grid" class:gridless={!lines}>
<div class="grid">
{#each board as rowCells, r (r)}
{#each rowCells as cell, c (c)}
{@const p = pending.get(key(r, c))}
@@ -311,18 +308,21 @@
width 0.25s ease,
height 0.25s ease;
}
/* A gapless checkerboard with no grid lines (the board has no lined variant): plain cells
alternate shades and tiles get rounded corners plus a soft right-side shadow so adjacent
gapless tiles still read as separate pieces. */
.grid {
display: grid;
grid-template-columns: repeat(15, 1fr);
gap: 1px;
background: var(--cell-line);
padding: 1px;
gap: 0;
background: var(--board-bg);
padding: 0;
}
.cell {
position: relative;
aspect-ratio: 1;
border: none;
border-radius: 1px;
border-radius: 0;
background: var(--cell-bg);
color: var(--prem-text);
/* No mobile tap flash on a cell tap (parity with the web click; the only intentional
@@ -344,11 +344,20 @@
.cell.dl {
background: var(--prem-dl);
}
.cell.dark {
/* A gentle checkerboard tint: enough to read the alternation without competing with the
bonus cells, standing in for the grid lines that once separated the cells. Lightened
from a stronger mix that looked too contrasty in light theme. */
background: color-mix(in srgb, var(--cell-bg) 94%, #000);
}
.cell.filled,
.cell.pending {
background: var(--tile-bg);
color: var(--tile-text);
box-shadow: inset 0 -2px 0 var(--tile-edge);
border-radius: 4px;
box-shadow:
inset 0 -2px 0 var(--tile-edge),
2px 0 3px -1px rgba(0, 0, 0, 0.4);
}
.cell.pending {
background: var(--tile-pending);
@@ -356,30 +365,6 @@
board) instead of the touch starting a board pan. */
touch-action: none;
}
/* Lines-off variant: a gapless checkerboard. The 1px grid gaps (and the cell-line they
reveal) collapse, saving ~14px of board width; plain cells alternate shades, and tiles
get rounded corners and a soft right-side shadow so adjacent gapless tiles still read
as separate pieces. */
.grid.gridless {
gap: 0;
padding: 0;
background: var(--board-bg);
}
.grid.gridless .cell {
border-radius: 0;
}
.grid.gridless .cell.dark {
/* A gentle checkerboard tint: enough to read the alternation without competing with the
bonus cells. Lightened from a stronger mix that looked too contrasty in light theme. */
background: color-mix(in srgb, var(--cell-bg) 94%, #000);
}
.grid.gridless .cell.filled,
.grid.gridless .cell.pending {
border-radius: 4px;
box-shadow:
inset 0 -2px 0 var(--tile-edge),
2px 0 3px -1px rgba(0, 0, 0, 0.4);
}
.cell.droptarget {
/* The cell a carried tile is aimed at: an accent ring plus a light accent wash, so the
target reads clearly while dragging without obscuring the bonus label underneath. */