feat(shell): sticky tabs+toolbar on the channel page
Generalise the fixed-chrome pattern to the channel detail page: the banner + identity now scroll away, while the tab row and the channel feed's toolbar stick to the top as a sticky sub-header — only the video grid scrolls. Mechanism: PageToolbarSlot (the toolbar portal target) is now an exported, overridable context. ChannelPage provides its own sticky sub-header node as the target, so the channelScoped Feed portals its toolbar up next to the tabs instead of into the shell's top band. Feed always portals its toolbar now (the slot decides where it lands). Also: the page scroller now fades only its BOTTOM edge — the top is bounded by the fixed/sticky chrome, so a top fade only bit into it. E2E: adds a lock that the channel tabs/toolbar stay pinned while the banner scrolls away; suite 15/15 on :5173, tsc + knip clean.
This commit is contained in:
@@ -655,27 +655,24 @@ export default function Feed({
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={channelScoped ? "p-4" : "px-4 pb-4 pt-2"}>
|
||||
{/* On the feed page the toolbar + active-filter chips are FIXED chrome: they pin in the
|
||||
shell's toolbar band (above the scroller) so they stay put — and reachable — while the
|
||||
cards scroll (bug 4). On a channel page the Feed is embedded below the channel's own
|
||||
banner/tabs, which scroll, so there the toolbar rides inline with the content as before.
|
||||
Channel pages get no chips: their Feed starts from its OWN baseline (channel-scoped,
|
||||
whole-catalog, show-all), so each would read as a "filter you applied" when it's just the
|
||||
page being itself. */}
|
||||
{channelScoped ? (
|
||||
toolbar
|
||||
) : (
|
||||
<PageToolbar>
|
||||
<div className="px-4 pt-4 pb-1">
|
||||
{toolbar}
|
||||
<div className={channelScoped ? "px-4 sm:px-6 pb-4" : "px-4 pb-4 pt-2"}>
|
||||
{/* The toolbar (+ active-filter chips) is FIXED chrome: it portals into a PageToolbarSlot so
|
||||
it stays put while the cards scroll (bug 4). On the feed page that slot is the shell's top
|
||||
band; on a channel page ChannelPage overrides the slot with its own sticky sub-header, so
|
||||
the toolbar rides with the tabs. Channel pages get no chips: their Feed starts from its OWN
|
||||
baseline (channel-scoped, whole-catalog, show-all), so each would read as a "filter you
|
||||
applied" when it's just the page being itself. */}
|
||||
<PageToolbar>
|
||||
<div className={channelScoped ? "px-4 sm:px-6 pb-2" : "px-4 pt-4 pb-1"}>
|
||||
{toolbar}
|
||||
{!channelScoped && (
|
||||
<ActiveFilterChips
|
||||
filters={activeFilters}
|
||||
onClearAll={() => setFilters(clearedFilters(filters))}
|
||||
/>
|
||||
</div>
|
||||
</PageToolbar>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</PageToolbar>
|
||||
{items.length === 0 ? (
|
||||
<div className="py-16 text-center text-muted">
|
||||
<p>{t("feed.noMatches")}</p>
|
||||
|
||||
Reference in New Issue
Block a user