improvement(scroll): fade the page scroller's clipped edges

The subdued edge-fade the rail and side panels use now hints at more content on
the page scroller too, which the feed, the channel page and Plex all scroll
inside. Both <main>s move into one PageScroller so the invariants they share —
the load-bearing scrollbar gutter, and the bar staying visible because hiding it
would zero that gutter — are stated once.

Two fixes the hook needed first: it set fresh state on every scroll event, which
above a page tree would re-render it per frame; and it watched a single child
captured at mount, so a lazy page swapping out its Suspense fallback left the
observer on a detached node and the fade frozen at its pre-load value (measured
on the Plex page: no bottom fade over a 3119px list).
This commit is contained in:
2026-07-17 03:14:37 +02:00
parent 0b56eb9d53
commit a032324513
4 changed files with 72 additions and 24 deletions
+3 -5
View File
@@ -4,6 +4,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { ArrowLeft, Ban, Check, ExternalLink, Loader2, Plus, RefreshCw, SlidersHorizontal } from "lucide-react";
import Avatar from "./Avatar";
import Feed from "./Feed";
import PageScroller from "./PageScroller";
import { useConfirm } from "./ConfirmProvider";
import { notify } from "../lib/notifications";
import { notifyYouTubeActionError } from "../lib/youtubeErrors";
@@ -208,10 +209,7 @@ export default function ChannelPage({
: "pb-2 text-sm text-muted hover:text-fg border-b-2 border-transparent";
return (
// scrollbar-gutter:stable reserves the scrollbar track on BOTH tabs, so switching between the
// tall Videos tab (scrollbar) and the short About tab (no scrollbar) no longer shifts the
// header/logo/buttons horizontally as the scrollbar appears/disappears.
<main className="flex-1 min-w-0 overflow-y-auto [scrollbar-gutter:stable]">
<PageScroller>
{/* Banner + back — OPTION C: inset, rounded card (not full-bleed) */}
<div className="relative px-4 sm:px-6 pt-3">
{ch?.banner_url && bannerAttempt <= MAX_BANNER_RETRIES ? (
@@ -470,6 +468,6 @@ export default function ChannelPage({
)}
</div>
)}
</main>
</PageScroller>
);
}