From b4984dc38b94c9de45736682c8bc793228f0f5a5 Mon Sep 17 00:00:00 2001 From: npeter83 Date: Sat, 22 Aug 2026 07:51:54 +0200 Subject: [PATCH] feat(plex): move Watch-state out of the rail into a toolbar pill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Show" (watch-state) filter leaves the left rail and becomes a FilterSelect pill next to the item count, mirroring the feed's Watch-state control — a top-level "what am I looking at" choice, always in reach, not buried in the rail. It still emits a removable chip when non-default (same as the feed). --- frontend/src/components/PlexBrowse.tsx | 20 ++++++++++++++++++-- frontend/src/components/PlexSidebar.tsx | 15 +-------------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/frontend/src/components/PlexBrowse.tsx b/frontend/src/components/PlexBrowse.tsx index 75f86f38..1a3f5550 100644 --- a/frontend/src/components/PlexBrowse.tsx +++ b/frontend/src/components/PlexBrowse.tsx @@ -26,6 +26,7 @@ import { PLEX_SUB_URL, type Sub } from "./plexSubUrl"; import { toggleWatchState } from "../lib/plexWatch"; import SortControl from "./SortControl"; import SegmentedToggle from "./SegmentedToggle"; +import FilterSelect from "./FilterSelect"; import PlexDiscover from "./PlexDiscover"; import { PageToolbar } from "./PageShell"; import ActiveFilterChips from "./ActiveFilterChips"; @@ -48,6 +49,10 @@ const PlexPlaylistView = lazy(() => import("./PlexPlaylistView")); const PAGE = 40; +// Watch-state options for the toolbar pill (moved out of the filter rail — it's a top-level "what am +// I looking at" control now, like the feed's Watch-state pill, not a rail widget). +const SHOW_OPTS = ["all", "unwatched", "in_progress", "watched"] as const; + export default function PlexBrowse() { const { t } = useTranslation(); const qc = useQueryClient(); @@ -55,7 +60,7 @@ export default function PlexBrowse() { // search term (q) comes from the shared header box; the rail hands off a playlist to open via the // shared `playlistOpen` slot, which we consume into a history subview then clear. const { q, scope, show, sort, filters, field, playlistOpen: openPlaylist, jumpTo } = usePlex(); - const { setScope, setSort, setFilters, setPlaylistOpen, setJumpTo } = usePlexActions(); + const { setScope, setShow, setSort, setFilters, setPlaylistOpen, setJumpTo } = usePlexActions(); const dq = useDebounced(q.trim(), 350); // Active language for the HU overlay: "hu" serves Hungarian metadata, else EN. In the query keys so // a switch refetches the grid/facets/detail; useTranslation re-renders this component on switch. @@ -408,7 +413,18 @@ export default function PlexBrowse() { while only the poster grid scrolls. */}
- +
+ + {/* Watch state — a top-level toolbar pill next to the count (moved out of the rail), + the same idiom as the feed's Watch-state FilterSelect. */} + ({ value: s, label: t(`plex.filter.showOpt.${s}`) }))} + selected={[show]} + onChange={(next) => setShow(next[0] ?? "all")} + /> +
{/* The controls row sits directly above the grid: the applied-filter chips flow from the left (overflowing to a "+N"/count pill so they never crowd the controls), while Sort + the Discover/Browse toggle stay pinned to the right — the same layout as the Feed. */} diff --git a/frontend/src/components/PlexSidebar.tsx b/frontend/src/components/PlexSidebar.tsx index 017cfc28..c16933ba 100644 --- a/frontend/src/components/PlexSidebar.tsx +++ b/frontend/src/components/PlexSidebar.tsx @@ -27,7 +27,6 @@ type Props = { onToggleCollapse: () => void; }; -const SHOW_OPTS = ["all", "unwatched", "in_progress", "watched"] as const; const RATING_STEPS = [5, 6, 7, 8, 9]; const ADDED_OPTS = ["24h", "1w", "1m", "6m", "1y"] as const; const DURATION_BUCKETS: { key: string; min: number | null; max: number | null }[] = [ @@ -66,7 +65,7 @@ export default function PlexSidebar({ layout, setLayout, collapsed, onToggleColl // the header search box); this rail is the primary editor of them. Opening a playlist is a // hand-off to PlexBrowse via the shared `playlistOpen` slot. const { scope, show, filters } = usePlex(); - const { setShow, setFilters, setPlaylistOpen: onOpenPlaylist } = usePlexActions(); + const { setFilters, setPlaylistOpen: onOpenPlaylist } = usePlexActions(); const playlistsQ = useQuery({ queryKey: qk.plexPlaylists(), queryFn: () => api.plexPlaylists() }); const [newPlaylist, setNewPlaylist] = useState(""); // This rail's media source (the Plex library) — names the abstraction the feed and Plex rails @@ -151,18 +150,6 @@ export default function PlexSidebar({ layout, setLayout, collapsed, onToggleColl ), }, - { - id: "watch", - title: t("plex.filter.show"), - body: ( - ({ value: s, label: t(`plex.filter.showOpt.${s}`) }))} - value={show} - onChange={setShow} - /> - ), - }, ...(peopleActive ? [ {