web/app/components/ui/badge.tsxblame
View source
4dfd09b1const presets: Record<string, { bg: string; text: string; border: string }> = {
4dfd09b2 open: {
bf6031c3 bg: "var(--status-open-bg)",
bf6031c4 text: "var(--status-open-text)",
bf6031c5 border: "var(--status-open-border)",
4dfd09b6 },
4dfd09b7 active: {
bf6031c8 bg: "var(--status-open-bg)",
bf6031c9 text: "var(--status-open-text)",
bf6031c10 border: "var(--status-open-border)",
4dfd09b11 },
4dfd09b12 running: {
bf6031c13 bg: "var(--status-merged-bg)",
bf6031c14 text: "var(--status-merged-text)",
bf6031c15 border: "var(--status-merged-border)",
4dfd09b16 },
4dfd09b17 merged: {
bf6031c18 bg: "var(--status-merged-bg)",
bf6031c19 text: "var(--status-merged-text)",
bf6031c20 border: "var(--status-merged-border)",
4dfd09b21 },
4dfd09b22 creating: {
bf6031c23 bg: "var(--status-merged-bg)",
bf6031c24 text: "var(--status-merged-text)",
bf6031c25 border: "var(--status-merged-border)",
4dfd09b26 },
4dfd09b27 passed: {
bf6031c28 bg: "var(--status-open-bg)",
bf6031c29 text: "var(--status-open-text)",
bf6031c30 border: "var(--status-open-border)",
4dfd09b31 },
4dfd09b32 closed: {
bf6031c33 bg: "var(--status-closed-bg)",
bf6031c34 text: "var(--status-closed-text)",
bf6031c35 border: "var(--status-closed-border)",
4dfd09b36 },
4dfd09b37 failed: {
bf6031c38 bg: "var(--status-closed-bg)",
bf6031c39 text: "var(--status-closed-text)",
bf6031c40 border: "var(--status-closed-border)",
4dfd09b41 },
4dfd09b42 error: {
bf6031c43 bg: "var(--status-closed-bg)",
bf6031c44 text: "var(--status-closed-text)",
bf6031c45 border: "var(--status-closed-border)",
4dfd09b46 },
4dfd09b47 pending: {
4dfd09b48 bg: "var(--bg-inset)",
4dfd09b49 text: "var(--text-faint)",
4dfd09b50 border: "var(--border)",
4dfd09b51 },
4dfd09b52 cancelled: {
4dfd09b53 bg: "var(--bg-inset)",
4dfd09b54 text: "var(--text-faint)",
4dfd09b55 border: "var(--border)",
4dfd09b56 },
4dfd09b57 neutral: {
4dfd09b58 bg: "var(--bg-inset)",
4dfd09b59 text: "var(--text-muted)",
4dfd09b60 border: "var(--border)",
4dfd09b61 },
4dfd09b62 accent: {
4dfd09b63 bg: "var(--accent-subtle)",
4dfd09b64 text: "var(--accent)",
4dfd09b65 border: "var(--accent-subtle)",
4dfd09b66 },
4dfd09b67};
4dfd09b68
4dfd09b69export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
4dfd09b70 variant?: string;
4dfd09b71 colors?: { bg: string; text: string; border?: string };
4dfd09b72 pill?: boolean;
8a2c7d473 compact?: boolean;
4dfd09b74}
4dfd09b75
4dfd09b76export function Badge({
4dfd09b77 variant,
4dfd09b78 colors,
4dfd09b79 pill = false,
8a2c7d480 compact = false,
4dfd09b81 className = "",
4dfd09b82 style,
4dfd09b83 children,
4dfd09b84 ...props
4dfd09b85}: BadgeProps) {
4dfd09b86 const preset = variant ? presets[variant] : undefined;
4dfd09b87 const c = colors ?? preset ?? presets.neutral;
4dfd09b88
a011f1e89 const isRunning = variant === "running" || variant === "creating";
a011f1e90
8a2c7d491 const compactStyles = compact
8a2c7d492 ? { width: "1.25rem", textAlign: "center" as const, padding: "0.125rem 0" }
8a2c7d493 : {};
8a2c7d494
f406a0f95 const baseStyle = {
f406a0f96 backgroundColor: c.bg,
f406a0f97 color: c.text,
bf6031c98 border: `1px solid ${c.border ?? c.bg}`,
f406a0f99 borderRadius: "9999px",
f406a0f100 textTransform: "uppercase" as const,
f406a0f101 fontFamily: "system-ui, -apple-system, sans-serif",
f406a0f102 letterSpacing: "0.04em",
f406a0f103 ...compactStyles,
f406a0f104 ...style,
f406a0f105 };
f406a0f106
a011f1e107 if (isRunning) {
a011f1e108 return (
a011f1e109 <span
7deb6c8110 className={`badge-running-text-pulse text-xs font-bold ${compact ? "" : "px-1.5"} py-0.5 inline-block ${className}`}
f406a0f111 style={baseStyle}
a011f1e112 {...props}
a011f1e113 >
b2bd123114 {children}
a011f1e115 </span>
a011f1e116 );
a011f1e117 }
a011f1e118
4dfd09b119 return (
4dfd09b120 <span
7deb6c8121 className={`text-xs font-bold ${compact ? "" : "px-1.5"} py-0.5 inline-block ${className}`}
f406a0f122 style={baseStyle}
4dfd09b123 {...props}
4dfd09b124 >
4dfd09b125 {children}
4dfd09b126 </span>
4dfd09b127 );
4dfd09b128}