feat(ui): 添加 IDE 组件(文件浏览器 + 代码编辑器)

- 新增 CodeEditor 组件,基于 CodeMirror 实现多标签代码编辑
- 新增 FileExplorer 组件,支持文件树展开/折叠和文件选择
- 新增 IDE 组件,整合文件浏览器和代码编辑器
- 新增 SessionPanel 组件,用于会话管理
- 添加文件写入 API(PUT /api/files/write)
- 优化布局:IDE 始终显示,移除文件切换按钮
- 工作目录路径显示在文件浏览器标题栏,支持悬浮显示完整路径
This commit is contained in:
2025-12-17 16:55:22 +08:00
parent ddec356117
commit 250d2cb4b5
11 changed files with 1376 additions and 113 deletions
+11 -31
View File
@@ -3,7 +3,7 @@
*/
import { useEffect, useRef } from 'react';
import { WifiOff, MessageSquare, FolderOpen, Terminal, Plug, Zap, Bot, History, Server, Folder } from 'lucide-react';
import { WifiOff, MessageSquare, Terminal, Plug, Zap, Bot, History, Server, MessagesSquare } from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import { toast } from 'sonner';
import {
@@ -23,8 +23,6 @@ interface ChatPageProps {
onSessionUpdated?: (sessionId: string, name: string) => void;
responsive?: boolean;
// 工具栏按钮
showFileBrowser?: boolean;
onToggleFileBrowser?: () => void;
onOpenCommands?: () => void;
onOpenMCP?: () => void;
onOpenHooks?: () => void;
@@ -33,8 +31,7 @@ interface ChatPageProps {
onOpenProviders?: () => void;
onOpenLSP?: () => void;
onOpenDiagnostics?: () => void;
// Working Directory
workingDirectory?: string;
onOpenSessions?: () => void;
}
export function ChatPage({
@@ -42,8 +39,6 @@ export function ChatPage({
onSessionNotFound,
onSessionUpdated,
responsive = false,
showFileBrowser,
onToggleFileBrowser,
onOpenCommands,
onOpenMCP,
onOpenHooks,
@@ -52,7 +47,7 @@ export function ChatPage({
onOpenProviders,
onOpenLSP,
onOpenDiagnostics,
workingDirectory,
onOpenSessions,
}: ChatPageProps) {
const {
messages,
@@ -162,18 +157,7 @@ export function ChatPage({
<div className="flex-1 flex flex-col h-screen">
{/* Header */}
<div className="flex items-center justify-between px-4 md:px-6 py-3 border-b border-line bg-surface-subtle">
<div className="flex items-center gap-3 min-w-0">
<h1 className="text-lg font-medium text-fg flex-shrink-0">Chat</h1>
{/* Working Directory */}
{workingDirectory && (
<div className="flex items-center gap-1.5 text-sm text-fg-muted min-w-0">
<Folder size={14} className="flex-shrink-0 text-fg-subtle" />
<span className="truncate font-mono text-xs" title={workingDirectory}>
{workingDirectory}
</span>
</div>
)}
</div>
<h1 className="text-lg font-medium text-fg">Chat</h1>
<div className="flex items-center gap-3 flex-shrink-0">
{/* 上下文使用情况 - 紧凑模式 */}
{sessionId && (
@@ -189,7 +173,7 @@ export function ChatPage({
<ConnectionStatus />
{/* 工具栏按钮 */}
{(onToggleFileBrowser || onOpenCommands || onOpenMCP || onOpenHooks || onOpenAgents || onOpenCheckpoints || onOpenProviders || onOpenLSP || onOpenDiagnostics) && (
{(onOpenCommands || onOpenMCP || onOpenHooks || onOpenAgents || onOpenCheckpoints || onOpenProviders || onOpenLSP || onOpenDiagnostics || onOpenSessions) && (
<div className="flex items-center gap-1.5 border-l border-line-muted pl-3">
{/* LSP 诊断指示器 */}
{(onOpenLSP || onOpenDiagnostics) && (
@@ -278,20 +262,16 @@ export function ChatPage({
</motion.button>
)}
{/* 文件浏览器按钮 - 仅桌面端显示 */}
{onToggleFileBrowser && (
{/* Sessions 按钮 */}
{onOpenSessions && (
<motion.button
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
onClick={onToggleFileBrowser}
className={`hidden md:block p-1.5 rounded-lg transition-colors ${
showFileBrowser
? 'text-blue-400 bg-blue-500/20'
: 'text-fg-muted hover:text-fg-secondary hover:bg-surface-muted'
}`}
title={showFileBrowser ? 'Hide Files' : 'Show Files'}
onClick={onOpenSessions}
className="p-1.5 rounded-lg text-fg-muted hover:text-fg-secondary hover:bg-surface-muted transition-colors"
title="Sessions"
>
<FolderOpen size={20} />
<MessagesSquare size={20} />
</motion.button>
)}
</div>