From b56c80a4544677fdc90328bda1c156311f4a3c8b Mon Sep 17 00:00:00 2001 From: Nicolas Varrot Date: Wed, 11 Feb 2026 17:56:09 +0000 Subject: [PATCH] feat: add scroll-to-bottom button when scrolled up in chat Floating button appears when user scrolls away from the bottom of the conversation, making it easy to jump back to the latest messages. Includes i18n labels (EN/FR) and smooth scroll animation. --- src/components/Chat.tsx | 21 ++++++++++++++++++--- src/lib/i18n.ts | 2 ++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/components/Chat.tsx b/src/components/Chat.tsx index 8d7e6c5..bb2c400 100644 --- a/src/components/Chat.tsx +++ b/src/components/Chat.tsx @@ -1,9 +1,9 @@ -import { useEffect, useRef, useCallback } from 'react'; +import { useEffect, useRef, useCallback, useState } from 'react'; import { ChatMessageComponent } from './ChatMessage'; import { ChatInput } from './ChatInput'; import { TypingIndicator } from './TypingIndicator'; import type { ChatMessage, ConnectionStatus } from '../types'; -import { Bot } from 'lucide-react'; +import { Bot, ArrowDown } from 'lucide-react'; import { useT } from '../hooks/useLocale'; interface Props { @@ -50,12 +50,14 @@ export function Chat({ messages, isGenerating, status, onSend, onAbort }: Props) const scrollContainerRef = useRef(null); const isNearBottomRef = useRef(true); const userSentRef = useRef(false); + const [showScrollBtn, setShowScrollBtn] = useState(false); const checkIfNearBottom = useCallback(() => { const el = scrollContainerRef.current; if (!el) return; const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight; isNearBottomRef.current = distanceFromBottom <= SCROLL_THRESHOLD; + setShowScrollBtn(distanceFromBottom > SCROLL_THRESHOLD * 2); }, []); const scrollToBottom = useCallback((behavior: ScrollBehavior = 'smooth') => { @@ -94,7 +96,7 @@ export function Chat({ messages, isGenerating, status, onSend, onAbort }: Props) const showTyping = isGenerating && !hasStreamedText(messages); return ( -
+
{messages.length === 0 && ( @@ -116,6 +118,19 @@ export function Chat({ messages, isGenerating, status, onSend, onAbort }: Props)
+ {/* Scroll to bottom FAB */} + {showScrollBtn && ( +
+ +
+ )}
); diff --git a/src/lib/i18n.ts b/src/lib/i18n.ts index b375723..e5bd6e9 100644 --- a/src/lib/i18n.ts +++ b/src/lib/i18n.ts @@ -36,6 +36,7 @@ const en = { 'chat.attachFile': 'Attach file', 'chat.send': 'Send', 'chat.stop': 'Stop', + 'chat.scrollToBottom': 'New messages', 'chat.messages': 'Chat messages', // Sidebar @@ -78,6 +79,7 @@ const fr: Record = { 'chat.attachFile': 'Joindre un fichier', 'chat.send': 'Envoyer', 'chat.stop': 'ArrĂȘter', + 'chat.scrollToBottom': 'Nouveaux messages', 'chat.messages': 'Messages du chat', 'sidebar.title': 'Sessions',