feat: ability to expand sidebar to see chats names (#7816)

Signed-off-by: Abhijay007 <Abhijay007j@gmail.com>
Signed-off-by: Abhijay Jain <Abhijay007j@gmail.com>
This commit is contained in:
Abhijay Jain
2026-03-20 19:25:33 +05:30
committed by GitHub
parent 5836f6fa4c
commit 387f1247c1
5 changed files with 114 additions and 9 deletions
+2
View File
@@ -171,6 +171,8 @@ const mockElectron = {
getAllowedExtensions: vi.fn().mockResolvedValue([]),
platform: 'darwin',
createChatWindow: vi.fn(),
getSetting: vi.fn().mockResolvedValue(null),
setSetting: vi.fn().mockResolvedValue(undefined),
};
// Mock appConfig
+105 -9
View File
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { Outlet, useLocation } from 'react-router-dom';
import { motion } from 'framer-motion';
import { Menu } from 'lucide-react';
@@ -34,6 +34,82 @@ const AppLayoutContent: React.FC<AppLayoutContentProps> = ({ activeSessions }) =
isCondensedIconOnly,
} = useNavigationContext();
const [navWidth, setNavWidth] = useState<number | null>(null);
const navWidthRef = useRef<number | null>(null);
useEffect(() => {
window.electron.getSetting('navExpandedWidth').then((delta) => {
if (delta !== null) {
setNavWidth(
Math.min(
NAV_DIMENSIONS.MAX_NAV_WIDTH,
Math.max(NAV_DIMENSIONS.MIN_NAV_WIDTH, NAV_DIMENSIONS.CONDENSED_WIDTH + delta)
)
);
}
});
}, []);
const isResizable =
!isHorizontalNav && !isCondensedIconOnly && effectiveNavigationMode === 'push' && isNavExpanded;
const dragStateRef = useRef<{ startX: number; startWidth: number; direction: 1 | -1 } | null>(
null
);
const navRef = useRef<HTMLDivElement>(null);
const onMouseMove = useCallback((e: MouseEvent) => {
if (!dragStateRef.current) return;
const delta = (e.clientX - dragStateRef.current.startX) * dragStateRef.current.direction;
const newWidth = Math.min(
NAV_DIMENSIONS.MAX_NAV_WIDTH,
Math.max(NAV_DIMENSIONS.MIN_NAV_WIDTH, dragStateRef.current.startWidth + delta)
);
navWidthRef.current = newWidth;
setNavWidth(newWidth);
}, []);
const onMouseUp = useCallback(() => {
dragStateRef.current = null;
document.body.style.cursor = '';
document.body.style.userSelect = '';
window.removeEventListener('mousemove', onMouseMove);
window.removeEventListener('mouseup', onMouseUp);
if (navWidthRef.current !== null) {
window.electron.setSetting(
'navExpandedWidth',
navWidthRef.current - NAV_DIMENSIONS.CONDENSED_WIDTH
);
}
}, [onMouseMove]);
const onHandleMouseDown = useCallback(
(e: React.MouseEvent) => {
e.preventDefault();
const currentWidth =
navRef.current?.getBoundingClientRect().width ?? NAV_DIMENSIONS.CONDENSED_WIDTH;
dragStateRef.current = {
startX: e.clientX,
startWidth: currentWidth,
direction: navigationPosition === 'right' ? -1 : 1,
};
document.body.style.cursor = 'col-resize';
document.body.style.userSelect = 'none';
window.addEventListener('mousemove', onMouseMove);
window.addEventListener('mouseup', onMouseUp);
},
[navigationPosition, onMouseMove, onMouseUp]
);
useEffect(() => {
return () => {
window.removeEventListener('mousemove', onMouseMove);
window.removeEventListener('mouseup', onMouseUp);
document.body.style.cursor = '';
document.body.style.userSelect = '';
};
}, [onMouseMove, onMouseUp]);
if (!chatContext) {
throw new Error('AppLayoutContent must be used within ChatProvider');
}
@@ -134,6 +210,7 @@ const AppLayoutContent: React.FC<AppLayoutContentProps> = ({ activeSessions }) =
{/* Push mode navigation (inline) with animation */}
{effectiveNavigationMode === 'push' && (
<motion.div
ref={navRef}
key="push-nav"
initial={false}
animate={{
@@ -141,10 +218,10 @@ const AppLayoutContent: React.FC<AppLayoutContentProps> = ({ activeSessions }) =
? '100%'
: isNavExpanded
? effectiveNavigationStyle === 'expanded'
? '30%'
? (navWidth ?? '30%')
: isCondensedIconOnly
? NAV_DIMENSIONS.CONDENSED_ICON_ONLY_WIDTH
: NAV_DIMENSIONS.CONDENSED_WIDTH
: (navWidth ?? NAV_DIMENSIONS.CONDENSED_WIDTH)
: 0,
height: isHorizontalNav
? isNavExpanded
@@ -161,7 +238,9 @@ const AppLayoutContent: React.FC<AppLayoutContentProps> = ({ activeSessions }) =
}}
style={{
maxWidth:
!isHorizontalNav && effectiveNavigationStyle === 'expanded' ? '400px' : undefined,
!isHorizontalNav && effectiveNavigationStyle === 'expanded'
? NAV_DIMENSIONS.MAX_NAV_WIDTH
: undefined,
minWidth:
!isHorizontalNav && effectiveNavigationStyle === 'condensed' && isNavExpanded
? isCondensedIconOnly
@@ -177,14 +256,31 @@ const AppLayoutContent: React.FC<AppLayoutContentProps> = ({ activeSessions }) =
height: !isHorizontalNav ? '100%' : undefined,
}}
className={cn(
'flex-shrink-0',
effectiveNavigationStyle === 'condensed' && !isHorizontalNav
? 'overflow-visible'
: 'overflow-hidden',
'relative flex-shrink-0 overflow-visible',
isHorizontalNav ? 'w-full' : 'h-full'
)}
>
<Navigation />
<div
className={cn(
'w-full h-full',
effectiveNavigationStyle === 'condensed' && !isHorizontalNav
? 'overflow-visible'
: 'overflow-hidden'
)}
>
<Navigation />
</div>
{isResizable && (
<div
onMouseDown={onHandleMouseDown}
className={cn(
'absolute top-0 w-2 h-full z-20 cursor-col-resize group flex items-center justify-center',
navigationPosition === 'right' ? '-left-1' : '-right-1'
)}
>
<div className="w-px h-full bg-border-subtle opacity-0 group-hover:opacity-100 transition-opacity" />
</div>
)}
</motion.div>
)}
@@ -7,6 +7,10 @@ export const NAV_DIMENSIONS = {
EXPANDED_HEIGHT: 180,
/** Height of condensed navigation (horizontal mode) */
CONDENSED_HEIGHT: 46,
/** Minimum width when resizing the navigation panel */
MIN_NAV_WIDTH: 200,
/** Maximum width when resizing the navigation panel */
MAX_NAV_WIDTH: 600,
} as const;
export const Z_INDEX = {
+1
View File
@@ -1323,6 +1323,7 @@ const validSettingKeys: Set<string> = new Set([
'showPricing',
'sessionSharing',
'seenAnnouncementIds',
'navExpandedWidth',
]);
ipcMain.handle('set-setting', (_event, key: SettingKey, value: unknown) => {
+2
View File
@@ -44,6 +44,7 @@ export interface Settings {
showPricing: boolean;
sessionSharing: SessionSharingConfig;
seenAnnouncementIds: string[];
navExpandedWidth: number | null;
}
export type SettingKey = keyof Settings;
@@ -85,6 +86,7 @@ export const defaultSettings: Settings = {
baseUrl: '',
},
seenAnnouncementIds: [],
navExpandedWidth: null,
};
export function getKeyboardShortcuts(settings: Settings): KeyboardShortcuts {