AnimatedClaudeAsterisk.tsx
1 import React from 'react' 2 import { Text } from 'ink' 3 import { 4 smallAnimatedArray, 5 largeAnimatedAray, 6 } from '../constants/claude-asterisk-ascii-art.js' 7 import { getTheme } from '../utils/theme.js' 8 9 export type ClaudeAsteriskSize = 'small' | 'medium' | 'large' 10 11 interface AnimatedClaudeAsteriskProps { 12 size?: ClaudeAsteriskSize 13 cycles?: number 14 color?: string 15 intervalMs?: number 16 } 17 18 export function AnimatedClaudeAsterisk({ 19 size = 'small', 20 cycles, 21 color, 22 intervalMs, 23 }: AnimatedClaudeAsteriskProps): React.ReactNode { 24 const [currentAsciiArtIndex, setCurrentAsciiArtIndex] = React.useState(0) 25 const direction = React.useRef(1) 26 const animateLoopCount = React.useRef(0) 27 const theme = getTheme() 28 29 // Determine which array to use based on size 30 const animatedArray = 31 size === 'large' ? largeAnimatedAray : smallAnimatedArray 32 33 // Animation interval for ascii art 34 React.useEffect(() => { 35 const timer = setInterval( 36 () => { 37 setCurrentAsciiArtIndex(prevIndex => { 38 // Stop animating after specified number of cycles if provided 39 if ( 40 cycles !== undefined && 41 cycles !== null && 42 animateLoopCount.current >= cycles 43 ) { 44 return 0 45 } 46 47 // Cycle through array indices 48 if (prevIndex === animatedArray.length - 1) { 49 direction.current = -1 50 animateLoopCount.current += 1 51 } 52 if (prevIndex === 0) { 53 direction.current = 1 54 } 55 return prevIndex + direction.current 56 }) 57 }, 58 intervalMs || (size === 'large' ? 100 : 200), 59 ) // Default: 100ms for large, 200ms for small/medium 60 61 return () => clearInterval(timer) 62 }, [animatedArray.length, cycles, intervalMs, size]) 63 64 return ( 65 <Text color={color || theme.claude}> 66 {animatedArray[currentAsciiArtIndex]} 67 </Text> 68 ) 69 }