UI: drop tab-bar tap highlight; don't slide the first screen on launch #45

Merged
developer merged 3 commits from feature/ui-tap-startup-polish into development 2026-06-11 21:55:21 +00:00
2 changed files with 17 additions and 10 deletions
Showing only changes of commit 9277a70565 - Show all commits
+12 -3
View File
@@ -32,8 +32,9 @@
// Screen transitions: the lobby is the navigation root. Entering a screen from the // Screen transitions: the lobby is the navigation root. Entering a screen from the
// lobby slides it in from the right (forward); returning to the lobby slides the // lobby slides it in from the right (forward); returning to the lobby slides the
// screen out to the right and reveals the lobby (back). Transitions are local, so // screen out to the right and reveals the lobby (back). The first pane shown after boot
// they do not play on the initial mount, and collapse to nothing under reduce-motion. // does not slide (the `started` gate below), and transitions collapse to nothing under
// reduce-motion.
// Slide direction by route depth: going deeper (lobby → game → chat/check) slides forward, // Slide direction by route depth: going deeper (lobby → game → chat/check) slides forward,
// returning to a shallower screen slides back. A plain "lobby is back" rule slid the chat/check // returning to a shallower screen slides back. A plain "lobby is back" rule slid the chat/check
// back-to-the-game the wrong way. dir is read with the previous depth (the effect updates it // back-to-the-game the wrong way. dir is read with the previous depth (the effect updates it
@@ -52,7 +53,15 @@
const enterSign = $derived(dir === 'forward' ? 1 : -1); const enterSign = $derived(dir === 'forward' ? 1 : -1);
const leaveSign = $derived(dir === 'forward' ? -1 : 1); const leaveSign = $derived(dir === 'forward' ? -1 : 1);
const routeKey = $derived(router.route.name + (router.route.params.id ?? '')); const routeKey = $derived(router.route.name + (router.route.params.id ?? ''));
const animMs = $derived(app.reduceMotion ? 0 : 260); // The first pane shown once the app is ready must not slide: it would look like the app
// was navigated into rather than launched. The pane is a local transition inside a {#key}
// block, so it plays on that block's own first mount anyway — hold the duration at 0 until
// just after that mount (the effect runs post-render), then animate every later change.
let started = $state(false);
$effect(() => {
if (app.ready) started = true;
});
const animMs = $derived(!started || app.reduceMotion ? 0 : 260);
// slideX slides a pane horizontally by a full width. sign>0 enters from / exits to // slideX slides a pane horizontally by a full width. sign>0 enters from / exits to
// the right; sign<0 the left. Percentage keeps it viewport-relative without reading // the right; sign<0 the left. Percentage keeps it viewport-relative without reading
+5 -7
View File
@@ -34,12 +34,13 @@
width: 100%; width: 100%;
user-select: none; user-select: none;
-webkit-user-select: none; -webkit-user-select: none;
-webkit-tap-highlight-color: transparent; /* no WebKit flash on tap */
} }
:global(.tab:disabled) { :global(.tab:disabled) {
opacity: 0.4; opacity: 0.4;
} }
/* The icon square hugs the emoji (just a little padding) so it is the press-highlight /* The icon square hugs the emoji (just a little padding) so the badge can sit on its
target and the badge can sit on its corner. */ corner. */
:global(.tab .sq) { :global(.tab .sq) {
position: relative; position: relative;
display: inline-grid; display: inline-grid;
@@ -50,12 +51,9 @@
line-height: 1; line-height: 1;
transition: background-color 0.12s; transition: background-color 0.12s;
} }
:global(.tab:active:not(:disabled) .sq) {
background: var(--surface-2);
}
/* A tab that navigates between peer views (Settings / Comms hubs) stays highlighted /* A tab that navigates between peer views (Settings / Comms hubs) stays highlighted
while selected: a filled square with an accent underline, distinct from the while selected: a filled square with an accent underline. A tap itself leaves no
momentary press tint above. */ highlight — there is no press tint, and the WebKit tap flash is disabled on .tab. */
:global(.tab.active .sq) { :global(.tab.active .sq) {
background: var(--surface-2); background: var(--surface-2);
box-shadow: inset 0 -2px 0 var(--accent); box-shadow: inset 0 -2px 0 var(--accent);