From 80cdafdbfecaa0824dd72245bfff02a90bdc6845 Mon Sep 17 00:00:00 2001 From: npeter83 Date: Sat, 15 Aug 2026 01:37:05 +0200 Subject: [PATCH] fix(ui): address self-review findings (R13 S2c) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three low-severity findings from the /code-review high self-pass: - Plex duration: the "Any" chip no longer false-highlights when durationMin/Max hold a set-but-off-bucket value (stale/version-skew state) — it selects nothing then, matching the pre-sweep behaviour, instead of colliding on the empty-string sentinel. - FilterChipGroup: count badge now guards on count > 0 (was `!= null`), matching the Tabs badge so a future count:0 can't render a stray "0" pill. - Extract the shared CountBadge component; Tabs and FilterChipGroup now render the count-badge token from one source (was two near-identical inline spans). gate green (tsc/eslint-0/vitest 136/knip/prettier). Duration self-E2E'd: bucket select + Any toggle intact. Branch not merged. --- frontend/src/components/CountBadge.tsx | 15 +++++++++++++++ frontend/src/components/FilterChipGroup.tsx | 11 ++--------- frontend/src/components/PlexSidebar.tsx | 7 ++++++- frontend/src/components/Tabs.tsx | 11 ++--------- 4 files changed, 25 insertions(+), 19 deletions(-) create mode 100644 frontend/src/components/CountBadge.tsx diff --git a/frontend/src/components/CountBadge.tsx b/frontend/src/components/CountBadge.tsx new file mode 100644 index 00000000..a99265bb --- /dev/null +++ b/frontend/src/components/CountBadge.tsx @@ -0,0 +1,15 @@ +// A small count pill shown beside a tab label or filter chip (pending requests, item counts). One +// source for the count-badge token so Tabs and FilterChipGroup can't drift. The `active` variant sits +// on an accent-filled parent (a pressed tab/chip), so it tints against accent-fg; the resting variant +// carries its own accent tint. Callers guard on `count > 0` — this just renders the pill. +export default function CountBadge({ count, active }: { count: number; active?: boolean }) { + return ( + + {count} + + ); +} diff --git a/frontend/src/components/FilterChipGroup.tsx b/frontend/src/components/FilterChipGroup.tsx index e5ae5db6..99bc79d9 100644 --- a/frontend/src/components/FilterChipGroup.tsx +++ b/frontend/src/components/FilterChipGroup.tsx @@ -1,4 +1,5 @@ import { type ReactNode } from "react"; +import CountBadge from "./CountBadge"; // Canonical filter-chip geometry — the rounded-full "Filters bar" look used app-wide for a selectable // filter chip. Exported so single-select groups (this component) AND standalone/multi-select filter @@ -48,15 +49,7 @@ export default function FilterChipGroup({ > {o.icon} {o.label} - {o.count != null && ( - - {o.count} - - )} + {o.count != null && o.count > 0 && } ); })} diff --git a/frontend/src/components/PlexSidebar.tsx b/frontend/src/components/PlexSidebar.tsx index ce96be23..236865cf 100644 --- a/frontend/src/components/PlexSidebar.tsx +++ b/frontend/src/components/PlexSidebar.tsx @@ -373,7 +373,12 @@ export default function PlexSidebar({ layout, setLayout, collapsed, onToggleColl body: ( ({ diff --git a/frontend/src/components/Tabs.tsx b/frontend/src/components/Tabs.tsx index b2480f47..1a2b4841 100644 --- a/frontend/src/components/Tabs.tsx +++ b/frontend/src/components/Tabs.tsx @@ -1,5 +1,6 @@ import { type LucideIcon } from "lucide-react"; import { useAccountPersistedState } from "../lib/storage"; +import CountBadge from "./CountBadge"; // Reusable pill tab-rail for in-page sub-navigation (Configuration, Users & roles, the Settings // sections, the Stats overview/system split…). Horizontal by default; `orientation="vertical"` gives @@ -55,15 +56,7 @@ export default function Tabs({ > {Icon && } {tb.label} - {tb.badge != null && tb.badge > 0 && ( - - {tb.badge} - - )} + {tb.badge != null && tb.badge > 0 && } ); })}