feat(plex): add Playlist/Collection browse modes to the header pill
The header library-scope pill gains two entry points — Playlist and Collection — next to All/Movies/Shows, a second way into each area (the rail filter is the other). Picking Playlist shows a grid of the user's playlists (a tile opens that playlist's view); Collection shows a searchable grid of collections (a tile filters the title grid by that collection). Pure front-end — reuses the existing plexPlaylists / plexCollections(union) list endpoints. Two new top-level sub-views (`playlists` / `collections`, bookmarkable as ?v=playlists / ?v=collections) rendered by PlexBrowse via the new plexBrowseLists surfaces (hue-tiled like the Discover genre tiles). The PlexViewBridge now carries the view `kind`; PlexScopeToggle is a 5-way that derives its active segment from it (browse-mode when in one, else scope) and drives the two views through the bridge — picking a scope from a browse mode returns to the title grid. The Discover/Browse toggle hides in these modes; Backspace + the search→grid flip cover them. Tests: PlexScopeToggle (5-way + browse-mode drive/active), plexSubUrl round-trip for the two new views. Gate: tsc/lint/knip/prettier + 402 vitest.
This commit is contained in:
@@ -1,25 +1,48 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import SegmentedToggle from "./SegmentedToggle";
|
||||
import { usePlex, usePlexActions } from "./PlexProvider";
|
||||
import { usePlexViewControls } from "./PlexViewBridge";
|
||||
|
||||
// The Plex library scope (both | movie | show) as a compact header control, sitting next to the
|
||||
// search box (S3 toolbar relocation — it used to be a sidebar island). Reads/writes the same
|
||||
// provider state the sidebar did, so scope stays in sync everywhere; reuses the shared
|
||||
// SegmentedToggle and the existing plex.filter.scopeOpt.* labels.
|
||||
// The Plex "browse target" as a compact header control next to the search box: the three library
|
||||
// scopes (both | movie | show, which browse TITLES) plus two extra entry points — Playlist and
|
||||
// Collection — that switch the content area to a grid of the user's playlists / of the collections.
|
||||
// The scopes read/write the shared provider state (so scope stays in sync everywhere); the two extra
|
||||
// modes drive PlexBrowse's sub-view through the PlexViewBridge. Picking a scope while in a
|
||||
// playlists/collections surface returns to the title grid at that scope.
|
||||
const SCOPES = ["both", "movie", "show"] as const;
|
||||
|
||||
export default function PlexScopeToggle() {
|
||||
const { t } = useTranslation();
|
||||
const { scope } = usePlex();
|
||||
const { setScope } = usePlexActions();
|
||||
const ctl = usePlexViewControls();
|
||||
const inPlaylists = ctl?.kind === "playlists";
|
||||
const inCollections = ctl?.kind === "collections";
|
||||
// The active segment: the browse-mode when in one, else the library scope.
|
||||
const value = inPlaylists ? "playlists" : inCollections ? "collections" : scope;
|
||||
|
||||
const onChange = (v: string) => {
|
||||
if (v === "playlists" || v === "collections") {
|
||||
ctl?.open({ kind: v });
|
||||
return;
|
||||
}
|
||||
setScope(v);
|
||||
// Leaving the playlists/collections surface for a title scope → show the title grid.
|
||||
if (inPlaylists || inCollections) ctl?.open({ kind: "grid" });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="pointer-events-auto shrink-0">
|
||||
<SegmentedToggle
|
||||
size="md"
|
||||
ariaLabel={t("plex.filter.scope")}
|
||||
options={SCOPES.map((s) => ({ value: s, label: t(`plex.filter.scopeOpt.${s}`) }))}
|
||||
value={scope}
|
||||
onChange={setScope}
|
||||
options={[
|
||||
...SCOPES.map((s) => ({ value: s, label: t(`plex.filter.scopeOpt.${s}`) })),
|
||||
{ value: "playlists", label: t("plex.filter.scopeOpt.playlists") },
|
||||
{ value: "collections", label: t("plex.filter.scopeOpt.collections") },
|
||||
]}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user