From eaee29841d07b7ffd295d3748a019cf023fd8d99 Mon Sep 17 00:00:00 2001 From: oudecheng <13802883547@139.com> Date: Fri, 14 Aug 2026 19:15:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(web):=20=E5=AF=B9=E9=BD=90=20deepseek-harn?= =?UTF-8?q?ess=20=E8=AE=BE=E8=AE=A1=E8=AF=AD=E8=A8=80=EF=BC=8C=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E5=89=8D=E7=AB=AF=E8=A7=86=E8=A7=89=E4=B8=8E=E4=B8=89?= =?UTF-8?q?=E6=A0=8F=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 设计 token 重映射为 DeepSeek 调色板(深浅双主题),正文改无衬线字体栈,全面去霓虹化 - 移除顶部 Header,控件迁入左栏(Logo/连接/通道/会话/tabs/底部操作区),左右栏支持拖拽调宽并持久化,折叠为图标 rail - 对话区对齐 DeepSeek 聊天风:hero/docked 状态机、736px 居中列、用户右对齐柔和气泡、助手无气泡平铺、composer 卡片与反差发送键;子智能体点击导航完整保留 - 全功能区同步换肤:侧栏列表、右栏面板、ConfigPage、弹窗、选择器等 - fix: 修复 virtual-core 3.17.x 陈旧行高导致消息行重叠(宽度变化/滚动停止后强制 resizeItem 重测) - fix: 修复 ConfigPage/Modal 引用不存在的 fadeIn/scaleIn keyframes 致入场动画失效 --- web/src/App.tsx | 499 +++++++++++------- web/src/components/Chat/ChatContainer.tsx | 95 +++- web/src/components/Chat/ExpertSelector.tsx | 2 +- web/src/components/Chat/MessageBubble.tsx | 248 ++++----- web/src/components/Chat/MessageInput.tsx | 196 +++---- web/src/components/Chat/MessageList.tsx | 84 ++- web/src/components/Chat/ModelSelector.tsx | 4 +- web/src/components/Chat/ToolDetailModal.tsx | 6 +- web/src/components/ConnectionStatus.tsx | 38 +- web/src/components/Header/ChannelSelector.tsx | 19 +- web/src/components/Header/SessionSelector.tsx | 10 +- web/src/components/Panel/MemoryPanel.tsx | 30 +- web/src/components/Panel/SkillList.tsx | 12 +- web/src/components/Panel/TodoPanel.tsx | 8 +- web/src/components/Panel/ToolPanel.tsx | 24 +- .../components/Panel/TopicTokenStatsPanel.tsx | 6 +- web/src/components/Settings/ConfigPage.tsx | 22 +- web/src/components/Settings/constants.ts | 2 +- .../Settings/modals/ExpertModal.tsx | 2 +- .../Settings/modals/SubagentModal.tsx | 2 +- web/src/components/Settings/shared.tsx | 2 +- .../components/Settings/tabs/ExpertsTab.tsx | 2 +- web/src/components/Settings/tabs/McpTab.tsx | 6 +- .../components/Settings/tabs/SubagentsTab.tsx | 6 +- web/src/components/Settings/ui.tsx | 2 +- .../components/Sidebar/SchedulerJobList.tsx | 24 +- web/src/components/Sidebar/SessionInfo.tsx | 2 +- web/src/components/Sidebar/TopicList.tsx | 30 +- web/src/index.css | 175 +++--- web/src/utils/tokenStats.ts | 6 +- 30 files changed, 868 insertions(+), 696 deletions(-) diff --git a/web/src/App.tsx b/web/src/App.tsx index 07739f1..33148cc 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState, type MouseEvent as ReactMouseEvent } from 'react'; import { Zap, ArrowLeft, @@ -11,6 +11,8 @@ import { Brain, Settings as SettingsIcon, ChevronRight, + MessageSquare, + Calendar, } from 'lucide-react'; import { ChatContainer } from './components/Chat/ChatContainer'; import { TopicList } from './components/Sidebar/TopicList'; @@ -200,6 +202,75 @@ function App() { // 设置弹窗关闭计数器:每次关闭时递增,用于通知 ExpertSelector 刷新已选专家状态 const [settingsClosedTick, setSettingsClosedTick] = useState(0); + // ---- 三栏列宽(拖拽调宽,对齐 harness AppFrame)---- + const [sidebarWidth, setSidebarWidth] = useState(() => { + const parsed = parseInt(localStorage.getItem('picobot-sidebar-width') ?? '', 10); + return Number.isFinite(parsed) ? Math.min(Math.max(parsed, 216), 400) : 288; + }); + const [rightPanelWidth, setRightPanelWidth] = useState(() => { + const parsed = parseInt(localStorage.getItem('picobot-right-panel-width') ?? '', 10); + return Number.isFinite(parsed) ? Math.min(Math.max(parsed, 240), 420) : 320; + }); + + // 拖拽期间禁用 width transition,避免面板"追鼠标"延迟感 + const [isResizing, setIsResizing] = useState(false); + + const startSidebarDrag = useCallback( + (e: ReactMouseEvent) => { + e.preventDefault(); + const startX = e.clientX; + const startWidth = sidebarWidth; + setIsResizing(true); + const onMove = (ev: MouseEvent) => { + setSidebarWidth(Math.min(Math.max(startWidth + ev.clientX - startX, 216), 400)); + }; + const onUp = (ev: MouseEvent) => { + document.removeEventListener('mousemove', onMove); + document.removeEventListener('mouseup', onUp); + document.body.style.cursor = ''; + document.body.style.userSelect = ''; + setIsResizing(false); + localStorage.setItem( + 'picobot-sidebar-width', + String(Math.min(Math.max(startWidth + ev.clientX - startX, 216), 400)), + ); + }; + document.addEventListener('mousemove', onMove); + document.addEventListener('mouseup', onUp); + document.body.style.cursor = 'col-resize'; + document.body.style.userSelect = 'none'; + }, + [sidebarWidth], + ); + + const startRightPanelDrag = useCallback( + (e: ReactMouseEvent) => { + e.preventDefault(); + const startX = e.clientX; + const startWidth = rightPanelWidth; + setIsResizing(true); + const onMove = (ev: MouseEvent) => { + setRightPanelWidth(Math.min(Math.max(startWidth - (ev.clientX - startX), 240), 420)); + }; + const onUp = (ev: MouseEvent) => { + document.removeEventListener('mousemove', onMove); + document.removeEventListener('mouseup', onUp); + document.body.style.cursor = ''; + document.body.style.userSelect = ''; + setIsResizing(false); + localStorage.setItem( + 'picobot-right-panel-width', + String(Math.min(Math.max(startWidth - (ev.clientX - startX), 240), 420)), + ); + }; + document.addEventListener('mousemove', onMove); + document.addEventListener('mouseup', onUp); + document.body.style.cursor = 'col-resize'; + document.body.style.userSelect = 'none'; + }, + [rightPanelWidth], + ); + const handleSaveConnection = useCallback((host: string, port: number) => { setGatewaySettings({ host, port }); }, []); @@ -615,189 +686,222 @@ function App() { }, [schedulerView, subAgentView, selectedTopic]); return ( -