mirror of
https://github.com/stablyai/orca.git
synced 2026-10-23 08:03:39 +00:00
Brennan chose #14205's original treatment over the turquoise dot, so the visual goes back to nwparker's: lucide Radio in text-yellow-500 across the sidebar, dashboard dot, cmd-j palette and agent-map ring. Reverts only the visual surface. The turn-boundary notification pins stay — the monitoring predicate and the turnCompletedAt stamp share an expression, so a rename can silently drop the stamp and kill a completion that works today with nothing else going red. The --agent-monitoring token is removed with its last consumer rather than left dead in main.css.
76 lines
2.3 KiB
TypeScript
76 lines
2.3 KiB
TypeScript
import { useEffect, useRef } from 'react'
|
|
import { Radio } from 'lucide-react-native'
|
|
import { Animated, Easing, StyleSheet, View } from 'react-native'
|
|
import type { AgentDotState } from '../worktree/agent-row-display'
|
|
|
|
// Per-agent state indicator, 1:1 with desktop AgentStateDot
|
|
// (src/renderer/src/components/AgentStateDot.tsx): yellow spinner for 'working',
|
|
// emerald for 'done', red for blocked/waiting/interrupted (attention), neutral
|
|
// for idle. Distinct from the worktree-level AgentSpinner, which collapses the
|
|
// agent vocabulary into the 5-state rollup the sidebar dot uses.
|
|
const DOT_COLORS: Record<Exclude<AgentDotState, 'working' | 'monitoring'>, string> = {
|
|
done: '#10b981',
|
|
blocked: '#ef4444',
|
|
waiting: '#ef4444',
|
|
interrupted: '#ef4444',
|
|
idle: 'rgba(115,115,115,0.4)'
|
|
}
|
|
const WORKING_COLOR = '#eab308'
|
|
|
|
export function AgentStateDot({ state }: { state: AgentDotState }) {
|
|
const spinValue = useRef(new Animated.Value(0)).current
|
|
|
|
useEffect(() => {
|
|
if (state === 'working') {
|
|
const animation = Animated.loop(
|
|
Animated.timing(spinValue, {
|
|
toValue: 1,
|
|
duration: 1000,
|
|
easing: Easing.linear,
|
|
useNativeDriver: true
|
|
})
|
|
)
|
|
animation.start()
|
|
return () => animation.stop()
|
|
}
|
|
spinValue.setValue(0)
|
|
return undefined
|
|
}, [state, spinValue])
|
|
|
|
if (state === 'working') {
|
|
const rotate = spinValue.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '360deg'] })
|
|
return (
|
|
<View style={styles.wrapper}>
|
|
<Animated.View style={[styles.spinner, { transform: [{ rotate }] }]} />
|
|
</View>
|
|
)
|
|
}
|
|
|
|
if (state === 'monitoring') {
|
|
return (
|
|
<View style={styles.wrapper} accessibilityLabel="Monitoring background tasks">
|
|
<Radio size={10} color={WORKING_COLOR} />
|
|
</View>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<View style={styles.wrapper}>
|
|
<View style={[styles.dot, { backgroundColor: DOT_COLORS[state] }]} />
|
|
</View>
|
|
)
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
wrapper: { width: 10, height: 10, alignItems: 'center', justifyContent: 'center' },
|
|
dot: { width: 6, height: 6, borderRadius: 3 },
|
|
spinner: {
|
|
width: 6,
|
|
height: 6,
|
|
borderRadius: 3,
|
|
borderWidth: 1.5,
|
|
borderColor: WORKING_COLOR,
|
|
borderTopColor: 'transparent'
|
|
}
|
|
})
|