fix(offline): keep the offline banner off the full-screen player

Every other shell rule in layoutShell.ts already treats /player/* as
immersive; the amber "You're offline" strip was the one piece of chrome
still rendered above it. On the native Android video path that is not
cosmetic: VideoPlayer makes itself transparent so the ExoPlayer
SurfaceView behind the WebView is visible (DR-185), so a shell child that
still paints shows through the picture as a stripe across the top of the
film. Offline is also precisely when a downloaded video plays, so the
banner appeared when it was most in the way — and it offers the viewer
nothing to act on, since local playback needs no server.

The rule moves into the pure module as showOfflineBanner() rather than
staying an inline {#if} in the shell, so the immersive-route contract is
stated in one tested place.

TRACES: UR-003, UR-043 | DR-291 | UT-255
This commit is contained in:
2026-09-22 21:08:03 -04:00
parent 0f928798d7
commit b98cbfe28a
4 changed files with 70 additions and 4 deletions
+14 -2
View File
@@ -39,6 +39,7 @@
showGlobalHeader as computeShowGlobalHeader,
routeOwnsLayout as computeRouteOwnsLayout,
shellReservesBottomInset,
showOfflineBanner as computeShowOfflineBanner,
} from "$lib/utils/layoutShell";
import { registerNavigationTracking } from "$lib/utils/navigation";
import { useScrollRestore } from "$lib/utils/scrollContainer";
@@ -108,6 +109,17 @@
shellReservesBottomInset({ pathname, isAuthenticated: $isAuthenticated }),
);
// The offline banner is shell chrome like the rest, so it stays off the
// full-screen player — where on the native video path it would paint a
// stripe straight through the film (DR-291).
const offlineBannerVisible = $derived(
computeShowOfflineBanner({
pathname,
isAuthenticated: $isAuthenticated,
isConnected: $isConnected,
}),
);
onMount(async () => {
// Detect platform first (synchronously, before any await) so the global
// mini player's Android visibility gate is correct from the first render.
@@ -283,8 +295,8 @@
style:padding-bottom={shellPadsBottom ? "var(--safe-bottom)" : undefined}
>
{#if isInitialized}
<!-- Offline indicator banner -->
{#if $isAuthenticated && !$isConnected}
<!-- Offline indicator banner (never over the player — DR-291) -->
{#if offlineBannerVisible}
<div
class="bg-amber-600/90 text-white px-4 py-2 text-sm flex items-center justify-center gap-2 shrink-0"
>