2025-12-01 22:28:51 +08:00
|
|
|
import { useState, useEffect, useCallback } from 'react';
|
|
|
|
|
import { X, BarChart3, Maximize2, Minimize2 } from 'lucide-react';
|
2025-11-30 00:22:47 +08:00
|
|
|
import { ProfilerService } from '../services/ProfilerService';
|
|
|
|
|
import { AdvancedProfiler } from './AdvancedProfiler';
|
|
|
|
|
import '../styles/ProfilerWindow.css';
|
|
|
|
|
|
|
|
|
|
interface AdvancedProfilerWindowProps {
|
|
|
|
|
onClose: () => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface WindowWithProfiler extends Window {
|
|
|
|
|
__PROFILER_SERVICE__?: ProfilerService;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function AdvancedProfilerWindow({ onClose }: AdvancedProfilerWindowProps) {
|
|
|
|
|
const [profilerService, setProfilerService] = useState<ProfilerService | null>(null);
|
|
|
|
|
const [isConnected, setIsConnected] = useState(false);
|
2025-12-01 22:28:51 +08:00
|
|
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
2025-11-30 00:22:47 +08:00
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const service = (window as WindowWithProfiler).__PROFILER_SERVICE__;
|
|
|
|
|
if (service) {
|
|
|
|
|
setProfilerService(service);
|
|
|
|
|
}
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!profilerService) return;
|
|
|
|
|
|
|
|
|
|
const checkStatus = () => {
|
|
|
|
|
setIsConnected(profilerService.isConnected());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
checkStatus();
|
|
|
|
|
const interval = setInterval(checkStatus, 1000);
|
|
|
|
|
|
|
|
|
|
return () => clearInterval(interval);
|
|
|
|
|
}, [profilerService]);
|
|
|
|
|
|
2025-12-01 22:28:51 +08:00
|
|
|
// 处理 ESC 键退出全屏
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
|
|
|
if (e.key === 'Escape' && isFullscreen) {
|
|
|
|
|
setIsFullscreen(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
window.addEventListener('keydown', handleKeyDown);
|
|
|
|
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
|
|
|
}, [isFullscreen]);
|
|
|
|
|
|
|
|
|
|
const toggleFullscreen = useCallback(() => {
|
|
|
|
|
setIsFullscreen(prev => !prev);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const windowStyle = isFullscreen
|
|
|
|
|
? { width: '100vw', height: '100vh', maxWidth: 'none', borderRadius: 0 }
|
|
|
|
|
: { width: '90vw', height: '85vh', maxWidth: '1600px' };
|
|
|
|
|
|
2025-11-30 00:22:47 +08:00
|
|
|
return (
|
2025-12-01 22:28:51 +08:00
|
|
|
<div
|
|
|
|
|
className={`profiler-window-overlay ${isFullscreen ? 'fullscreen' : ''}`}
|
|
|
|
|
onClick={isFullscreen ? undefined : onClose}
|
|
|
|
|
>
|
2025-11-30 00:22:47 +08:00
|
|
|
<div
|
2025-12-01 22:28:51 +08:00
|
|
|
className={`profiler-window advanced-profiler-window ${isFullscreen ? 'fullscreen' : ''}`}
|
2025-11-30 00:22:47 +08:00
|
|
|
onClick={(e) => e.stopPropagation()}
|
2025-12-01 22:28:51 +08:00
|
|
|
style={windowStyle}
|
2025-11-30 00:22:47 +08:00
|
|
|
>
|
|
|
|
|
<div className="profiler-window-header">
|
|
|
|
|
<div className="profiler-window-title">
|
|
|
|
|
<BarChart3 size={20} />
|
|
|
|
|
<h2>Advanced Performance Profiler</h2>
|
|
|
|
|
{!isConnected && (
|
|
|
|
|
<span className="paused-indicator" style={{ background: '#ef4444' }}>
|
|
|
|
|
DISCONNECTED
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2025-12-01 22:28:51 +08:00
|
|
|
<div className="profiler-window-controls">
|
|
|
|
|
<button
|
|
|
|
|
className="profiler-window-btn"
|
|
|
|
|
onClick={toggleFullscreen}
|
|
|
|
|
title={isFullscreen ? 'Exit Fullscreen (Esc)' : 'Fullscreen'}
|
|
|
|
|
>
|
|
|
|
|
{isFullscreen ? <Minimize2 size={16} /> : <Maximize2 size={16} />}
|
|
|
|
|
</button>
|
|
|
|
|
<button className="profiler-window-close" onClick={onClose} title="Close">
|
|
|
|
|
<X size={20} />
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
2025-11-30 00:22:47 +08:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="profiler-window-content" style={{ padding: 0 }}>
|
|
|
|
|
<AdvancedProfiler profilerService={profilerService} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|