@@ -2315,18 +2315,51 @@ function ChatNavigator(props: {
23152315 const PREVIEW_LENGTH = 20 ;
23162316 const listRef = useRef < HTMLDivElement > ( null ) ;
23172317 const activeItemRef = useRef < HTMLDivElement > ( null ) ;
2318+ const navigatorRef = useRef < HTMLDivElement > ( null ) ;
2319+ const [ searchQuery , setSearchQuery ] = useState ( "" ) ;
2320+ const [ isSearchFocused , setIsSearchFocused ] = useState ( false ) ;
23182321
2319- // 过滤用户消息并生成缩略列表
2320- const userMessages = useMemo ( ( ) => {
2321- return props . messages
2322- . map ( ( msg , index ) => ( {
2323- id : msg . id ,
2324- index,
2325- preview : getMessageTextContent ( msg ) . slice ( 0 , PREVIEW_LENGTH ) ,
2326- role : msg . role ,
2327- } ) )
2328- . filter ( ( msg ) => msg . role === "user" ) ;
2329- } , [ props . messages ] ) ;
2322+ // 面板是否应该保持展开(搜索框聚焦或有搜索内容时)
2323+ const shouldKeepOpen = isSearchFocused || searchQuery . trim ( ) . length > 0 ;
2324+
2325+ // 点击导航区外部时清空搜索
2326+ useEffect ( ( ) => {
2327+ if ( ! shouldKeepOpen ) return ;
2328+
2329+ const handleClickOutside = ( e : MouseEvent ) => {
2330+ if (
2331+ navigatorRef . current &&
2332+ ! navigatorRef . current . contains ( e . target as Node )
2333+ ) {
2334+ setSearchQuery ( "" ) ;
2335+ }
2336+ } ;
2337+
2338+ document . addEventListener ( "click" , handleClickOutside ) ;
2339+ return ( ) => document . removeEventListener ( "click" , handleClickOutside ) ;
2340+ } , [ shouldKeepOpen ] ) ;
2341+
2342+ // 生成消息列表(用户消息 or 搜索结果)
2343+ const displayMessages = useMemo ( ( ) => {
2344+ const allMessages = props . messages . map ( ( msg , index ) => ( {
2345+ id : msg . id ,
2346+ index,
2347+ content : getMessageTextContent ( msg ) ,
2348+ preview : getMessageTextContent ( msg ) . slice ( 0 , PREVIEW_LENGTH ) ,
2349+ role : msg . role ,
2350+ } ) ) ;
2351+
2352+ // 如果有搜索词,搜索所有消息
2353+ if ( searchQuery . trim ( ) ) {
2354+ const query = searchQuery . toLowerCase ( ) ;
2355+ return allMessages . filter ( ( msg ) =>
2356+ msg . content . toLowerCase ( ) . includes ( query ) ,
2357+ ) ;
2358+ }
2359+
2360+ // 否则只显示用户消息
2361+ return allMessages . filter ( ( msg ) => msg . role === "user" ) ;
2362+ } , [ props . messages , searchQuery ] ) ;
23302363
23312364 // 当 hover 面板时,滚动到当前高亮项
23322365 const scrollToActiveItem = useCallback ( ( ) => {
@@ -2340,9 +2373,11 @@ function ChatNavigator(props: {
23402373
23412374 return (
23422375 < div
2376+ ref = { navigatorRef }
23432377 className = { clsx (
23442378 styles [ "chat-navigator" ] ,
23452379 props . inPanel && styles [ "chat-navigator-in-panel" ] ,
2380+ shouldKeepOpen && styles [ "chat-navigator-active" ] ,
23462381 ) }
23472382 onMouseEnter = { scrollToActiveItem }
23482383 >
@@ -2351,15 +2386,28 @@ function ChatNavigator(props: {
23512386 </ div >
23522387 < div className = { styles [ "chat-navigator-panel" ] } >
23532388 < div className = { styles [ "chat-navigator-header" ] } >
2354- { Locale . Chat . Navigator . Title }
2389+ < span className = { styles [ "chat-navigator-title" ] } >
2390+ { Locale . Chat . Navigator . Title }
2391+ </ span >
2392+ < input
2393+ type = "text"
2394+ placeholder = { Locale . Chat . Navigator . Search }
2395+ value = { searchQuery }
2396+ onChange = { ( e ) => setSearchQuery ( e . target . value ) }
2397+ onFocus = { ( ) => setIsSearchFocused ( true ) }
2398+ onBlur = { ( ) => setIsSearchFocused ( false ) }
2399+ className = { styles [ "chat-navigator-search-input" ] }
2400+ />
23552401 </ div >
23562402 < div className = { styles [ "chat-navigator-list" ] } ref = { listRef } >
2357- { userMessages . length === 0 ? (
2403+ { displayMessages . length === 0 ? (
23582404 < div className = { styles [ "chat-navigator-empty" ] } >
2359- { Locale . Chat . Navigator . Empty }
2405+ { searchQuery . trim ( )
2406+ ? Locale . Chat . Navigator . NoResults
2407+ : Locale . Chat . Navigator . Empty }
23602408 </ div >
23612409 ) : (
2362- userMessages . map ( ( item ) => {
2410+ displayMessages . map ( ( item ) => {
23632411 const isActive = props . currentIndex === item . index ;
23642412 return (
23652413 < div
@@ -2371,6 +2419,9 @@ function ChatNavigator(props: {
23712419 ) }
23722420 onClick = { ( ) => props . onJumpTo ( item . index ) }
23732421 >
2422+ < div className = { styles [ "chat-navigator-item-role" ] } >
2423+ { item . role === "user" ? "👨" : "💡" }
2424+ </ div >
23742425 < div className = { styles [ "chat-navigator-item-preview" ] } >
23752426 { item . preview || "(空消息)" }
23762427 </ div >
0 commit comments