Skip to content

Commit

Permalink
sidebar + ux
Browse files Browse the repository at this point in the history
  • Loading branch information
mathewpareles committed Dec 15, 2024
1 parent 0589a2a commit a42ff2d
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,37 @@ export const Sidebar = () => {
const { isHistoryOpen, currentTab: tab } = sidebarState

// className='@@void-scope'
return <div className='@@void-scope'>
<div className={`flex flex-col w-full px-2 py-2`}>
return <div className='@@void-scope w-full h-full'>
<div className={`flex flex-col px-2 py-2 w-full h-full`}>

{/* <span onClick={() => {
const tabs = ['chat', 'settings', 'threadSelector']
const index = tabs.indexOf(tab)
sidebarStateService.setState({ currentTab: tabs[(index + 1) % tabs.length] as any })
}}>clickme {tab}</span> */}

<div className={`mb-2 ${isHistoryOpen ? '' : 'hidden'}`}>
<div className={`mb-2 w-full h-full ${isHistoryOpen ? '' : 'hidden'}`}>
<ErrorBoundary>
<SidebarThreadSelector />
</ErrorBoundary>
</div>

<div className={`${tab === 'chat' ? '' : 'hidden'}`}>
<div className={`w-full h-full ${tab === 'chat' ? '' : 'hidden'}`}>
<ErrorBoundary>
<SidebarChat />
</ErrorBoundary>

{/* <ErrorBoundary>
<ModelSelectionSettings />
</ErrorBoundary> */}
</div>

{/* <div className={`w-full h-full ${tab === 'settings' ? '' : 'hidden'}`}>
<ErrorBoundary>
<VoidProviderSettings />
</ErrorBoundary>
</div> */}

</div>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLDivElement>(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 (
<div
ref={divRef}
onScroll={onScroll}
style={{ height: height }}
className={className}
>
{children}
</div>
);
};


// read files from VSCode
const VSReadFile = async (modelService: IModelService, uri: URI): Promise<string | null> => {
const model = modelService.getModel(uri)
Expand All @@ -112,7 +158,7 @@ export const SelectedFiles = (

return (
!!selections && selections.length !== 0 && (
<div className='flex flex-wrap gap-4'>
<div className='flex flex-wrap gap-4 p-2'>
{selections.map((selection, i) => (
<Fragment key={i}>
{/* selected file summary */}
Expand All @@ -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 => {
Expand All @@ -145,9 +192,11 @@ export const SelectedFiles = (
{/* X button */}
{type === 'staging' && // hoveredIdx === i
<span className='absolute right-0 top-0 translate-x-[50%] translate-y-[-50%] cursor-pointer bg-white rounded-full border border-vscode-input-border z-1'
onClick={() => {
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)])
}}
>
<IconX size={16} className="p-[2px] stroke-[3]" />
Expand Down Expand Up @@ -252,7 +301,6 @@ export const SidebarChat = () => {
const isDisabled = !instructions.trim()
const formRef = useRef<HTMLFormElement | null>(null)


const onSubmit = async (e: FormEvent<HTMLFormElement>) => {

e.preventDefault()
Expand Down Expand Up @@ -359,31 +407,33 @@ export const SidebarChat = () => {
const previousMessages = currentThread?.messages ?? []

return <>
<div className="overflow-x-hidden space-y-4">
<ScrollToBottomContainer
height={`calc(100%-${formRef.current?.height ?? 0}px)`}
className='overflow-x-hidden overflow-y-auto space-y-4'
>
{/* previous messages */}
{previousMessages.map((message, i) =>
<ChatBubble key={i} chatMessage={message} />
)}

{/* message stream */}
<ChatBubble chatMessage={{ role: 'assistant', content: messageStream, displayContent: messageStream || null }} />
</div>
</ScrollToBottomContainer>


{/* input box */}
<div // this div is used to position the input box properly
className={`right-0 left-0 m-2
${previousMessages.length === 0 ? '' : 'absolute bottom-0'}
`}
className={`right-0 left-0 m-2 z-[999] ${previousMessages.length > 0 ? 'absolute bottom-0' : ''}`}
>
<form
ref={formRef}
className={`flex flex-col gap-2 p-2 relative input text-left shrink-0
transition-all duration-200
rounded-md
bg-vscode-input-bg
border border-vscode-commandcenter-border hover:border-vscode-commandcenter-active-border
`}
className={`
flex flex-col gap-2 px-2 py-0.5 relative input text-left shrink-0
transition-all duration-200
rounded-md
bg-vscode-input-bg
border border-vscode-commandcenter-inactive-border focus-within:border-vscode-commandcenter-active-border hover:border-vscode-commandcenter-active-border
`}
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey) {
onSubmit(e)
Expand Down Expand Up @@ -434,19 +484,21 @@ export const SidebarChat = () => {
{isLoading ?
// stop button
<button
className="p-[5px] bg-white rounded-full cursor-pointer"
className={`size-[24px] rounded-full bg-white cursor-pointer`}
onClick={onAbort}
type='button'
>
<IconSquare size={24} className="stroke-[2]" />
<IconSquare size={16} className="stroke-[2]" />
</button>
:
// submit button (up arrow)
<button
className={`${isDisabled ? 'bg-vscode-disabled-fg cursor-not-allowed' : 'bg-white cursor-pointer'}
rounded-full
shrink-0 grow-0
`}
className={`size-[24px] rounded-full shrink-0 grow-0 cursor-pointer
${isDisabled ?
'bg-vscode-disabled-fg' // cursor-not-allowed
: 'bg-white' // cursor-pointer
}
`}
disabled={isDisabled}
type='submit'
>
Expand Down
49 changes: 23 additions & 26 deletions src/vs/workbench/contrib/void/browser/react/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,31 +38,31 @@ module.exports = {
"input-bg": "var(--vscode-input-background)",
"input-border": "var(--vscode-input-border)",
"input-fg": "var(--vscode-input-foreground)",
"input-placeholder-fg": "input-var(--vscode-placeholderForeground)",
"input-active-bg": "inputOption-var(--vscode-activeBackground)",
"input-option-active-border": "inputOption-var(--vscode-activeBorder)",
"input-option-active-fg": "inputOption-var(--vscode-activeForeground)",
"input-option-hover-bg": "inputOption-var(--vscode-hoverBackground)",
"input-validation-error-bg": "inputValidation-var(--vscode-errorBackground)",
"input-validation-error-fg": "inputValidation-var(--vscode-errorForeground)",
"input-validation-error-border": "inputValidation-var(--vscode-errorBorder)",
"input-validation-info-bg": "inputValidation-var(--vscode-infoBackground)",
"input-validation-info-fg": "inputValidation-var(--vscode-infoForeground)",
"input-validation-info-border": "inputValidation-var(--vscode-infoBorder)",
"input-validation-warning-bg": "inputValidation-var(--vscode-warningBackground)",
"input-validation-warning-fg": "inputValidation-var(--vscode-warningForeground)",
"input-validation-warning-border": "inputValidation-var(--vscode-warningBorder)",
"input-placeholder-fg": "var(--vscode-placeholderForeground)",
"input-active-bg": "var(--vscode-activeBackground)",
"input-option-active-border": "var(--vscode-activeBorder)",
"input-option-active-fg": "var(--vscode-activeForeground)",
"input-option-hover-bg": "var(--vscode-hoverBackground)",
"input-validation-error-bg": "var(--vscode-errorBackground)",
"input-validation-error-fg": "var(--vscode-errorForeground)",
"input-validation-error-border": "var(--vscode-errorBorder)",
"input-validation-info-bg": "var(--vscode-infoBackground)",
"input-validation-info-fg": "var(--vscode-infoForeground)",
"input-validation-info-border": "var(--vscode-infoBorder)",
"input-validation-warning-bg": "var(--vscode-warningBackground)",
"input-validation-warning-fg": "var(--vscode-warningForeground)",
"input-validation-warning-border": "var(--vscode-warningBorder)",

// command center colors (the top bar)
"commandcenter-fg": "commandCenter.foreground",
"commandcenter-active-fg": "commandCenter.activeForeground",
"commandcenter-bg": "commandCenter.background",
"commandcenter-active-bg": "commandCenter.activeBackground",
"commandcenter-border": "commandCenter.border",
"commandcenter-inactive-fg": "commandCenter.inactiveForeground",
"commandcenter-inactive-border": "commandCenter.inactiveBorder",
"commandcenter-active-border": "commandCenter.activeBorder",
"commandcenter-debugging-bg": "commandCenter.debuggingBackground",
"commandcenter-fg": "var(--vscode-commandCenter-foreground)",
"commandcenter-active-fg": "var(--vscode-commandCenter-activeForeground)",
"commandcenter-bg": "var(--vscode-commandCenter-background)",
"commandcenter-active-bg": "var(--vscode-commandCenter-activeBackground)",
"commandcenter-border": "var(--vscode-commandCenter-border)",
"commandcenter-inactive-fg": "var(--vscode-commandCenter-inactiveForeground)",
"commandcenter-inactive-border": "var(--vscode-commandCenter-inactiveBorder)",
"commandcenter-active-border": "var(--vscode-commandCenter-activeBorder)",
"commandcenter-debugging-bg": "var(--vscode-commandCenter-debuggingBackground)",

// badge colors
"badge-fg": "var(--vscode-badge-foreground)",
Expand All @@ -84,7 +84,6 @@ module.exports = {
"checkbox-border": "var(--vscode-checkbox-border)",
"checkbox-select-bg": "var(--vscode-checkbox-selectBackground)",


// sidebar colors
"sidebar-bg": "var(--vscode-sideBar-background)",
"sidebar-fg": "var(--vscode-sideBar-foreground)",
Expand All @@ -101,7 +100,6 @@ module.exports = {
"sidebar-stickyscroll-border": "var(--vscode-sideBarStickyScroll-border)",
"sidebar-stickyscroll-shadow": "var(--vscode-sideBarStickyScroll-shadow)",


// other colors (these are partially complete)

// editor colors
Expand All @@ -113,7 +111,6 @@ module.exports = {
"editorwidget-bg": "var(--vscode-editorWidget-background)",
"editorwidget-border": "var(--vscode-editorWidget-border)",


},
},
},
Expand Down
13 changes: 11 additions & 2 deletions src/vs/workbench/contrib/void/browser/registerActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,18 @@ registerAction2(class extends Action2 {
)

if (selectionRange) {
const selection: CodeStagingSelection = {
selectionStr: getContentInRange(model, selectionRange),

const selectionStr = getContentInRange(model, selectionRange)

const selection: CodeStagingSelection = selectionStr === null ? {
type: 'File',
fileURI: model.uri,
selectionStr: null,
range: null,
} : {
type: 'Selection',
fileURI: model.uri,
selectionStr: selectionStr,
range: selectionRange,
}

Expand Down
12 changes: 9 additions & 3 deletions src/vs/workbench/contrib/void/browser/registerThreads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,15 @@ export type CodeSelection = {

// if selectionStr is null, it means to use the entire file at send time
export type CodeStagingSelection = {
fileURI: URI;
selectionStr: string | null;
range: IRange;
type: 'Selection',
fileURI: URI,
selectionStr: string,
range: IRange
} | {
type: 'File',
fileURI: URI,
selectionStr: null,
range: null
}


Expand Down

0 comments on commit a42ff2d

Please sign in to comment.