43 lines
1.4 KiB
TypeScript
43 lines
1.4 KiB
TypeScript
import clsx from "clsx";
|
|
import type { ReactNode } from "react";
|
|
|
|
// A static label (a topic, a keyword, a genre, a status): flat and tonal, with NO edge (owner, E28 S3d).
|
|
// Every chip that does something has an edge, so "edged = pressable, flat = just says" holds at a
|
|
// glance; a static tag painted like a chip is clicked and does nothing. The tint is the text colour
|
|
// at 8%, so it reads on the dark schemes and on white alike; `onDark` is the always-dark player's. A
|
|
// `tone` says which kind of label it is (a role, a state to notice): its own colour at 6%, the most
|
|
// that keeps its text at 4.5:1 on light (theme.contract.test.ts measures all three in every scheme).
|
|
const TONES = {
|
|
neutral: "bg-fg/8 text-muted",
|
|
accent: "bg-accent/6 text-accent",
|
|
warn: "bg-warn/6 text-warn",
|
|
} as const;
|
|
|
|
export function Badge({
|
|
tone = "neutral",
|
|
onDark = false,
|
|
title,
|
|
className,
|
|
children,
|
|
}: {
|
|
tone?: keyof typeof TONES;
|
|
onDark?: boolean;
|
|
title?: string;
|
|
/** Layout only (margin); the paint is the primitive's. */
|
|
className?: string;
|
|
children: ReactNode;
|
|
}) {
|
|
return (
|
|
<span
|
|
title={title}
|
|
className={clsx(
|
|
"inline-flex h-5 max-w-full shrink-0 items-center gap-1 truncate rounded-full px-2 text-xs whitespace-nowrap [&>svg]:size-3 [&>svg]:shrink-0",
|
|
onDark ? "bg-white/10 text-white/90" : TONES[tone],
|
|
className,
|
|
)}
|
|
>
|
|
{children}
|
|
</span>
|
|
);
|
|
}
|