feat(design): glass surfaces by role, the static Badge, LinkButton, user pickers on the Combobox (E28 S3d1)

This commit is contained in:
2026-09-25 00:34:35 +02:00
parent db10bfbbca
commit c47c193ad1
89 changed files with 818 additions and 478 deletions
+28 -23
View File
@@ -4,7 +4,6 @@ import {
BarChart3,
Bell,
Check,
ChevronDown,
Clapperboard,
Download,
Home,
@@ -25,6 +24,8 @@ import { hexContrast, hueGap } from "../lib/colorMath";
import { Reference, Sample } from "./labKit";
import { FADE_ABOVE_PANEL, FADE_BELOW, FADE_BELOW_PANEL, FILLED, H, LAYER } from "./labTokens";
import { Chip } from "../components/ui/Chip";
import { SURFACE } from "../components/ui/surfaces";
import { SelectTrigger } from "../components/ui/SelectTrigger";
// E28 S2 · Batch B — surfaces, chrome and colour, DECIDED (owner, 2026-09-24): every recommendation,
// except B7, where the owner combined the soft tint + edge bar with optional labels. B1 (density) and
@@ -157,7 +158,7 @@ function Cards() {
return (
<div className="grid grid-cols-3 gap-2 p-3">
{Array.from({ length: 12 }, (_, i) => (
<div key={i} className="glass-card flex flex-col gap-1 rounded-xl p-1.5">
<div key={i} className={`${SURFACE.card} flex flex-col gap-1 p-1.5`}>
<div className="aspect-video rounded-lg bg-linear-to-br from-accent/40 to-card" />
<span className="truncate text-2xs">Video title number {i + 1}</span>
<span className="text-3xs text-muted">Channel · 2 days ago</span>
@@ -172,10 +173,6 @@ const tab = (on: boolean) =>
"rounded-lg px-2.5 py-1 text-xs",
on ? "bg-accent text-accent-fg" : clsx("text-muted hover:text-fg", LAYER),
);
const pillCtl = clsx(
"glass-card inline-flex items-center gap-1 rounded-full border px-2.5 text-xs",
H.bar,
);
function Tabs() {
return (
@@ -193,17 +190,25 @@ function Band({ collapsed }: { collapsed?: boolean }) {
<div className="flex items-center justify-between gap-2">
<Tabs />
{collapsed && (
<span className={pillCtl}>
<SlidersHorizontal className="h-3 w-3" /> Filters · 3
</span>
<SelectTrigger
context="toolbar"
open={false}
icon={<SlidersHorizontal className="size-3.5 shrink-0 text-muted" />}
>
Filters · 3
</SelectTrigger>
)}
</div>
{!collapsed && (
<div className="flex flex-wrap gap-1.5">
{["State: Unwatched", "Date: Any", "Sort: Newest"].map((f) => (
<span key={f} className={pillCtl}>
{f} <ChevronDown className="h-3 w-3 text-muted" />
</span>
{[
["State", "Unwatched"],
["Date", "Any"],
["Sort", "Newest"],
].map(([k, v]) => (
<SelectTrigger key={k} context="toolbar" open={false} label={k}>
{v}
</SelectTrigger>
))}
</div>
)}
@@ -215,22 +220,22 @@ function Band({ collapsed }: { collapsed?: boolean }) {
function Surfaces() {
return (
<div className="flex flex-col gap-3 rounded-xl bg-linear-to-br from-accent/35 via-card to-bg p-3">
<div className="glass flex flex-col gap-2 rounded-2xl p-3">
<div className={`${SURFACE.panel} flex flex-col gap-2 p-3`}>
<span className="text-sm font-semibold">Dialog · .glass r16</span>
<div className="grid grid-cols-2 gap-2">
<div className="glass-card rounded-xl p-2 text-xs">Card · r12</div>
<div className="glass-card rounded-xl p-2 text-xs">Picker · r12</div>
<div className={`${SURFACE.card} p-2 text-xs`}>Card · r12</div>
<div className={`${SURFACE.card} p-2 text-xs`}>Picker · r12</div>
</div>
</div>
<div className="flex items-start gap-3">
<div className="glass-menu flex w-44 flex-col rounded-xl p-1 text-xs">
<div className={`${SURFACE.menu} flex w-44 flex-col text-xs`}>
{["Watch later", "Add to playlist", "Copy link"].map((t) => (
<span key={t} className={clsx("flex h-7 items-center rounded-lg px-2", LAYER)}>
{t}
</span>
))}
</div>
<span className="glass-menu rounded-lg px-2 py-1 text-2xs">Tooltip · .glass-menu r8</span>
<span className={`${SURFACE.tooltip} px-2 py-1 text-2xs`}>Tooltip · .glass-menu r8</span>
</div>
</div>
);
@@ -247,7 +252,7 @@ function WatchPage() {
<div className="grid aspect-video place-items-center rounded-xl border border-border bg-black text-2xs text-white/60">
the browser&apos;s own video controls
</div>
<div className="glass flex flex-wrap items-start gap-2 rounded-2xl p-3">
<div className={`${SURFACE.panel} flex flex-wrap items-start gap-2 p-3`}>
<div className="min-w-0 flex-1 basis-40">
<div className="text-sm font-semibold">Building a home lab on a budget</div>
<div className="text-xs text-muted">Techno Tim</div>
@@ -333,7 +338,7 @@ function Rail({ lang }: { lang?: "en" | "hu" }) {
<div className="flex flex-col items-start gap-1.5">
<div
ref={ref}
className="glass flex w-15 flex-col items-center gap-0.5 rounded-2xl px-1 py-2.5"
className={`${SURFACE.panel} flex w-15 flex-col items-center gap-0.5 px-1 py-2.5`}
>
{NAV.map((d, i) => (
<RailItem key={d.en} d={d} on={i === 1} lang={lang} />
@@ -361,7 +366,7 @@ function Loading() {
<Sample label="A grid, first load: its skeleton (after ~300ms)">
<div className="grid max-w-md grid-cols-3 gap-2">
{Array.from({ length: 3 }, (_, i) => (
<div key={i} className="glass-card flex flex-col gap-1.5 rounded-xl p-1.5">
<div key={i} className={`${SURFACE.card} flex flex-col gap-1.5 p-1.5`}>
<div className={clsx("aspect-video rounded-lg", bone)} />
<div className={clsx("h-2 w-4/5", bone)} />
<div className={clsx("h-2 w-1/2", bone)} />
@@ -413,7 +418,7 @@ function Fades() {
<ScrollBody />
</Frame>
<Sample label="2 · Tabs over a scrolling panel">
<div className="glass relative flex h-44 flex-col overflow-hidden rounded-2xl">
<div className={`${SURFACE.panel} relative flex h-44 flex-col overflow-hidden`}>
<div className={clsx("relative z-base px-3 pb-2 pt-3", FADE_BELOW_PANEL)}>
<Tabs />
</div>
@@ -423,7 +428,7 @@ function Fades() {
</div>
</Sample>
<Sample label="3 · A dialog's header and footer">
<div className="glass relative flex h-44 flex-col overflow-hidden rounded-2xl">
<div className={`${SURFACE.panel} relative flex h-44 flex-col overflow-hidden`}>
<div
className={clsx(
"relative z-base flex items-center gap-2 px-3 py-2 text-sm font-semibold",