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:
2026-09-24 23:03:23 +02:00
parent 86f467bd65
commit 81936e9f56
94 changed files with 1327 additions and 1093 deletions
+3 -7
View File
@@ -109,11 +109,7 @@ function Actions({
// overlay for the thumbnailed views, and inline beside the actions for the one-line row.
const INFO_REVEAL =
"reveal-hover opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100 transition-opacity";
const INFO_OVERLAY = clsx(
INFO_REVEAL,
"absolute bottom-1.5 left-1.5 z-10 rounded-md bg-black/70 p-1 text-white hover:bg-black/85",
);
const INFO_INLINE = clsx(INFO_REVEAL, "rounded-md p-1.5 text-muted hover:bg-surface hover:text-fg");
const INFO_OVERLAY = clsx(INFO_REVEAL, "absolute bottom-1.5 left-1.5 z-10");
// Plain left-click opens the in-app player (the experiment); Ctrl/Cmd/middle-click
// keep the native "open youtube.com in a new tab" behavior via the underlying href.
@@ -339,7 +335,7 @@ function Thumb({
{/* Hover infobox trigger (E8·S3), docked bottom-left so it clears the centered play overlay, the
corner badges (saved / stream, top corners) and the duration (bottom-right). Revealed with the
rest of the hover chrome, dropped on touch. */}
<VideoInfoCard video={video} className={INFO_OVERLAY} />
<VideoInfoCard video={video} onMedia className={INFO_OVERLAY} />
{/* Resume progress bar (sits at the very bottom, under the duration badge). */}
{pct > 0 && (
<div className="absolute bottom-0 left-0 right-0 h-1 bg-black/40">
@@ -559,7 +555,7 @@ function VideoCard({
budget). ROW_COL.actions already counts its width. */}
<div className="shrink-0 flex items-center gap-1">
<div className="w-48">{actions}</div>
<VideoInfoCard video={video} className={INFO_INLINE} />
<VideoInfoCard video={video} className={INFO_REVEAL} />
</div>
{/* Everything else is shrink-0, so the title is the only thing that can give — which means
once the fixed columns outgrow the row, it gives ALL of it and vanishes. Columns drop