design(files): the one-library round in the lab — aligned list columns, the tray, the done notice
The Files page replaces the Downloads page: list rows with one column per value kind and a right-click menu, an app-wide download tray, a done notice that copies the link. Picked variants are logged in DESIGN.md.
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import { useSyncExternalStore, type ReactNode } from "react";
|
||||
import clsx from "clsx";
|
||||
import { Badge } from "../components/ui/Badge";
|
||||
import { SURFACE } from "../components/ui/surfaces";
|
||||
|
||||
// Building blocks of the design lab. Every decision is taken, so the lab is the reference half
|
||||
// only: each <Reference> is the chosen rendering with the rule it became. A new design round brings
|
||||
// back the side-by-side <Decision>/<Variant> pair (as before) for its open questions. Everything
|
||||
// Building blocks of the design lab. A taken decision is a <Reference>: the chosen rendering with the
|
||||
// rule it became. An open design round shows its questions as <Decision>s with their <Variant>s side
|
||||
// by side, until the owner picks. Everything
|
||||
// is static markup on purpose: a rendering that only exists here must not need app state.
|
||||
|
||||
/** A decision already taken: the chosen rendering only, with the rule it became. The lab's
|
||||
@@ -36,6 +37,76 @@ export function Reference({
|
||||
);
|
||||
}
|
||||
|
||||
/** An open question of a design round: what the app does today, then the variants side by side. */
|
||||
export function Decision({
|
||||
id,
|
||||
code,
|
||||
title,
|
||||
question,
|
||||
now,
|
||||
children,
|
||||
}: {
|
||||
id: string;
|
||||
code: string;
|
||||
title: string;
|
||||
question: string;
|
||||
/** What the app does today. */
|
||||
now: ReactNode;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<section id={id} className={`${SURFACE.panel} p-5 scroll-mt-20`}>
|
||||
<header className="mb-4">
|
||||
<div className="flex items-baseline gap-3">
|
||||
<span className="text-xs font-bold tracking-widest text-accent">{code}</span>
|
||||
<h3 className="text-lg font-bold">{title}</h3>
|
||||
</div>
|
||||
<p className="mt-1 text-sm">{question}</p>
|
||||
<p className="mt-1 text-xs text-muted">
|
||||
<span className="font-semibold">Today: </span>
|
||||
{now}
|
||||
</p>
|
||||
</header>
|
||||
<div className="flex flex-col gap-4">{children}</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
/** One answer to a Decision; the recommended one carries the accent edge. */
|
||||
export function Variant({
|
||||
letter,
|
||||
name,
|
||||
recommended = false,
|
||||
why,
|
||||
children,
|
||||
}: {
|
||||
letter: string;
|
||||
name: string;
|
||||
recommended?: boolean;
|
||||
why: string;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<article
|
||||
className={clsx(
|
||||
SURFACE.card,
|
||||
"flex flex-col gap-3 border p-4",
|
||||
recommended ? "border-accent" : "border-transparent",
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="grid h-6 w-6 place-items-center rounded-full bg-fg/8 text-xs font-bold">
|
||||
{letter}
|
||||
</span>
|
||||
<h4 className="flex-1 text-sm font-semibold">{name}</h4>
|
||||
{recommended && <Badge tone="accent">Recommended</Badge>}
|
||||
</div>
|
||||
<div className="flex flex-col gap-3">{children}</div>
|
||||
<p className="mt-auto border-t border-border/60 pt-2 text-xs text-muted">{why}</p>
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
/** A small caption above a sample inside a variant. */
|
||||
export function Sample({ label, children }: { label: string; children: ReactNode }) {
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user