diff --git a/web/src/App.tsx b/web/src/App.tsx index be2c9c2..124dd52 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -1,5 +1,5 @@ -import { useCallback, useEffect, useMemo, useRef } from 'react' -import { Zap, Cpu, MessageSquare, ArrowLeft, Bot, Clock } from 'lucide-react' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { Zap, Cpu, MessageSquare, ArrowLeft, Bot, Clock, Sun, Moon } from 'lucide-react' import { ChatContainer } from './components/Chat/ChatContainer' import { TopicList } from './components/Sidebar/TopicList' import { SessionInfo } from './components/Sidebar/SessionInfo' @@ -59,6 +59,32 @@ function App() { onMessage: handleServerMessage, }) + // ---- 主题状态 ---- + + const [theme, setTheme] = useState<'dark' | 'light'>(() => { + const saved = localStorage.getItem('picobot-theme') + return saved === 'light' ? 'light' : 'dark' + }) + + useEffect(() => { + const root = document.documentElement + if (theme === 'light') { + root.classList.add('light') + } else { + root.classList.remove('light') + } + localStorage.setItem('picobot-theme', theme) + + // 切换时启用平滑过渡 + root.classList.add('theme-transitioning') + const timer = setTimeout(() => { + root.classList.remove('theme-transitioning') + }, 350) + return () => clearTimeout(timer) + }, [theme]) + + // ---- WebSocket 初始化 ---- + // 连接建立后自动加载 Session useEffect(() => { if (isConnected && status === 'connected') { @@ -261,23 +287,33 @@ function App() { const toolMessages = messages return ( -
+任务指令+{taskPrompt}
+
{children}
@@ -563,13 +563,13 @@ export function MessageBubble({ message, onNavigateToSubAgent }: MessageBubblePr
},
// 标题样式
h1: ({ children }) => (
- {children}
+ {children}
),
h2: ({ children }) => (
- {children}
+ {children}
),
h3: ({ children }) => (
- {children}
+ {children}
),
// 段落
p: ({ children }) => {children}
,
@@ -582,7 +582,7 @@ export function MessageBubble({ message, onNavigateToSubAgent }: MessageBubblePr
href={href}
target="_blank"
rel="noopener noreferrer"
- className="text-[#00f0ff] hover:underline"
+ className="text-[var(--accent-cyan)] hover:underline"
>
{children}
@@ -591,24 +591,24 @@ export function MessageBubble({ message, onNavigateToSubAgent }: MessageBubblePr
table: ({ children }) => (
+{children}), // 分隔线 - hr: () =>
, + hr: () =>
, // 加粗和斜体 - strong: ({ children }) => {children}, - em: ({ children }) => {children}, + strong: ({ children }) => {children}, + em: ({ children }) => {children}, }} > {message.content} diff --git a/web/src/components/Chat/MessageInput.tsx b/web/src/components/Chat/MessageInput.tsx index 36aa92c..ce8506f 100644 --- a/web/src/components/Chat/MessageInput.tsx +++ b/web/src/components/Chat/MessageInput.tsx @@ -251,22 +251,22 @@ export function MessageInput({ // 只读模式:显示提示占位符 if (isReadOnly) { return ( -+-+-+@@ -277,7 +277,7 @@ export function MessageInput({ } return ( --只读模式 +
{channelName ? ( <>{channelName} 通道仅支持查看历史消息> ) : ( '当前通道仅支持查看历史消息' )}
-+
请切换至 WebSocket 通道进行输入
+{/* 错误提示 */} {error && ( @@ -292,7 +292,7 @@ export function MessageInput({ {attachments.map((att, index) => ({att.preview ? () : ( -
+{getAttachmentIcon(att.attachment.media_type)})} - + {att.attachment.file_name} @@ -321,7 +321,7 @@ export function MessageInput({ {/* 输入区域 */}{/* 拖拽提示 */} {isDragging && ( -) -} \ No newline at end of file +} diff --git a/web/src/components/Chat/MessageList.tsx b/web/src/components/Chat/MessageList.tsx index 2538b99..3f5ddb4 100644 --- a/web/src/components/Chat/MessageList.tsx +++ b/web/src/components/Chat/MessageList.tsx @@ -131,14 +131,14 @@ export function MessageList({ messages, onNavigateToSubAgent }: MessageListProps return (-{/* 提示 */} -+{/* 发送/停止按钮 */} @@ -381,7 +381,7 @@ export function MessageInput({+@@ -340,7 +340,7 @@ export function MessageInput({ @@ -363,9 +363,9 @@ export function MessageInput({ placeholder={placeholder} disabled={disabled} rows={1} - className="w-full resize-none rounded-xl border border-white/10 bg-[#1a1a25] px-4 py-3 pr-12 text-sm text-white placeholder:text-zinc-500 focus:border-[#00f0ff]/50 focus:outline-none focus:ring-1 focus:ring-[#00f0ff]/20 disabled:opacity-50 transition-all self-center scrollbar-hide" + className="w-full resize-none rounded-xl border border-[var(--border-color)] bg-[var(--bg-tertiary)] px-4 py-3 pr-12 text-sm text-[var(--text-primary)] placeholder:text-[var(--text-muted)] focus:border-[var(--accent-cyan)]/50 focus:outline-none focus:ring-1 focus:ring-[var(--focus-ring)] disabled:opacity-50 transition-all self-center scrollbar-hide" /> -拖放文件到这里+ +按 Enter 发送,Shift+Enter 换行 · 支持拖拽/粘贴文件 · 最大 50MB--@@ -168,11 +168,11 @@ export function MessageList({ messages, onNavigateToSubAgent }: MessageListProps onClick={scrollToTop} className="pointer-events-auto group relative flex items-center justify-center w-9 h-9 rounded-full - bg-[#1a1a25]/80 backdrop-blur-md - border border-white/[0.06] - text-zinc-500 hover:text-[#00f0ff] - hover:border-[#00f0ff]/30 - hover:shadow-[0_0_20px_rgba(0,240,255,0.12)] + bg-[var(--bg-tertiary)]/80 backdrop-blur-md + border border-[var(--border-color)] + text-[var(--text-muted)] hover:text-[var(--accent-cyan)] + hover:border-[var(--accent-cyan)]/30 + hover:shadow-[0_0_20px_var(--shadow-glow-sm)] transition-all duration-300 ease-out animate-fade-in" aria-label="回到顶部" @@ -187,11 +187,11 @@ export function MessageList({ messages, onNavigateToSubAgent }: MessageListProps onClick={() => scrollToBottom('smooth')} className="pointer-events-auto group relative flex items-center justify-center w-9 h-9 rounded-full - bg-[#1a1a25]/80 backdrop-blur-md - border border-white/[0.06] - text-zinc-500 hover:text-[#00f0ff] - hover:border-[#00f0ff]/30 - hover:shadow-[0_0_20px_rgba(0,240,255,0.12)] + bg-[var(--bg-tertiary)]/80 backdrop-blur-md + border border-[var(--border-color)] + text-[var(--text-muted)] hover:text-[var(--accent-cyan)] + hover:border-[var(--accent-cyan)]/30 + hover:shadow-[0_0_20px_var(--shadow-glow-sm)] transition-all duration-300 ease-out animate-fade-in" aria-label="回到底部" @@ -201,8 +201,8 @@ export function MessageList({ messages, onNavigateToSubAgent }: MessageListProps {/* 未读消息指示点 */} {hasNewMessage && ( - - + + )} diff --git a/web/src/components/Panel/ToolPanel.tsx b/web/src/components/Panel/ToolPanel.tsx index 38a7559..347bddc 100644 --- a/web/src/components/Panel/ToolPanel.tsx +++ b/web/src/components/Panel/ToolPanel.tsx @@ -128,11 +128,11 @@ export function ToolPanel({ messages }: ToolPanelProps) { return (+ +-开始新的对话
-在下方输入消息开始与 AI 助手聊天
-- /new 创建话题 - /list 查看列表 +开始新的对话
+在下方输入消息开始与 AI 助手聊天
++ /new 创建话题 + /list 查看列表--+ +-工具调用 +暂无工具调用 @@ -145,10 +145,10 @@ export function ToolPanel({ messages }: ToolPanelProps) { return ( --+ +@@ -167,31 +167,31 @@ export function ToolPanel({ messages }: ToolPanelProps) { return (工具调用 - + {toolCalls.length} @@ -200,7 +200,7 @@ export function ToolPanel({ messages }: ToolPanelProps) { {hasResult && (toggleExpand(tool.toolCallId)} @@ -212,7 +212,7 @@ export function ToolPanel({ messages }: ToolPanelProps) { )}{!isExpanded && hasMore && ( -+点击展开全部 ({displayContent.split('\n').length} 行))} @@ -221,9 +221,9 @@ export function ToolPanel({ messages }: ToolPanelProps) { {/* 展开区域:参数 */} {isExpanded && tool.arguments ? ( --参数:-++diff --git a/web/src/components/Sidebar/SchedulerJobList.tsx b/web/src/components/Sidebar/SchedulerJobList.tsx index 9c80e1f..225c4ea 100644 --- a/web/src/components/Sidebar/SchedulerJobList.tsx +++ b/web/src/components/Sidebar/SchedulerJobList.tsx @@ -68,7 +68,7 @@ function lastStatusIcon(lastStatus: string | undefined) { case 'error': return参数:+{JSON.stringify(tool.arguments, null, 2)}default: - return + return } } @@ -76,17 +76,17 @@ export function SchedulerJobList({ jobs, onRefresh, onViewJob, sessionId }: Sche return ( {/* Header */} ---
+ ++
定时任务 {jobs.length > 0 && ( - ({jobs.length}) + ({jobs.length}) )}