From e1347fd0777af5a81dc4d17e1cbd236ff0dc2ade Mon Sep 17 00:00:00 2001 From: TELVIN TEUM Date: Tue, 7 Jul 2026 00:47:51 +0300 Subject: [PATCH] feat(ui): add five-bar SessionSpinner for active session indicators Replace the ring spinner with a staggered bar spinner in session rows, worktree tabs, and the center header while agent runs are in flight. Co-authored-by: Cursor --- src/renderer/components/ui/SessionSpinner.tsx | 54 +++++++++++++++++++ src/renderer/components/ui/index.ts | 1 + src/renderer/features/sessions/SessionRow.tsx | 4 +- .../features/sessions/WorktreeTabs.tsx | 4 +- .../features/workspace/CenterWorkspace.tsx | 4 +- 5 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 src/renderer/components/ui/SessionSpinner.tsx diff --git a/src/renderer/components/ui/SessionSpinner.tsx b/src/renderer/components/ui/SessionSpinner.tsx new file mode 100644 index 0000000..654f14f --- /dev/null +++ b/src/renderer/components/ui/SessionSpinner.tsx @@ -0,0 +1,54 @@ +/** + * Five-bar radial spinner for session "agent run in flight" indicators. Uses + * staggered `animate-spin` layers; honors reduced-motion via the global + * stylesheet when `data-reduced-motion="true"` is set on . + */ +import type { ComponentProps } from 'react'; +import { cn } from '@/renderer/lib/cn'; + +interface SessionSpinnerProps extends ComponentProps<'div'> { + size?: number; + invert?: boolean; + disabled?: boolean; +} + +export function SessionSpinner({ + size = 16, + invert, + disabled, + className, + ...props +}: SessionSpinnerProps) { + if (disabled) return null; + + const sizePx = `${size}px`; + const barWidth = `${(size * 0.2).toFixed(2)}px`; + const barHeight = `${(size * 0.075).toFixed(2)}px`; + + return ( +
+ {[...Array(5)].map((_, i) => ( +
+
+
+ ))} +
+ ); +} diff --git a/src/renderer/components/ui/index.ts b/src/renderer/components/ui/index.ts index 26a0c55..bc1d79f 100644 --- a/src/renderer/components/ui/index.ts +++ b/src/renderer/components/ui/index.ts @@ -5,6 +5,7 @@ export { EmptyState } from './EmptyState'; export { Badge } from './Badge'; export { Kbd } from './Kbd'; export { Spinner } from './Spinner'; +export { SessionSpinner } from './SessionSpinner'; export { SuccessCheck } from './SuccessCheck'; export { CircularProgress } from './CircularProgress'; export { Waveform } from './Waveform'; diff --git a/src/renderer/features/sessions/SessionRow.tsx b/src/renderer/features/sessions/SessionRow.tsx index c50896e..42634a6 100644 --- a/src/renderer/features/sessions/SessionRow.tsx +++ b/src/renderer/features/sessions/SessionRow.tsx @@ -14,7 +14,7 @@ import { useEffect, useRef, useState } from 'react'; import { CircleDot, GitBranch, Pin, Archive, MoreHorizontal } from 'lucide-react'; import type { Session, SessionStatus } from '@shared/types'; -import { Badge, DiffStat, IconButton, Spinner } from '@/renderer/components/ui'; +import { Badge, DiffStat, IconButton, SessionSpinner } from '@/renderer/components/ui'; import { cn } from '@/renderer/lib/cn'; import { relativeTime } from '@/renderer/lib/format'; import { useSessionStore } from '@/renderer/stores/useSessionStore'; @@ -96,7 +96,7 @@ export function SessionRow({ ) : running ? ( - + ) : ( )} diff --git a/src/renderer/features/sessions/WorktreeTabs.tsx b/src/renderer/features/sessions/WorktreeTabs.tsx index 10825b4..4a09421 100644 --- a/src/renderer/features/sessions/WorktreeTabs.tsx +++ b/src/renderer/features/sessions/WorktreeTabs.tsx @@ -12,7 +12,7 @@ */ import { AlertTriangle, GitBranch, X } from 'lucide-react'; import type { Session } from '@shared/types'; -import { Badge, Spinner } from '@/renderer/components/ui'; +import { Badge, SessionSpinner } from '@/renderer/components/ui'; import { cn } from '@/renderer/lib/cn'; import { useSessionStore } from '@/renderer/stores/useSessionStore'; import { useIsSessionRunning } from './useSessionRunning'; @@ -93,7 +93,7 @@ function WorktreeTab({ )} > {running ? ( - + ) : missing ? ( ) : ( diff --git a/src/renderer/features/workspace/CenterWorkspace.tsx b/src/renderer/features/workspace/CenterWorkspace.tsx index e98316f..1d55681 100644 --- a/src/renderer/features/workspace/CenterWorkspace.tsx +++ b/src/renderer/features/workspace/CenterWorkspace.tsx @@ -13,7 +13,7 @@ */ import { useEffect, useState } from 'react'; import { AlertTriangle, CircleDot, GitBranch, Plus, TerminalSquare } from 'lucide-react'; -import { DiffStat, IconButton, Spinner } from '@/renderer/components/ui'; +import { DiffStat, IconButton, SessionSpinner, Spinner } from '@/renderer/components/ui'; import { useIsSessionRunning } from '@/renderer/features/sessions/useSessionRunning'; import { WorktreeTabs } from '@/renderer/features/sessions/WorktreeTabs'; import { ServicesStrip } from '@/renderer/features/sessions/ServicesStrip'; @@ -200,7 +200,7 @@ function SessionHeader({ const revalidating = useResumeStore((s) => s.bySession[sessionId]?.phase === 'checking'); return (
- {running ? : } + {running ? : } {title} {branch}