3.0 KB129 lines
Blame
1const presets: Record<string, { bg: string; text: string; border: string }> = {
2 open: {
3 bg: "var(--status-open-bg)",
4 text: "var(--status-open-text)",
5 border: "var(--status-open-border)",
6 },
7 active: {
8 bg: "var(--status-open-bg)",
9 text: "var(--status-open-text)",
10 border: "var(--status-open-border)",
11 },
12 running: {
13 bg: "var(--status-merged-bg)",
14 text: "var(--status-merged-text)",
15 border: "var(--status-merged-border)",
16 },
17 merged: {
18 bg: "var(--status-merged-bg)",
19 text: "var(--status-merged-text)",
20 border: "var(--status-merged-border)",
21 },
22 creating: {
23 bg: "var(--status-merged-bg)",
24 text: "var(--status-merged-text)",
25 border: "var(--status-merged-border)",
26 },
27 passed: {
28 bg: "var(--status-open-bg)",
29 text: "var(--status-open-text)",
30 border: "var(--status-open-border)",
31 },
32 closed: {
33 bg: "var(--status-closed-bg)",
34 text: "var(--status-closed-text)",
35 border: "var(--status-closed-border)",
36 },
37 failed: {
38 bg: "var(--status-closed-bg)",
39 text: "var(--status-closed-text)",
40 border: "var(--status-closed-border)",
41 },
42 error: {
43 bg: "var(--status-closed-bg)",
44 text: "var(--status-closed-text)",
45 border: "var(--status-closed-border)",
46 },
47 pending: {
48 bg: "var(--bg-inset)",
49 text: "var(--text-faint)",
50 border: "var(--border)",
51 },
52 cancelled: {
53 bg: "var(--bg-inset)",
54 text: "var(--text-faint)",
55 border: "var(--border)",
56 },
57 neutral: {
58 bg: "var(--bg-inset)",
59 text: "var(--text-muted)",
60 border: "var(--border)",
61 },
62 accent: {
63 bg: "var(--accent-subtle)",
64 text: "var(--accent)",
65 border: "var(--accent-subtle)",
66 },
67};
68
69export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
70 variant?: string;
71 colors?: { bg: string; text: string; border?: string };
72 pill?: boolean;
73 compact?: boolean;
74}
75
76export function Badge({
77 variant,
78 colors,
79 pill = false,
80 compact = false,
81 className = "",
82 style,
83 children,
84 ...props
85}: BadgeProps) {
86 const preset = variant ? presets[variant] : undefined;
87 const c = colors ?? preset ?? presets.neutral;
88
89 const isRunning = variant === "running" || variant === "creating";
90
91 const compactStyles = compact
92 ? { width: "1.25rem", textAlign: "center" as const, padding: "0.125rem 0" }
93 : {};
94
95 const baseStyle = {
96 backgroundColor: c.bg,
97 color: c.text,
98 border: `1px solid ${c.border ?? c.bg}`,
99 borderRadius: "9999px",
100 textTransform: "uppercase" as const,
101 fontFamily: "system-ui, -apple-system, sans-serif",
102 letterSpacing: "0.04em",
103 ...compactStyles,
104 ...style,
105 };
106
107 if (isRunning) {
108 return (
109 <span
110 className={`badge-running-text-pulse text-xs font-bold ${compact ? "" : "px-1.5"} py-0.5 inline-block ${className}`}
111 style={baseStyle}
112 {...props}
113 >
114 {children}
115 </span>
116 );
117 }
118
119 return (
120 <span
121 className={`text-xs font-bold ${compact ? "" : "px-1.5"} py-0.5 inline-block ${className}`}
122 style={baseStyle}
123 {...props}
124 >
125 {children}
126 </span>
127 );
128}
129