feat(design): every button on its family, the chip primitive, the lint rule (E28 S3b2)
The second half of the button sweep: the remaining hand-rolled buttons in
feature components, the design lab and the components/ui composites now
stand on Button, IconButton, Pressable, Chip or DragHandle.
- Chip + DismissibleChip (filter / token / tag / suggest / ghost, 24px
floor, 44 on touch) replace five chip geometries; FilterChipGroup
renders Chips; overflow lanes measure a mirror painted by chipClass.
- The Plex control row is IconButton's player rung (36, 20px glyph,
round, overlay; 44 on touch); the YT modal bar is on the sm rung with
pressed cycle toggles and names that survive a folded label.
- New variants: IconButton ghost-accent, danger-soft; Button warn on a
new state-warn utility. The .btn-{tone} recipes and btnCls are gone.
- Fixed on the way: membership rows (collection editor, Plex playlist
add) announce checked/mixed; a one-letter tag chip was 21px wide;
descriptionLinks moved out of lib/ (it renders components).
- local/button-primitive: a raw <button>/<FocusSafeButton> outside the
control-primitive files is a lint error (contract-tested, seen red).
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import { useLayoutEffect, useState } from "react";
|
||||
import clsx from "clsx";
|
||||
import { SCHEMES, type Scheme } from "../lib/theme";
|
||||
import { BatchA } from "./batchA";
|
||||
import { BatchB } from "./batchB";
|
||||
import { BatchC } from "./batchC";
|
||||
import { Chip } from "../components/ui/Chip";
|
||||
|
||||
// The design lab (E28): the living style guide. Dev-only — see main.tsx and devOnlyGuard.ts. It sits
|
||||
// OUTSIDE <App>, so it owns the theme attributes on <html> itself, through the same data-theme /
|
||||
@@ -23,12 +23,6 @@ function applyLook(l: Look) {
|
||||
el.style.setProperty("--font-scale", String(l.fontScale));
|
||||
}
|
||||
|
||||
const chip = (on: boolean) =>
|
||||
clsx(
|
||||
"inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs transition",
|
||||
on ? "border-accent bg-accent text-accent-fg" : "border-border text-muted hover:text-fg",
|
||||
);
|
||||
|
||||
export default function DesignLab() {
|
||||
const [look, setLook] = useState<Look>(START);
|
||||
useLayoutEffect(() => {
|
||||
@@ -47,36 +41,22 @@ export default function DesignLab() {
|
||||
<strong className="text-sm">Design lab</strong>
|
||||
<span className="flex gap-1">
|
||||
{(["dark", "light"] as const).map((m) => (
|
||||
<button
|
||||
key={m}
|
||||
type="button"
|
||||
className={chip(look.mode === m)}
|
||||
onClick={() => set({ mode: m })}
|
||||
>
|
||||
<Chip key={m} pressed={look.mode === m} onClick={() => set({ mode: m })}>
|
||||
{m}
|
||||
</button>
|
||||
</Chip>
|
||||
))}
|
||||
</span>
|
||||
<span className="flex flex-wrap gap-1">
|
||||
{SCHEMES.map((s) => (
|
||||
<button
|
||||
key={s.id}
|
||||
type="button"
|
||||
className={chip(look.scheme === s.id)}
|
||||
onClick={() => set({ scheme: s.id })}
|
||||
>
|
||||
<Chip key={s.id} pressed={look.scheme === s.id} onClick={() => set({ scheme: s.id })}>
|
||||
<span className="h-2.5 w-2.5 rounded-full" style={{ background: s.swatch }} />
|
||||
{s.name}
|
||||
</button>
|
||||
</Chip>
|
||||
))}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
className={chip(look.backdrop)}
|
||||
onClick={() => set({ backdrop: !look.backdrop })}
|
||||
>
|
||||
<Chip pressed={look.backdrop} onClick={() => set({ backdrop: !look.backdrop })}>
|
||||
backdrop
|
||||
</button>
|
||||
</Chip>
|
||||
<label className="flex items-center gap-2 text-xs text-muted">
|
||||
text {look.fontScale.toFixed(2)}
|
||||
<input
|
||||
|
||||
Reference in New Issue
Block a user