Refactor GTM Architect to v2: Python-driven architecture, 9-phase process, new DB and Docker setup
This commit is contained in:
79
k-pop-thumbnail-genie/components/DebugConsole.tsx
Normal file
79
k-pop-thumbnail-genie/components/DebugConsole.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { useLogger, LogMessage, LogType } from '../contexts/LoggingContext';
|
||||
|
||||
const LOG_COLORS: Record<LogType, string> = {
|
||||
info: 'text-gray-300',
|
||||
success: 'text-green-400',
|
||||
error: 'text-red-400',
|
||||
warn: 'text-yellow-400',
|
||||
};
|
||||
|
||||
const DebugConsole: React.FC = () => {
|
||||
const { logs, clearLogs } = useLogger();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [copyStatus, setCopyStatus] = useState('Copy');
|
||||
const logsEndRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const scrollToBottom = () => {
|
||||
logsEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||
};
|
||||
|
||||
useEffect(scrollToBottom, [logs]);
|
||||
|
||||
const handleCopy = () => {
|
||||
const logText = logs.map(log => `[${log.timestamp}] [${log.type.toUpperCase()}] ${log.message}`).join('\n');
|
||||
navigator.clipboard.writeText(logText).then(() => {
|
||||
setCopyStatus('Copied!');
|
||||
setTimeout(() => setCopyStatus('Copy'), 2000);
|
||||
}, () => {
|
||||
setCopyStatus('Failed!');
|
||||
setTimeout(() => setCopyStatus('Copy'), 2000);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
className="fixed bottom-4 right-4 bg-purple-700 hover:bg-purple-800 text-white rounded-full p-3 shadow-lg z-50 transition-transform hover:scale-110"
|
||||
aria-label="Toggle Debug Console"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{isOpen && (
|
||||
<div className="fixed bottom-0 left-0 right-0 h-1/3 bg-gray-900/95 backdrop-blur-sm border-t-2 border-purple-800 z-40 flex flex-col p-2 shadow-2xl">
|
||||
<div className="flex items-center justify-between mb-2 px-2 flex-shrink-0">
|
||||
<h3 className="font-teko text-2xl text-purple-300 tracking-wide">DEBUG CONSOLE</h3>
|
||||
<div className="flex items-center gap-2">
|
||||
<button onClick={handleCopy} className="text-xs bg-gray-700 hover:bg-gray-600 text-gray-300 px-3 py-1 rounded-md transition-colors">{copyStatus}</button>
|
||||
<button onClick={clearLogs} className="text-xs bg-gray-700 hover:bg-gray-600 text-gray-300 px-3 py-1 rounded-md transition-colors">Clear</button>
|
||||
<button onClick={() => setIsOpen(false)} className="text-gray-400 hover:text-white">×</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="overflow-y-auto flex-grow bg-black/50 p-2 rounded-md font-mono text-sm">
|
||||
{logs.length === 0 ? (
|
||||
<p className="text-gray-500">No logs yet. Start using the app to see messages here.</p>
|
||||
) : (
|
||||
logs.map((log, index) => (
|
||||
<div key={index} className="flex">
|
||||
<span className="text-gray-500 mr-2 flex-shrink-0">{log.timestamp}</span>
|
||||
<span className={`${LOG_COLORS[log.type]} whitespace-pre-wrap break-all`}>
|
||||
<span className='font-bold mr-2'>[{log.type.toUpperCase()}]</span>
|
||||
{log.message}
|
||||
</span>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
<div ref={logsEndRef} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DebugConsole;
|
||||
Reference in New Issue
Block a user