A light theme's accent as text on the always-dark chrome was 2.84:1 (Slate). `--chosen` is the accent unless a scope names its own; `media-marks` (was media-focus) points it, with the focus ring, at the media amber. A chosen track stays white with an amber tick (MenuCheck reads `text-chosen`); a chosen settings tab or toggle is white with an amber underline (MEDIA_CHOSEN). The theme contract test holds the token, the tick and the player components free of accent text.
30 lines
1.3 KiB
TypeScript
30 lines
1.3 KiB
TypeScript
import { Check, Minus } from "lucide-react";
|
|
|
|
// The ONE drawn check of a checkable row that cannot hold the browser's own checkbox (A6) — a menu
|
|
// row, or a whole-row button whose `role` says checkbox: an `<input>` inside a `<button>` is invalid
|
|
// nesting. It sits in the row's leading icon slot, so every label in a list starts at the same x.
|
|
// - `many`: one of a set that can all be on (tags, playlists, a filter's values) — a box, filled
|
|
// with the accent when on; `mixed` for a group only partly in (a Plex show's episodes).
|
|
// - `one`: one choice of several (a language, a sort, a priority step) — a bare tick; an unticked
|
|
// choice keeps the slot empty.
|
|
// Decorative: the row carries the state (`aria-checked` on its menuitemcheckbox / radio / checkbox).
|
|
export function MenuCheck({ kind, on }: { kind: "many" | "one"; on: boolean | "mixed" }) {
|
|
if (kind === "one")
|
|
return (
|
|
<Check
|
|
aria-hidden="true"
|
|
className={`size-4 shrink-0 ${on === true ? "text-chosen" : "opacity-0"}`}
|
|
/>
|
|
);
|
|
return (
|
|
<span
|
|
aria-hidden="true"
|
|
className={`grid size-4 shrink-0 place-items-center rounded border ${
|
|
on ? "border-accent bg-accent text-accent-fg" : "border-border"
|
|
}`}
|
|
>
|
|
{on === "mixed" ? <Minus className="size-3" /> : on && <Check className="size-3" />}
|
|
</span>
|
|
);
|
|
}
|