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.
58 lines
2.3 KiB
TypeScript
58 lines
2.3 KiB
TypeScript
// The channel page's address-bar keys. The page opens over any page (`?chan=`, the shell's), so its own
|
|
// keys are the shell's too: no module owns them, a page switch clears them with `chan`, and the page
|
|
// under it writes none of ITS keys while the channel stands over it — the address names only what the
|
|
// screen shows. The watch state is not here: it is an account preference that follows every channel
|
|
// (`channelShow`).
|
|
export const CHANNEL_PAGE_KEYS = ["chtab", "chsort", "chtypes"] as const;
|
|
|
|
export type ChannelTab = "videos" | "about";
|
|
type ChannelContentTypes = {
|
|
includeNormal: boolean;
|
|
includeShorts: boolean;
|
|
includeLive: boolean;
|
|
};
|
|
export type ChannelPageView = { tab: ChannelTab; sort: string; types: ChannelContentTypes };
|
|
|
|
const DEFAULT_SORT = "newest";
|
|
// The content types as letters: n(ormal) s(horts) l(ive); "none" for an empty choice.
|
|
const TYPE_LETTERS: [keyof ChannelContentTypes, string][] = [
|
|
["includeNormal", "n"],
|
|
["includeShorts", "s"],
|
|
["includeLive", "l"],
|
|
];
|
|
|
|
/** The address-bar delta for the channel page's view; `null` clears every key (the page closed). The
|
|
* content types are always written: a page opened fresh takes them from the feed, so a link without
|
|
* them would reopen with whatever the feed of the browser opening it holds. */
|
|
export function channelPageParamUpdates(v: ChannelPageView | null): Record<string, string | null> {
|
|
if (v == null) return { chtab: null, chsort: null, chtypes: null };
|
|
const letters = TYPE_LETTERS.filter(([k]) => v.types[k])
|
|
.map(([, l]) => l)
|
|
.join("");
|
|
return {
|
|
chtab: v.tab === "about" ? "about" : null,
|
|
chsort: v.sort && v.sort !== DEFAULT_SORT ? v.sort : null,
|
|
chtypes: letters || "none",
|
|
};
|
|
}
|
|
|
|
/** The view a channel page's address names; what it leaves out comes from `fresh` (the defaults of a
|
|
* page opened without a link: the videos tab, newest first, the feed's content types). */
|
|
export function channelPageViewFrom(
|
|
params: URLSearchParams,
|
|
fresh: ChannelPageView,
|
|
): ChannelPageView {
|
|
const raw = params.get("chtypes");
|
|
const types =
|
|
raw == null
|
|
? fresh.types
|
|
: (Object.fromEntries(
|
|
TYPE_LETTERS.map(([k, l]) => [k, raw !== "none" && raw.includes(l)]),
|
|
) as ChannelContentTypes);
|
|
return {
|
|
tab: params.get("chtab") === "about" ? "about" : fresh.tab,
|
|
sort: params.get("chsort") || fresh.sort,
|
|
types,
|
|
};
|
|
}
|