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
@@ -1,18 +1,23 @@
|
||||
import React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useUIStore } from '@/stores/useUIStore';
|
||||
import { isDesktopShell } from '@/lib/desktop';
|
||||
|
||||
export const RIGHT_SIDEBAR_CONTENT_WIDTH = 420;
|
||||
const RIGHT_SIDEBAR_MIN_WIDTH = 400;
|
||||
const RIGHT_SIDEBAR_MAX_WIDTH = 860;
|
||||
|
||||
interface RightSidebarProps {
|
||||
isOpen: boolean;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
onTopActionsHostChange?: (element: HTMLDivElement | null) => void;
|
||||
}
|
||||
|
||||
export const RightSidebar: React.FC<RightSidebarProps> = ({ isOpen, children }) => {
|
||||
export const RightSidebar: React.FC<RightSidebarProps> = ({ isOpen, children, className, onTopActionsHostChange }) => {
|
||||
const rightSidebarWidth = useUIStore((state) => state.rightSidebarWidth);
|
||||
const setRightSidebarWidth = useUIStore((state) => state.setRightSidebarWidth);
|
||||
const isDesktopApp = React.useMemo(() => isDesktopShell(), []);
|
||||
const [isResizing, setIsResizing] = React.useState(false);
|
||||
const startXRef = React.useRef(0);
|
||||
const startWidthRef = React.useRef(rightSidebarWidth || 420);
|
||||
@@ -34,7 +39,7 @@ export const RightSidebar: React.FC<RightSidebarProps> = ({ isOpen, children })
|
||||
}, []);
|
||||
|
||||
const appliedWidth = isOpen
|
||||
? Math.min(RIGHT_SIDEBAR_MAX_WIDTH, Math.max(RIGHT_SIDEBAR_MIN_WIDTH, rightSidebarWidth || 420))
|
||||
? Math.min(RIGHT_SIDEBAR_MAX_WIDTH, Math.max(RIGHT_SIDEBAR_MIN_WIDTH, rightSidebarWidth || RIGHT_SIDEBAR_CONTENT_WIDTH))
|
||||
: 0;
|
||||
|
||||
const handlePointerDown = (event: React.PointerEvent) => {
|
||||
@@ -97,13 +102,47 @@ export const RightSidebar: React.FC<RightSidebarProps> = ({ isOpen, children })
|
||||
}
|
||||
}, [isResizing]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!isOpen) {
|
||||
onTopActionsHostChange?.(null);
|
||||
}
|
||||
}, [isOpen, onTopActionsHostChange]);
|
||||
|
||||
const handleDragStart = React.useCallback(async (event: React.MouseEvent) => {
|
||||
const target = event.target as HTMLElement;
|
||||
if (target.closest('.app-region-no-drag')) {
|
||||
return;
|
||||
}
|
||||
if (target.closest('button, a, input, select, textarea')) {
|
||||
return;
|
||||
}
|
||||
if (event.button !== 0) {
|
||||
return;
|
||||
}
|
||||
if (!isDesktopApp) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { getCurrentWindow } = await import('@tauri-apps/api/window');
|
||||
const appWindow = getCurrentWindow();
|
||||
await appWindow.startDragging();
|
||||
} catch (error) {
|
||||
console.error('Failed to start window dragging:', error);
|
||||
}
|
||||
}, [isDesktopApp]);
|
||||
|
||||
return (
|
||||
<aside
|
||||
ref={sidebarRef}
|
||||
className={cn(
|
||||
'relative flex h-full overflow-hidden border-l border-border/40 bg-sidebar/50',
|
||||
'relative flex h-full overflow-hidden border-l border-border/40',
|
||||
isOpen
|
||||
? 'bg-[color:var(--sidebar-overlay-strong)] backdrop-blur supports-[backdrop-filter]:bg-[color:var(--sidebar-overlay-soft)]'
|
||||
: 'bg-sidebar',
|
||||
isResizing ? 'transition-none' : 'transition-[width] duration-300 ease-in-out',
|
||||
!isOpen && 'border-l-0'
|
||||
!isOpen && 'border-l-0',
|
||||
className,
|
||||
)}
|
||||
style={{
|
||||
width: 'var(--oc-right-sidebar-width)',
|
||||
@@ -114,11 +153,23 @@ export const RightSidebar: React.FC<RightSidebarProps> = ({ isOpen, children })
|
||||
}}
|
||||
aria-hidden={!isOpen || appliedWidth === 0}
|
||||
>
|
||||
{isOpen ? (
|
||||
<div
|
||||
onMouseDown={handleDragStart}
|
||||
className="app-region-drag absolute inset-x-0 top-0 z-20 flex h-[var(--oc-header-height,56px)] items-center justify-end px-3"
|
||||
aria-hidden
|
||||
>
|
||||
<div
|
||||
ref={onTopActionsHostChange}
|
||||
className="app-region-no-drag flex items-center gap-1"
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{isOpen && (
|
||||
<div
|
||||
className={cn(
|
||||
'absolute left-0 top-0 z-20 h-full w-[4px] cursor-col-resize hover:bg-primary/50 transition-colors',
|
||||
isResizing && 'bg-primary'
|
||||
'absolute left-0 top-0 z-20 h-full w-[3px] cursor-col-resize hover:bg-[var(--interactive-border)]/80 transition-colors',
|
||||
isResizing && 'bg-[var(--interactive-border)]'
|
||||
)}
|
||||
onPointerDown={handlePointerDown}
|
||||
onPointerMove={handlePointerMove}
|
||||
@@ -135,6 +186,7 @@ export const RightSidebar: React.FC<RightSidebarProps> = ({ isOpen, children })
|
||||
isResizing && 'pointer-events-none',
|
||||
!isOpen && 'pointer-events-none select-none opacity-0'
|
||||
)}
|
||||
style={isOpen ? { paddingTop: 'var(--oc-header-height, 56px)' } : undefined}
|
||||
aria-hidden={!isOpen}
|
||||
>
|
||||
{isOpen ? children : null}
|
||||
|
||||
Reference in New Issue
Block a user