History

refactor(ui): adopt Badge component consistently (#163)

* refactor(ui): adopt Badge component consistently Replaces hand-rolled `<span class="rounded ...">` pill markup with the shared `<Badge>` component in billing, team, source detail, and tools pages. Also documents the preference in AGENTS.md so new code reaches for `<Badge>` and `<CardStack>` instead of reinventing them. No behaviour change — the visual output is equivalent to the previous inline styles, just routed through the shared component so the styling stays consistent across the app. * Update AGENTS.md ---------

Moritz Meyer committed 7 months ago

Commit 060e9ff1 parent 2a6312c5 files · +22 −25Browse files

Unified · Split

5 files
  1. apps/cloud/src/routes/billing.tsx +5 −4
  2. apps/cloud/src/routes/billing_.plans.tsx +7 −6
  3. apps/cloud/src/routes/team.tsx +4 −5
  4. packages/react/src/pages/source-detail.tsx +4 −7
  5. packages/react/src/pages/tools.tsx +2 −3
apps/cloud/src/routes/billing.tsx+5−4
@@ -1,6 +1,7 @@
1import { createFileRoute, Link } from "@tanstack/react-router";1import { createFileRoute, Link } from "@tanstack/react-router";
2import { useCustomer, useListPlans } from "autumn-js/react";2import { useCustomer, useListPlans } from "autumn-js/react";
3import { Button } from "@executor/react/components/button";3import { Button } from "@executor/react/components/button";
4import { Badge } from "@executor/react/components/badge";
4 5
5type Plan = NonNullable<ReturnType<typeof useListPlans>["data"]>[number];6type Plan = NonNullable<ReturnType<typeof useListPlans>["data"]>[number];
6 7
@@ -68,14 +69,14 @@ function BillingPage() { · 61 unmodified lines
68 {planName}69 {planName}
69 </p>70 </p>
70 {isSwitching && (71 {isSwitching && (
71 <span className="rounded-full bg-amber-500/10 px-1.5 py-0.5 text-[0.625rem] font-medium text-amber-600 dark:text-amber-400 leading-none">72 <Badge className="bg-amber-500/10 text-amber-600 dark:text-amber-400">
72 Switching73 Switching
73 </span>74 </Badge>
74 )}75 )}
75 {isCanceling && !isSwitching && (76 {isCanceling && !isSwitching && (
76 <span className="rounded-full bg-amber-500/10 px-1.5 py-0.5 text-[0.625rem] font-medium text-amber-600 dark:text-amber-400 leading-none">77 <Badge className="bg-amber-500/10 text-amber-600 dark:text-amber-400">
77 Canceling78 Canceling
78 </span>79 </Badge>
79 )}80 )}
80 </div>81 </div>
81 <p className="mt-1 text-[0.75rem] text-muted-foreground/70 leading-none">82 <p className="mt-1 text-[0.75rem] text-muted-foreground/70 leading-none">
apps/cloud/src/routes/billing_.plans.tsx+7−6
@@ -2,6 +2,7 @@ import { useState } from "react"; · 1 unmodified line
2import { createFileRoute, Link } from "@tanstack/react-router";2import { createFileRoute, Link } from "@tanstack/react-router";
3import { useCustomer, useListPlans } from "autumn-js/react";3import { useCustomer, useListPlans } from "autumn-js/react";
4import { Button } from "@executor/react/components/button";4import { Button } from "@executor/react/components/button";
5import { Badge } from "@executor/react/components/badge";
5 6
6type Plan = NonNullable<ReturnType<typeof useListPlans>["data"]>[number];7type Plan = NonNullable<ReturnType<typeof useListPlans>["data"]>[number];
7 8
@@ -120,19 +121,19 @@ function PlansPage() { · 112 unmodified lines
120 {plan.name}121 {plan.name}
121 </p>122 </p>
122 {isCurrent && (123 {isCurrent && (
123 <span className="rounded-full bg-amber-500/10 px-1.5 py-0.5 text-[0.625rem] font-medium text-amber-600 dark:text-amber-400 leading-none">124 <Badge className="bg-amber-500/10 text-amber-600 dark:text-amber-400">
124 Your plan125 Your plan
125 </span>126 </Badge>
126 )}127 )}
127 {isCanceling && (128 {isCanceling && (
128 <span className="rounded-full bg-amber-500/10 px-1.5 py-0.5 text-[0.625rem] font-medium text-amber-600 dark:text-amber-400 leading-none">129 <Badge className="bg-amber-500/10 text-amber-600 dark:text-amber-400">
129 Canceling130 Canceling
130 </span>131 </Badge>
131 )}132 )}
132 {isScheduled && (133 {isScheduled && (
133 <span className="rounded-full bg-emerald-500/10 px-1.5 py-0.5 text-[0.625rem] font-medium text-emerald-600 dark:text-emerald-400 leading-none">134 <Badge className="bg-emerald-500/10 text-emerald-600 dark:text-emerald-400">
134 Scheduled135 Scheduled
135 </span>136 </Badge>
136 )}137 )}
137 </div>138 </div>
138 <p className="mt-1 text-[0.75rem] text-muted-foreground/70">{meta.tagline}</p>139 <p className="mt-1 text-[0.75rem] text-muted-foreground/70">{meta.tagline}</p>
apps/cloud/src/routes/team.tsx+4−5
@@ -13,6 +13,7 @@ import { · 12 unmodified lines
13 DialogClose,13 DialogClose,
14} from "@executor/react/components/dialog";14} from "@executor/react/components/dialog";
15import { Button } from "@executor/react/components/button";15import { Button } from "@executor/react/components/button";
16import { Badge } from "@executor/react/components/badge";
16import { Input } from "@executor/react/components/input";17import { Input } from "@executor/react/components/input";
17import { Label } from "@executor/react/components/label";18import { Label } from "@executor/react/components/label";
18import {19import {
@@ -214,14 +215,12 @@ function TeamPage() { · 195 unmodified lines
214 {member.name ?? member.email}215 {member.name ?? member.email}
215 </p>216 </p>
216 {member.isCurrentUser && (217 {member.isCurrentUser && (
217 <span className="rounded bg-muted px-1.5 py-0.5 text-[0.625rem] font-medium text-muted-foreground leading-none">218 <Badge className="bg-muted text-muted-foreground">You</Badge>
218 You
219 </span>
220 )}219 )}
221 {member.status === "pending" && (220 {member.status === "pending" && (
222 <span className="rounded bg-amber-500/10 px-1.5 py-0.5 text-[0.625rem] font-medium text-amber-600 dark:text-amber-400 leading-none">221 <Badge className="bg-amber-500/10 text-amber-600 dark:text-amber-400">
223 Invited222 Invited
224 </span>223 </Badge>
225 )}224 )}
226 </div>225 </div>
227 {member.name && (226 {member.name && (
packages/react/src/pages/source-detail.tsx+4−7
@@ -14,6 +14,7 @@ import type { ToolSummary } from "../components/tool-tree"; · 13 unmodified lines
14import { useScope } from "../hooks/use-scope";14import { useScope } from "../hooks/use-scope";
15import type { SourcePlugin } from "../plugins/source-plugin";15import type { SourcePlugin } from "../plugins/source-plugin";
16import { Button } from "../components/button";16import { Button } from "../components/button";
17import { Badge } from "../components/badge";
17 18
18export function SourceDetailPage(props: {19export function SourceDetailPage(props: {
19 namespace: string;20 namespace: string;
@@ -116,13 +117,9 @@ export function SourceDetailPage(props: { · 96 unmodified lines
116 {sourceData?.name ?? namespace}117 {sourceData?.name ?? namespace}
117 </h2>118 </h2>
118 {sourceData?.runtime && (119 {sourceData?.runtime && (
119 <span className="rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground">120 <Badge className="bg-muted text-muted-foreground">built-in</Badge>
120 built-in
121 </span>
122 )}121 )}
123 <span className="rounded bg-secondary px-1.5 py-0.5 text-[10px] font-medium text-secondary-foreground">122 <Badge variant="secondary">{sourceData?.kind ?? "source"}</Badge>
124 {sourceData?.kind ?? "source"}
125 </span>
126 {Result.isSuccess(tools) && !editing && (123 {Result.isSuccess(tools) && !editing && (
127 <span className="hidden text-[11px] tabular-nums text-muted-foreground/50 sm:block">124 <span className="hidden text-[11px] tabular-nums text-muted-foreground/50 sm:block">
128 {sourceTools.length} {sourceTools.length === 1 ? "tool" : "tools"}125 {sourceTools.length} {sourceTools.length === 1 ? "tool" : "tools"}
@@ -208,7 +205,7 @@ export function SourceDetailPage(props: { · 79 unmodified lines
208 onSuccess: () => (205 onSuccess: () => (
209 <div className="flex min-h-0 flex-1 overflow-hidden">206 <div className="flex min-h-0 flex-1 overflow-hidden">
210 {/* Left: tool tree */}207 {/* Left: tool tree */}
211 <div className="flex w-72 shrink-0 flex-col border-r border-border bg-card/30 lg:w-80 xl:w-[22rem]">208 <div className="flex w-72 shrink-0 flex-col border-r border-border/60 lg:w-80 xl:w-[22rem]">
212 <ToolTree209 <ToolTree
213 tools={sourceTools}210 tools={sourceTools}
214 selectedToolId={selectedToolId}211 selectedToolId={selectedToolId}
packages/react/src/pages/tools.tsx+2−3
@@ -1,6 +1,7 @@
1import { useAtomValue, Result } from "@effect-atom/atom-react";1import { useAtomValue, Result } from "@effect-atom/atom-react";
2import { toolsAtom } from "../api/atoms";2import { toolsAtom } from "../api/atoms";
3import { useScope } from "../hooks/use-scope";3import { useScope } from "../hooks/use-scope";
4import { Badge } from "../components/badge";
4 5
5export function ToolsPage() {6export function ToolsPage() {
6 const scopeId = useScope();7 const scopeId = useScope();
@@ -61,9 +62,7 @@ export function ToolsPage() { · 54 unmodified lines
61 </p>62 </p>
62 )}63 )}
63 </div>64 </div>
64 <span className="shrink-0 rounded bg-secondary px-1.5 py-0.5 text-[10px] font-medium text-secondary-foreground">65 <Badge variant="secondary">{t.sourceId}</Badge>
65 {t.sourceId}
66 </span>
67 </div>66 </div>
68 ))}67 ))}
69 </div>68 </div>

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t