ui: apply interface polish from design article review

- Add global font smoothing (antialiased) to body
- Add tabular-nums to all numeric displays: MetricCard values, Costs page,
  AgentDetail token/cost grids and tables, IssueDetail cost summary,
  Companies page budget display
- Replace markdown image hard border with subtle inset box-shadow overlay
- Replace all animate-ping status dots with calmer animate-pulse across
  AgentDetail, IssueDetail, Agents, sidebar, kanban, issues list, and
  active agents panel

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dotta
2026-03-11 08:20:24 -05:00
parent a503d2c12c
commit 57dcdb51af
14 changed files with 26 additions and 26 deletions

View File

@@ -434,7 +434,7 @@ function AgentRunCard({
<div className="flex items-center gap-2 min-w-0"> <div className="flex items-center gap-2 min-w-0">
{isActive ? ( {isActive ? (
<span className="relative flex h-2 w-2 shrink-0"> <span className="relative flex h-2 w-2 shrink-0">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" /> <span className="animate-pulse absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" />
<span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" /> <span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" />
</span> </span>
) : ( ) : (

View File

@@ -132,7 +132,7 @@ function SortableCompanyItem({
{hasLiveAgents && ( {hasLiveAgents && (
<span className="pointer-events-none absolute -right-0.5 -top-0.5 z-10"> <span className="pointer-events-none absolute -right-0.5 -top-0.5 z-10">
<span className="relative flex h-2.5 w-2.5"> <span className="relative flex h-2.5 w-2.5">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-blue-400 opacity-80" /> <span className="absolute inline-flex h-full w-full animate-pulse rounded-full bg-blue-400 opacity-80" />
<span className="relative inline-flex h-2.5 w-2.5 rounded-full bg-blue-500 ring-2 ring-background" /> <span className="relative inline-flex h-2.5 w-2.5 rounded-full bg-blue-500 ring-2 ring-background" />
</span> </span>
</span> </span>

View File

@@ -628,7 +628,7 @@ export function IssuesList({
{liveIssueIds?.has(issue.id) && ( {liveIssueIds?.has(issue.id) && (
<span className="inline-flex items-center gap-1 sm:gap-1.5 px-1.5 sm:px-2 py-0.5 rounded-full bg-blue-500/10"> <span className="inline-flex items-center gap-1 sm:gap-1.5 px-1.5 sm:px-2 py-0.5 rounded-full bg-blue-500/10">
<span className="relative flex h-2 w-2"> <span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" /> <span className="animate-pulse absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" />
<span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" /> <span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" />
</span> </span>
<span className="text-[11px] font-medium text-blue-600 dark:text-blue-400 hidden sm:inline">Live</span> <span className="text-[11px] font-medium text-blue-600 dark:text-blue-400 hidden sm:inline">Live</span>

View File

@@ -154,7 +154,7 @@ function KanbanCard({
</span> </span>
{isLive && ( {isLive && (
<span className="relative flex h-2 w-2 shrink-0 mt-0.5"> <span className="relative flex h-2 w-2 shrink-0 mt-0.5">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" /> <span className="animate-pulse absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" />
<span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" /> <span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" />
</span> </span>
)} )}

View File

@@ -18,7 +18,7 @@ export function MetricCard({ icon: Icon, value, label, description, to, onClick
<div className={`h-full px-4 py-4 sm:px-5 sm:py-5 rounded-lg transition-colors${isClickable ? " hover:bg-accent/50 cursor-pointer" : ""}`}> <div className={`h-full px-4 py-4 sm:px-5 sm:py-5 rounded-lg transition-colors${isClickable ? " hover:bg-accent/50 cursor-pointer" : ""}`}>
<div className="flex items-start justify-between gap-3"> <div className="flex items-start justify-between gap-3">
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<p className="text-2xl sm:text-3xl font-semibold tracking-tight"> <p className="text-2xl sm:text-3xl font-semibold tracking-tight tabular-nums">
{value} {value}
</p> </p>
<p className="text-xs sm:text-sm font-medium text-muted-foreground mt-1"> <p className="text-xs sm:text-sm font-medium text-muted-foreground mt-1">

View File

@@ -127,7 +127,7 @@ export function SidebarAgents() {
{runCount > 0 && ( {runCount > 0 && (
<span className="ml-auto flex items-center gap-1.5 shrink-0"> <span className="ml-auto flex items-center gap-1.5 shrink-0">
<span className="relative flex h-2 w-2"> <span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" /> <span className="animate-pulse absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" />
<span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" /> <span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" />
</span> </span>
<span className="text-[11px] font-medium text-blue-600 dark:text-blue-400"> <span className="text-[11px] font-medium text-blue-600 dark:text-blue-400">

View File

@@ -53,7 +53,7 @@ export function SidebarNavItem({
{liveCount != null && liveCount > 0 && ( {liveCount != null && liveCount > 0 && (
<span className="ml-auto flex items-center gap-1.5"> <span className="ml-auto flex items-center gap-1.5">
<span className="relative flex h-2 w-2"> <span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" /> <span className="animate-pulse absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" />
<span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" /> <span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" />
</span> </span>
<span className="text-[11px] font-medium text-blue-600 dark:text-blue-400">{liveCount} live</span> <span className="text-[11px] font-medium text-blue-600 dark:text-blue-400">{liveCount} live</span>

View File

@@ -123,7 +123,7 @@
-webkit-tap-highlight-color: color-mix(in oklab, var(--foreground) 20%, transparent); -webkit-tap-highlight-color: color-mix(in oklab, var(--foreground) 20%, transparent);
} }
body { body {
@apply bg-background text-foreground; @apply bg-background text-foreground antialiased;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
} }
@@ -528,8 +528,8 @@
} }
.paperclip-markdown img { .paperclip-markdown img {
border: 1px solid var(--border);
border-radius: calc(var(--radius) + 2px); border-radius: calc(var(--radius) + 2px);
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--foreground) 10%, transparent);
} }
.paperclip-markdown table { .paperclip-markdown table {

View File

@@ -511,7 +511,7 @@ export function AgentDetail() {
className="sm:hidden flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-blue-500/10 hover:bg-blue-500/20 transition-colors no-underline" className="sm:hidden flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-blue-500/10 hover:bg-blue-500/20 transition-colors no-underline"
> >
<span className="relative flex h-2 w-2"> <span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" /> <span className="animate-pulse absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" />
<span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" /> <span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" />
</span> </span>
<span className="text-[11px] font-medium text-blue-600 dark:text-blue-400">Live</span> <span className="text-[11px] font-medium text-blue-600 dark:text-blue-400">Live</span>
@@ -713,7 +713,7 @@ function LatestRunCard({ runs, agentId }: { runs: HeartbeatRun[]; agentId: strin
<h3 className="flex items-center gap-2 text-sm font-medium"> <h3 className="flex items-center gap-2 text-sm font-medium">
{isLive && ( {isLive && (
<span className="relative flex h-2 w-2"> <span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-cyan-400 opacity-75" /> <span className="animate-pulse absolute inline-flex h-full w-full rounded-full bg-cyan-400 opacity-75" />
<span className="relative inline-flex rounded-full h-2 w-2 bg-cyan-400" /> <span className="relative inline-flex rounded-full h-2 w-2 bg-cyan-400" />
</span> </span>
)} )}
@@ -857,7 +857,7 @@ function CostsSection({
<div className="space-y-4"> <div className="space-y-4">
{runtimeState && ( {runtimeState && (
<div className="border border-border rounded-lg p-4"> <div className="border border-border rounded-lg p-4">
<div className="grid grid-cols-2 md:grid-cols-4 gap-4"> <div className="grid grid-cols-2 md:grid-cols-4 gap-4 tabular-nums">
<div> <div>
<span className="text-xs text-muted-foreground block">Input tokens</span> <span className="text-xs text-muted-foreground block">Input tokens</span>
<span className="text-lg font-semibold">{formatTokens(runtimeState.totalInputTokens)}</span> <span className="text-lg font-semibold">{formatTokens(runtimeState.totalInputTokens)}</span>
@@ -896,9 +896,9 @@ function CostsSection({
<tr key={run.id} className="border-b border-border last:border-b-0"> <tr key={run.id} className="border-b border-border last:border-b-0">
<td className="px-3 py-2">{formatDate(run.createdAt)}</td> <td className="px-3 py-2">{formatDate(run.createdAt)}</td>
<td className="px-3 py-2 font-mono">{run.id.slice(0, 8)}</td> <td className="px-3 py-2 font-mono">{run.id.slice(0, 8)}</td>
<td className="px-3 py-2 text-right">{formatTokens(Number(u.input_tokens ?? 0))}</td> <td className="px-3 py-2 text-right tabular-nums">{formatTokens(Number(u.input_tokens ?? 0))}</td>
<td className="px-3 py-2 text-right">{formatTokens(Number(u.output_tokens ?? 0))}</td> <td className="px-3 py-2 text-right tabular-nums">{formatTokens(Number(u.output_tokens ?? 0))}</td>
<td className="px-3 py-2 text-right"> <td className="px-3 py-2 text-right tabular-nums">
{(u.cost_usd || u.total_cost_usd) {(u.cost_usd || u.total_cost_usd)
? `$${Number(u.cost_usd ?? u.total_cost_usd ?? 0).toFixed(4)}` ? `$${Number(u.cost_usd ?? u.total_cost_usd ?? 0).toFixed(4)}`
: "-" : "-"
@@ -1163,7 +1163,7 @@ function RunListItem({ run, isSelected, agentId }: { run: HeartbeatRun; isSelect
</span> </span>
)} )}
{(metrics.totalTokens > 0 || metrics.cost > 0) && ( {(metrics.totalTokens > 0 || metrics.cost > 0) && (
<div className="flex items-center gap-2 pl-5.5 text-[11px] text-muted-foreground"> <div className="flex items-center gap-2 pl-5.5 text-[11px] text-muted-foreground tabular-nums">
{metrics.totalTokens > 0 && <span>{formatTokens(metrics.totalTokens)} tok</span>} {metrics.totalTokens > 0 && <span>{formatTokens(metrics.totalTokens)} tok</span>}
{metrics.cost > 0 && <span>${metrics.cost.toFixed(3)}</span>} {metrics.cost > 0 && <span>${metrics.cost.toFixed(3)}</span>}
</div> </div>
@@ -1539,7 +1539,7 @@ function RunDetail({ run: initialRun, agentRouteId, adapterType }: { run: Heartb
{/* Right column: metrics */} {/* Right column: metrics */}
{hasMetrics && ( {hasMetrics && (
<div className="border-t sm:border-t-0 sm:border-l border-border p-4 grid grid-cols-2 gap-x-4 sm:gap-x-8 gap-y-3 content-center"> <div className="border-t sm:border-t-0 sm:border-l border-border p-4 grid grid-cols-2 gap-x-4 sm:gap-x-8 gap-y-3 content-center tabular-nums">
<div> <div>
<div className="text-xs text-muted-foreground">Input</div> <div className="text-xs text-muted-foreground">Input</div>
<div className="text-sm font-medium font-mono">{formatTokens(metrics.input)}</div> <div className="text-sm font-medium font-mono">{formatTokens(metrics.input)}</div>
@@ -2138,7 +2138,7 @@ function LogViewer({ run, adapterType }: { run: HeartbeatRun; adapterType: strin
{isLive && ( {isLive && (
<span className="flex items-center gap-1 text-xs text-cyan-400"> <span className="flex items-center gap-1 text-xs text-cyan-400">
<span className="relative flex h-2 w-2"> <span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-cyan-400 opacity-75" /> <span className="animate-pulse absolute inline-flex h-full w-full rounded-full bg-cyan-400 opacity-75" />
<span className="relative inline-flex rounded-full h-2 w-2 bg-cyan-400" /> <span className="relative inline-flex rounded-full h-2 w-2 bg-cyan-400" />
</span> </span>
Live Live

View File

@@ -398,7 +398,7 @@ function LiveRunIndicator({
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
<span className="relative flex h-2 w-2"> <span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" /> <span className="animate-pulse absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" />
<span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" /> <span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" />
</span> </span>
<span className="text-[11px] font-medium text-blue-600 dark:text-blue-400"> <span className="text-[11px] font-medium text-blue-600 dark:text-blue-400">

View File

@@ -244,7 +244,7 @@ export function Companies() {
{issueCount} {issueCount === 1 ? "issue" : "issues"} {issueCount} {issueCount === 1 ? "issue" : "issues"}
</span> </span>
</div> </div>
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5 tabular-nums">
<DollarSign className="h-3.5 w-3.5" /> <DollarSign className="h-3.5 w-3.5" />
<span> <span>
{formatCents(company.spentMonthlyCents)} {formatCents(company.spentMonthlyCents)}

View File

@@ -144,7 +144,7 @@ export function Costs() {
</p> </p>
)} )}
</div> </div>
<p className="text-2xl font-bold"> <p className="text-2xl font-bold tabular-nums">
{formatCents(data.summary.spendCents)}{" "} {formatCents(data.summary.spendCents)}{" "}
<span className="text-base font-normal text-muted-foreground"> <span className="text-base font-normal text-muted-foreground">
{data.summary.budgetCents > 0 {data.summary.budgetCents > 0
@@ -192,7 +192,7 @@ export function Costs() {
<StatusBadge status="terminated" /> <StatusBadge status="terminated" />
)} )}
</div> </div>
<div className="text-right shrink-0 ml-2"> <div className="text-right shrink-0 ml-2 tabular-nums">
<span className="font-medium block">{formatCents(row.costCents)}</span> <span className="font-medium block">{formatCents(row.costCents)}</span>
<span className="text-xs text-muted-foreground block"> <span className="text-xs text-muted-foreground block">
in {formatTokens(row.inputTokens)} / out {formatTokens(row.outputTokens)} tok in {formatTokens(row.inputTokens)} / out {formatTokens(row.outputTokens)} tok
@@ -229,7 +229,7 @@ export function Costs() {
<span className="truncate"> <span className="truncate">
{row.projectName ?? row.projectId ?? "Unattributed"} {row.projectName ?? row.projectId ?? "Unattributed"}
</span> </span>
<span className="font-medium">{formatCents(row.costCents)}</span> <span className="font-medium tabular-nums">{formatCents(row.costCents)}</span>
</div> </div>
))} ))}
</div> </div>

View File

@@ -1061,7 +1061,7 @@ export function DesignGuide() {
<div className="text-foreground">[12:00:17] INFO Reconnected successfully</div> <div className="text-foreground">[12:00:17] INFO Reconnected successfully</div>
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<span className="relative flex h-1.5 w-1.5"> <span className="relative flex h-1.5 w-1.5">
<span className="absolute inline-flex h-full w-full rounded-full bg-cyan-400 animate-ping" /> <span className="absolute inline-flex h-full w-full rounded-full bg-cyan-400 animate-pulse" />
<span className="inline-flex h-full w-full rounded-full bg-cyan-400" /> <span className="inline-flex h-full w-full rounded-full bg-cyan-400" />
</span> </span>
<span className="text-cyan-400">Live</span> <span className="text-cyan-400">Live</span>

View File

@@ -565,7 +565,7 @@ export function IssueDetail() {
{hasLiveRuns && ( {hasLiveRuns && (
<span className="inline-flex items-center gap-1.5 rounded-full bg-cyan-500/10 border border-cyan-500/30 px-2 py-0.5 text-[10px] font-medium text-cyan-600 dark:text-cyan-400 shrink-0"> <span className="inline-flex items-center gap-1.5 rounded-full bg-cyan-500/10 border border-cyan-500/30 px-2 py-0.5 text-[10px] font-medium text-cyan-600 dark:text-cyan-400 shrink-0">
<span className="relative flex h-1.5 w-1.5"> <span className="relative flex h-1.5 w-1.5">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-cyan-400 opacity-75" /> <span className="animate-pulse absolute inline-flex h-full w-full rounded-full bg-cyan-400 opacity-75" />
<span className="relative inline-flex rounded-full h-1.5 w-1.5 bg-cyan-400" /> <span className="relative inline-flex rounded-full h-1.5 w-1.5 bg-cyan-400" />
</span> </span>
Live Live
@@ -901,7 +901,7 @@ export function IssueDetail() {
{!issueCostSummary.hasCost && !issueCostSummary.hasTokens ? ( {!issueCostSummary.hasCost && !issueCostSummary.hasTokens ? (
<div className="text-xs text-muted-foreground">No cost data yet.</div> <div className="text-xs text-muted-foreground">No cost data yet.</div>
) : ( ) : (
<div className="flex flex-wrap gap-3 text-xs text-muted-foreground"> <div className="flex flex-wrap gap-3 text-xs text-muted-foreground tabular-nums">
{issueCostSummary.hasCost && ( {issueCostSummary.hasCost && (
<span className="font-medium text-foreground"> <span className="font-medium text-foreground">
${issueCostSummary.cost.toFixed(4)} ${issueCostSummary.cost.toFixed(4)}