"use client"; import { useEffect, useRef, useState } from "react"; import type { LogLine } from "@/lib/types"; const LEVELS = ["DEBUG", "INFO", "WARN", "ERROR"] as const; const levelColor: Record = { DEBUG: "text-zinc-500", INFO: "text-zinc-300", WARN: "text-yellow-400", ERROR: "text-red-400", }; interface ServerLogsPanelProps { lines: LogLine[]; connected: boolean; onClear: () => void; } export function ServerLogsPanel({ lines, connected, onClear }: ServerLogsPanelProps) { const scrollRef = useRef(null); const [autoScroll, setAutoScroll] = useState(true); const [levelFilter, setLevelFilter] = useState>( new Set(["DEBUG", "INFO", "WARN", "ERROR"]), ); const filtered = lines.filter((l) => levelFilter.has(l.level.toUpperCase())); useEffect(() => { if (!autoScroll) return; scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight }); }, [filtered.length, autoScroll]); const toggleLevel = (level: string) => { setLevelFilter((prev) => { const next = new Set(prev); if (next.has(level)) next.delete(level); else next.add(level); return next; }); }; const handleScroll = () => { const el = scrollRef.current; if (!el) return; const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 40; setAutoScroll(atBottom); }; const fmtTime = (ts: string) => { if (!ts) return ""; try { return new Date(ts).toLocaleTimeString(undefined, { hour12: false }); } catch { return ts; } }; return (
{/* Header */}
Server Logs {connected ? "● live" : "○ disconnected"}
{LEVELS.map((lvl) => ( ))}
{/* Log lines */}
{filtered.length === 0 ? (

{connected ? "Waiting for log events…" : "Connecting to server…"}

) : ( filtered.map((line, i) => (
{fmtTime(line.timestamp)} {line.level?.toUpperCase()} {line.target} {line.message}
)) )}
{connected && lines.length > 0 ? "▋" : ""}
); }