Skip to content

Commit 76a27b6

Browse files
committed
feat(webapp): AgentSpinner — the dot-matrix mono logo animates wherever the agent works
One component in the spinner primitives; chat progress, pending tools, the history thinking/watching markers, panel loading, chart loading and testing hypotheses all use it, so agent activity reads as the agent rather than generic loading.
1 parent 84bd08f commit 76a27b6

7 files changed

Lines changed: 28 additions & 13 deletions

File tree

apps/webapp/app/components/dashboard-agent/AgentChart.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { useEffect, useState } from "react";
99
import { QueryResultsChart } from "~/components/code/QueryResultsChart";
1010
import type { ChartConfiguration } from "~/components/metrics/QueryWidget";
1111
import { Button } from "~/components/primitives/Buttons";
12-
import { Spinner } from "~/components/primitives/Spinner";
12+
import { AgentSpinner } from "~/components/primitives/Spinner";
1313
import { useOptionalEnvironment } from "~/hooks/useEnvironment";
1414
import { useOptionalOrganization } from "~/hooks/useOrganizations";
1515
import { useOptionalProject } from "~/hooks/useProject";
@@ -193,7 +193,7 @@ export function AgentChart({
193193
<div className={cn(AGENT_CHART_PLOT_CLASS)}>
194194
{state.status === "loading" ? (
195195
<div className="flex h-full items-center justify-center gap-2 text-xs text-text-dimmed">
196-
<Spinner className="size-3" />
196+
<AgentSpinner size={12} />
197197
Running query…
198198
</div>
199199
) : state.status === "error" ? (

apps/webapp/app/components/dashboard-agent/DashboardAgentHistory.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Button } from "~/components/primitives/Buttons";
55
import { Dialog, DialogContent, DialogHeader } from "~/components/primitives/Dialog";
66
import { FormButtons } from "~/components/primitives/FormButtons";
77
import { Paragraph } from "~/components/primitives/Paragraph";
8-
import { Spinner } from "~/components/primitives/Spinner";
8+
import { AgentSpinner } from "~/components/primitives/Spinner";
99
import { AgentList, AgentListRow, AgentListRowAction } from "./list-row";
1010

1111
// Date fields arrive as strings over the loader's JSON.
@@ -44,7 +44,7 @@ function ProcessIcon({ process }: { process: ChatProcess }) {
4444
{process === "investigating" ? (
4545
<MagnifyingGlassIcon className="size-3.5" />
4646
) : (
47-
<Spinner className="size-3.5" />
47+
<AgentSpinner size={14} />
4848
)}
4949
</span>
5050
);

apps/webapp/app/components/dashboard-agent/DashboardAgentPanel.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { UIMessage } from "@ai-sdk/react";
22
import { useLocation } from "@remix-run/react";
33
import { generateFriendlyId } from "@trigger.dev/core/v3/isomorphic";
44
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
5-
import { Spinner } from "~/components/primitives/Spinner";
5+
import { AgentSpinner } from "~/components/primitives/Spinner";
66
import { useToast } from "~/components/primitives/Toast";
77
import { useAgentPageContext } from "~/hooks/useAgentPageContext";
88
import { useApiOrigin } from "~/hooks/useApiOrigin";
@@ -427,7 +427,7 @@ export function DashboardAgentPanel({
427427
<AgentPanelColumn fullscreen={isFullscreen}>
428428
{loading ? (
429429
<div className="flex flex-1 items-center justify-center">
430-
<Spinner className="size-5" />
430+
<AgentSpinner size={20} />
431431
</div>
432432
) : active ? (
433433
<DashboardAgentChat

apps/webapp/app/components/dashboard-agent/InvestigationCard.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import type {
3131
import { useState } from "react";
3232
import { Button } from "~/components/primitives/Buttons";
3333
import { Callout } from "~/components/primitives/Callout";
34-
import { Spinner } from "~/components/primitives/Spinner";
34+
import { AgentSpinner } from "~/components/primitives/Spinner";
3535
import {
3636
CategoryBadge,
3737
ConfidenceBadge,
@@ -118,7 +118,7 @@ function HypothesisRow({
118118
<VerdictBadge verdict={hypothesis.verdict}>
119119
{VERDICT_LABELS[hypothesis.verdict]}
120120
</VerdictBadge>
121-
{hypothesis.verdict === "testing" ? <Spinner className="size-3" /> : null}
121+
{hypothesis.verdict === "testing" ? <AgentSpinner size={12} /> : null}
122122
</div>
123123
<p className="text-sm text-text-bright">{hypothesis.statement}</p>
124124
{hypothesis.finding ? <p className="text-xs text-text-dimmed">{hypothesis.finding}</p> : null}

apps/webapp/app/components/dashboard-agent/chat-layout.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
import type { Ref } from "react";
5252
import { createContext, Suspense, useContext } from "react";
5353
import { StreamdownRenderer } from "~/components/code/StreamdownRenderer";
54-
import { Spinner } from "~/components/primitives/Spinner";
54+
import { AgentSpinner } from "~/components/primitives/Spinner";
5555
import { cn } from "~/utils/cn";
5656

5757
/** The transcript's horizontal inset. Owned by `ChatTurn`. */
@@ -214,7 +214,9 @@ export function ChatProgress({ children }: { children: React.ReactNode }) {
214214
return (
215215
<div className={cn(insetClass, "flex items-start text-sm text-text-dimmed", ROW_GAP)}>
216216
{/* text-sm line box is 20px, the spinner 12px: 4px centres it on line one. */}
217-
<Spinner className="mt-1 size-3 shrink-0" />
217+
<span className="mt-1 shrink-0">
218+
<AgentSpinner size={12} />
219+
</span>
218220
{children}
219221
</div>
220222
);
@@ -236,7 +238,9 @@ export function ChatPendingTool({ label }: { label: string }) {
236238
// stay, while in-flight work is transient — the same register as ChatProgress.
237239
return (
238240
<div className={cn(insetClass, "flex min-w-0 items-center text-xs text-text-dimmed", CHIP_GAP)}>
239-
<Spinner className="size-3 shrink-0" />
241+
<span className="shrink-0">
242+
<AgentSpinner size={12} />
243+
</span>
240244
<span className="truncate">{label}</span>
241245
</div>
242246
);

apps/webapp/app/components/dashboard-agent/demo/components/DemoInvestigationCard.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import type { Evidence } from "@internal/dashboard-agent-contracts";
1616
import { useState } from "react";
1717
import { Button } from "~/components/primitives/Buttons";
1818
import { Callout } from "~/components/primitives/Callout";
19-
import { Spinner } from "~/components/primitives/Spinner";
19+
import { AgentSpinner } from "~/components/primitives/Spinner";
2020
import { ChatProgress } from "../../chat-layout";
2121
import {
2222
CategoryBadge,
@@ -86,7 +86,7 @@ function HypothesisRow({ hypothesis }: { hypothesis: DemoHypothesis }) {
8686
<VerdictBadge verdict={hypothesis.verdict}>
8787
{VERDICT_LABELS[hypothesis.verdict]}
8888
</VerdictBadge>
89-
{hypothesis.verdict === "testing" ? <Spinner className="size-3" /> : null}
89+
{hypothesis.verdict === "testing" ? <AgentSpinner size={12} /> : null}
9090
</div>
9191
<p className="text-sm text-text-bright">{hypothesis.statement}</p>
9292
{hypothesis.finding ? <p className="text-xs text-text-dimmed">{hypothesis.finding}</p> : null}

apps/webapp/app/components/primitives/Spinner.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { AgentDotMatrix } from "~/components/primitives/AgentDotMatrix";
12
import { cn } from "~/utils/cn";
23

34
type CustomColor = {
@@ -76,3 +77,13 @@ export function ButtonSpinner() {
7677
export function SpinnerWhite({ className }: { className?: string }) {
7778
return <Spinner className={className} color="white" />;
7879
}
80+
81+
/**
82+
* The dashboard agent's own spinner: the animated dot-matrix logo in the mono
83+
* palette. Use it wherever the AGENT is the one working — chat progress, pending
84+
* tools, thinking markers — so agent activity reads as the agent, not as generic
85+
* loading. `size` is the logo's pixel size (the matrix does not scale from CSS).
86+
*/
87+
export function AgentSpinner({ size = 16 }: { size?: number }) {
88+
return <AgentDotMatrix size={size} active palette="mono" restColor="#ffffff" decorative />;
89+
}

0 commit comments

Comments
 (0)