Skip to content

Commit 6bb64e9

Browse files
authored
feat: the chat content has added a button to return to the bottom (#495)
* feat: the chat content has added a button to return to the bottom * docs: update changelog * refactor: optimization effect
1 parent 7962c32 commit 6bb64e9

2 files changed

Lines changed: 37 additions & 3 deletions

File tree

docs/content.en/docs/release-notes/_index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Information about release notes of Coco Server is provided here.
2020
- feat: history list add put away button #482
2121
- feat: the chat input box supports multi-line input #490
2222
- feat: add `~/Applications` to the search path #493
23+
- feat: the chat content has added a button to return to the bottom #495
2324

2425
### 🐛 Bug fix
2526

src/components/Assistant/ChatContent.tsx

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useRef, useEffect } from "react";
1+
import { useRef, useEffect, UIEvent, useState } from "react";
22
import { useTranslation } from "react-i18next";
33

44
import { ChatMessage } from "@/components/ChatMessage";
@@ -11,6 +11,8 @@ import type { Chat, IChunkData } from "./types";
1111
import { useConnectStore } from "@/stores/connectStore";
1212
import SessionFile from "./SessionFile";
1313
import Splash from "./Splash";
14+
import { ArrowDown } from "lucide-react";
15+
import clsx from "clsx";
1416

1517
interface ChatContentProps {
1618
activeChat?: Chat;
@@ -57,10 +59,11 @@ export const ChatContent = ({
5759
const { t } = useTranslation();
5860

5961
const uploadFiles = useChatStore((state) => state.uploadFiles);
60-
6162
const messagesEndRef = useRef<HTMLDivElement>(null);
6263

6364
const { scrollToBottom } = useChatScroll(messagesEndRef);
65+
const scrollRef = useRef<HTMLDivElement>(null);
66+
const [isAtBottom, setIsAtBottom] = useState(true);
6467

6568
useEffect(() => {
6669
scrollToBottom();
@@ -83,9 +86,22 @@ export const ChatContent = ({
8386

8487
const allMessages = activeChat?.messages || [];
8588

89+
const handleScroll = (event: UIEvent<HTMLDivElement>) => {
90+
const { scrollHeight, scrollTop, clientHeight } =
91+
event.currentTarget as HTMLDivElement;
92+
93+
const isAtBottom = scrollHeight - scrollTop - clientHeight < 50;
94+
95+
setIsAtBottom(isAtBottom);
96+
};
97+
8698
return (
8799
<div className="flex-1 overflow-hidden flex flex-col justify-between relative">
88-
<div className="flex-1 w-full overflow-x-hidden overflow-y-auto border-t border-[rgba(0,0,0,0.1)] dark:border-[rgba(255,255,255,0.15)] custom-scrollbar relative">
100+
<div
101+
ref={scrollRef}
102+
className="flex-1 w-full overflow-x-hidden overflow-y-auto border-t border-[rgba(0,0,0,0.1)] dark:border-[rgba(255,255,255,0.15)] custom-scrollbar relative"
103+
onScroll={handleScroll}
104+
>
89105
<Greetings />
90106

91107
{activeChat?.messages?.map((message, index) => (
@@ -158,6 +174,23 @@ export const ChatContent = ({
158174
{sessionId && <SessionFile sessionId={sessionId} />}
159175

160176
<Splash />
177+
178+
<button
179+
className={clsx(
180+
"absolute right-4 bottom-4 flex items-center justify-center size-8 border bg-white rounded-full shadow dark:border-[#272828] dark:bg-black dark:shadow-white/15",
181+
{
182+
hidden: isAtBottom,
183+
}
184+
)}
185+
onClick={() => {
186+
scrollRef.current?.scrollTo({
187+
top: scrollRef.current?.scrollHeight,
188+
behavior: "smooth",
189+
});
190+
}}
191+
>
192+
<ArrowDown className="size-5" />
193+
</button>
161194
</div>
162195
);
163196
};

0 commit comments

Comments
 (0)