fix(mobile): close dock-internal gap by top-aligning the d-pad

Round 1 anchored the board to .board-wrap's bottom but exposed a 32px
gap caused by .mobile-dock { align-items: flex-end } combined with
.dock-left (148px tall) being taller than .dpad (116px). With both
columns bottom-aligned, the d-pad's top sat ~32px below the action
stack's top, so the arrows still felt far from the board.

Switch the dock to align-items: stretch so each column picks its own
cross-axis position: action stack stays bottom-anchored (closer to the
thumb), d-pad uses align-self: flex-start to hug the dock top (closer
to the board). Movement is the primary interaction; UNDO/RESET are
secondary. Shrink arrows 56 -> 48px (still well above 44pt HIG) and
bump grid gap 4 -> 6px.

Trim the JS computeTileSize coarse-pointer chrome margin 220 -> 195 to
reflect the slimmer dock so the board can grow into the freed space on
tall puzzles. Add an explicit margin-top: auto on .board inside a
coarse media query in Board.svelte as a belt-and-suspenders cross-axis
push that survives future parent-flex refactors.

Combined with the round-1 changes, the board-bottom to arrow-top
distance drops from ~42px to ~10px on touch viewports. Desktop is
untouched (all changes gated by @media (pointer: coarse)).
This commit is contained in:
tiennm99 committed 2026-04-28 23:11:43 +07:00
1 parent 1530afabfd
commit 18d63d07c7
3 files changed
+20 -5

No files matched your search

+8
View File
@@ -107,6 +107,14 @@
-webkit-user-select: none;
}
/* On touch devices the parent .board-wrap is a flex container with
align-items: flex-end. Adding margin-top: auto is a belt-and-suspenders
cross-axis push so the board hugs the dock even if a future refactor
drops the parent's align-items. No effect on desktop (parent is not flex). */
@media (pointer: coarse) {
.board { margin-top: auto; }
}
.floor,
.target,
.wall,
+3 -1
View File
@@ -43,7 +43,9 @@
const minTile = 16;
// Dock is now in-flow (flex row at bottom); margin only covers header + hud + padding.
const isCoarse = typeof window !== 'undefined' && window.matchMedia('(pointer: coarse)').matches;
const margin = isCoarse ? 220 : 120; // header + hud (+ in-flow mobile dock) + padding
// 195 reflects the slimmer mobile chrome after R6+R7 (top-aligned d-pad
// at 48px arrows). If the dock layout changes, retune this.
const margin = isCoarse ? 195 : 120; // header + hud (+ in-flow mobile dock) + padding
const maxByWidth = Math.floor((window.innerWidth - 80) / level.width);
const maxByHeight = Math.floor((window.innerHeight - margin - 100) / level.height);
return Math.max(minTile, Math.min(maxTile, maxByWidth, maxByHeight));
+9 -4
View File
@@ -108,10 +108,13 @@
}
@media (pointer: coarse) {
/* stretch lets each column choose its own cross-axis position so the
D-pad can hug the dock top (closer to board) while the action stack
stays bottom-anchored (closer to thumb). */
.mobile-dock {
display: flex;
justify-content: space-between;
align-items: flex-end;
align-items: stretch;
gap: 12px;
width: 100%;
padding:
@@ -125,17 +128,19 @@
.dock-left {
display: flex;
flex-direction: column;
justify-content: flex-end;
gap: 8px;
}
.dpad {
display: grid;
grid-template-columns: 56px 56px 56px;
grid-template-rows: 56px 56px;
grid-template-columns: 48px 48px 48px;
grid-template-rows: 48px 48px;
grid-template-areas:
". up . "
"left down right";
gap: 4px;
gap: 6px;
align-self: flex-start;
}
}