feat: add rotating activity messages to generation loading state

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-02-24 00:46:42 -05:00
parent 42fc3a5b6e
commit bf005fa1f1

View File

@@ -1,31 +1,60 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { Sparkles } from 'lucide-react' import { cn } from '@/lib/utils'
const MESSAGES = [ const MESSAGES = [
'Analyzing your flow requirements...', 'Setting up your flow...',
'Building decision paths...', 'Building diagnostic paths...',
'Generating troubleshooting logic...', 'Putting the pieces in place...',
'Crafting resolution steps...', 'Almost there...',
'Structuring the flow...', ] as const
]
export function GeneratingAnimation() { const MESSAGE_DURATIONS = [4000, 8000, 8000, Infinity] // ms each message shows
interface GeneratingAnimationProps {
branchContext?: { current: number; total: number }
}
export function GeneratingAnimation({ branchContext }: GeneratingAnimationProps) {
const [messageIndex, setMessageIndex] = useState(0) const [messageIndex, setMessageIndex] = useState(0)
// Reset and advance message on mount/remount
useEffect(() => { useEffect(() => {
const interval = setInterval(() => { setMessageIndex(0)
setMessageIndex((prev) => (prev + 1) % MESSAGES.length) let current = 0
}, 3000)
return () => clearInterval(interval) const advance = () => {
current += 1
if (current < MESSAGES.length - 1) {
setMessageIndex(current)
timer = setTimeout(advance, MESSAGE_DURATIONS[current])
} else {
setMessageIndex(MESSAGES.length - 1)
}
}
let timer = setTimeout(advance, MESSAGE_DURATIONS[0])
return () => clearTimeout(timer)
}, []) }, [])
return ( return (
<div className="flex flex-col items-center justify-center gap-4 py-12"> <div className="flex flex-col items-center justify-center gap-4 py-10">
<div className="relative"> {/* Spinner */}
<div className="h-12 w-12 animate-spin rounded-full border-4 border-border border-t-primary" /> <div className="h-8 w-8 animate-spin rounded-full border-2 border-border border-t-primary" />
<Sparkles className="absolute left-1/2 top-1/2 h-5 w-5 -translate-x-1/2 -translate-y-1/2 text-primary" />
</div> {/* Branch context (Generate All mode) */}
<p className="text-sm text-muted-foreground animate-pulse"> {branchContext && (
<p className="text-xs font-label uppercase tracking-wide text-muted-foreground">
Branch {branchContext.current} of {branchContext.total}
</p>
)}
{/* Rotating message */}
<p
key={messageIndex}
className={cn(
'text-sm text-muted-foreground transition-opacity duration-500',
)}
>
{MESSAGES[messageIndex]} {MESSAGES[messageIndex]}
</p> </p>
</div> </div>