From 90b33fc32576f7670a035fe3d9a9d2a2e06a9dca Mon Sep 17 00:00:00 2001 From: npeter83 Date: Tue, 11 Aug 2026 00:27:04 +0200 Subject: [PATCH] =?UTF-8?q?refactor(ui):=20R10=20S4=20=E2=80=94=20complete?= =?UTF-8?q?=20the=20selection-paint=20sweep=20(all=20pill=20idioms)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first S4 pass migrated a subset, which left same-idiom selection pills hand-rolled and made adjacent controls inconsistent (a /code-review finding). This completes the sweep so every selected-among-options control shares the recipe: - plain pills → .pill (+ aria-pressed): Channels status filters + view tabs, Sidebar filter-tag chips + date presets + custom-dates, Stats tabs + ranges. - glass-card-resting pills → .pill with the resting `glass-card glass-hover` kept in the non-pressed branch (solid accent when pressed): PlexSidebar library scope + the facet Chip (retired the round-1 "deferred" note — the recipe already expresses this via the resting branch, no new variant needed). - custom-dates aria-pressed is coerced with !! so a date string can't leak into the attribute and miss the [aria-pressed="true"] paint. - drop the dead `border` on ChannelTags' chip-solid (accent border on accent bg). Out of scope (a separate concern, NOT selection-among-options): primary/action buttons that share the accent fill — Banner action, ConfirmProvider primary, PlexBrowse primary, PlayerModal watched-toggle — these want a future .btn-primary recipe. Left by-design: tableHeader filter options (PopoverItem + keepSelectedPaint, owned by the popover platform). --- frontend/src/components/ChannelTags.tsx | 2 +- frontend/src/components/Channels.tsx | 14 ++++---------- frontend/src/components/PlexSidebar.tsx | 10 +++++----- frontend/src/components/Sidebar.tsx | 21 ++++++--------------- frontend/src/components/Stats.tsx | 14 ++++---------- frontend/src/index.css | 2 +- 6 files changed, 21 insertions(+), 42 deletions(-) diff --git a/frontend/src/components/ChannelTags.tsx b/frontend/src/components/ChannelTags.tsx index 703b1990..ee985a8d 100644 --- a/frontend/src/components/ChannelTags.tsx +++ b/frontend/src/components/ChannelTags.tsx @@ -22,7 +22,7 @@ interface TagChipProps { } function TagChip({ tag, onClick, title }: TagChipProps) { - const cls = "chip-solid shrink-0 text-3xs px-1.5 py-0.5 rounded-full border max-w-36 truncate"; + const cls = "chip-solid shrink-0 text-3xs px-1.5 py-0.5 rounded-full max-w-36 truncate"; return onClick ? ( @@ -622,11 +619,8 @@ export default function Channels() { diff --git a/frontend/src/components/PlexSidebar.tsx b/frontend/src/components/PlexSidebar.tsx index 4e882374..2b1ac4b9 100644 --- a/frontend/src/components/PlexSidebar.tsx +++ b/frontend/src/components/PlexSidebar.tsx @@ -148,8 +148,9 @@ export default function PlexSidebar({ layout, setLayout, collapsed, onToggleColl diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index ae0a8f97..0eda45a9 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -46,11 +46,8 @@ function TagChip({ data-tag={tag.name} onClick={onClick} title={t("sidebar.channelCount", { count })} - className={`inline-flex items-center gap-1.5 text-xs px-2.5 py-1 rounded-full border shadow-xs hover:shadow-sm active:translate-y-px transition ${ - active - ? "bg-accent text-accent-fg border-accent" - : "bg-card border-border text-fg hover:border-accent" - }`} + aria-pressed={active} + className="pill inline-flex items-center gap-1.5 text-xs px-2.5 py-1 rounded-full border shadow-xs hover:shadow-sm active:translate-y-px" > {tag.name} {t("sidebar.datePreset." + p.key)} @@ -185,11 +179,8 @@ export default function Sidebar({ setCustomDates(next); if (next) setFilters({ ...filters, maxAgeDays: undefined }); }} - className={`text-xs px-2.5 py-1 rounded-full border shadow-xs active:translate-y-px transition ${ - customDates || filters.dateFrom || filters.dateTo - ? "bg-accent text-accent-fg border-accent" - : "bg-card border-border hover:border-accent" - }`} + aria-pressed={!!(customDates || filters.dateFrom || filters.dateTo)} + className="pill text-xs px-2.5 py-1 rounded-full border shadow-xs active:translate-y-px" > {t("sidebar.custom")} diff --git a/frontend/src/components/Stats.tsx b/frontend/src/components/Stats.tsx index a7d44392..59c4602e 100644 --- a/frontend/src/components/Stats.tsx +++ b/frontend/src/components/Stats.tsx @@ -35,11 +35,8 @@ export default function Stats() { @@ -236,11 +233,8 @@ function SystemStats() { diff --git a/frontend/src/index.css b/frontend/src/index.css index 560b6b4c..dba7d92f 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -474,7 +474,7 @@ body { .chip-solid is intentionally a PAINT-ONLY modifier (bg/text/border colour, no display or geometry): it sits on a site's OWN chip geometry so a truncating single-element chip (ChannelTags) isn't forced into inline-flex, which would break its text-overflow. Use it WITH a - site's `rounded-full`/`border` utilities (or on top of `.chip`), never bare. */ + site's own geometry (`rounded-full`, optional `border`) or on top of `.chip`, never bare. */ .chip { display: inline-flex; align-items: center;