From a42ff2d59a4cfa51762993a86bd8e30c3b559ee4 Mon Sep 17 00:00:00 2001 From: mp Date: Sun, 15 Dec 2024 01:30:44 -0800 Subject: [PATCH] sidebar + ux --- .../browser/react/src/sidebar-tsx/Sidebar.tsx | 18 +++- .../react/src/sidebar-tsx/SidebarChat.tsx | 92 +++++++++++++++---- .../void/browser/react/tailwind.config.js | 49 +++++----- .../contrib/void/browser/registerActions.ts | 13 ++- .../contrib/void/browser/registerThreads.ts | 12 ++- 5 files changed, 129 insertions(+), 55 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/Sidebar.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/Sidebar.tsx index e4714679..7725b16a 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/Sidebar.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/Sidebar.tsx @@ -24,8 +24,8 @@ export const Sidebar = () => { const { isHistoryOpen, currentTab: tab } = sidebarState // className='@@void-scope' - return
-
+ return
+
{/* { const tabs = ['chat', 'settings', 'threadSelector'] @@ -33,18 +33,28 @@ export const Sidebar = () => { sidebarStateService.setState({ currentTab: tabs[(index + 1) % tabs.length] as any }) }}>clickme {tab} */} -
+
-
+
+ + {/* + + */}
+ {/*
+ + + +
*/} +
diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index 13ee1b6c..92e44671 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -86,6 +86,52 @@ const IconSquare = ({ size, className = '' }: { size: number, className?: string }; +const ScrollToBottomContainer = ({ children, height, className }: { children: React.ReactNode, height: React.CSSProperties['height'], className?: string }) => { + const [isAtBottom, setIsAtBottom] = useState(true); // Start at bottom + const divRef = useRef(null); + + const scrollToBottom = () => { + if (divRef.current) { + divRef.current.scrollTop = divRef.current.scrollHeight; + } + }; + + const onScroll = () => { + const div = divRef.current; + if (!div) return; + + const isBottom = Math.abs( + div.scrollHeight - div.clientHeight - div.scrollTop + ) < 1; + + setIsAtBottom(isBottom); + }; + + // When children change (new messages added) + useEffect(() => { + if (isAtBottom) { + scrollToBottom(); + } + }, [children, isAtBottom]); // Dependency on children to detect new messages + + // Initial scroll to bottom + useEffect(() => { + scrollToBottom(); + }, []); + + return ( +
+ {children} +
+ ); +}; + + // read files from VSCode const VSReadFile = async (modelService: IModelService, uri: URI): Promise => { const model = modelService.getModel(uri) @@ -112,7 +158,7 @@ export const SelectedFiles = ( return ( !!selections && selections.length !== 0 && ( -
+
{selections.map((selection, i) => ( {/* selected file summary */} @@ -122,6 +168,7 @@ export const SelectedFiles = ( select-none bg-vscode-badge-bg border border-vscode-button-border rounded-md w-fit h-fit min-w-[80px] p-1 + text-left `} onClick={() => { setSelectionIsOpened(s => { @@ -145,9 +192,11 @@ export const SelectedFiles = ( {/* X button */} {type === 'staging' && // hoveredIdx === i { + onClick={(e) => { + e.stopPropagation(); if (type !== 'staging') return; setStaging([...selections.slice(0, i), ...selections.slice(i + 1)]) + setSelectionIsOpened(o => [...o.slice(0, i), ...o.slice(i + 1)]) }} > @@ -252,7 +301,6 @@ export const SidebarChat = () => { const isDisabled = !instructions.trim() const formRef = useRef(null) - const onSubmit = async (e: FormEvent) => { e.preventDefault() @@ -359,7 +407,10 @@ export const SidebarChat = () => { const previousMessages = currentThread?.messages ?? [] return <> -
+ {/* previous messages */} {previousMessages.map((message, i) => @@ -367,23 +418,22 @@ export const SidebarChat = () => { {/* message stream */} -
+ {/* input box */}
0 ? 'absolute bottom-0' : ''}`} >
{ if (e.key === 'Enter' && !e.shiftKey) { onSubmit(e) @@ -434,19 +484,21 @@ export const SidebarChat = () => { {isLoading ? // stop button : // submit button (up arrow)