fix(design): claim audit part 1 — a closing key no longer re-presses its trigger, the Switch box and name, named z-levels (E28)

- In-place editors (Playlists heading + rail rename, Plex collection + playlist rename, PriorityStepper,
  Scheduler interval): a real Enter closed the editor, returned the focus to the trigger, and the same
  keystroke's activation pressed that trigger again - re-opening the editor, or in the rail selecting
  the renamed playlist. useReturnFocus.arm(e) now cancels the key's default (type-enforced); the rail and
  Scheduler editors do the same. The earlier tests dispatched a synthetic keydown, which has no default.
- Plex playlist rename: an unchanged or empty title closes with no write, as the collection rename does.
- Switch: a 36x24 box around the track (the 24 floor), 44 on a coarse pointer; `label` is required, and
  the Plex two-way-sync switch had no name.
- z-index: numeric z-10/z-20 and a literal 40 moved onto the named layer scale; a lint rule + contract.
- The /watch file card's Download is the filled primary: the page's one action.
- Stale comments: the 1024x768 floor, the retired glass tuner.
This commit is contained in:
2026-09-25 02:25:54 +02:00
parent b4a6569d0d
commit 0521149cf1
25 changed files with 227 additions and 41 deletions
+14 -8
View File
@@ -6,8 +6,10 @@ import { SURFACE } from "./surfaces";
// Shared form/settings primitives, factored out of the many panels that each re-declared
// them (Settings, Config, Stats, admin pages, Setup wizard). Visual contract unchanged.
/** Pill on/off switch — the bare control; compose it with your own label/row. Pass `label` for
* the accessible name (the visible row text) since the control itself has no inner text. */
/** Pill on/off switch — the bare control; compose it with your own label/row. `label` is the
* accessible name (the visible row text), required: the control has no inner text to be named by.
* The button is its own box around the 36×20 track: 24 tall on a mouse (the B1 floor) and the 44
* touch target on a coarse pointer (A3), a real box rather than an invisible hit area. */
export function Switch({
checked,
onChange,
@@ -16,7 +18,7 @@ export function Switch({
}: {
checked: boolean;
onChange: (v: boolean) => void;
label?: string;
label: string;
disabled?: boolean;
}) {
// FocusSafeButton: a switch is disabled by its caller while the change it made is saving, and a
@@ -29,13 +31,17 @@ export function Switch({
aria-label={label}
disabled={disabled}
onClick={() => onChange(!checked)}
className={`w-9 h-5 rounded-full transition relative shrink-0 disabled:opacity-50 disabled:cursor-not-allowed ${checked ? "bg-accent" : "bg-border"}`}
className="group inline-flex h-6 min-w-9 shrink-0 items-center justify-center rounded-full disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:min-h-(--touch-target) pointer-coarse:min-w-(--touch-target)"
>
<span
className={`absolute top-0.5 w-4 h-4 rounded-full shadow transition-all ${
checked ? "left-4.5 bg-accent-fg" : "left-0.5 bg-white"
}`}
/>
className={`relative h-5 w-9 rounded-full transition ${checked ? "bg-accent" : "bg-border"}`}
>
<span
className={`absolute top-0.5 w-4 h-4 rounded-full shadow transition-all ${
checked ? "left-4.5 bg-accent-fg" : "left-0.5 bg-white"
}`}
/>
</span>
</FocusSafeButton>
);
}