diff options
author | Nate Sesti <sestinj@gmail.com> | 2023-09-04 23:34:04 -0700 |
---|---|---|
committer | Nate Sesti <sestinj@gmail.com> | 2023-09-04 23:34:04 -0700 |
commit | e6d369f4312f0c8d175251e149c62d08608cb18c (patch) | |
tree | f03c42b77276d4ca3c7d11cffee306b8d88ffb68 | |
parent | a1328cb5431f99cfe16b246ee4201b19530404e2 (diff) | |
download | sncontinue-e6d369f4312f0c8d175251e149c62d08608cb18c.tar.gz sncontinue-e6d369f4312f0c8d175251e149c62d08608cb18c.tar.bz2 sncontinue-e6d369f4312f0c8d175251e149c62d08608cb18c.zip |
feat: :sparkles: autoscrolling
-rw-r--r-- | extension/react-app/src/components/Layout.tsx | 2 | ||||
-rw-r--r-- | extension/react-app/src/components/ModelSelect.tsx | 7 | ||||
-rw-r--r-- | extension/react-app/src/pages/gui.tsx | 93 |
3 files changed, 74 insertions, 28 deletions
diff --git a/extension/react-app/src/components/Layout.tsx b/extension/react-app/src/components/Layout.tsx index c328a206..4bc1845f 100644 --- a/extension/react-app/src/components/Layout.tsx +++ b/extension/react-app/src/components/Layout.tsx @@ -142,7 +142,7 @@ const Layout = () => { /> <GridDiv> - <div style={{ overflow: "scroll" }}> + <div> <Outlet /> </div> <Footer> diff --git a/extension/react-app/src/components/ModelSelect.tsx b/extension/react-app/src/components/ModelSelect.tsx index 83f005c7..317c164a 100644 --- a/extension/react-app/src/components/ModelSelect.tsx +++ b/extension/react-app/src/components/ModelSelect.tsx @@ -61,6 +61,13 @@ const MODEL_INFO: { title: string; class: string; args: any }[] = [ class: "LlamaCpp", args: {}, }, + { + title: "gpt-4 (limited free usage)", + class: "MaybeProxyOpenAI", + args: { + model: "gpt-4", + }, + }, ]; const Select = styled.select` diff --git a/extension/react-app/src/pages/gui.tsx b/extension/react-app/src/pages/gui.tsx index 60ad0c2c..3d98522a 100644 --- a/extension/react-app/src/pages/gui.tsx +++ b/extension/react-app/src/pages/gui.tsx @@ -99,24 +99,70 @@ function GUI(props: GUIProps) { ); }, [bottomMessage, aboveComboBoxDivRef.current]); - const [scrollTimeout, setScrollTimeout] = useState<NodeJS.Timeout | null>( - null + const [isScrolling, setIsScrolling] = useState(false); + + const [scrollTimeoutId, setScrollTimeoutId] = useState<NodeJS.Timeout>(); + + const scrollToBottom = useCallback( + (force: boolean = false) => { + if (scrollTimeoutId) { + return; + } + + // Scroll only if user is within 100 pixels of the bottom of the window. + const edgeOffset = 50; + const scrollPosition = window.scrollY || 0; + const scrollHeight = topGuiDivRef.current?.scrollHeight || 0; + const clientHeight = window.innerHeight || 0; + + const atBottomEdge = + scrollPosition + clientHeight + edgeOffset >= scrollHeight; + + if (isScrolling || (!atBottomEdge && !force)) { + return; + } + + window.scrollTo({ + top: scrollHeight, + behavior: "smooth", + }); + + setScrollTimeoutId( + setTimeout(() => { + setScrollTimeoutId(undefined); + }, 800) + ); + }, + [ + window.scrollY, + topGuiDivRef.current?.scrollHeight, + topGuiDivRef.current?.clientHeight, + isScrolling, + scrollTimeoutId, + ] ); - const scrollToBottom = useCallback(() => { - if (scrollTimeout) { - clearTimeout(scrollTimeout); - } - // Debounced smooth scroll to bottom of screen - if (topGuiDivRef.current) { - const timeout = setTimeout(() => { - window.scrollTo({ - top: topGuiDivRef.current!.offsetHeight, - behavior: "smooth", - }); - }, 200); - setScrollTimeout(timeout); - } - }, [topGuiDivRef.current, scrollTimeout]); + + const [timerId, setTimerId] = useState<NodeJS.Timeout>(); + + useEffect(() => { + const handleScrollEnd = () => { + setIsScrolling(false); + }; + + const handleScroll = () => { + window.clearTimeout(timerId); + + setIsScrolling(true); + + setTimerId(setTimeout(() => handleScrollEnd(), 800)); + }; + + window.addEventListener("scroll", handleScroll); + + return () => { + window.removeEventListener("scroll", handleScroll); + }; + }, []); useEffect(() => { // Cmd + Backspace to delete current step @@ -141,11 +187,6 @@ function GUI(props: GUIProps) { useEffect(() => { client?.onStateUpdate((state: FullState) => { - // Scroll only if user is at very bottom of the window. - const shouldScrollToBottom = - topGuiDivRef.current && - topGuiDivRef.current?.offsetHeight - window.scrollY < 100; - const waitingForSteps = state.active && state.history.current_index < state.history.timeline.length && @@ -177,14 +218,12 @@ function GUI(props: GUIProps) { return nextStepsOpen; }); - if (shouldScrollToBottom) { - scrollToBottom(); - } + scrollToBottom(); }); }, [client]); useEffect(() => { - scrollToBottom(); + scrollToBottom(true); }, [waitingForSteps]); // #endregion @@ -339,7 +378,7 @@ function GUI(props: GUIProps) { }, []); return ( <div - className="overflow-hidden" + className="overflow-scroll" ref={topGuiDivRef} onKeyDown={(e) => { if (e.key === "Enter" && e.ctrlKey) { |