Major UI refresh: sidebar redesign, theme expansion, and chat performance optimizations (#706)
## Summary Complete sidebar redesign and comprehensive UI polish pass with performance optimizations, theme system refinements, and desktop integration improvements. ## Key Changes **Sidebar & Navigation Redesign** - Redesigned sessions sidebar layout with unified button primitives - Added activity sections with project grouping and improved session organization - Refined sidebar corners, spacing, and visual hierarchy - Removed NavRail component in favor of streamlined sidebar - Stabilized sessions bar toggle position in fullscreen mode **Performance Optimizations** - Reduced chat streaming CPU usage and storage churn - Optimized task tool polling and live timers with debouncing - Prevented chat state races and reduced background request load - Debounced draft writes and coalesced session reloads - Optimized message store updates and turn tracking **Theme & Visual System** - Added theme-aware window corners (desktop) and border radius tokens - Introduced glassmorphism effects on desktop sidebar - Added backdrop blur to UI elements **Chat Experience** - Added session-based permission auto-accept toggle in chat input - Polished permission shield UX with improved icon sizing and spacing - Fixed chat scroll-to-bottom behavior and timeline tracking - Enhanced tool output display with better path label detection - Removed duplicate draft context details in chat header - Added text selection menu to chat messages **Git Improvements** - Refreshed git history visual design with cleaner dividers - Added remote removal action in sync selector - Stabilized git polling to prevent excessive requests - Improved tool output rendering for git operations **Settings & Panels** - Fixed mobile scrolling on settings pages - Made outside-click settings close instantly - Reduced settings load churn and CPU spikes - Improved services dropdown layout and spacing - Softened panel resize handles **Desktop Integration** - Synced macOS window theme with app theme - Restored window dragging in sidebar header zones - Fixed system window corners on macOS - Improved header session metadata and action controls **Button & Component Standardization** - Unified button primitives across all components - Standardized destructive action patterns - Removed unused button variants (button-large, button-small) - Aligned context tab close hit areas --------- Co-authored-by: Iuliia Ivashko <yulia.ivashko@gmail.com>
This commit is contained in:
committed by
GitHub
co-authored by
Iuliia Ivashko
parent
359879153a
commit
321cc7252a
@@ -37,7 +37,6 @@ import { Input } from '@/components/ui/input';
|
||||
import { MobileOverlayPanel } from '@/components/ui/MobileOverlayPanel';
|
||||
import { ProviderLogo } from '@/components/ui/ProviderLogo';
|
||||
import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { TextLoop } from '@/components/ui/TextLoop';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useIsVSCodeRuntime } from '@/hooks/useRuntimeAPIs';
|
||||
@@ -350,14 +349,6 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
? (sessionSavedAgentName || stickySessionAgentName || currentAgentName)
|
||||
: currentAgentName;
|
||||
|
||||
const sessionIdForEditMode = currentSessionId ?? '__global__';
|
||||
const sessionEditMode = useContextStore((state) => {
|
||||
if (!uiAgentName) {
|
||||
return undefined;
|
||||
}
|
||||
return state.getSessionAgentEditMode(sessionIdForEditMode, uiAgentName, 'ask');
|
||||
});
|
||||
const setSessionAgentEditMode = useContextStore((state) => state.setSessionAgentEditMode);
|
||||
const {
|
||||
toggleFavoriteModel,
|
||||
isFavoriteModel,
|
||||
@@ -506,21 +497,6 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
return getCurrentAgent?.();
|
||||
}, [agents, getCurrentAgent, uiAgentName]);
|
||||
|
||||
const agentEditAction = React.useMemo<PermissionAction>(() => {
|
||||
if (!currentAgent) {
|
||||
return 'deny';
|
||||
}
|
||||
return resolveWildcardPermissionAction(currentAgent.permission, 'edit') ?? 'allow';
|
||||
}, [currentAgent]);
|
||||
|
||||
const selectionContextReady = Boolean(uiAgentName);
|
||||
|
||||
const approveEditsAvailable = agentEditAction === 'ask';
|
||||
const approveEditsChecked = approveEditsAvailable
|
||||
? sessionEditMode === 'allow' || sessionEditMode === 'full'
|
||||
: agentEditAction === 'allow';
|
||||
const approveEditsDisabled = !selectionContextReady || !approveEditsAvailable;
|
||||
|
||||
const sizeVariant: 'mobile' | 'vscode' | 'default' = isMobile ? 'mobile' : isVSCodeRuntime ? 'vscode' : 'default';
|
||||
const buttonHeight = sizeVariant === 'mobile' ? 'h-9' : sizeVariant === 'vscode' ? 'h-6' : 'h-8';
|
||||
const editToggleIconClass = sizeVariant === 'mobile' ? 'h-5 w-5' : sizeVariant === 'vscode' ? 'h-4 w-4' : 'h-4 w-4';
|
||||
@@ -545,13 +521,6 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
return <RiQuestionLine className={combinedClassName} style={iconStyle} />;
|
||||
}, [editToggleIconClass]);
|
||||
|
||||
const handleApproveEditsToggle = React.useCallback((checked: boolean) => {
|
||||
if (!selectionContextReady || !currentAgentName || !approveEditsAvailable) {
|
||||
return;
|
||||
}
|
||||
setSessionAgentEditMode(sessionIdForEditMode, currentAgentName, checked ? 'allow' : 'ask', 'ask');
|
||||
}, [approveEditsAvailable, currentAgentName, selectionContextReady, setSessionAgentEditMode, sessionIdForEditMode]);
|
||||
|
||||
const currentProvider = getCurrentProvider();
|
||||
const models = Array.isArray(currentProvider?.models) ? currentProvider.models : [];
|
||||
|
||||
@@ -1819,23 +1788,6 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
onClose={closeMobilePanel}
|
||||
title="Select agent"
|
||||
contentMaxHeightClassName="max-h-[min(52dvh,360px)]"
|
||||
footer={(
|
||||
<div className="flex items-center justify-between">
|
||||
<span
|
||||
className={cn(
|
||||
'typography-meta font-medium',
|
||||
approveEditsDisabled ? 'text-muted-foreground' : 'text-foreground'
|
||||
)}
|
||||
>
|
||||
Auto-approve edits
|
||||
</span>
|
||||
<Switch
|
||||
checked={approveEditsChecked}
|
||||
disabled={approveEditsDisabled}
|
||||
onCheckedChange={handleApproveEditsToggle}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-col gap-2">
|
||||
{selectableDesktopAgents.map((agent) => {
|
||||
@@ -2302,10 +2254,9 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
|
||||
{/* Favorites Section */}
|
||||
{filteredFavorites.length > 0 && (
|
||||
<>
|
||||
<div>
|
||||
<DropdownMenuLabel
|
||||
style={{ backgroundColor: 'var(--surface-elevated)' }}
|
||||
className="typography-micro font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-2 -mx-1 px-3 py-1.5 sticky top-0 z-10 border-b border-border/30"
|
||||
className="typography-micro font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-2 -mx-1 px-3 py-1.5 border-b border-border/30"
|
||||
>
|
||||
<RiStarFill className="h-4 w-4 text-primary" />
|
||||
Favorites
|
||||
@@ -2314,16 +2265,15 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
const idx = currentFlatIndex++;
|
||||
return renderModelRow(model, providerID, modelID, 'fav', idx, modelSelectedIndex === idx);
|
||||
})}
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Recents Section */}
|
||||
{filteredRecents.length > 0 && (
|
||||
<>
|
||||
<div>
|
||||
{filteredFavorites.length > 0 && <DropdownMenuSeparator />}
|
||||
<DropdownMenuLabel
|
||||
style={{ backgroundColor: 'var(--surface-elevated)' }}
|
||||
className="typography-micro font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-2 -mx-1 px-3 py-1.5 sticky top-0 z-10 border-b border-border/30"
|
||||
className="typography-micro font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-2 -mx-1 px-3 py-1.5 border-b border-border/30"
|
||||
>
|
||||
<RiTimeLine className="h-4 w-4" />
|
||||
Recent
|
||||
@@ -2332,7 +2282,7 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
const idx = currentFlatIndex++;
|
||||
return renderModelRow(model, providerID, modelID, 'recent', idx, modelSelectedIndex === idx);
|
||||
})}
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Separator before providers */}
|
||||
@@ -2342,7 +2292,7 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
|
||||
{/* All Providers - Flat List */}
|
||||
{providerSections.map(({ provider, isExpanded, visibleModels }, index) => (
|
||||
<React.Fragment key={provider.id}>
|
||||
<div key={provider.id}>
|
||||
{index > 0 && <DropdownMenuSeparator />}
|
||||
<div
|
||||
role="button"
|
||||
@@ -2366,8 +2316,8 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
}
|
||||
}}
|
||||
className={cn(
|
||||
'typography-micro font-semibold text-muted-foreground uppercase tracking-wider flex w-full items-center gap-2 -mx-1 px-3 py-1.5 sticky top-0 z-10 border-b border-border/30',
|
||||
'bg-[var(--surface-elevated)] text-left transition-colors',
|
||||
'typography-micro font-semibold text-muted-foreground uppercase tracking-wider flex w-full items-center gap-2 -mx-1 px-3 py-1.5 border-b border-border/30',
|
||||
'text-left transition-colors',
|
||||
forceExpandProviders ? 'cursor-default' : 'cursor-pointer'
|
||||
)}
|
||||
aria-expanded={isExpanded}
|
||||
@@ -2392,7 +2342,7 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
const idx = currentFlatIndex++;
|
||||
return renderModelRow(model, provider.id as string, model.id as string, 'provider', idx, modelSelectedIndex === idx);
|
||||
})}
|
||||
</React.Fragment>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ScrollableOverlay>
|
||||
@@ -2755,24 +2705,6 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
)}
|
||||
</div>
|
||||
</ScrollableOverlay>
|
||||
<DropdownMenuSeparator />
|
||||
<div className="flex flex-col gap-1 px-1 py-0.5">
|
||||
<div className="rounded-xl bg-transparent">
|
||||
<div className="flex items-center justify-between px-2 py-2">
|
||||
<span className={cn(
|
||||
'typography-meta font-medium',
|
||||
approveEditsDisabled ? 'text-muted-foreground' : 'text-foreground'
|
||||
)}>
|
||||
Auto-approve edits
|
||||
</span>
|
||||
<Switch
|
||||
checked={approveEditsChecked}
|
||||
disabled={approveEditsDisabled}
|
||||
onCheckedChange={handleApproveEditsToggle}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
{renderAgentTooltipContent()}
|
||||
|
||||
Reference in New Issue
Block a user