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 the page's store: the playlist shown and the rail's search (each null * when not named). */ export function playlistsParams( selected: number | null, search: string, ): Record { return { pl: selected != null ? String(selected) : null, plq: search || null }; } /** The address-bar delta for an open playlist's view; `null` clears it (no playlist open). */ export function playlistViewParamUpdates(v: PlaylistView | null): Record { 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", }; }