feat(nav): each module declares its URL keys; a page switch clears them and a page opens without another's
The shell cleared a hand-kept key list on a page switch (it missed the Files and feed keys) and cleared nothing when a page opened from a link carrying another page's keys. ModuleDef.urlKeys now names every key a page's view writes, the shell derives both from the registry, and moduleUrl.contract.test holds the declarations true: one owner per key, no shell key, exactly what each codec writes, and no undeclared key literal in the app.
This commit is contained in:
@@ -17,7 +17,8 @@ export interface ChannelsUrlState {
|
||||
filters: FilterMap;
|
||||
}
|
||||
|
||||
const KEYS = ["ctab", "csort", "cf"] as const;
|
||||
export const CHANNELS_KEYS = ["ctab", "csort", "cf"] as const;
|
||||
const KEYS = CHANNELS_KEYS;
|
||||
const VIEWS = ["subscribed", "discovery", "hidden", "blocked"];
|
||||
|
||||
// Sort ⇄ `key:dir` (e.g. `subscribers:desc`) via the shared codec in columnSort. There is no default
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
// The Files page's address-bar keys: the folder shown (`?folder=`, its encoding in
|
||||
// modules/files/filesContext) and the file it turns to once (`?item=`). Here, beside the other pages'
|
||||
// key lists, so the page's definition can declare them without importing its own folder.
|
||||
export const FILES_FOLDER_KEY = "folder";
|
||||
export const FILES_ITEM_KEY = "item";
|
||||
export const FILES_KEYS = [FILES_FOLDER_KEY, FILES_ITEM_KEY] as const;
|
||||
@@ -44,4 +44,10 @@ export type ModuleDef = {
|
||||
// Static, unlike the page: it is on the boot path by design. It reads no other module's store, so
|
||||
// the order the stores nest in does not matter (moduleStores.contract.test).
|
||||
Store?: ComponentType<{ children: ReactNode }>;
|
||||
// Every address-bar key this page's view writes: its filters, sort, tab, the item it shows. The URL
|
||||
// IS the view, so a bookmark reopens it. The shell clears them all on a page switch, and opens a page
|
||||
// with no other page's keys in its address (NavigationProvider), so one page's state never rides
|
||||
// along onto another's URL. Empty for a page with nothing of its own in the URL. Each key belongs to
|
||||
// one module and none is a shell key (moduleUrl.contract.test).
|
||||
urlKeys: readonly string[];
|
||||
};
|
||||
|
||||
@@ -18,7 +18,10 @@ export interface PlexUrlState {
|
||||
filters: PlexFilters;
|
||||
}
|
||||
|
||||
const KEYS = ["pscope", "psort", "pshow", "pf"] as const;
|
||||
export const PLEX_KEYS = ["pscope", "psort", "pshow", "pf"] as const;
|
||||
const KEYS = PLEX_KEYS;
|
||||
// The Plex sub-view's key (show, season, info, person… — modules/plex/plexSubUrl encodes it).
|
||||
export const PLEX_SUB_KEY = "v";
|
||||
const SCOPES = ["movie", "show", "both"];
|
||||
const SHOWS = ["all", "unwatched", "in_progress", "watched"];
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// the short module/channel name (NavigationProvider owns document.title) — the query never leaks into it.
|
||||
import { TAG_CATEGORIES, type FeedFilters } from "./api";
|
||||
|
||||
const KEYS = [
|
||||
export const FEED_KEYS = [
|
||||
"q",
|
||||
"show",
|
||||
"sort",
|
||||
@@ -29,6 +29,23 @@ const KEYS = [
|
||||
"mindur",
|
||||
"maxdur",
|
||||
] as const;
|
||||
const KEYS = FEED_KEYS;
|
||||
|
||||
// The keys the shell itself reads, whatever page is on screen: the page, the channel page (it opens
|
||||
// over any page), the welcome card's mode and the one-time entry links. No module may declare one of
|
||||
// these (moduleUrl.contract.test), and a page switch never clears them.
|
||||
export const SHELL_KEYS = [
|
||||
"page",
|
||||
"chan",
|
||||
"m",
|
||||
"link",
|
||||
"oauth",
|
||||
"admin",
|
||||
"account",
|
||||
"login",
|
||||
"deleted",
|
||||
"token",
|
||||
] as const;
|
||||
|
||||
export function filtersToParams(f: FeedFilters): URLSearchParams {
|
||||
const p = new URLSearchParams();
|
||||
|
||||
Reference in New Issue
Block a user