feat(nav): tabs, list views and name searches are named in the address
Settings, Configuration and Users name their tab (stab/cfgtab/utab); a link's tab wins and a tab pre-selected while its page is on screen now switches it. A playlist's sort, filters and grouping (plsort/plf/plgroup), the Files sort (fsort, always written) and the name searches of Channels, Files, Playlists and Plex (cq/fq/plq/pq+pqf) reopen from the address; the searches are written once the typing pauses.
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
import { decodeSortParam, encodeSortParam, type SortState } from "./columnSort";
|
||||
import { decodeFilterMap, encodeFilterMap } from "./filterMapParam";
|
||||
import { type FilterMap } from "./tableColumns";
|
||||
|
||||
// The Playlists page's address-bar keys: the playlist shown (`pl`), the rail's name search (`plq`), and
|
||||
// the open playlist's view — its track sort, column filters and grouping (`plsort`/`plf`/`plgroup`).
|
||||
// The playlist is remembered per account too (PlaylistsProvider); the search and the view are
|
||||
// remembered nowhere else (the view starts over on every playlist), so each of those is written only
|
||||
// when it differs from the default: its key's absence IS the default.
|
||||
export const PLAYLISTS_KEYS = ["pl", "plq", "plsort", "plf", "plgroup"] as const;
|
||||
|
||||
export type PlaylistView = { sort: SortState; filters: FilterMap; groupBy: boolean };
|
||||
|
||||
// The neutral view: "#" ascending IS the stored order, so the header can show a real arrow for it
|
||||
// instead of the list looking unsorted (or, worse, looking sorted by whatever column the stored
|
||||
// order happens to correlate with — the user read a channel-grouped playlist as sorted by Channel).
|
||||
export const PLAYLIST_STORED_SORT: SortState = { key: "pos", dir: "asc" };
|
||||
|
||||
export function isStoredSort(s: SortState): boolean {
|
||||
return s?.key === PLAYLIST_STORED_SORT?.key && s?.dir === PLAYLIST_STORED_SORT?.dir;
|
||||
}
|
||||
|
||||
/** The address-bar delta for an open playlist's view; `null` clears it (no playlist open). */
|
||||
export function playlistViewParamUpdates(v: PlaylistView | null): Record<string, string | null> {
|
||||
if (!v) return { plsort: null, plf: null, plgroup: null };
|
||||
return {
|
||||
// An unsorted view (a header clicked through to "none") is the stored order too.
|
||||
plsort: v.sort && !isStoredSort(v.sort) ? encodeSortParam(v.sort) : null,
|
||||
plf: encodeFilterMap(v.filters),
|
||||
plgroup: v.groupBy ? "1" : null,
|
||||
};
|
||||
}
|
||||
|
||||
/** The view an address names; what it leaves out is the default. */
|
||||
export function playlistViewFrom(params: URLSearchParams): PlaylistView {
|
||||
const sort = params.get("plsort");
|
||||
const filters = params.get("plf");
|
||||
return {
|
||||
sort: (sort != null && decodeSortParam(sort)) || PLAYLIST_STORED_SORT,
|
||||
filters: filters != null ? decodeFilterMap(filters) : {},
|
||||
groupBy: params.get("plgroup") === "1",
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user