mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 08:02:28 +00:00
Recolor agent 'done' state from sky blue to emerald green (#1246)
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -58,7 +58,7 @@ export const AgentStateDot = React.memo(function AgentStateDot({
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
'block rounded-full border-2 border-emerald-500 border-t-transparent animate-spin',
|
||||
'block rounded-full border-2 border-yellow-500 border-t-transparent animate-spin',
|
||||
inner
|
||||
)}
|
||||
/>
|
||||
@@ -76,9 +76,11 @@ export const AgentStateDot = React.memo(function AgentStateDot({
|
||||
'block rounded-full',
|
||||
inner,
|
||||
state === 'blocked' || state === 'waiting' || state === 'permission'
|
||||
? 'bg-red-500 animate-pulse'
|
||||
? 'bg-red-500'
|
||||
: state === 'done'
|
||||
? 'bg-sky-500/80'
|
||||
? // Why: emerald-500 matches StatusIndicator's done dot so the
|
||||
// dashboard and sidebar read as the same state.
|
||||
'bg-emerald-500'
|
||||
: 'bg-neutral-500/40'
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -255,19 +255,19 @@ const AgentDashboard = React.memo(function AgentDashboard() {
|
||||
<span className="ml-auto flex shrink-0 items-center gap-2 text-[10px] text-muted-foreground">
|
||||
{groupRunning > 0 && (
|
||||
<span>
|
||||
<span className="font-semibold text-emerald-500">{groupRunning}</span>{' '}
|
||||
<span className="font-semibold text-yellow-500">{groupRunning}</span>{' '}
|
||||
active
|
||||
</span>
|
||||
)}
|
||||
{groupBlocked > 0 && (
|
||||
<span>
|
||||
<span className="font-semibold text-amber-500">{groupBlocked}</span>{' '}
|
||||
<span className="font-semibold text-red-500">{groupBlocked}</span>{' '}
|
||||
blocked
|
||||
</span>
|
||||
)}
|
||||
{groupDone > 0 && (
|
||||
<span>
|
||||
<span className="font-semibold text-sky-500/80">{groupDone}</span>{' '}
|
||||
<span className="font-semibold text-emerald-500">{groupDone}</span>{' '}
|
||||
done
|
||||
</span>
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import { cn } from '@/lib/utils'
|
||||
import type { WorktreeStatus } from '@/lib/worktree-status'
|
||||
import { getWorktreeStatusLabel, type WorktreeStatus } from '@/lib/worktree-status'
|
||||
|
||||
// Why: re-export WorktreeStatus under the existing `Status` alias so the
|
||||
// sidebar component and the canonical lib share one source of truth — the
|
||||
@@ -15,15 +15,25 @@ type StatusIndicatorProps = React.ComponentProps<'span'> & {
|
||||
const StatusIndicator = React.memo(function StatusIndicator({
|
||||
status,
|
||||
className,
|
||||
title,
|
||||
...rest
|
||||
}: StatusIndicatorProps) {
|
||||
// Why: surface the status label as a native tooltip so hovering the dot
|
||||
// reveals the state — matters especially for 'active' vs 'inactive', which
|
||||
// share the same grey dot (see color-branch comment below). Callers pass
|
||||
// aria-hidden="true" alongside an sr-only label, so the `title` attribute
|
||||
// is ignored by AT and only serves sighted users on hover. Callers can
|
||||
// override by passing their own `title`.
|
||||
const resolvedTitle = title ?? getWorktreeStatusLabel(status)
|
||||
|
||||
if (status === 'working') {
|
||||
return (
|
||||
<span
|
||||
className={cn('inline-flex h-3 w-3 shrink-0 items-center justify-center', className)}
|
||||
title={resolvedTitle}
|
||||
{...rest}
|
||||
>
|
||||
<span className="block size-2 rounded-full border-2 border-emerald-500 border-t-transparent animate-spin" />
|
||||
<span className="block size-2 rounded-full border-2 border-yellow-500 border-t-transparent animate-spin" />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
@@ -31,20 +41,22 @@ const StatusIndicator = React.memo(function StatusIndicator({
|
||||
return (
|
||||
<span
|
||||
className={cn('inline-flex h-3 w-3 shrink-0 items-center justify-center', className)}
|
||||
title={resolvedTitle}
|
||||
{...rest}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
'block size-2 rounded-full',
|
||||
status === 'active'
|
||||
? 'bg-emerald-500'
|
||||
: status === 'permission'
|
||||
? 'bg-red-500'
|
||||
: status === 'done'
|
||||
? // Why: sky-500/80 matches the dashboard AgentStateDot's
|
||||
// `done` color so the two surfaces read as the same state.
|
||||
'bg-sky-500/80'
|
||||
: 'bg-neutral-500/40'
|
||||
status === 'permission'
|
||||
? 'bg-red-500'
|
||||
: status === 'done'
|
||||
? // Green dot for done; working uses a yellow spinner so the
|
||||
// two states differ by both hue and motion. 'active' (terminal
|
||||
// open, quiet) collapses to the same grey as 'inactive' — the
|
||||
// tooltip carries the distinction for sighted users and the
|
||||
// sr-only sibling in callers carries it for AT.
|
||||
'bg-emerald-500'
|
||||
: 'bg-neutral-500/40'
|
||||
)}
|
||||
/>
|
||||
</span>
|
||||
|
||||
@@ -157,7 +157,7 @@ const WorktreeCard = React.memo(function WorktreeCard({
|
||||
// that the spinner flickered; the blocked/waiting/done states don't have
|
||||
// that problem — they're terminal (done) or attention-needed (blocked/
|
||||
// waiting) and persist until the user acts. Retained "done" snapshots are
|
||||
// consulted too so the sky dot keeps glowing after the agent process exits,
|
||||
// consulted too so the done dot keeps glowing after the agent process exits,
|
||||
// matching the dashboard's retention behavior.
|
||||
//
|
||||
// Priority (highest first): permission (blocked/waiting) > heuristic
|
||||
|
||||
Reference in New Issue
Block a user