fix(channel): the channel page's address names the channel and its own view, not the page under it
Opening a channel kept every key of the page under it (`?q=music&sort=oldest&chan=…`, a sort the channel did not show), and the channel's own tab, sort and content types lived in its state alone, so a reload or a bookmark lost them. Now the channel's address is `channelUrl`: the shell's keys and `chan`, shared by `openChannel` and the channel link's href. The page writes its view (`chtab`, `chsort`, `chtypes`, lib/channelPageUrlState) and reopens it; these are shell keys, cleared by a page switch and by closing it in place. While a channel stands over a page, no module store writes its keys (`urlPage`); Back finds them on the page's own entry. A link written by an older build opens without the page's keys.
This commit is contained in:
@@ -34,6 +34,12 @@ import { useFeedView, useFeedViewActions } from "./feedViewContext";
|
||||
import { useShowChannelInFeed } from "./useFeedPageHooks";
|
||||
import { SHOW_IDS } from "./feedFiltersInit";
|
||||
import { usePref } from "../../lib/usePref";
|
||||
import { useUrlMirror } from "../../lib/useUrlMirror";
|
||||
import {
|
||||
channelPageParamUpdates,
|
||||
channelPageViewFrom,
|
||||
type ChannelTab,
|
||||
} from "../../lib/channelPageUrlState";
|
||||
import { LS } from "../../lib/storage";
|
||||
import { useConfirm } from "../../components/ui/confirmContext";
|
||||
import { notify } from "../../lib/notifications";
|
||||
@@ -88,7 +94,21 @@ export default function ChannelPage({
|
||||
// to: the feed defaults to scope "my", so filtering it to a channel you don't follow would just
|
||||
// land you on an empty page.
|
||||
const onShowInFeed = useShowChannelInFeed(channelId);
|
||||
const [tab, setTab] = useState<"videos" | "about">("videos");
|
||||
// The view this page opens in: what its address names (a reload, a bookmark), else a fresh page —
|
||||
// the videos, newest first, in the feed's content types (see `ownFilters` below). Read once, at
|
||||
// mount: the page is keyed by its channel, and from here on it writes its address itself.
|
||||
const [opened] = useState(() =>
|
||||
channelPageViewFrom(new URLSearchParams(window.location.search), {
|
||||
tab: "videos",
|
||||
sort: "newest",
|
||||
types: {
|
||||
includeNormal: globalFilters.includeNormal,
|
||||
includeShorts: globalFilters.includeShorts,
|
||||
includeLive: globalFilters.includeLive,
|
||||
},
|
||||
}),
|
||||
);
|
||||
const [tab, setTab] = useState<ChannelTab>(opened.tab);
|
||||
const panel = useTabPanel();
|
||||
// The whole channel chrome (banner, identity, tabs, toolbar) is fixed: it portals into the shell's
|
||||
// fixed band so only the video grid scrolls. This node sits at the bottom of that chrome and is
|
||||
@@ -266,17 +286,27 @@ export default function ChannelPage({
|
||||
tags: [],
|
||||
tagModes: DEFAULT_TAG_MODES,
|
||||
q: "",
|
||||
sort: "newest",
|
||||
sort: opened.sort,
|
||||
scope: "all",
|
||||
librarySource: "all",
|
||||
// Content-type prefs inherited from the global feed (seeded once) — no longer forced.
|
||||
includeNormal: globalFilters.includeNormal,
|
||||
includeShorts: globalFilters.includeShorts,
|
||||
includeLive: globalFilters.includeLive,
|
||||
...opened.types,
|
||||
show: "unwatched",
|
||||
channelIds: [channelId],
|
||||
}));
|
||||
const filters: FeedFilters = { ...ownFilters, show };
|
||||
// The address is this view: a reload or a bookmark reopens the tab, the sort and the content types.
|
||||
useUrlMirror(
|
||||
channelPageParamUpdates({
|
||||
tab,
|
||||
sort: ownFilters.sort,
|
||||
types: {
|
||||
includeNormal: ownFilters.includeNormal,
|
||||
includeShorts: ownFilters.includeShorts,
|
||||
includeLive: ownFilters.includeLive,
|
||||
},
|
||||
}),
|
||||
);
|
||||
const setFilters = (next: FeedFilters) => {
|
||||
if (next.show !== show) setShow(next.show);
|
||||
setOwnFilters(next);
|
||||
@@ -436,7 +466,7 @@ export default function ChannelPage({
|
||||
idBase={panel.idBase}
|
||||
className="flex gap-1"
|
||||
active={tab}
|
||||
onChange={(id) => setTab(id as "videos" | "about")}
|
||||
onChange={(id) => setTab(id as ChannelTab)}
|
||||
tabs={[
|
||||
{ id: "videos", label: t("channel.tabVideos") },
|
||||
{ id: "about", label: t("channel.tabAbout") },
|
||||
|
||||
Reference in New Issue
Block a user