UI: drop tab-bar tap highlight; don't slide the first screen on launch
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 44s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m0s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 44s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m0s
Tab bar: tapping a bottom-tab icon flashed a background — the icon square's
:active press tint plus the default WebKit tap flash, the same pair removed from
the lobby rows. Drop the press tint and set -webkit-tap-highlight-color:
transparent on .tab. The selected-tab highlight (Settings / Comms hubs) stays.
Startup slide: the route pane's in:slideX is local to its {#key} block, so it
plays on that block's own first mount when app.ready flips — the lobby slid in on
launch as if navigated into from another screen. Gate the slide duration to 0 for
the first pane shown after boot (a `started` flag set right after it mounts), so
launch is static while every later route change animates as before.
This commit is contained in:
+12
-3
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user