ui changes

This commit is contained in:
Mathew Pareles 2025-04-09 01:10:32 -07:00
parent c87d1886cd
commit eefa9648c4
8 changed files with 245 additions and 118 deletions

View file

@ -78,7 +78,6 @@
/* styles for all containers used by void */ /* styles for all containers used by void */
.void-scope { .void-scope {
background-color: var(--vscode-editor-background);
--scrollbar-vertical-width: 8px; --scrollbar-vertical-width: 8px;
--scrollbar-horizontal-height: 6px; --scrollbar-horizontal-height: 6px;
} }

View file

@ -11,6 +11,7 @@ import { URI } from '../../../../../../../base/common/uri.js'
import { FileSymlink, LucideIcon, RotateCw, Terminal } from 'lucide-react' import { FileSymlink, LucideIcon, RotateCw, Terminal } from 'lucide-react'
import { Check, X, Square, Copy, Play, } from 'lucide-react' import { Check, X, Square, Copy, Play, } from 'lucide-react'
import { getBasename, ListableToolItem, ToolChildrenWrapper } from '../sidebar-tsx/SidebarChat.js' import { getBasename, ListableToolItem, ToolChildrenWrapper } from '../sidebar-tsx/SidebarChat.js'
import { PlacesType, VariantType } from 'react-tooltip'
enum CopyButtonText { enum CopyButtonText {
Idle = 'Copy', Idle = 'Copy',
@ -31,13 +32,13 @@ export const IconShell1 = ({ onClick, Icon, disabled, className, ...props }: Ico
e.stopPropagation(); e.stopPropagation();
onClick?.(e); onClick?.(e);
}} }}
// border border-void-border-1 rounded
className={` className={`
size-[22px] size-[18px]
p-[4px] p-[2px]
flex items-center justify-center flex items-center justify-center
text-sm bg-void-bg-3 text-void-fg-1 text-sm bg-void-bg-3 text-void-fg-3
hover:brightness-110 hover:brightness-110
border border-void-border-1 rounded
disabled:opacity-50 disabled:cursor-not-allowed disabled:opacity-50 disabled:cursor-not-allowed
${className} ${className}
`} `}
@ -92,13 +93,14 @@ export const CopyButton = ({ codeStr }: { codeStr: string }) => {
return <IconShell1 return <IconShell1
Icon={copyButtonText === CopyButtonText.Copied ? Check : copyButtonText === CopyButtonText.Error ? X : Copy} Icon={copyButtonText === CopyButtonText.Copied ? Check : copyButtonText === CopyButtonText.Error ? X : Copy}
onClick={onCopy} onClick={onCopy}
{...tooltipPropsForApplyBlock({ tooltipName: 'Copy' })}
/> />
} }
export const JumpToFileButton = ({ uri }: { uri: URI | 'current' }) => { export const JumpToFileButton = ({ uri, ...props }: { uri: URI | 'current' } & React.ButtonHTMLAttributes<HTMLButtonElement>) => {
const accessor = useAccessor() const accessor = useAccessor()
const commandService = accessor.get('ICommandService') const commandService = accessor.get('ICommandService')
@ -108,6 +110,8 @@ export const JumpToFileButton = ({ uri }: { uri: URI | 'current' }) => {
onClick={() => { onClick={() => {
commandService.executeCommand('vscode.open', uri, { preview: true }) commandService.executeCommand('vscode.open', uri, { preview: true })
}} }}
{...tooltipPropsForApplyBlock({ tooltipName: 'Goto file' })}
{...props}
/> />
) )
return jumpToFileButton return jumpToFileButton
@ -120,7 +124,6 @@ export const JumpToTerminalButton = ({ onClick }: { onClick: () => void }) => {
<IconShell1 <IconShell1
Icon={Terminal} Icon={Terminal}
onClick={onClick} onClick={onClick}
className="text-void-fg-1"
/> />
) )
} }
@ -174,16 +177,18 @@ export const useApplyButtonState = ({ applyBoxId, uri }: { applyBoxId: string, u
} }
export const StatusIndicator = ({ color, title, className }: { color: 'green' | 'orange' | 'dark' | null, title?: React.ReactNode, className?: string }) => { type IndicatorColor = 'green' | 'orange' | 'dark' | 'yellow' | null
export const StatusIndicator = ({ indicatorColor, title, className, ...props }: { indicatorColor: IndicatorColor, title?: React.ReactNode, className?: string } & React.HTMLAttributes<HTMLDivElement>) => {
return ( return (
<div className={`flex flex-row text-void-fg-3 text-xs items-center gap-1 ${className}`}> <div className={`flex flex-row text-void-fg-3 text-xs items-center gap-1 ${className}`} {...props}>
{title && <span>{title}</span>} {title && <span className='opacity-80'>{title}</span>}
<div <div
className={` size-1.5 rounded-full border className={` size-1.5 rounded-full border
${color === 'dark' ? 'bg-void-bg-3 border-void-border-1' : ${indicatorColor === 'dark' ? 'bg-void-bg-3 border-void-border-1' :
color === 'orange' ? 'bg-orange-500 border-orange-500 shadow-[0_0_4px_0px_rgba(234,88,12,0.6)]' : indicatorColor === 'orange' ? 'bg-orange-500 border-orange-500 shadow-[0_0_4px_0px_rgba(234,88,12,0.6)]' :
color === 'green' ? 'bg-green-500 border-green-500 shadow-[0_0_4px_0px_rgba(22,163,74,0.6)]' : indicatorColor === 'green' ? 'bg-green-500 border-green-500 shadow-[0_0_4px_0px_rgba(22,163,74,0.6)]' :
'bg-void-border-1 border-void-border-1' indicatorColor === 'yellow' ? 'bg-yellow-500 border-yellow-500 shadow-[0_0_4px_0px_rgba(22,163,74,0.6)]' :
'bg-void-border-1 border-void-border-1'
} }
`} `}
/> />
@ -191,7 +196,15 @@ export const StatusIndicator = ({ color, title, className }: { color: 'green' |
); );
}; };
export const StatusIndicatorForApplyButton = ({ applyBoxId, uri }: { applyBoxId: string, uri: URI | 'current' }) => { const tooltipPropsForApplyBlock = ({ tooltipName, color = undefined, position = 'top-end', offset = undefined }: { tooltipName: string, color?: IndicatorColor, position?: PlacesType, offset?: number }) => ({
'data-tooltip-id': color === 'orange' ? `void-tooltip-orange` : color === 'green' ? 'void-tooltip-green' : 'void-tooltip',
'data-tooltip-place': position as PlacesType,
'data-tooltip-content': `${tooltipName}`,
'data-tooltip-offset': offset,
})
export const StatusIndicatorForApplyButton = ({ applyBoxId, uri }: { applyBoxId: string, uri: URI | 'current' } & React.HTMLAttributes<HTMLDivElement>) => {
const { currStreamState } = useApplyButtonState({ applyBoxId, uri }) const { currStreamState } = useApplyButtonState({ applyBoxId, uri })
@ -202,7 +215,19 @@ export const StatusIndicatorForApplyButton = ({ applyBoxId, uri }: { applyBoxId:
null null
) )
const statusIndicatorHTML = <StatusIndicator className='mx-2' color={color} /> const tooltipName = (
currStreamState === 'idle-no-changes' ? 'Done' :
currStreamState === 'streaming' ? 'Applying' :
currStreamState === 'idle-has-changes' ? 'Done' : // also 'Done'? 'Applied' looked bad
''
)
const statusIndicatorHTML = <StatusIndicator
key={currStreamState}
className='mx-2'
indicatorColor={color}
{...tooltipPropsForApplyBlock({ tooltipName, color, position: 'top', offset: 12 })}
/>
return statusIndicatorHTML return statusIndicatorHTML
} }
@ -267,11 +292,22 @@ export const ApplyButtonsHTML = ({ codeStr, applyBoxId, reapplyIcon, uri }: { co
if (currStreamState === 'streaming') { if (currStreamState === 'streaming') {
return <IconShell1 Icon={Square} onClick={onInterrupt} /> return <IconShell1
Icon={Square}
onClick={onInterrupt}
{...tooltipPropsForApplyBlock({ tooltipName: 'Stop' })}
/>
} }
if (currStreamState === 'idle-no-changes') { if (currStreamState === 'idle-no-changes') {
return <IconShell1 Icon={reapplyIcon ? RotateCw : Play} onClick={onClickSubmit} />
return <IconShell1
Icon={reapplyIcon ? RotateCw : Play}
onClick={onClickSubmit}
{...tooltipPropsForApplyBlock({ tooltipName: reapplyIcon ? 'Reapply' : 'Apply' })}
/>
} }
if (currStreamState === 'idle-has-changes') { if (currStreamState === 'idle-has-changes') {
@ -283,12 +319,12 @@ export const ApplyButtonsHTML = ({ codeStr, applyBoxId, reapplyIcon, uri }: { co
<IconShell1 <IconShell1
Icon={X} Icon={X}
onClick={onReject} onClick={onReject}
className="text-red-600" {...tooltipPropsForApplyBlock({ tooltipName: 'Reject file' })}
/> />
<IconShell1 <IconShell1
Icon={Check} Icon={Check}
onClick={onAccept} onClick={onAccept}
className="text-green-600" {...tooltipPropsForApplyBlock({ tooltipName: 'Accept file' })}
/> />
</> </>
} }

View file

@ -23,9 +23,10 @@ import { getModelCapabilities, getIsReasoningEnabledState } from '../../../../co
import { AlertTriangle, Ban, Check, ChevronRight, Dot, FileIcon, Pencil, Undo, Undo2, X } from 'lucide-react'; import { AlertTriangle, Ban, Check, ChevronRight, Dot, FileIcon, Pencil, Undo, Undo2, X } from 'lucide-react';
import { ChatMessage, CheckpointEntry, StagingSelectionItem, ToolMessage } from '../../../../common/chatThreadServiceTypes.js'; import { ChatMessage, CheckpointEntry, StagingSelectionItem, ToolMessage } from '../../../../common/chatThreadServiceTypes.js';
import { ToolCallParams, ToolName, toolNames, ToolNameWithApproval } from '../../../../common/toolsServiceTypes.js'; import { ToolCallParams, ToolName, toolNames, ToolNameWithApproval } from '../../../../common/toolsServiceTypes.js';
import { ApplyButtonsHTML, CopyButton, JumpToFileButton, JumpToTerminalButton, StatusIndicator, StatusIndicatorForApplyButton, useApplyButtonState } from '../markdown/ApplyBlockHoverButtons.js'; import { ApplyButtonsHTML, CopyButton, IconShell1, JumpToFileButton, JumpToTerminalButton, StatusIndicator, StatusIndicatorForApplyButton, useApplyButtonState } from '../markdown/ApplyBlockHoverButtons.js';
import { IsRunningType } from '../../../chatThreadService.js'; import { IsRunningType } from '../../../chatThreadService.js';
import { acceptAllBg, acceptBorder, buttonFontSize, buttonTextColor, rejectAllBg, rejectBg, rejectBorder } from '../../../../common/helpers/colors.js'; import { acceptAllBg, acceptBorder, buttonFontSize, buttonTextColor, rejectAllBg, rejectBg, rejectBorder } from '../../../../common/helpers/colors.js';
import { PlacesType } from 'react-tooltip';
@ -391,6 +392,9 @@ export const ButtonSubmit = ({ className, disabled, ...props }: ButtonProps & Re
${disabled ? 'bg-vscode-disabled-fg cursor-default' : 'bg-white cursor-pointer'} ${disabled ? 'bg-vscode-disabled-fg cursor-default' : 'bg-white cursor-pointer'}
${className} ${className}
`} `}
// data-tooltip-id='void-tooltip'
// data-tooltip-content={'Send'}
// data-tooltip-place='left'
{...props} {...props}
> >
<IconArrowUp size={DEFAULT_BUTTON_SIZE} className="stroke-[2] p-[2px]" /> <IconArrowUp size={DEFAULT_BUTTON_SIZE} className="stroke-[2] p-[2px]" />
@ -955,25 +959,32 @@ const UserMessageComponent = ({ chatMessage, messageIdx, isCheckpointGhost, _scr
</div> </div>
<EditSymbol
size={18} <div
className={` className="absolute -top-1 -right-1 translate-x-0 -translate-y-0 z-1"
absolute -top-1 -right-1 // data-tooltip-id='void-tooltip'
translate-x-0 -translate-y-0 // data-tooltip-content='Edit message'
cursor-pointer z-1 // data-tooltip-place='left'
p-[2px] >
bg-void-bg-1 border border-void-border-1 rounded-md <EditSymbol
transition-opacity duration-200 ease-in-out size={18}
${isHovered || (isFocused && mode === 'edit') ? 'opacity-100' : 'opacity-0'} className={`
`} cursor-pointer
onClick={() => { p-[2px]
if (mode === 'display') { bg-void-bg-1 border border-void-border-1 rounded-md
onOpenEdit() transition-opacity duration-200 ease-in-out
} else if (mode === 'edit') { ${isHovered || (isFocused && mode === 'edit') ? 'opacity-100' : 'opacity-0'}
onCloseEdit() `}
} onClick={() => {
}} if (mode === 'display') {
/> onOpenEdit()
} else if (mode === 'edit') {
onCloseEdit()
}
}}
/>
</div>
</div> </div>
@ -1240,7 +1251,7 @@ const ToolRequestAcceptRejectButtons = () => {
<button <button
onClick={onAccept} onClick={onAccept}
className={` className={`
px-4 py-1.5 px-2 py-1
bg-[var(--vscode-button-background)] bg-[var(--vscode-button-background)]
text-[var(--vscode-button-foreground)] text-[var(--vscode-button-foreground)]
hover:bg-[var(--vscode-button-hoverBackground)] hover:bg-[var(--vscode-button-hoverBackground)]
@ -1256,7 +1267,7 @@ const ToolRequestAcceptRejectButtons = () => {
<button <button
onClick={onReject} onClick={onReject}
className={` className={`
px-4 py-1.5 px-2 py-1
bg-[var(--vscode-button-secondaryBackground)] bg-[var(--vscode-button-secondaryBackground)]
text-[var(--vscode-button-secondaryForeground)] text-[var(--vscode-button-secondaryForeground)]
hover:bg-[var(--vscode-button-secondaryHoverBackground)] hover:bg-[var(--vscode-button-secondaryHoverBackground)]
@ -1271,7 +1282,7 @@ const ToolRequestAcceptRejectButtons = () => {
const autoApproveToggle = ( const autoApproveToggle = (
<div className="flex items-center ml-2 gap-x-1"> <div className="flex items-center ml-2 gap-x-1">
<VoidSwitch <VoidSwitch
size="xs" size="xxs"
value={voidSettingsState.globalSettings.autoApprove} value={voidSettingsState.globalSettings.autoApprove}
onChange={onToggleAutoApprove} onChange={onToggleAutoApprove}
/> />
@ -2002,17 +2013,24 @@ const CommandBarInChat = () => {
const chatThreadsState = useChatThreadsState() const chatThreadsState = useChatThreadsState()
const chatThreadsStreamState = useChatThreadsStreamState(chatThreadsState.currentThreadId) const chatThreadsStreamState = useChatThreadsStreamState(chatThreadsState.currentThreadId)
const [isFileDetailsOpened, setFileDetailsOpened] = useState(false); const [fileDetailsOpenedState, setFileDetailsOpenedState] = useState<'auto-opened' | 'auto-closed' | 'user-opened' | 'user-closed'>('auto-closed');
const isFileDetailsOpened = fileDetailsOpenedState === 'auto-opened' || fileDetailsOpenedState === 'user-opened';
// close the file details if there are no files
useEffect(() => { useEffect(() => {
if (isFileDetailsOpened && numFilesChanged === 0) { // close the file details if there are no files
setFileDetailsOpened(false) // this converts 'user-closed' to 'auto-closed'
if (numFilesChanged === 0) {
setFileDetailsOpenedState('auto-closed')
} }
}, [isFileDetailsOpened, numFilesChanged, setFileDetailsOpened]) // open the file details if it hasnt been closed
if (numFilesChanged > 0 && fileDetailsOpenedState !== 'user-closed') {
setFileDetailsOpenedState('auto-opened')
}
}, [fileDetailsOpenedState, setFileDetailsOpenedState, numFilesChanged])
const isFinishedMakingThreadChanges = chatThreadsStreamState && !chatThreadsStreamState.isRunning && numFilesChanged !== 0 const isFinishedMakingThreadChanges = numFilesChanged !== 0 && (chatThreadsStreamState ? !chatThreadsStreamState.isRunning : true)
// ======== status of agent ======== // ======== status of agent ========
// This icon answers the question "is the LLM doing work on this thread?" // This icon answers the question "is the LLM doing work on this thread?"
@ -2022,13 +2040,13 @@ const CommandBarInChat = () => {
// dark = Done // dark = Done
const threadStatus = ( const threadStatus = (
chatThreadsStreamState?.isRunning === 'awaiting_user' ? { title: 'Needs Approval', color: 'orange', } as const chatThreadsStreamState?.isRunning === 'awaiting_user' ? { title: 'Needs Approval', color: 'yellow', } as const
: chatThreadsStreamState?.isRunning ? { title: 'Running', color: 'green', } as const : chatThreadsStreamState?.isRunning ? { title: 'Running', color: 'orange', } as const
: { title: 'Done', color: 'dark', } as const : { title: 'Done', color: 'dark', } as const
) )
const threadStatusHTML = <StatusIndicator color={threadStatus.color} title={threadStatus.title} /> const threadStatusHTML = <StatusIndicator className='mx-1' indicatorColor={threadStatus.color} title={threadStatus.title} />
// ======== info about changes ======== // ======== info about changes ========
@ -2037,29 +2055,21 @@ const CommandBarInChat = () => {
// popup info about each change (each with num changes + acceptall + rejectall of their own) // popup info about each change (each with num changes + acceptall + rejectall of their own)
const numFilesChangedStr = numFilesChanged === 0 ? 'No files with changes' const numFilesChangedStr = numFilesChanged === 0 ? 'No files with changes'
: `${sortedCommandBarURIs.length} file${numFilesChanged === 1 ? '' : 's'} changed` : `${sortedCommandBarURIs.length} file${numFilesChanged === 1 ? '' : 's'} with changes`
const acceptAllButton = (
<AcceptAllButtonWrapper
text="Accept All"
className="text-xs"
onClick={() => {
sortedCommandBarURIs.forEach(uri => {
editCodeService.acceptOrRejectAllDiffAreas({
uri,
removeCtrlKs: true,
behavior: "accept",
_addToHistory: true,
})
})
}}
/>
)
const rejectAllButton = (
<RejectAllButtonWrapper
text="Reject All" const acceptRejectAllButtons = <div
className="text-xs" // do this with opacity so that the height remains the same at all times
className={`flex items-center gap-0.5
${isFinishedMakingThreadChanges ? '' : 'opacity-0 pointer-events-none'}`
}
>
<IconShell1 // RejectAllButtonWrapper
// text="Reject All"
// className="text-xs"
Icon={X}
onClick={() => { onClick={() => {
sortedCommandBarURIs.forEach(uri => { sortedCommandBarURIs.forEach(uri => {
editCodeService.acceptOrRejectAllDiffAreas({ editCodeService.acceptOrRejectAllDiffAreas({
@ -2067,16 +2077,35 @@ const CommandBarInChat = () => {
removeCtrlKs: true, removeCtrlKs: true,
behavior: "reject", behavior: "reject",
_addToHistory: true, _addToHistory: true,
}) });
}) });
}} }}
data-tooltip-id='void-tooltip'
data-tooltip-place='top'
data-tooltip-content='Reject all'
/>
<IconShell1 // AcceptAllButtonWrapper
// text="Accept All"
// className="text-xs"
Icon={Check}
onClick={() => {
sortedCommandBarURIs.forEach(uri => {
editCodeService.acceptOrRejectAllDiffAreas({
uri,
removeCtrlKs: true,
behavior: "accept",
_addToHistory: true,
});
});
}}
data-tooltip-id='void-tooltip'
data-tooltip-place='top'
data-tooltip-content='Accept all'
/> />
)
const acceptRejectAllButtons = isFinishedMakingThreadChanges && <div className='flex items-center gap-1'>
{acceptAllButton}
{rejectAllButton}
</div> </div>
@ -2092,44 +2121,60 @@ const CommandBarInChat = () => {
const fileStatus = (isFinishedMakingFileChanges const fileStatus = (isFinishedMakingFileChanges
? { title: 'Done', color: 'dark', } as const ? { title: 'Done', color: 'dark', } as const
: { title: 'Running', color: 'green', } as const : { title: 'Running', color: 'orange', } as const
) )
const acceptButton = <AcceptAllButtonWrapper
text="Accept"
className="text-xs"
onClick={() => { editCodeService.acceptOrRejectAllDiffAreas({ uri, removeCtrlKs: true, behavior: "accept", _addToHistory: true, }) }}
/>
const rejectButton = <RejectAllButtonWrapper
text="Reject"
className="text-xs"
onClick={() => { editCodeService.acceptOrRejectAllDiffAreas({ uri, removeCtrlKs: true, behavior: "reject", _addToHistory: true, }) }}
/>
const fileNameHTML = <div const fileNameHTML = <div
className="flex items-center gap-1.5 hover:brightness-125 transition-all duration-200 cursor-pointer" className="flex items-center gap-1.5 text-void-fg-3 hover:brightness-125 transition-all duration-200 cursor-pointer"
onClick={() => commandService.executeCommand('vscode.open', uri, { preview: true })} onClick={() => commandService.executeCommand('vscode.open', uri, { preview: true })}
> >
<FileIcon size={14} className="text-void-fg-3" /> {/* <FileIcon size={14} className="text-void-fg-3" /> */}
<span className="text-void-fg-2">{basename}</span> <span className="text-void-fg-3">{basename}</span>
</div> </div>
const detailsContent = <>
<span className="text-void-fg-3">{numDiffs} change{numDiffs !== 1 ? 's' : ''}</span>
</>
const acceptRejectButtons = isFinishedMakingFileChanges && <div className='flex gap-1'>
{acceptButton}
{rejectButton} const detailsContent = <div className='flex px-4'>
<span className="text-void-fg-3 opacity-80">{numDiffs} diff{numDiffs !== 1 ? 's' : ''}</span>
</div> </div>
const fileStatusHTML = <StatusIndicator color={fileStatus.color} title={fileStatus.title} /> const acceptRejectButtons = <div
// do this with opacity so that the height remains the same at all times
className={`flex
${isFinishedMakingThreadChanges ? '' : 'opacity-0 pointer-events-none'}
`}
>
<JumpToFileButton
uri={uri}
data-tooltip-id='void-tooltip'
data-tooltip-place='top'
data-tooltip-content='Goto file'
/>
<IconShell1 // RejectAllButtonWrapper
Icon={X}
onClick={() => { editCodeService.acceptOrRejectAllDiffAreas({ uri, removeCtrlKs: true, behavior: "reject", _addToHistory: true, }); }}
data-tooltip-id='void-tooltip'
data-tooltip-place='top'
data-tooltip-content='Reject file'
/>
<IconShell1 // AcceptAllButtonWrapper
Icon={Check}
onClick={() => { editCodeService.acceptOrRejectAllDiffAreas({ uri, removeCtrlKs: true, behavior: "accept", _addToHistory: true, }); }}
data-tooltip-id='void-tooltip'
data-tooltip-place='top'
data-tooltip-content='Accept file'
/>
</div>
const fileStatusHTML = <StatusIndicator className='mx-1' indicatorColor={fileStatus.color} title={fileStatus.title} />
return ( return (
// name, details // name, details
<div key={i} className="flex justify-between items-center gap-2"> <div key={i} className="flex justify-between items-center">
<div className="flex items-center gap-2"> <div className="flex items-center">
{fileNameHTML} {fileNameHTML}
{detailsContent} {detailsContent}
</div> </div>
@ -2145,7 +2190,7 @@ const CommandBarInChat = () => {
const fileDetailsButton = ( const fileDetailsButton = (
<button <button
className={`flex items-center gap-1 rounded ${numFilesChanged === 0 ? 'cursor-pointer' : 'cursor-pointer hover:brightness-125 transition-all duration-200'}`} className={`flex items-center gap-1 rounded ${numFilesChanged === 0 ? 'cursor-pointer' : 'cursor-pointer hover:brightness-125 transition-all duration-200'}`}
onClick={() => setFileDetailsOpened(!isFileDetailsOpened)} onClick={() => isFileDetailsOpened ? setFileDetailsOpenedState('user-closed') : setFileDetailsOpenedState('user-opened')}
type='button' type='button'
disabled={numFilesChanged === 0} disabled={numFilesChanged === 0}
> >
@ -2171,8 +2216,8 @@ const CommandBarInChat = () => {
flex w-full rounded-t-lg bg-void-bg-3 flex w-full rounded-t-lg bg-void-bg-3
text-void-fg-3 text-xs text-nowrap text-void-fg-3 text-xs text-nowrap
overflow-hidden transition-all duration-200 ease-in-out origin-top overflow-hidden transition-all duration-200 ease-in-out
${isFileDetailsOpened ? 'max-h-32' : 'max-h-0'} ${isFileDetailsOpened ? 'max-h-24' : 'max-h-0'}
`} `}
> >
{fileDetailsContent} {fileDetailsContent}
@ -2183,7 +2228,8 @@ const CommandBarInChat = () => {
className={` className={`
select-none select-none
flex w-full rounded-t-lg bg-void-bg-3 flex w-full rounded-t-lg bg-void-bg-3
text-void-fg-4 text-xs text-nowrap text-void-fg-3 text-xs text-nowrap
border-t border-l border-r border-zinc-300/10
px-2 py-1 px-2 py-1
justify-between justify-between

View file

@ -139,6 +139,20 @@ const VoidSelectionHelper = ({ rerenderKey }: VoidSelectionHelperProps) => {
> >
Disable Suggestions? Disable Suggestions?
</div> </div>
{dividerHTML}
<div
className='
flex items-center px-0.5
cursor-pointer
'
onClick={() => {
setClickState('init');
}}
>
<MoreVertical className="w-4" />
</div>
</> </>
return <div className=' return <div className='

View file

@ -19,8 +19,7 @@ import { WarningBox } from './WarningBox.js'
import { os } from '../../../../common/helpers/systemInfo.js' import { os } from '../../../../common/helpers/systemInfo.js'
import { IconLoading, IconX } from '../sidebar-tsx/SidebarChat.js' import { IconLoading, IconX } from '../sidebar-tsx/SidebarChat.js'
import { getModelCapabilities, getProviderCapabilities, ollamaRecommendedModels, VoidStaticModelInfo } from '../../../../common/modelCapabilities.js' import { getModelCapabilities, getProviderCapabilities, ollamaRecommendedModels, VoidStaticModelInfo } from '../../../../common/modelCapabilities.js'
import { ToolCallType, AnthropicReasoning } from '../../../../common/sendLLMMessageTypes.js'
import { IconShell1, StatusIndicatorForApplyButton } from '../markdown/ApplyBlockHoverButtons.js'
const ButtonLeftTextRightOption = ({ text, leftButton }: { text: string, leftButton?: React.ReactNode }) => { const ButtonLeftTextRightOption = ({ text, leftButton }: { text: string, leftButton?: React.ReactNode }) => {

View file

@ -5,6 +5,7 @@
import { Tooltip } from 'react-tooltip'; import { Tooltip } from 'react-tooltip';
import 'react-tooltip/dist/react-tooltip.css'; import 'react-tooltip/dist/react-tooltip.css';
import { useIsDark } from '../util/services.js';
/** /**
* Creates a configured global tooltip component with consistent styling * Creates a configured global tooltip component with consistent styling
@ -13,6 +14,10 @@ import 'react-tooltip/dist/react-tooltip.css';
* 2. Add data-tooltip-id="void-tooltip" and data-tooltip-content="Your tooltip text" to any element * 2. Add data-tooltip-id="void-tooltip" and data-tooltip-content="Your tooltip text" to any element
*/ */
export const VoidTooltip = () => { export const VoidTooltip = () => {
const isDark = useIsDark()
return ( return (
// use native colors so we don't have to worry about @@void-scope styles // use native colors so we don't have to worry about @@void-scope styles
@ -39,15 +44,30 @@ export const VoidTooltip = () => {
<> <>
<style> <style>
{` {`
#void-tooltip, #void-tooltip-orange, #void-tooltip-green {
font-size: 12px;
padding: 0px 8px;
border-radius: 6px;
z-index: 999;
}
#void-tooltip { #void-tooltip {
background-color: var(--vscode-editor-background); background-color: var(--vscode-editor-background);
color: var(--vscode-input-foreground); color: var(--vscode-input-foreground);
}
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2); #void-tooltip-orange {
font-size: 10px; background-color: #F6762A;
padding: 0px 8px; color: white;
border-radius: 6px; }
z-index: 9999;
#void-tooltip-green {
background-color: #228B22;
color: white;
}
.react-tooltip-arrow {
z-index: -1 !important; /* Keep arrow behind content (somehow this isnt done automatically) */
} }
`} `}
</style> </style>
@ -55,7 +75,20 @@ export const VoidTooltip = () => {
<Tooltip <Tooltip
id="void-tooltip" id="void-tooltip"
border='1px solid var(--vscode-commandCenter-border)' // border='1px solid var(--vscode-editorGroup-border)'
border='1px solid rgba(100,100,100,.2)'
opacity={1}
delayShow={50}
/>
<Tooltip
id="void-tooltip-orange"
border='1px solid rgba(200,200,200,.3)'
opacity={1}
delayShow={50}
/>
<Tooltip
id="void-tooltip-green"
border='1px solid rgba(200,200,200,.3)'
opacity={1} opacity={1}
delayShow={50} delayShow={50}
/> />

View file

@ -95,7 +95,7 @@ const _updatedModelsAfterDefaultModelsChange = (defaultModelNames: string[], opt
export const modelFilterOfFeatureName: { [featureName in FeatureName]: { filter: (o: ModelSelection, opts: { chatMode: ChatMode }) => boolean; emptyMessage: null | { message: string, priority: 'always' | 'fallback' } } } = { export const modelFilterOfFeatureName: { [featureName in FeatureName]: { filter: (o: ModelSelection, opts: { chatMode: ChatMode }) => boolean; emptyMessage: null | { message: string, priority: 'always' | 'fallback' } } } = {
'Autocomplete': { filter: (o) => getModelCapabilities(o.providerName, o.modelName).supportsFIM, emptyMessage: { message: 'No models support FIM', priority: 'always' } }, 'Autocomplete': { filter: (o) => getModelCapabilities(o.providerName, o.modelName).supportsFIM, emptyMessage: { message: 'No models support FIM', priority: 'always' } },
'Chat': { filter: (o, { chatMode }) => chatMode === 'normal' ? true : !!getModelCapabilities(o.providerName, o.modelName).supportsTools, emptyMessage: { message: 'No models support tool use', priority: 'fallback' } }, 'Chat': { filter: o => true, emptyMessage: null, },
'Ctrl+K': { filter: o => true, emptyMessage: null, }, 'Ctrl+K': { filter: o => true, emptyMessage: null, },
'Apply': { filter: o => true, emptyMessage: null, }, 'Apply': { filter: o => true, emptyMessage: null, },
} }

View file

@ -95,7 +95,7 @@ const newOpenAICompatibleSDK = ({ settingsOfProvider, providerName, includeInPay
} }
else if (providerName === 'gemini') { else if (providerName === 'gemini') {
const thisConfig = settingsOfProvider[providerName] const thisConfig = settingsOfProvider[providerName]
return new OpenAI({ baseURL: 'https://generativelanguage.googleapis.com/v1beta/openai', apiKey: thisConfig.apiKey, ...commonPayloadOpts }) return new OpenAI({ baseURL: 'https://generativelanguage.googleapis.com/v1beta/openai/', apiKey: thisConfig.apiKey, ...commonPayloadOpts })
} }
else if (providerName === 'deepseek') { else if (providerName === 'deepseek') {
const thisConfig = settingsOfProvider[providerName] const thisConfig = settingsOfProvider[providerName]