fix(design): the lab draws with the primitives' own classes, not a height-ladder copy; DESIGN no longer claims accent-color tints the colour well (E28)

This commit is contained in:
2026-09-25 17:15:03 +02:00
parent e13d93a3ed
commit 29abf609f3
4 changed files with 22 additions and 27 deletions
+2 -1
View File
@@ -143,7 +143,8 @@ The chosen rendering of each rule is in the lab under "Decided". The primitives
choice"), r8 and full width in a form, where it wears the field's frame (see-through, the ≥ 3:1 edge) and choice"), r8 and full width in a form, where it wears the field's frame (see-through, the ≥ 3:1 edge) and
lines up with the inputs. Open is the accent edge and the chevron turned over. lines up with the inputs. Open is the accent edge and the chevron turned over.
- **Checkbox, switch, slider (A6):** the browser's own controls tinted with `accent-color` (`Checkbox`, - **Checkbox, switch, slider (A6):** the browser's own controls tinted with `accent-color` (`Checkbox`,
`CheckRow`, `Slider`, `ColorInput`); the whole labelled row is the 44px target. Keyboard, screen reader and `CheckRow`, `Slider`); `ColorInput` is the browser's colour well, which `accent-color` does not reach (it
tints only checkboxes, radios, ranges and progress bars). The whole labelled row is the 44px target. Keyboard, screen reader and
forced-colours support come from the browser. The switch stays `form`'s `Switch`: no browser has a native forced-colours support come from the browser. The switch stays `form`'s `Switch`: no browser has a native
one yet. A raw `<input>` or `<textarea>` outside those primitives is a lint error (a hidden file picker one yet. A raw `<input>` or `<textarea>` outside those primitives is a lint error (a hidden file picker
passes). passes).
+13 -9
View File
@@ -23,8 +23,13 @@ import {
import { Btn } from "./batchA"; import { Btn } from "./batchA";
import { C1 } from "./batchCActions"; import { C1 } from "./batchCActions";
import { Reference, Sample } from "./labKit"; import { Reference, Sample } from "./labKit";
import { FADE_ABOVE_PANEL, FADE_BELOW_PANEL, H, LAYER, STRONG } from "./labTokens"; import { FADE_ABOVE_PANEL, FADE_BELOW_PANEL, LAYER } from "./labTokens";
import { SURFACE } from "../components/ui/surfaces"; import { SURFACE } from "../components/ui/surfaces";
import { iconButtonClass } from "../components/ui/buttonStyles";
import { fieldClass } from "../components/ui/fieldStyles";
// The ui/ primitives' own classes on static spans: the lab draws what the app ships, not a copy.
const ICON = iconButtonClass({ variant: "ghost", size: "sm" });
// E28 S2 · Batch C — behaviour on touch and on a narrow window, DECIDED (owner, 2026-09-24): C1–C4 as // E28 S2 · Batch C — behaviour on touch and on a narrow window, DECIDED (owner, 2026-09-24): C1–C4 as
// proposed; C5 is the owner's reworked Plex control set (found by the live player pass, E28 S2d: the // proposed; C5 is the owner's reworked Plex control set (found by the live player pass, E28 S2d: the
@@ -61,10 +66,10 @@ function FilterPanel() {
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<span className="font-semibold">Filters</span> <span className="font-semibold">Filters</span>
<span className="flex gap-0.5"> <span className="flex gap-0.5">
<span className={clsx("grid place-items-center rounded-lg text-muted", H.iconSm, LAYER)}> <span className={ICON}>
<Pin className="h-3.5 w-3.5" /> <Pin className="h-3.5 w-3.5" />
</span> </span>
<span className={clsx("grid place-items-center rounded-lg text-muted", H.iconSm, LAYER)}> <span className={ICON}>
<X className="h-3.5 w-3.5" /> <X className="h-3.5 w-3.5" />
</span> </span>
</span> </span>
@@ -144,12 +149,11 @@ function Field({ label, value, focused }: { label: string; value: string; focuse
<span className="font-medium">{label}</span> <span className="font-medium">{label}</span>
<span <span
className={clsx( className={clsx(
// eslint-disable-next-line no-restricted-syntax -- a drawing of a field, not a label fieldClass({ size: "md" }),
"flex items-center rounded-lg border px-3 text-sm", "flex items-center",
H.field, // The primitive's focus-within look, drawn: a mock span can hold no focus.
focused && "ring-2 ring-accent", focused && "border-accent ring-1 ring-accent",
)} )}
style={{ borderColor: STRONG }}
> >
{value} {value}
</span> </span>
@@ -173,7 +177,7 @@ function C4() {
)} )}
> >
Edit details Edit details
<span className={clsx("grid place-items-center rounded-lg text-muted", H.iconSm)}> <span className={ICON}>
<X className={ico} /> <X className={ico} />
</span> </span>
</div> </div>
+5 -5
View File
@@ -1,7 +1,8 @@
import clsx from "clsx"; import clsx from "clsx";
import { Bookmark, Check, ListPlus, MoreHorizontal, Play } from "lucide-react"; import { Bookmark, Check, ListPlus, MoreHorizontal, Play } from "lucide-react";
import { Reference, Sample } from "./labKit"; import { Reference, Sample } from "./labKit";
import { H, LAYER } from "./labTokens"; import { LAYER } from "./labTokens";
import { iconButtonClass } from "../components/ui/buttonStyles";
import { SURFACE } from "../components/ui/surfaces"; import { SURFACE } from "../components/ui/surfaces";
// E28 S2 · Batch C, part 1 — action placement: the classification table (object × action → where it // E28 S2 · Batch C, part 1 — action placement: the classification table (object × action → where it
@@ -312,10 +313,9 @@ function Table() {
} }
function Card({ touch }: { touch: boolean }) { function Card({ touch }: { touch: boolean }) {
const act = clsx( // The IconButton `media` face (a dark button on a picture); the touch rendering shows the 44 box
"grid place-items-center rounded-lg bg-black/55 text-white", // that a coarse pointer gives it (A3).
touch ? "h-11 w-11" : H.iconSm, const act = clsx(iconButtonClass({ variant: "media", size: "sm" }), touch && "size-11");
);
return ( return (
<div className={`${SURFACE.card} group flex w-60 flex-col gap-1.5 p-1.5`}> <div className={`${SURFACE.card} group flex w-60 flex-col gap-1.5 p-1.5`}>
<div className="relative aspect-video overflow-hidden rounded-lg bg-linear-to-br from-accent/50 to-card"> <div className="relative aspect-video overflow-hidden rounded-lg bg-linear-to-br from-accent/50 to-card">
+2 -12
View File
@@ -1,17 +1,7 @@
// The decided values the lab's reference renderings share (batches A and B, 2026-09-24). The colour // The decided values the lab's reference renderings share (batches A and B, 2026-09-24). The colour
// rules are real now (E28 S3a): each constant below names the index.css utility or token that holds // rules are real now (E28 S3a): each constant below names the index.css utility or token that holds
// it, so the lab renders what the app ships. The height ladder moves into ui/Button in S3b. // it, so the lab renders what the app ships. The height ladder lives in the primitives (ui/buttonStyles,
// ui/fieldStyles), and a lab drawing takes their classes (F31).
/** B1 compact ladder: explicit heights, so one toolbar row lines up at 28. */
export const H = {
md: "h-8 px-3 text-sm gap-1.5",
sm: "h-7 px-2.5 text-sm gap-1.5",
xs: "h-6 px-2 text-xs gap-1",
iconSm: "w-7 h-7",
icon: "w-8 h-8",
field: "h-8",
bar: "h-7",
} as const;
/** A4: the input edge, ≥ 3:1 against the page in every scheme and mode (index.css --edge-strong). */ /** A4: the input edge, ≥ 3:1 against the page in every scheme and mode (index.css --edge-strong). */
export const STRONG = "var(--edge-strong)"; export const STRONG = "var(--edge-strong)";