47 lines
1.9 KiB
TypeScript
47 lines
1.9 KiB
TypeScript
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
import { Terminal } from "lucide-react";
|
|
import { useEffect, useRef } from "react";
|
|
import { motion, AnimatePresence } from "motion/react";
|
|
|
|
interface StatusLogProps {
|
|
logs: string[];
|
|
}
|
|
|
|
export function StatusLog({ logs }: StatusLogProps) {
|
|
const scrollRef = useRef<HTMLDivElement>(null);
|
|
|
|
// Auto-scroll to bottom when logs change
|
|
useEffect(() => {
|
|
if (scrollRef.current) {
|
|
scrollRef.current.scrollIntoView({ behavior: "smooth" });
|
|
}
|
|
}, [logs]);
|
|
|
|
return (
|
|
<div className="rounded-lg border bg-neutral-900/40 backdrop-blur text-gray-500 font-mono text-xs p-4 h-48 flex flex-col shadow-inner border-gray-900/30">
|
|
<div className="flex items-center gap-2 mb-2 border-b border-gray-900/50 pb-1">
|
|
<Terminal className="w-3 h-3" />
|
|
<span className="uppercase tracking-wider text-[10px] text-gray-400">System Log</span>
|
|
</div>
|
|
<ScrollArea className="flex-1">
|
|
<div className="flex flex-col gap-1 max-h-10">
|
|
<AnimatePresence initial={false}>
|
|
{logs.map((log, i) => (
|
|
<motion.div
|
|
key={`${i}-${log.substring(0, 10)}`} // Use index + content snippet for key to ensure uniqueness but allow animation
|
|
initial={{ opacity: 0, x: -10 }}
|
|
animate={{ opacity: 1, x: 0 }}
|
|
className="break-all"
|
|
>
|
|
<span className="opacity-50 mr-2 select-none">{">"}</span>
|
|
{log}
|
|
</motion.div>
|
|
))}
|
|
</AnimatePresence>
|
|
<div ref={scrollRef} />
|
|
</div>
|
|
</ScrollArea>
|
|
</div>
|
|
);
|
|
}
|