import { Copy, Download, Filter, Search, Trash2, X } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { useLogsStore } from "@/stores/logs-store"; import { useUIStore } from "@/stores/ui-store"; export function GameConsole() { const uiStore = useUIStore(); const logsStore = useLogsStore(); const [searchTerm, setSearchTerm] = useState(""); const [selectedLevels, setSelectedLevels] = useState>( new Set(["info", "warn", "error", "debug", "fatal"]), ); const [autoScroll, setAutoScroll] = useState(true); const consoleEndRef = useRef(null); const logsContainerRef = useRef(null); const levelColors: Record = { info: "text-blue-400", warn: "text-amber-400", error: "text-red-400", debug: "text-purple-400", fatal: "text-rose-400", }; const levelBgColors: Record = { info: "bg-blue-400/10", warn: "bg-amber-400/10", error: "bg-red-400/10", debug: "bg-purple-400/10", fatal: "bg-rose-400/10", }; // Filter logs based on search term and selected levels const filteredLogs = logsStore.logs.filter((log) => { const matchesSearch = searchTerm === "" || log.message.toLowerCase().includes(searchTerm.toLowerCase()) || log.source.toLowerCase().includes(searchTerm.toLowerCase()); const matchesLevel = selectedLevels.has(log.level); return matchesSearch && matchesLevel; }); // Auto-scroll to bottom when new logs arrive or autoScroll is enabled useEffect(() => { if (autoScroll && consoleEndRef.current && filteredLogs.length > 0) { consoleEndRef.current.scrollIntoView({ behavior: "smooth" }); } }, [filteredLogs, autoScroll]); // Handle keyboard shortcuts useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { // Ctrl/Cmd + K to focus search if ((e.ctrlKey || e.metaKey) && e.key === "k") { e.preventDefault(); // Focus search input const searchInput = document.querySelector( 'input[type="text"]', ) as HTMLInputElement; if (searchInput) searchInput.focus(); } // Escape to close console if (e.key === "Escape") { uiStore.toggleConsole(); } }; window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); }, [uiStore.toggleConsole]); const toggleLevel = (level: string) => { const newLevels = new Set(selectedLevels); if (newLevels.has(level)) { newLevels.delete(level); } else { newLevels.add(level); } setSelectedLevels(newLevels); }; const handleCopyAll = () => { const logsText = logsStore.exportLogs(filteredLogs); navigator.clipboard.writeText(logsText); }; const handleExport = () => { const logsText = logsStore.exportLogs(filteredLogs); const blob = new Blob([logsText], { type: "text/plain" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = `dropout_logs_${new Date().toISOString().replace(/[:.]/g, "-")}.txt`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); }; const handleClear = () => { logsStore.clear(); }; return ( <> {/* Header */}

Game Console

Logs: {filteredLogs.length} / {logsStore.logs.length}
{/* Toolbar */}
{/* Search */}
setSearchTerm(e.target.value)} placeholder="Search logs..." className="w-full pl-10 pr-4 py-2 bg-[#3E3E42] border border-zinc-600 rounded text-sm text-white placeholder:text-zinc-500 focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500" /> {searchTerm && ( )}
{/* Level Filters */}
{Object.entries(levelColors).map(([level, colorClass]) => ( ))}
{/* Actions */}
{/* Auto-scroll Toggle */}
{/* Logs Container */}
{filteredLogs.length === 0 ? (

No logs match the current filters

) : (
{filteredLogs.map((log) => (
{log.level.toUpperCase()}
{log.timestamp}
[{log.source}]
{log.message}
))}
)}
{/* Footer */}
Total: {logsStore.logs.length} | Filtered: {filteredLogs.length}
Ctrl+K to search
Updated: {new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit", })}
); }