import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import TitleBar from './components/TitleBar'; import Sidebar from './components/Sidebar'; import Terminal from './components/Terminal'; import HostManager from './components/HostManager'; import Settings from './components/Settings'; import CommandPalette from './components/CommandPalette'; function App() { const [hosts, setHosts] = useState([]); const [activeTabs, setActiveTabs] = useState([]); const [activeTabId, setActiveTabId] = useState(null); const [showHostManager, setShowHostManager] = useState(false); const [editingHost, setEditingHost] = useState(null); const [showSettings, setShowSettings] = useState(false); const [showCommandPalette, setShowCommandPalette] = useState(false); const [isRemoteConnected, setIsRemoteConnected] = useState(false); const [sidebarCollapsed, setSidebarCollapsed] = useState(false); // 加载主机列表 const loadHosts = useCallback(async () => { if (window.electronAPI) { const hostList = await window.electronAPI.hosts.getAll(); setHosts(hostList); } }, []); // 检查远程连接状态 const checkRemoteStatus = useCallback(async () => { if (window.electronAPI) { const connected = await window.electronAPI.db.isRemoteConnected(); setIsRemoteConnected(connected); // 如果已连接,刷新主机列表(因为启动时可能已自动同步) if (connected) { loadHosts(); } } }, [loadHosts]); useEffect(() => { loadHosts(); checkRemoteStatus(); }, [loadHosts, checkRemoteStatus]); // 键盘快捷键 useEffect(() => { const handleKeyDown = (e) => { if ((e.ctrlKey || e.metaKey) && e.key === 'k') { e.preventDefault(); setShowCommandPalette(true); } if (e.key === 'Escape') { setShowCommandPalette(false); setShowHostManager(false); setShowSettings(false); } }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, []); // 连接主机 const connectHost = useCallback((host) => { const tabId = `terminal-${host.id}-${Date.now()}`; const newTab = { id: tabId, hostId: host.id, title: host.name, host: host.host, type: 'terminal', connected: false, }; setActiveTabs((prev) => [...prev, newTab]); setActiveTabId(tabId); setShowHostManager(false); }, []); // 关闭标签页 const closeTab = useCallback((tabId) => { setActiveTabs((prev) => { const newTabs = prev.filter((t) => t.id !== tabId); return newTabs; }); setActiveTabId((prevActiveId) => { if (prevActiveId === tabId) { const remainingTabs = activeTabs.filter((t) => t.id !== tabId); return remainingTabs.length > 0 ? remainingTabs[remainingTabs.length - 1].id : null; } return prevActiveId; }); }, [activeTabs]); // 更新连接状态 const handleConnectionChange = useCallback((tabId, connected) => { setActiveTabs((prev) => prev.map((t) => (t.id === tabId ? { ...t, connected } : t)) ); }, []); // 处理主机更新 const handleHostsUpdate = useCallback(() => { loadHosts(); }, [loadHosts]); // 编辑主机 const handleEditHost = useCallback((host) => { setEditingHost(host); setShowHostManager(true); }, []); const openHostManager = useCallback(() => { setEditingHost(null); setShowHostManager(true); }, []); const openSettings = useCallback(() => { setShowSettings(true); }, []); const openCommandPalette = useCallback(() => { setShowCommandPalette(true); }, []); return (
setSidebarCollapsed(!sidebarCollapsed)} />
{/* 标签栏 */} {activeTabs.length > 0 && (
{activeTabs.map((tab) => (
setActiveTabId(tab.id)} > {tab.title}
))}
)} {/* 终端内容 - 所有终端都渲染,通过显示/隐藏切换 */}
{activeTabs.length === 0 ? (
🚀

欢迎使用 EasyShell

高颜值远程 Shell 管理终端

Ctrl+K 打开命令面板

) : ( activeTabs.map((tab) => (
handleConnectionChange(tab.id, connected)} onShowCommandPalette={openCommandPalette} />
)) )}
{/* 弹窗 */} {showHostManager && ( { setShowHostManager(false); setEditingHost(null); }} onConnect={connectHost} onUpdate={handleHostsUpdate} /> )} {showSettings && ( setShowSettings(false)} isRemoteConnected={isRemoteConnected} onConnectionChange={(connected) => { setIsRemoteConnected(connected); if (connected) loadHosts(); }} onHostsUpdate={loadHosts} /> )} {showCommandPalette && ( setShowCommandPalette(false)} onSelectCommand={(cmd) => { if (activeTabId) { const event = new CustomEvent('terminal-command', { detail: { tabId: activeTabId, command: cmd }, }); window.dispatchEvent(event); } setShowCommandPalette(false); }} /> )}
); } export default App;