diff --git a/src/renderer/components/MessageCard.tsx b/src/renderer/components/MessageCard.tsx index f2e062b..60dcacf 100644 --- a/src/renderer/components/MessageCard.tsx +++ b/src/renderer/components/MessageCard.tsx @@ -2,6 +2,7 @@ import { useState } from 'react'; import ReactMarkdown from 'react-markdown'; import { useIPC } from '../hooks/useIPC'; import { useAppStore } from '../store'; +import { MESSAGE_CARD, CODE_BLOCK } from '../constants/ui'; import type { Message, ContentBlock, ToolUseContent, ToolResultContent, QuestionItem } from '../types'; import { ChevronDown, @@ -477,7 +478,27 @@ function AskUserQuestionBlock({ block }: { block: ToolUseContent }) { } function ToolResultBlock({ block }: { block: ToolResultContent }) { - const [expanded, setExpanded] = useState(true); + // 智能判断初始展开状态:如果内容过长,默认收起 + const contentLength = block.content?.length || 0; + const lineCount = block.content?.split('\n').length || 0; + const isLongContent = + contentLength > MESSAGE_CARD.TOOL_RESULT_COLLAPSE_CHARS || + lineCount > MESSAGE_CARD.TOOL_RESULT_COLLAPSE_LINES; + + const [expanded, setExpanded] = useState(!isLongContent); + + // 生成预览文本 + const getPreviewText = () => { + if (!block.content) return ''; + const lines = block.content.split('\n'); + const preview = lines.slice(0, MESSAGE_CARD.TOOL_RESULT_PREVIEW_LINES).join('\n'); + if (lines.length > MESSAGE_CARD.TOOL_RESULT_PREVIEW_LINES) { + return preview + '\n...'; + } + return preview.length > MESSAGE_CARD.TOOL_RESULT_PREVIEW_CHARS + ? preview.slice(0, MESSAGE_CARD.TOOL_RESULT_PREVIEW_CHARS) + '...' + : preview; + }; return (
@@ -492,9 +513,16 @@ function ToolResultBlock({ block }: { block: ToolResultContent }) { ) : ( )} - - {block.isError ? 'Error' : 'Result'} - +
+ + {block.isError ? 'Error' : 'Result'} + + {isLongContent && ( + + ({contentLength} 字符, {lineCount} 行) + + )} +
{expanded ? ( ) : ( @@ -502,13 +530,29 @@ function ToolResultBlock({ block }: { block: ToolResultContent }) { )} - {expanded && ( + {expanded ? (
             {block.content}
           
- )} + ) : isLongContent ? ( + // 收起状态显示预览 +
+
+            {getPreviewText()}
+          
+ +
+ ) : null}
); } @@ -519,7 +563,7 @@ function CodeBlock({ language, children }: { language: string; children: string const handleCopy = async () => { await navigator.clipboard.writeText(children); setCopied(true); - setTimeout(() => setCopied(false), 2000); + setTimeout(() => setCopied(false), CODE_BLOCK.COPY_SUCCESS_DURATION); }; return ( diff --git a/src/renderer/constants/index.ts b/src/renderer/constants/index.ts new file mode 100644 index 0000000..cb9cb53 --- /dev/null +++ b/src/renderer/constants/index.ts @@ -0,0 +1,4 @@ +/** + * 统一导出所有常量配置 + */ +export * from './ui'; diff --git a/src/renderer/constants/ui.ts b/src/renderer/constants/ui.ts new file mode 100644 index 0000000..cfbb50a --- /dev/null +++ b/src/renderer/constants/ui.ts @@ -0,0 +1,30 @@ +/** + * UI 组件常量配置 + * 用于统一管理界面组件的阈值、限制等魔法数字 + */ + +/** + * MessageCard 组件相关常量 + */ +export const MESSAGE_CARD = { + /** ToolResultBlock 折叠阈值 - 字符数 */ + TOOL_RESULT_COLLAPSE_CHARS: 800, + + /** ToolResultBlock 折叠阈值 - 行数 */ + TOOL_RESULT_COLLAPSE_LINES: 15, + + /** ToolResultBlock 预览显示行数 */ + TOOL_RESULT_PREVIEW_LINES: 3, + + /** ToolResultBlock 预览显示字符数 */ + TOOL_RESULT_PREVIEW_CHARS: 200, +} as const; + +/** + * CodeBlock 组件相关常量 + */ +export const CODE_BLOCK = { + /** 代码复制成功提示持续时间(毫秒) */ + COPY_SUCCESS_DURATION: 2000, +} as const; +