From 5fa3794610132046e8eadcb65f680d40daff603d Mon Sep 17 00:00:00 2001 From: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com> Date: Tue, 1 Oct 2024 00:11:15 -0400 Subject: [PATCH] Add scroll to bottom button --- webview-ui/src/components/chat/ChatView.tsx | 126 +++++++++++++------- 1 file changed, 86 insertions(+), 40 deletions(-) diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index 133f242..70178df 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -2,19 +2,20 @@ import { VSCodeButton, VSCodeLink } from "@vscode/webview-ui-toolkit/react" import { useCallback, useEffect, useMemo, useRef, useState } from "react" import { useEvent, useMount } from "react-use" import { Virtuoso, type VirtuosoHandle } from "react-virtuoso" +import styled from "styled-components" import { ClaudeAsk, ClaudeSayTool, ExtensionMessage } from "../../../../src/shared/ExtensionMessage" +import { findLast } from "../../../../src/shared/array" import { combineApiRequests } from "../../../../src/shared/combineApiRequests" import { combineCommandSequences } from "../../../../src/shared/combineCommandSequences" import { getApiMetrics } from "../../../../src/shared/getApiMetrics" import { useExtensionState } from "../../context/ExtensionStateContext" import { vscode } from "../../utils/vscode" -import Announcement from "./Announcement" +import HistoryPreview from "../history/HistoryPreview" import { normalizeApiConfiguration } from "../settings/ApiOptions" +import Announcement from "./Announcement" import ChatRow from "./ChatRow" import ChatTextArea from "./ChatTextArea" -import HistoryPreview from "../history/HistoryPreview" import TaskHeader from "./TaskHeader" -import { findLast } from "../../../../src/shared/array" interface ChatViewProps { isHidden: boolean @@ -41,7 +42,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie // we need to hold on to the ask because useEffect > lastMessage will always let us know when an ask comes in and handle it, but by the time handleMessage is called, the last message might not be the ask anymore (it could be a say that followed) const [claudeAsk, setClaudeAsk] = useState(undefined) - + const [showScrollToBottom, setShowScrollToBottom] = useState(false) const [enableButtons, setEnableButtons] = useState(false) const [primaryButtonText, setPrimaryButtonText] = useState(undefined) const [secondaryButtonText, setSecondaryButtonText] = useState(undefined) @@ -494,6 +495,15 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie [expandedRows, modifiedMessages, visibleMessages.length, toggleRowExpansion] ) + const handleScroll = useCallback>((event) => { + const scroller = event.currentTarget + const scrollTop = scroller.scrollTop + const scrollHeight = scroller.scrollHeight + const clientHeight = scroller.clientHeight + const scrollToBottomThreshold = 600 + setShowScrollToBottom(scrollHeight - scrollTop - clientHeight > scrollToBottomThreshold) + }, []) + return (
-
- {primaryButtonText && !isStreaming && ( - - {primaryButtonText} - - )} - {(secondaryButtonText || isStreaming) && ( - - {isStreaming ? "Cancel" : secondaryButtonText} - - )} -
+ {showScrollToBottom ? ( +
+ + virtuosoRef.current?.scrollTo({ top: Number.MAX_SAFE_INTEGER, behavior: "smooth" }) + }> + + +
+ ) : ( +
+ {primaryButtonText && !isStreaming && ( + + {primaryButtonText} + + )} + {(secondaryButtonText || isStreaming) && ( + + {isStreaming ? "Cancel" : secondaryButtonText} + + )} +
+ )} )}