refactor(ui): shared SegmentedToggle for MATCH controls (R13 S2c step 1)
New source-agnostic SegmentedToggle primitive (rounded-full pill track, one active option, aria-pressed drives the paint via the .pill recipe). Migrates the three hand-rolled MATCH segments onto it: - feed tag any/all "Match" toggle (Sidebar) - feed Mine/Library scope bar (Sidebar; fullWidth + icons + per-option tips) - Plex any/all combine toggle (PlexSidebar MatchToggle is now a thin binding) Caption mode (justify-between + label) covers the match toggles; fullWidth + size="md" covers the scope bar. Adds SegmentedToggle.dom.test.tsx (6 tests). Part of the app-wide single-select control unification; branch not merged.
This commit is contained in:
@@ -11,6 +11,7 @@ import { useScrollFade } from "../lib/useScrollFade";
|
||||
import SidePanel from "./SidePanel";
|
||||
import PanelGroups, { type PanelItem } from "./PanelGroups";
|
||||
import SortControl from "./SortControl";
|
||||
import SegmentedToggle from "./SegmentedToggle";
|
||||
import { usePlexClearFilters } from "./usePlexActiveFilters";
|
||||
import { usePlex, usePlexActions } from "./PlexProvider";
|
||||
|
||||
@@ -35,8 +36,8 @@ const DURATION_BUCKETS: { key: string; min: number | null; max: number | null }[
|
||||
{ key: "long", min: 120 * 60, max: null },
|
||||
];
|
||||
|
||||
// The any/all combine toggle for a multi-value filter (genres, actors). Same segmented-pill look as
|
||||
// the feed rail's tag MATCH toggle (rounded-full track + inset active pill), not a boxed button row.
|
||||
// The any/all combine toggle for a multi-value filter (genres, actors) — a thin binding of the shared
|
||||
// SegmentedToggle to the Plex match vocabulary (same look as the feed rail's tag MATCH toggle).
|
||||
function MatchToggle({
|
||||
mode,
|
||||
onChange,
|
||||
@@ -46,27 +47,16 @@ function MatchToggle({
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div className="mb-1.5 flex items-center justify-between">
|
||||
<span className="text-3xs uppercase tracking-wide text-muted">
|
||||
{t("plex.filter.matchLabel")}
|
||||
</span>
|
||||
<div
|
||||
className="flex items-center rounded-full border border-border bg-card p-0.5 text-3xs"
|
||||
role="group"
|
||||
aria-label={t("plex.filter.matchLabel")}
|
||||
>
|
||||
{(["any", "all"] as const).map((m) => (
|
||||
<button
|
||||
key={m}
|
||||
onClick={() => onChange(m)}
|
||||
aria-pressed={mode === m}
|
||||
className="pill rounded-full px-2 py-0.5"
|
||||
>
|
||||
{t(`plex.filter.match.${m}`)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<SegmentedToggle
|
||||
label={t("plex.filter.matchLabel")}
|
||||
ariaLabel={t("plex.filter.matchLabel")}
|
||||
options={[
|
||||
{ value: "any", label: t("plex.filter.match.any") },
|
||||
{ value: "all", label: t("plex.filter.match.all") },
|
||||
]}
|
||||
value={mode}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user