fix(player): a chosen tab's underline and an open or pressed icon read the scope's chosen colour
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.
This commit is contained in:
@@ -20,7 +20,8 @@ export interface IconButtonProps
|
|||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
variant?: IconButtonVariant;
|
variant?: IconButtonVariant;
|
||||||
size?: IconButtonSize;
|
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;
|
pressed?: boolean;
|
||||||
/** Not accepted: a toggle is `pressed` (JSX lets any undeclared `aria-*` through, so it is `never`). */
|
/** Not accepted: a toggle is `pressed` (JSX lets any undeclared `aria-*` through, so it is `never`). */
|
||||||
"aria-pressed"?: never;
|
"aria-pressed"?: never;
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ describe("Tabs", () => {
|
|||||||
const on = tab("Alpha").className;
|
const on = tab("Alpha").className;
|
||||||
expect(on).not.toMatch(/\btext-accent\b/);
|
expect(on).not.toMatch(/\btext-accent\b/);
|
||||||
expect(on).toMatch(/\btext-white\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/);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ const ICON_VARIANTS: Record<IconButtonVariant, string> = {
|
|||||||
|
|
||||||
// An icon toggle that is on shows it in the glyph (watched, saved, a selected track), not as a solid
|
// 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.
|
// 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<IconButtonSize, string> = {
|
const ICON_SIZES: Record<IconButtonSize, string> = {
|
||||||
sm: "size-7 [&>svg]:size-4",
|
sm: "size-7 [&>svg]:size-4",
|
||||||
@@ -172,7 +172,7 @@ export function iconButtonClass({
|
|||||||
pressed?: boolean;
|
pressed?: boolean;
|
||||||
}) {
|
}) {
|
||||||
return clsx(
|
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],
|
ICON_VARIANTS[variant],
|
||||||
round || variant === "media" ? "rounded-full" : "rounded-lg",
|
round || variant === "media" ? "rounded-full" : "rounded-lg",
|
||||||
pressed !== undefined && ICON_PRESSED,
|
pressed !== undefined && ICON_PRESSED,
|
||||||
|
|||||||
@@ -3,4 +3,5 @@
|
|||||||
|
|
||||||
/** A choice chosen on the chrome (a settings tab, a date style): white on a veil, underlined in the
|
/** 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. */
|
* 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))]";
|
||||||
|
|||||||
@@ -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.
|
// 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");
|
const check = readFileSync(new URL("../components/ui/MenuCheck.tsx", import.meta.url), "utf8");
|
||||||
expect(check).toMatch(/\btext-chosen\b/);
|
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
|
// 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).
|
// (a light theme's accent is dark on it — Slate 2.84:1).
|
||||||
for (const f of ["PlexPlayer.tsx", "PlexPlayerSettings.tsx", "UpNextCard.tsx"]) {
|
for (const f of ["PlexPlayer.tsx", "PlexPlayerSettings.tsx", "UpNextCard.tsx"]) {
|
||||||
|
|||||||
Reference in New Issue
Block a user