From 93192dadd89d228c8f180a861fd709d076259d4f Mon Sep 17 00:00:00 2001 From: npeter83 Date: Sat, 10 Oct 2026 22:26:22 +0200 Subject: [PATCH] fix(player): a chosen tab's underline and an open or pressed icon read the scope's chosen colour MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The underline named `--color-chosen`, which is resolved once on :root, so it stayed the accent under `media-marks` (seen in the browser: fuchsia on Slate light); it reads `--chosen` where it is used now. An icon button pressed or with its menu open tinted its glyph with the accent; it takes the chosen colour — the accent everywhere but the player chrome, where it is the media amber. --- frontend/src/components/ui/IconButton.tsx | 3 ++- frontend/src/components/ui/Tabs.dom.test.tsx | 5 ++++- frontend/src/components/ui/buttonStyles.ts | 4 ++-- frontend/src/components/ui/mediaChrome.ts | 3 ++- frontend/src/lib/theme.contract.test.ts | 9 +++++++++ 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/ui/IconButton.tsx b/frontend/src/components/ui/IconButton.tsx index 3427c472..94f5eb83 100644 --- a/frontend/src/components/ui/IconButton.tsx +++ b/frontend/src/components/ui/IconButton.tsx @@ -20,7 +20,8 @@ export interface IconButtonProps children: ReactNode; variant?: IconButtonVariant; size?: IconButtonSize; - /** A toggle: sets aria-pressed and tints the glyph with the accent. */ + /** A toggle: sets aria-pressed and tints the glyph with the chosen colour (the accent; the media + * amber on the player chrome). */ pressed?: boolean; /** Not accepted: a toggle is `pressed` (JSX lets any undeclared `aria-*` through, so it is `never`). */ "aria-pressed"?: never; diff --git a/frontend/src/components/ui/Tabs.dom.test.tsx b/frontend/src/components/ui/Tabs.dom.test.tsx index 7e932301..0cc434e7 100644 --- a/frontend/src/components/ui/Tabs.dom.test.tsx +++ b/frontend/src/components/ui/Tabs.dom.test.tsx @@ -68,6 +68,9 @@ describe("Tabs", () => { const on = tab("Alpha").className; expect(on).not.toMatch(/\btext-accent\b/); expect(on).toMatch(/\btext-white\b/); - expect(on).toMatch(/--color-chosen/); + // The scope's own `--chosen`, read where it is used: `--color-chosen` is resolved once on :root + // and would stay the accent under `media-marks`. + expect(on).toMatch(/var\(--chosen,/); + expect(on).not.toMatch(/--color-chosen/); }); }); diff --git a/frontend/src/components/ui/buttonStyles.ts b/frontend/src/components/ui/buttonStyles.ts index 7892826a..d155ee43 100644 --- a/frontend/src/components/ui/buttonStyles.ts +++ b/frontend/src/components/ui/buttonStyles.ts @@ -121,7 +121,7 @@ const ICON_VARIANTS: Record = { // An icon toggle that is on shows it in the glyph (watched, saved, a selected track), not as a solid // fill: a solid accent square in a row of quiet glyphs outshouts the row's primary action. -const ICON_PRESSED = "aria-pressed:text-accent"; +const ICON_PRESSED = "aria-pressed:text-chosen"; const ICON_SIZES: Record = { sm: "size-7 [&>svg]:size-4", @@ -172,7 +172,7 @@ export function iconButtonClass({ pressed?: boolean; }) { return clsx( - "inline-grid shrink-0 place-items-center transition touch-target aria-expanded:text-accent disabled:opacity-50 disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:cursor-not-allowed", + "inline-grid shrink-0 place-items-center transition touch-target aria-expanded:text-chosen disabled:opacity-50 disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:cursor-not-allowed", ICON_VARIANTS[variant], round || variant === "media" ? "rounded-full" : "rounded-lg", pressed !== undefined && ICON_PRESSED, diff --git a/frontend/src/components/ui/mediaChrome.ts b/frontend/src/components/ui/mediaChrome.ts index 8f3ef954..f4a22c9f 100644 --- a/frontend/src/components/ui/mediaChrome.ts +++ b/frontend/src/components/ui/mediaChrome.ts @@ -3,4 +3,5 @@ /** A choice chosen on the chrome (a settings tab, a date style): white on a veil, underlined in the * chosen mark — `media-marks` points it at the media amber, as a light theme's accent is dark there. */ -export const MEDIA_CHOSEN = "bg-white/15 text-white shadow-[inset_0_-2px_0_var(--color-chosen)]"; +export const MEDIA_CHOSEN = + "bg-white/15 text-white shadow-[inset_0_-2px_0_var(--chosen,var(--accent))]"; diff --git a/frontend/src/lib/theme.contract.test.ts b/frontend/src/lib/theme.contract.test.ts index 5e0dc3b3..b48e016e 100644 --- a/frontend/src/lib/theme.contract.test.ts +++ b/frontend/src/lib/theme.contract.test.ts @@ -93,6 +93,15 @@ describe("the media colours", () => { // The tick of a chosen row reads the chosen colour, so a scope can name its own. const check = readFileSync(new URL("../components/ui/MenuCheck.tsx", import.meta.url), "utf8"); expect(check).toMatch(/\btext-chosen\b/); + // So does an icon button that is on or has its menu open (the player's track menu button). + const buttons = readFileSync( + new URL("../components/ui/buttonStyles.ts", import.meta.url), + "utf8", + ); + expect(buttons).toMatch(/aria-pressed:text-chosen/); + expect(buttons).toMatch(/aria-expanded:text-chosen/); + // (A pressed FILLED button keeps the accent fill under its own `text-accent-fg`.) + expect(buttons).not.toMatch(/aria-(pressed|expanded):text-accent(?!-)/); // The player's own components are chrome throughout: nothing chosen there is the accent's text // (a light theme's accent is dark on it — Slate 2.84:1). for (const f of ["PlexPlayer.tsx", "PlexPlayerSettings.tsx", "UpNextCard.tsx"]) {