({
logoColor,
accentColor,
blockColor,
terminalWidth,
sheenPosition,
setSheenPosition,
}: UseSheenAnimationParams)
| 21 | * Animates a fill effect that loops: fill with accent color, then unfill back to original |
| 22 | */ |
| 23 | export function useSheenAnimation({ |
| 24 | logoColor, |
| 25 | accentColor, |
| 26 | blockColor, |
| 27 | terminalWidth, |
| 28 | sheenPosition, |
| 29 | setSheenPosition, |
| 30 | }: UseSheenAnimationParams) { |
| 31 | // Track whether we're in the reverse (unfill) phase |
| 32 | const [isReversing, setIsReversing] = useState(false) |
| 33 | |
| 34 | // Run looping sheen animation |
| 35 | useEffect(() => { |
| 36 | const maxPosition = Math.max(10, Math.min((terminalWidth || 80) - 4, 100)) |
| 37 | const step = SHEEN_STEP |
| 38 | |
| 39 | const interval = setInterval(() => { |
| 40 | setSheenPosition((prev) => { |
| 41 | const next = prev + step |
| 42 | |
| 43 | if (next >= maxPosition) { |
| 44 | // Reached the end, switch direction |
| 45 | setIsReversing((wasReversing) => !wasReversing) |
| 46 | return 0 // Reset position for next phase |
| 47 | } |
| 48 | |
| 49 | return next |
| 50 | }) |
| 51 | }, SHEEN_INTERVAL_MS) |
| 52 | |
| 53 | return () => { |
| 54 | clearInterval(interval) |
| 55 | } |
| 56 | }, [terminalWidth, setSheenPosition]) |
| 57 | |
| 58 | // Apply sheen effect to a character based on its position |
| 59 | const applySheenToChar = useCallback( |
| 60 | (char: string, charIndex: number) => { |
| 61 | if (char === ' ' || char === '\n') { |
| 62 | return <span key={charIndex}>{char}</span> |
| 63 | } |
| 64 | |
| 65 | const color = getSheenColor( |
| 66 | char, |
| 67 | charIndex, |
| 68 | sheenPosition, |
| 69 | logoColor, |
| 70 | SHADOW_CHARS, |
| 71 | accentColor, |
| 72 | blockColor, |
| 73 | isReversing, |
| 74 | ) |
| 75 | |
| 76 | return ( |
| 77 | <span key={charIndex} fg={color}> |
| 78 | {char} |
| 79 | </span> |
| 80 | ) |
no test coverage detected