diff options
| author | 2026-03-29 21:41:13 +0800 | |
|---|---|---|
| committer | 2026-03-29 21:41:13 +0800 | |
| commit | ff2b6ee23e9d57409c50533b80edb51c4082a7bb (patch) | |
| tree | 0758f02ff9d1069a7aa6fb305e05338e60d976ea /packages/ui/src/components/game-console.tsx | |
| parent | 70348cefb7de8c1e044800296a99177309c5a81e (diff) | |
| download | DropOut-ff2b6ee23e9d57409c50533b80edb51c4082a7bb.tar.gz DropOut-ff2b6ee23e9d57409c50533b80edb51c4082a7bb.zip | |
fix(build): fix pnpm buildfix/build
Diffstat (limited to 'packages/ui/src/components/game-console.tsx')
| -rw-r--r-- | packages/ui/src/components/game-console.tsx | 290 |
1 files changed, 0 insertions, 290 deletions
diff --git a/packages/ui/src/components/game-console.tsx b/packages/ui/src/components/game-console.tsx deleted file mode 100644 index 6980c8c..0000000 --- a/packages/ui/src/components/game-console.tsx +++ /dev/null @@ -1,290 +0,0 @@ -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<Set<string>>( - new Set(["info", "warn", "error", "debug", "fatal"]), - ); - const [autoScroll, setAutoScroll] = useState(true); - const consoleEndRef = useRef<HTMLDivElement>(null); - const logsContainerRef = useRef<HTMLDivElement>(null); - - const levelColors: Record<string, string> = { - info: "text-blue-400", - warn: "text-amber-400", - error: "text-red-400", - debug: "text-purple-400", - fatal: "text-rose-400", - }; - - const levelBgColors: Record<string, string> = { - 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 */} - <div className="flex items-center justify-between p-4 border-b border-zinc-700 bg-[#252526]"> - <div className="flex items-center gap-3"> - <h2 className="text-lg font-bold text-white">Game Console</h2> - <div className="flex items-center gap-1"> - <span className="text-xs text-zinc-400">Logs:</span> - <span className="text-xs font-medium text-emerald-400"> - {filteredLogs.length} - </span> - <span className="text-xs text-zinc-400">/</span> - <span className="text-xs text-zinc-400"> - {logsStore.logs.length} - </span> - </div> - </div> - <button - type="button" - onClick={() => uiStore.toggleConsole()} - className="p-2 text-zinc-400 hover:text-white transition-colors" - > - <X size={20} /> - </button> - </div> - - {/* Toolbar */} - <div className="flex items-center gap-3 p-3 border-b border-zinc-700 bg-[#2D2D30]"> - {/* Search */} - <div className="relative flex-1"> - <Search - className="absolute left-3 top-1/2 transform -translate-y-1/2 text-zinc-500" - size={16} - /> - <input - type="text" - value={searchTerm} - onChange={(e) => 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 && ( - <button - type="button" - onClick={() => setSearchTerm("")} - className="absolute right-3 top-1/2 transform -translate-y-1/2 text-zinc-400 hover:text-white" - > - × - </button> - )} - </div> - - {/* Level Filters */} - <div className="flex items-center gap-1"> - {Object.entries(levelColors).map(([level, colorClass]) => ( - <button - type="button" - key={level} - onClick={() => toggleLevel(level)} - className={`px-3 py-1.5 text-xs font-medium rounded transition-colors ${ - selectedLevels.has(level) - ? `${levelBgColors[level]} ${colorClass}` - : "bg-[#3E3E42] text-zinc-400 hover:text-white" - }`} - > - {level.toUpperCase()} - </button> - ))} - </div> - - {/* Actions */} - <div className="flex items-center gap-1"> - <button - type="button" - onClick={handleCopyAll} - className="p-2 text-zinc-400 hover:text-white transition-colors" - title="Copy all logs" - > - <Copy size={16} /> - </button> - <button - type="button" - onClick={handleExport} - className="p-2 text-zinc-400 hover:text-white transition-colors" - title="Export logs" - > - <Download size={16} /> - </button> - <button - type="button" - onClick={handleClear} - className="p-2 text-zinc-400 hover:text-white transition-colors" - title="Clear logs" - > - <Trash2 size={16} /> - </button> - </div> - - {/* Auto-scroll Toggle */} - <div className="flex items-center gap-2 pl-2 border-l border-zinc-700"> - <label className="inline-flex items-center cursor-pointer"> - <input - type="checkbox" - checked={autoScroll} - onChange={(e) => setAutoScroll(e.target.checked)} - className="sr-only peer" - /> - <div className="relative w-9 h-5 bg-zinc-700 peer-focus:outline-none peer-focus:ring-blue-800 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-0.5 after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-blue-600"></div> - <span className="ml-2 text-xs text-zinc-400">Auto-scroll</span> - </label> - </div> - </div> - - {/* Logs Container */} - <div - ref={logsContainerRef} - className="flex-1 overflow-y-auto font-mono text-sm bg-[#1E1E1E]" - style={{ fontFamily: "'Cascadia Code', 'Consolas', monospace" }} - > - {filteredLogs.length === 0 ? ( - <div className="flex items-center justify-center h-full"> - <div className="text-center text-zinc-500"> - <Filter className="mx-auto mb-2" size={24} /> - <p>No logs match the current filters</p> - </div> - </div> - ) : ( - <div className="p-4 space-y-1"> - {filteredLogs.map((log) => ( - <div - key={log.id} - className="group hover:bg-white/5 p-2 rounded transition-colors" - > - <div className="flex items-start gap-3"> - <div - className={`px-2 py-0.5 rounded text-xs font-medium ${levelBgColors[log.level]} ${levelColors[log.level]}`} - > - {log.level.toUpperCase()} - </div> - <div className="text-zinc-400 text-xs shrink-0"> - {log.timestamp} - </div> - <div className="text-amber-300 text-xs shrink-0"> - [{log.source}] - </div> - <div className="text-gray-300 flex-1">{log.message}</div> - </div> - </div> - ))} - <div ref={consoleEndRef} /> - </div> - )} - </div> - - {/* Footer */} - <div className="flex items-center justify-between p-3 border-t border-zinc-700 bg-[#252526] text-xs text-zinc-400"> - <div className="flex items-center gap-4"> - <div> - <span>Total: </span> - <span className="text-white">{logsStore.logs.length}</span> - <span> | Filtered: </span> - <span className="text-emerald-400">{filteredLogs.length}</span> - </div> - <div className="flex items-center gap-2"> - <kbd className="px-1.5 py-0.5 bg-[#3E3E42] rounded text-xs"> - Ctrl+K - </kbd> - <span>to search</span> - </div> - </div> - <div> - <span>Updated: </span> - <span> - {new Date().toLocaleTimeString([], { - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - })} - </span> - </div> - </div> - </> - ); -} |