From 04fc6e4acf97b7dbb9c1f42c20d9531df59f82d1 Mon Sep 17 00:00:00 2001 From: Ayush Date: Tue, 7 Nov 2023 20:19:46 -0500 Subject: [PATCH] implement autoscroll (#112) * implement autoscroll Refactored imports in "page.tsx" to improve readability and maintainability. Updated the type of the "input" ref to be more specific. Added a new state and ref to track the scroll position of the message container. Set up an event listener to update the state when the scroll position changes. Made adjustments to the scroll position in certain event handlers. * update scroll --------- Co-authored-by: Vineeth Voruganti <13438633+VVoruganti@users.noreply.github.com> --- www/app/globals.css | 5 +++- www/app/page.tsx | 56 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/www/app/globals.css b/www/app/globals.css index f788bea..526170c 100644 --- a/www/app/globals.css +++ b/www/app/globals.css @@ -2,6 +2,9 @@ @tailwind components; @tailwind utilities; +html { + scroll-behavior: smooth; +} .typing_dot { animation: typing 1s infinite; @@ -28,4 +31,4 @@ .typing_dot:nth-child(3) { animation-delay: 0.4s; -} \ No newline at end of file +} diff --git a/www/app/page.tsx b/www/app/page.tsx index de59175..ef8b62d 100644 --- a/www/app/page.tsx +++ b/www/app/page.tsx @@ -15,7 +15,14 @@ import { } from "react-icons/fa"; // import { IoIosArrowDown } from "react-icons/io"; // import { GrClose } from "react-icons/gr"; -import { useRef, useEffect, useState, useCallback } from "react"; +import { + useRef, + useEffect, + useState, + useCallback, + use, + ElementRef, +} from "react"; import { v4 as uuidv4 } from "uuid"; import Typing from "@/components/typing"; @@ -56,9 +63,12 @@ export default function Home() { conversation_id: "", name: "", }); - const input = useRef(null); + const input = useRef>(null); const supabase = createClientComponentClient(); + const isAtBottom = useRef(true); + const messageContainerRef = useRef>(null); + const newChat = useCallback(async () => { return await fetch(`${URL}/api/conversations/insert?user_id=${userId}`) .then((res) => res.json()) @@ -144,8 +154,33 @@ export default function Home() { setMessages([defaultMessage, ...messages]); }); } + + // scroll to bottom + const messageContainer = messageContainerRef.current; + if (messageContainer) { + messageContainer.scrollTop = messageContainer.scrollHeight; + } }, [currentConversation, userId]); + useEffect(() => { + const messageContainer = messageContainerRef.current; + if (!messageContainer) return; + + const func = () => { + const val = + Math.round( + messageContainer.scrollHeight - messageContainer.scrollTop + ) === messageContainer.clientHeight; + isAtBottom.current = val; + }; + + messageContainer.addEventListener("scroll", func); + + return () => { + messageContainer.removeEventListener("scroll", func); + }; + }, []); + // async function newChat() { // return await fetch(`${URL}/api/conversations/insert?user_id=${userId}`) // .then((res) => res.json()) @@ -207,6 +242,11 @@ export default function Home() { const reader = data.body?.pipeThrough(new TextDecoderStream()).getReader()!; + const messageContainer = messageContainerRef.current; + if (messageContainer) { + messageContainer.scrollTop = messageContainer.scrollHeight; + } + // clear the last message setMessages((prev) => { prev[prev.length - 1].text = ""; @@ -240,6 +280,13 @@ export default function Home() { prev[prev.length - 1].text += value; return [...prev]; }); + + if (isAtBottom.current) { + const messageContainer = messageContainerRef.current; + if (messageContainer) { + messageContainer.scrollTop = messageContainer.scrollHeight; + } + } } } } @@ -285,7 +332,10 @@ export default function Home() {

)} -
+
{messages.map((message, i) => (