"use client"; import { useEffect, useRef, useState } from "react"; import { ChevronDown, Loader2, Terminal } from "lucide-react"; import { useTranslation } from "react-i18next"; interface ProcessLogsProps { logs: string[]; executing: boolean; title?: string; emptyMessage?: string; } export default function ProcessLogs({ logs, executing, title, emptyMessage = "Waiting for output...", }: ProcessLogsProps) { const { t } = useTranslation(); const resolvedTitle = title ?? t("Process Logs"); const [open, setOpen] = useState(true); const logContainerRef = useRef(null); const stickToBottomRef = useRef(true); useEffect(() => { if (executing && logs.length === 0) { stickToBottomRef.current = true; } }, [executing, logs.length]); useEffect(() => { const container = logContainerRef.current; if (!container || !open || !logs.length) return; if (!stickToBottomRef.current) return; container.scrollTo({ top: container.scrollHeight, behavior: "smooth" }); }, [logs.length, open]); if (!logs.length && !executing) return null; return (
setOpen((e.target as HTMLDetailsElement).open)} className="group rounded-lg border border-[var(--border)] bg-[var(--card)]" > {resolvedTitle} {logs.length > 0 && ( {logs.length} )}
{executing && ( )}
{ const container = e.currentTarget; const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight; stickToBottomRef.current = distanceFromBottom <= 24; }} className="max-h-[220px] overflow-y-auto px-3 py-2.5 font-mono text-[11px] leading-[1.7] text-[var(--muted-foreground)]" > {logs.map((line, i) => (
{String(i + 1).padStart(3)} {line}
))} {executing && logs.length === 0 && (
{emptyMessage}
)}
); }