refactor(ui): 将工具栏按钮移入 Chat Header
- 移除 App.tsx 中 absolute 定位的悬浮按钮 - 将设置和文件浏览器按钮移入 Chat Header - 通过 props 传递按钮状态和回调函数 - 修复 tsconfig.json 的 include 配置错误
This commit is contained in:
@@ -70,54 +70,17 @@ export function App() {
|
|||||||
onCreateSession={handleCreateSession}
|
onCreateSession={handleCreateSession}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 工具栏按钮 */}
|
|
||||||
<div className="absolute top-3 right-4 z-10 flex gap-2">
|
|
||||||
{/* 配置按钮 */}
|
|
||||||
<button
|
|
||||||
onClick={() => setShowConfig(true)}
|
|
||||||
className="p-2 rounded-lg bg-gray-700 text-gray-300 hover:bg-gray-600 transition-colors"
|
|
||||||
title="Settings"
|
|
||||||
>
|
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
strokeWidth={2}
|
|
||||||
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
strokeWidth={2}
|
|
||||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{/* 文件浏览器切换按钮 */}
|
|
||||||
<button
|
|
||||||
onClick={() => setShowFileBrowser(!showFileBrowser)}
|
|
||||||
className={`p-2 rounded-lg transition-colors ${
|
|
||||||
showFileBrowser ? 'bg-blue-600 text-white' : 'bg-gray-700 text-gray-300 hover:bg-gray-600'
|
|
||||||
}`}
|
|
||||||
title={showFileBrowser ? 'Hide Files' : 'Show Files'}
|
|
||||||
>
|
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
strokeWidth={2}
|
|
||||||
d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex-1 flex">
|
<div className="flex-1 flex">
|
||||||
{/* 聊天区域 */}
|
{/* 聊天区域 */}
|
||||||
<div className={`flex-1 ${showFileBrowser ? 'w-1/2' : 'w-full'}`}>
|
<div className={`flex-1 ${showFileBrowser ? 'w-1/2' : 'w-full'}`}>
|
||||||
{currentSessionId ? (
|
{currentSessionId ? (
|
||||||
<ChatPage key={currentSessionId} sessionId={currentSessionId} />
|
<ChatPage
|
||||||
|
key={currentSessionId}
|
||||||
|
sessionId={currentSessionId}
|
||||||
|
showFileBrowser={showFileBrowser}
|
||||||
|
onToggleFileBrowser={() => setShowFileBrowser(!showFileBrowser)}
|
||||||
|
onOpenConfig={() => setShowConfig(true)}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex-1 flex items-center justify-center h-full">
|
<div className="flex-1 flex items-center justify-center h-full">
|
||||||
<p className="text-gray-400">Select or create a session</p>
|
<p className="text-gray-400">Select or create a session</p>
|
||||||
|
|||||||
@@ -14,9 +14,18 @@ import {
|
|||||||
|
|
||||||
interface ChatPageProps {
|
interface ChatPageProps {
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
|
// 工具栏按钮
|
||||||
|
showFileBrowser?: boolean;
|
||||||
|
onToggleFileBrowser?: () => void;
|
||||||
|
onOpenConfig?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ChatPage({ sessionId }: ChatPageProps) {
|
export function ChatPage({
|
||||||
|
sessionId,
|
||||||
|
showFileBrowser,
|
||||||
|
onToggleFileBrowser,
|
||||||
|
onOpenConfig,
|
||||||
|
}: ChatPageProps) {
|
||||||
const {
|
const {
|
||||||
messages,
|
messages,
|
||||||
isConnected,
|
isConnected,
|
||||||
@@ -43,17 +52,71 @@ export function ChatPage({ sessionId }: ChatPageProps) {
|
|||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between px-6 py-3 border-b border-gray-700 bg-gray-800">
|
<div className="flex items-center justify-between px-6 py-3 border-b border-gray-700 bg-gray-800">
|
||||||
<h1 className="text-lg font-medium">Chat</h1>
|
<h1 className="text-lg font-medium">Chat</h1>
|
||||||
<div className="flex items-center gap-2 text-sm">
|
<div className="flex items-center gap-3">
|
||||||
{isConnected ? (
|
{/* 连接状态 */}
|
||||||
<>
|
<div className="flex items-center gap-1.5 text-sm">
|
||||||
<Wifi size={16} className="text-green-500" />
|
{isConnected ? (
|
||||||
<span className="text-green-500">Connected</span>
|
<>
|
||||||
</>
|
<Wifi size={16} className="text-green-500" />
|
||||||
) : (
|
<span className="text-green-500">Connected</span>
|
||||||
<>
|
</>
|
||||||
<WifiOff size={16} className="text-red-500" />
|
) : (
|
||||||
<span className="text-red-500">Disconnected</span>
|
<>
|
||||||
</>
|
<WifiOff size={16} className="text-red-500" />
|
||||||
|
<span className="text-red-500">Disconnected</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 工具栏按钮 */}
|
||||||
|
{(onOpenConfig || onToggleFileBrowser) && (
|
||||||
|
<div className="flex items-center gap-1.5 border-l border-gray-600 pl-3">
|
||||||
|
{/* 配置按钮 */}
|
||||||
|
{onOpenConfig && (
|
||||||
|
<button
|
||||||
|
onClick={onOpenConfig}
|
||||||
|
className="p-1.5 rounded-lg text-gray-400 hover:text-gray-200 hover:bg-gray-700 transition-colors"
|
||||||
|
title="Settings"
|
||||||
|
>
|
||||||
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 文件浏览器按钮 */}
|
||||||
|
{onToggleFileBrowser && (
|
||||||
|
<button
|
||||||
|
onClick={onToggleFileBrowser}
|
||||||
|
className={`p-1.5 rounded-lg transition-colors ${
|
||||||
|
showFileBrowser
|
||||||
|
? 'text-blue-400 bg-blue-500/20'
|
||||||
|
: 'text-gray-400 hover:text-gray-200 hover:bg-gray-700'
|
||||||
|
}`}
|
||||||
|
title={showFileBrowser ? 'Hide Files' : 'Show Files'}
|
||||||
|
>
|
||||||
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -83,49 +83,6 @@ export function App() {
|
|||||||
responsive
|
responsive
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 工具栏按钮 - 移动端右移避开菜单按钮 */}
|
|
||||||
<div className="absolute top-3 right-3 md:right-4 z-30 flex gap-2">
|
|
||||||
{/* 配置按钮 */}
|
|
||||||
<button
|
|
||||||
onClick={() => setShowConfig(true)}
|
|
||||||
className="p-2 rounded-lg bg-gray-700 text-gray-300 hover:bg-gray-600 active:bg-gray-500 transition-colors"
|
|
||||||
title="Settings"
|
|
||||||
>
|
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
strokeWidth={2}
|
|
||||||
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
strokeWidth={2}
|
|
||||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{/* 文件浏览器切换按钮 - 移动端隐藏 */}
|
|
||||||
<button
|
|
||||||
onClick={() => setShowFileBrowser(!showFileBrowser)}
|
|
||||||
className={`hidden md:block p-2 rounded-lg transition-colors ${
|
|
||||||
showFileBrowser ? 'bg-blue-600 text-white' : 'bg-gray-700 text-gray-300 hover:bg-gray-600'
|
|
||||||
}`}
|
|
||||||
title={showFileBrowser ? 'Hide Files' : 'Show Files'}
|
|
||||||
>
|
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
strokeWidth={2}
|
|
||||||
d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 主内容区域 */}
|
{/* 主内容区域 */}
|
||||||
<div className="flex-1 flex min-w-0">
|
<div className="flex-1 flex min-w-0">
|
||||||
{/* 聊天区域 */}
|
{/* 聊天区域 */}
|
||||||
@@ -136,6 +93,9 @@ export function App() {
|
|||||||
sessionId={currentSessionId}
|
sessionId={currentSessionId}
|
||||||
onSessionNotFound={handleSessionNotFound}
|
onSessionNotFound={handleSessionNotFound}
|
||||||
responsive
|
responsive
|
||||||
|
showFileBrowser={showFileBrowser}
|
||||||
|
onToggleFileBrowser={() => setShowFileBrowser(!showFileBrowser)}
|
||||||
|
onOpenConfig={() => setShowConfig(true)}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex-1 flex items-center justify-center h-full">
|
<div className="flex-1 flex items-center justify-center h-full">
|
||||||
|
|||||||
@@ -16,9 +16,20 @@ interface ChatPageProps {
|
|||||||
sessionId: string;
|
sessionId: string;
|
||||||
onSessionNotFound?: () => void;
|
onSessionNotFound?: () => void;
|
||||||
responsive?: boolean;
|
responsive?: boolean;
|
||||||
|
// 工具栏按钮
|
||||||
|
showFileBrowser?: boolean;
|
||||||
|
onToggleFileBrowser?: () => void;
|
||||||
|
onOpenConfig?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ChatPage({ sessionId, onSessionNotFound, responsive = false }: ChatPageProps) {
|
export function ChatPage({
|
||||||
|
sessionId,
|
||||||
|
onSessionNotFound,
|
||||||
|
responsive = false,
|
||||||
|
showFileBrowser,
|
||||||
|
onToggleFileBrowser,
|
||||||
|
onOpenConfig,
|
||||||
|
}: ChatPageProps) {
|
||||||
const {
|
const {
|
||||||
messages,
|
messages,
|
||||||
isConnected,
|
isConnected,
|
||||||
@@ -44,19 +55,73 @@ export function ChatPage({ sessionId, onSessionNotFound, responsive = false }: C
|
|||||||
return (
|
return (
|
||||||
<div className="flex-1 flex flex-col h-screen">
|
<div className="flex-1 flex flex-col h-screen">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between px-6 py-3 border-b border-gray-700 bg-gray-800">
|
<div className="flex items-center justify-between px-4 md:px-6 py-3 border-b border-gray-700 bg-gray-800">
|
||||||
<h1 className="text-lg font-medium">Chat</h1>
|
<h1 className="text-lg font-medium">Chat</h1>
|
||||||
<div className="flex items-center gap-2 text-sm">
|
<div className="flex items-center gap-3">
|
||||||
{isConnected ? (
|
{/* 连接状态 */}
|
||||||
<>
|
<div className="flex items-center gap-1.5 text-sm">
|
||||||
<Wifi size={16} className="text-green-500" />
|
{isConnected ? (
|
||||||
<span className="text-green-500">Connected</span>
|
<>
|
||||||
</>
|
<Wifi size={16} className="text-green-500" />
|
||||||
) : (
|
<span className="text-green-500 hidden sm:inline">Connected</span>
|
||||||
<>
|
</>
|
||||||
<WifiOff size={16} className="text-red-500" />
|
) : (
|
||||||
<span className="text-red-500">Disconnected</span>
|
<>
|
||||||
</>
|
<WifiOff size={16} className="text-red-500" />
|
||||||
|
<span className="text-red-500 hidden sm:inline">Disconnected</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 工具栏按钮 */}
|
||||||
|
{(onOpenConfig || onToggleFileBrowser) && (
|
||||||
|
<div className="flex items-center gap-1.5 border-l border-gray-600 pl-3">
|
||||||
|
{/* 配置按钮 */}
|
||||||
|
{onOpenConfig && (
|
||||||
|
<button
|
||||||
|
onClick={onOpenConfig}
|
||||||
|
className="p-1.5 rounded-lg text-gray-400 hover:text-gray-200 hover:bg-gray-700 transition-colors"
|
||||||
|
title="Settings"
|
||||||
|
>
|
||||||
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 文件浏览器按钮 - 仅桌面端显示 */}
|
||||||
|
{onToggleFileBrowser && (
|
||||||
|
<button
|
||||||
|
onClick={onToggleFileBrowser}
|
||||||
|
className={`hidden md:block p-1.5 rounded-lg transition-colors ${
|
||||||
|
showFileBrowser
|
||||||
|
? 'text-blue-400 bg-blue-500/20'
|
||||||
|
: 'text-gray-400 hover:text-gray-200 hover:bg-gray-700'
|
||||||
|
}`}
|
||||||
|
title={showFileBrowser ? 'Hide Files' : 'Show Files'}
|
||||||
|
>
|
||||||
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
"module": "NodeNext",
|
"module": "NodeNext",
|
||||||
"moduleResolution": "NodeNext",
|
"moduleResolution": "NodeNext",
|
||||||
"lib": ["ES2022"],
|
"lib": ["ES2022"],
|
||||||
"outDir": "./dist",
|
|
||||||
"rootDir": "./src",
|
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
@@ -15,6 +13,5 @@
|
|||||||
"declarationMap": true,
|
"declarationMap": true,
|
||||||
"sourceMap": true
|
"sourceMap": true
|
||||||
},
|
},
|
||||||
"include": ["src/**/*"],
|
|
||||||
"exclude": ["node_modules", "dist"]
|
"exclude": ["node_modules", "dist"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user