"use client"; import { AnimatePresence, motion, useReducedMotion } from "motion/react"; import { type ReactNode, useEffect, useState } from "react"; import { Progress } from "@/components/motion/progress"; import { cn } from "@/lib/utils"; const EASE = [0.23, 1, 0.32, 1] as const; export interface ShimmerTextProps { children: ReactNode; className?: string; } /** Status text with a bright band sweeping across it, for a quiet "still working" signal. */ export function ShimmerText({ children, className }: ShimmerTextProps) { const reduce = useReducedMotion(); if (reduce) { return ( {children} ); } return ( {children} ); } export interface AgentProgressProps { label: string; /** 0 to 100. Omitted, the bar runs indeterminate. */ value?: number; className?: string; } /** A labeled progress bar with a pulsing dot marking it as a live, running step. */ export function AgentProgress({ label, value, className }: AgentProgressProps) { return (
{label}
); } export interface ReasoningPhasesProps { phases: string[]; /** Milliseconds each phrase stays before crossfading to the next. Default 2200. */ interval?: number; className?: string; } /** Cycles through short phrases, crossfading between them, to narrate an agent's steps. */ export function ReasoningPhases({ phases, interval = 2200, className }: ReasoningPhasesProps) { const [index, setIndex] = useState(0); const reduce = useReducedMotion(); useEffect(() => { if (phases.length < 2) return; const timer = setInterval(() => setIndex((i) => (i + 1) % phases.length), interval); return () => clearInterval(timer); }, [phases.length, interval]); return (
{phases[index]}
); }