feat(design): the field family, the dropdown trigger, native controls, the no-raw-input lint rule (E28 S3c)

- ui/Input, Textarea, InnerInput + fieldClass (A4): the >= 3:1 edge, a 2px accent
  focus edge, the danger edge for invalid, md/sm/xs/heading rungs, 1rem and 44 on touch
- ui/SelectTrigger (A5): SortControl, FilterSelect, the view switcher and the date
  filter on one trigger, a pill in a toolbar, r8 in a form
- ui/NativeControls (A6): Checkbox, CheckRow, Slider, ColorInput
- every raw input swept (~100 sites); inputCls retired; local/input-primitive
- useReturnFocus: an in-place editor hands the focus back to its trigger on
  Enter/Escape (the playlist and Plex title renames, the priority number);
  the Plex playlist rename gains Escape and an accessible name
- back to top: a round 48 FAB (owner decision); DESIGN.md A2 and the log
This commit is contained in:
2026-09-24 23:48:22 +02:00
parent 81936e9f56
commit dac9d89f91
63 changed files with 923 additions and 416 deletions
+9 -10
View File
@@ -28,6 +28,7 @@ import Tooltip from "./ui/Tooltip";
import { notifyActionError } from "../lib/actionErrors";
import { IconButton } from "./ui/IconButton";
import { Pressable } from "./ui/Pressable";
import { Input } from "./ui/Input";
const POLL_MS = 4000;
// While any job is running, poll faster so short scheduled runs aren't missed between ticks.
@@ -181,7 +182,10 @@ function JobRow({
</Tooltip>
{editing ? (
<span className="inline-flex items-center gap-1">
<input
<Input
className="w-16"
size="xs"
invalid={!valid}
type="number"
min={1}
max={1440}
@@ -194,11 +198,6 @@ function JobRow({
if (e.key === "Enter") save();
if (e.key === "Escape") close();
}}
className={`w-16 bg-surface border rounded-sm px-1.5 py-0.5 text-xs focus:outline-hidden focus:ring-2 ${
valid
? "border-border focus:ring-accent/40"
: "border-danger focus:ring-danger/40"
}`}
/>
<span className="text-muted text-xs">{t("scheduler.minutes")}</span>
<IconButton onClick={save} disabled={saving || !valid} label={t("common.save")}>
@@ -306,7 +305,10 @@ function MaintenanceSettings({
</span>
</Tooltip>
<span className="flex-1" />
<input
<Input
className="w-28 tabular-nums"
size="sm"
invalid={!valid}
type="number"
min={m.min}
max={m.max}
@@ -320,9 +322,6 @@ function MaintenanceSettings({
aria-label={t("scheduler.maintenance.batchLabel")}
aria-invalid={!valid}
aria-errormessage={valid ? undefined : rangeId}
className={`w-28 bg-surface border rounded-sm px-2 py-1 text-sm tabular-nums focus:outline-hidden focus:ring-2 ${
valid ? "border-border focus:ring-accent/40" : "border-danger focus:ring-danger/40"
}`}
/>
<Button variant="glass" size="sm" onClick={save} disabled={!dirty || saving || !valid}>
{t("common.save")}