diff --git a/src/renderer/components/chat/ChatHistory.tsx b/src/renderer/components/chat/ChatHistory.tsx index a6a4acbe..3fa7a2a7 100644 --- a/src/renderer/components/chat/ChatHistory.tsx +++ b/src/renderer/components/chat/ChatHistory.tsx @@ -1,11 +1,12 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { useAutoScrollBottom } from '@renderer/hooks/useAutoScrollBottom'; +import { isNearBottom, useAutoScrollBottom } from '@renderer/hooks/useAutoScrollBottom'; import { useTabNavigationController } from '@renderer/hooks/useTabNavigationController'; import { useTabUI } from '@renderer/hooks/useTabUI'; import { useVisibleAIGroup } from '@renderer/hooks/useVisibleAIGroup'; import { useStore } from '@renderer/store'; import { useVirtualizer } from '@tanstack/react-virtual'; +import { ChevronsDown } from 'lucide-react'; import { useShallow } from 'zustand/react/shallow'; import { SessionContextPanel } from './SessionContextPanel/index'; @@ -343,11 +344,21 @@ export const ChatHistory = ({ tabId }: ChatHistoryProps): JSX.Element => { rootRef: scrollContainerRef, }); + // Scroll-to-bottom button visibility + const [showScrollButton, setShowScrollButton] = useState(false); + + const checkScrollButton = useCallback(() => { + const container = scrollContainerRef.current; + if (!container) return; + const { scrollTop, scrollHeight, clientHeight } = container; + setShowScrollButton(!isNearBottom(scrollTop, scrollHeight, clientHeight, 300)); + }, []); + // Auto-follow when conversation updates, but only if the user was already near bottom. // This preserves manual reading position when the user scrolls up. // Disabled during navigation to prevent conflicts with deep-link/search scrolling. - useAutoScrollBottom([conversation], { - threshold: 150, + const { scrollToBottom } = useAutoScrollBottom([conversation], { + threshold: 300, smoothDuration: 300, autoBehavior: 'auto', disabled: shouldDisableAutoScroll, @@ -355,6 +366,11 @@ export const ChatHistory = ({ tabId }: ChatHistoryProps): JSX.Element => { resetKey: effectiveTabId, }); + // Re-check button visibility whenever conversation updates + useEffect(() => { + checkScrollButton(); + }, [conversation, checkScrollButton]); + // Callback to register AI group refs (combines with visibility hook) const registerAIGroupRefCombined = useCallback( (groupId: string) => { @@ -718,12 +734,13 @@ export const ChatHistory = ({ tabId }: ChatHistoryProps): JSX.Element => { className="flex flex-1 flex-col overflow-hidden" style={{ backgroundColor: 'var(--color-surface)' }} > -