Stage 7 polish: UI/UX refinements (shell, board zoom, hint-on-board, history, ...) #8

Merged
developer merged 11 commits from feature/stage-7-ui-polish into master 2026-06-03 15:39:41 +00:00
3 changed files with 33 additions and 5 deletions
Showing only changes of commit 10d48884ac - Show all commits
+26
View File
@@ -0,0 +1,26 @@
import { expect, test } from '@playwright/test';
// Item 5: zooming the board must enlarge the labels too (a magnifying-glass zoom).
// cqw is sized against the zoom-scaled board, so the font grows with the cells.
test('zoom enlarges the board labels with the board', async ({ page }) => {
await page.goto('/');
await page.getByRole('button', { name: /guest/i }).click();
await page.getByRole('button', { name: /Ann/ }).click();
const letter = page.locator('[data-cell] .letter').first();
await expect(letter).toBeVisible();
const base = await letter.evaluate((el) => parseFloat(getComputedStyle(el).fontSize));
// Double-tap an empty cell to zoom in (two synchronous clicks = a double-tap).
await page
.locator('[data-cell]:not(.filled)')
.nth(20)
.evaluate((el: HTMLElement) => {
el.click();
el.click();
});
await page.waitForTimeout(400); // let the width transition settle
const zoomed = await letter.evaluate((el) => parseFloat(getComputedStyle(el).fontSize));
expect(zoomed).toBeGreaterThan(base * 1.4);
});
+1 -2
View File
@@ -92,8 +92,7 @@
.popover { .popover {
position: absolute; position: absolute;
bottom: calc(100% + 6px); bottom: calc(100% + 6px);
left: 50%; right: 0;
transform: translateX(-50%);
z-index: 19; z-index: 19;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
+6 -3
View File
@@ -84,7 +84,7 @@
class="cell {premClass[premium[r][c]]}" class="cell {premClass[premium[r][c]]}"
class:filled={!!cell} class:filled={!!cell}
class:pending={!!p && !cell} class:pending={!!p && !cell}
class:hl={!!cell && highlight.has(key(r, c))} class:hl={!!cell && highlight.has(key(r, c)) && !flash}
class:flash={!!cell && flash && highlight.has(key(r, c))} class:flash={!!cell && flash && highlight.has(key(r, c))}
data-cell data-cell
data-row={r} data-row={r}
@@ -115,14 +115,16 @@
overflow: hidden; overflow: hidden;
background: var(--board-bg); background: var(--board-bg);
border-radius: var(--radius-sm); border-radius: var(--radius-sm);
container-type: inline-size;
} }
.viewport.zoomed { .viewport.zoomed {
overflow: auto; overflow: auto;
} }
/* The query container is the (zoom-scaled) board, so cqw labels scale WITH the board
— a magnifying-glass zoom. */
.scaler { .scaler {
width: calc(100% * var(--z)); width: calc(100% * var(--z));
transition: width 0.25s ease; transition: width 0.25s ease;
container-type: inline-size;
} }
.grid { .grid {
display: grid; display: grid;
@@ -167,7 +169,8 @@
background: var(--tile-recent); background: var(--tile-recent);
} }
.cell.flash { .cell.flash {
animation: tileflash 1s ease-in-out infinite; /* Two flashes to draw the eye, then settle back to normal so it does not distract. */
animation: tileflash 1s ease-in-out 2;
} }
@keyframes tileflash { @keyframes tileflash {
0%, 0%,