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:
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
// Central registry of every key the app keeps in the browser (localStorage, and a tab's
|
||||
// sessionStorage). One place to see them all, rename safely, and avoid collisions — instead of
|
||||
@@ -307,10 +307,11 @@ export function useAccountPersistedState(
|
||||
|
||||
// --- a page's sub-tab, per browser tab ---------------------------------------------------------
|
||||
|
||||
// Which sub-tab a page was left on (Settings, Configuration, Statistics, Users) is kept for THIS browser
|
||||
// tab only — sessionStorage, the account's (see ownKey): it survives a reload and a trip to another page, and a new
|
||||
// Which sub-tab a page was left on (Settings, Configuration, Users) is kept for THIS browser tab only —
|
||||
// sessionStorage, the account's (see ownKey): it survives a reload and a trip to another page, and a new
|
||||
// tab opens the page on its first sub-tab (the owner's call: a position remembered forever in
|
||||
// localStorage made Configuration open on "Plex" in every fresh tab, as if that were its home).
|
||||
// localStorage made Configuration open on "Plex" in every fresh tab, as if that were its home). The
|
||||
// address names the tab too (the page mirrors it): a link or a bookmark that carries one wins.
|
||||
|
||||
/** The sub-tab stored for this browser tab, or null. */
|
||||
function getTabRaw(base: string): string | null {
|
||||
@@ -322,8 +323,7 @@ function getTabRaw(base: string): string | null {
|
||||
}
|
||||
}
|
||||
|
||||
/** Pre-select a page's sub-tab before navigating there (a "Review" link, the Google-link return). */
|
||||
export function setTabRaw(base: string, value: string): void {
|
||||
function writeTabRaw(base: string, value: string): void {
|
||||
const k = ownKey(base);
|
||||
if (!k) return;
|
||||
try {
|
||||
@@ -333,10 +333,23 @@ export function setTabRaw(base: string, value: string): void {
|
||||
}
|
||||
}
|
||||
|
||||
/** `useAccountPersistedState` for a page's sub-tab, kept per browser tab (see above). */
|
||||
// A pre-selection made while the page is already on screen (a notice's link opened over Settings) has
|
||||
// no mount to be read at, and the navigation to the same page is a no-op: the page's hook hears it.
|
||||
const TAB_SELECT_EVENT = "siftlode:tab-select";
|
||||
type TabSelect = { base: string; value: string };
|
||||
|
||||
/** Pre-select a page's sub-tab before navigating there (a "Review" link, the Google-link return). */
|
||||
export function setTabRaw(base: string, value: string): void {
|
||||
writeTabRaw(base, value);
|
||||
window.dispatchEvent(new CustomEvent<TabSelect>(TAB_SELECT_EVENT, { detail: { base, value } }));
|
||||
}
|
||||
|
||||
/** `useAccountPersistedState` for a page's sub-tab, kept per browser tab (see above). `urlKey`: the
|
||||
* address-bar key the page mirrors its tab to — a tab it names is the one the page opens on. */
|
||||
export function useTabPersistedState(
|
||||
base: string,
|
||||
fallback = "",
|
||||
urlKey?: string,
|
||||
): [string, (value: string) => void] {
|
||||
const [value, setValue] = useState<string>(() => {
|
||||
// The position used to live in localStorage; a value left there would never be read again.
|
||||
@@ -348,12 +361,27 @@ export function useTabPersistedState(
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
const linked = urlKey ? new URLSearchParams(window.location.search).get(urlKey) : null;
|
||||
if (linked) {
|
||||
// Kept for this browser tab too, so a later trip back to the page (its address cleared by the
|
||||
// page switch) still opens it here.
|
||||
writeTabRaw(base, linked);
|
||||
return linked;
|
||||
}
|
||||
return getTabRaw(base) ?? fallback;
|
||||
});
|
||||
useEffect(() => {
|
||||
function onSelect(e: Event) {
|
||||
const { detail } = e as CustomEvent<TabSelect>;
|
||||
if (detail.base === base) setValue(detail.value);
|
||||
}
|
||||
window.addEventListener(TAB_SELECT_EVENT, onSelect);
|
||||
return () => window.removeEventListener(TAB_SELECT_EVENT, onSelect);
|
||||
}, [base]);
|
||||
const set = useCallback(
|
||||
(next: string) => {
|
||||
setValue(next);
|
||||
setTabRaw(base, next);
|
||||
writeTabRaw(base, next);
|
||||
},
|
||||
[base],
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user