@@ -9,15 +9,17 @@ import { abbreviatePath } from "@/utils/ui/pathAbbreviation";
99import { TooltipWrapper , Tooltip } from "./Tooltip" ;
1010
1111// Styled Components
12- const SidebarContainer = styled . div `
13- width: 280px;
12+ const SidebarContainer = styled . div < { collapsed ?: boolean } > `
13+ width: ${ ( props ) => ( props . collapsed ? "32px" : " 280px" ) } ;
1414 height: 100vh;
1515 background: #252526;
1616 border-right: 1px solid #1e1e1e;
1717 display: flex;
1818 flex-direction: column;
1919 flex-shrink: 0;
2020 font-family: var(--font-primary);
21+ transition: width 0.2s ease;
22+ overflow: hidden;
2123` ;
2224
2325const SidebarHeader = styled . div `
@@ -58,6 +60,28 @@ const AddProjectBtn = styled.button`
5860 }
5961` ;
6062
63+ const CollapseButton = styled . button `
64+ width: 100%;
65+ height: 36px;
66+ background: transparent;
67+ color: #888;
68+ border: none;
69+ border-top: 1px solid #1e1e1e;
70+ cursor: pointer;
71+ font-size: 14px;
72+ display: flex;
73+ align-items: center;
74+ justify-content: center;
75+ padding: 0;
76+ transition: all 0.2s;
77+ margin-top: auto;
78+
79+ &:hover {
80+ background: #2a2a2b;
81+ color: #ccc;
82+ }
83+ ` ;
84+
6185const ProjectsList = styled . div `
6286 flex: 1;
6387 overflow-y: auto;
@@ -337,6 +361,8 @@ interface ProjectSidebarProps {
337361 workspaceId : string ,
338362 newName : string
339363 ) => Promise < { success : boolean ; error ?: string } > ;
364+ collapsed : boolean ;
365+ onToggleCollapsed : ( ) => void ;
340366}
341367
342368const ProjectSidebar : React . FC < ProjectSidebarProps > = ( {
@@ -349,6 +375,8 @@ const ProjectSidebar: React.FC<ProjectSidebarProps> = ({
349375 onRemoveProject,
350376 onRemoveWorkspace,
351377 onRenameWorkspace,
378+ collapsed,
379+ onToggleCollapsed,
352380} ) => {
353381 // Store as array in localStorage, convert to Set for usage
354382 const [ expandedProjectsArray , setExpandedProjectsArray ] = usePersistedState < string [ ] > (
@@ -455,130 +483,141 @@ const ProjectSidebar: React.FC<ProjectSidebarProps> = ({
455483 } , [ selectedWorkspace , onAddWorkspace ] ) ;
456484
457485 return (
458- < SidebarContainer >
459- < SidebarHeader >
460- < h2 > Projects</ h2 >
461- < AddProjectBtn onClick = { onAddProject } title = "Add Project" >
462- +
463- </ AddProjectBtn >
464- </ SidebarHeader >
465- < ProjectsList >
466- { projects . size === 0 ? (
467- < EmptyState >
468- < p > No projects</ p >
469- < AddFirstProjectBtn onClick = { onAddProject } > Add Project</ AddFirstProjectBtn >
470- </ EmptyState >
471- ) : (
472- Array . from ( projects . entries ( ) ) . map ( ( [ projectPath , config ] ) => (
473- < ProjectGroup key = { projectPath } >
474- < ProjectItem onClick = { ( ) => toggleProject ( projectPath ) } >
475- < ExpandIcon expanded = { expandedProjects . has ( projectPath ) } > ▶</ ExpandIcon >
476- < ProjectInfo >
477- < ProjectName > { getProjectName ( projectPath ) } </ ProjectName >
478- < TooltipWrapper inline >
479- < ProjectPath > { abbreviatePath ( projectPath ) } </ ProjectPath >
480- < Tooltip className = "tooltip" align = "left" >
481- { projectPath }
482- </ Tooltip >
483- </ TooltipWrapper >
484- </ ProjectInfo >
485- < TooltipWrapper inline >
486- < RemoveBtn
487- onClick = { ( e ) => {
488- e . stopPropagation ( ) ;
489- onRemoveProject ( projectPath ) ;
490- } }
491- >
492- ×
493- </ RemoveBtn >
494- < Tooltip className = "tooltip" align = "right" >
495- Remove project
496- </ Tooltip >
497- </ TooltipWrapper >
498- </ ProjectItem >
499-
500- { expandedProjects . has ( projectPath ) && (
501- < WorkspacesContainer >
502- < WorkspaceHeader >
503- < AddWorkspaceBtn onClick = { ( ) => onAddWorkspace ( projectPath ) } >
504- + New Workspace
505- { selectedWorkspace ?. projectPath === projectPath &&
506- ` (${ formatKeybind ( KEYBINDS . NEW_WORKSPACE ) } )` }
507- </ AddWorkspaceBtn >
508- </ WorkspaceHeader >
509- { config . workspaces . map ( ( workspace ) => {
510- const projectName = getProjectName ( projectPath ) ;
511- const metadata = workspaceMetadata . get ( workspace . path ) ;
512- if ( ! metadata ) return null ; // Skip if metadata not loaded yet
513-
514- const workspaceId = metadata . id ;
515- const displayName = getWorkspaceDisplayName ( workspace . path ) ;
516- const isActive = false ; // Simplified - no active state tracking
517- const isEditing = editingWorkspaceId === workspaceId ;
518-
519- return (
520- < WorkspaceItem
521- key = { workspace . path }
522- selected = { selectedWorkspace ?. workspacePath === workspace . path }
523- onClick = { ( ) =>
524- onSelectWorkspace ( {
525- projectPath,
526- projectName,
527- workspacePath : workspace . path ,
528- workspaceId,
529- } )
530- }
486+ < SidebarContainer collapsed = { collapsed } >
487+ { ! collapsed && (
488+ < >
489+ < SidebarHeader >
490+ < h2 > Projects</ h2 >
491+ < AddProjectBtn onClick = { onAddProject } title = "Add Project" >
492+ +
493+ </ AddProjectBtn >
494+ </ SidebarHeader >
495+ < ProjectsList >
496+ { projects . size === 0 ? (
497+ < EmptyState >
498+ < p > No projects</ p >
499+ < AddFirstProjectBtn onClick = { onAddProject } > Add Project</ AddFirstProjectBtn >
500+ </ EmptyState >
501+ ) : (
502+ Array . from ( projects . entries ( ) ) . map ( ( [ projectPath , config ] ) => (
503+ < ProjectGroup key = { projectPath } >
504+ < ProjectItem onClick = { ( ) => toggleProject ( projectPath ) } >
505+ < ExpandIcon expanded = { expandedProjects . has ( projectPath ) } > ▶</ ExpandIcon >
506+ < ProjectInfo >
507+ < ProjectName > { getProjectName ( projectPath ) } </ ProjectName >
508+ < TooltipWrapper inline >
509+ < ProjectPath > { abbreviatePath ( projectPath ) } </ ProjectPath >
510+ < Tooltip className = "tooltip" align = "left" >
511+ { projectPath }
512+ </ Tooltip >
513+ </ TooltipWrapper >
514+ </ ProjectInfo >
515+ < TooltipWrapper inline >
516+ < RemoveBtn
517+ onClick = { ( e ) => {
518+ e . stopPropagation ( ) ;
519+ onRemoveProject ( projectPath ) ;
520+ } }
531521 >
532- < StatusIndicator active = { isActive } title = "AI Assistant" />
533- < BranchIcon > ⎇</ BranchIcon >
534- { isEditing ? (
535- < WorkspaceNameInput
536- value = { editingName }
537- onChange = { ( e ) => setEditingName ( e . target . value ) }
538- onKeyDown = { ( e ) => handleRenameKeyDown ( e , workspaceId ) }
539- onBlur = { ( ) => void confirmRename ( workspaceId ) }
540- autoFocus
541- onClick = { ( e ) => e . stopPropagation ( ) }
542- />
543- ) : (
544- < WorkspaceName
545- onDoubleClick = { ( e ) => {
546- e . stopPropagation ( ) ;
547- startRenaming ( workspaceId , displayName ) ;
548- } }
549- title = "Double-click to rename"
550- >
551- { displayName }
552- </ WorkspaceName >
553- ) }
554- < TooltipWrapper inline >
555- < WorkspaceRemoveBtn
556- onClick = { ( e ) => {
557- e . stopPropagation ( ) ;
558- void handleRemoveWorkspace ( workspaceId ) ;
559- } }
522+ ×
523+ </ RemoveBtn >
524+ < Tooltip className = "tooltip" align = "right" >
525+ Remove project
526+ </ Tooltip >
527+ </ TooltipWrapper >
528+ </ ProjectItem >
529+
530+ { expandedProjects . has ( projectPath ) && (
531+ < WorkspacesContainer >
532+ < WorkspaceHeader >
533+ < AddWorkspaceBtn onClick = { ( ) => onAddWorkspace ( projectPath ) } >
534+ + New Workspace
535+ { selectedWorkspace ?. projectPath === projectPath &&
536+ ` (${ formatKeybind ( KEYBINDS . NEW_WORKSPACE ) } )` }
537+ </ AddWorkspaceBtn >
538+ </ WorkspaceHeader >
539+ { config . workspaces . map ( ( workspace ) => {
540+ const projectName = getProjectName ( projectPath ) ;
541+ const metadata = workspaceMetadata . get ( workspace . path ) ;
542+ if ( ! metadata ) return null ; // Skip if metadata not loaded yet
543+
544+ const workspaceId = metadata . id ;
545+ const displayName = getWorkspaceDisplayName ( workspace . path ) ;
546+ const isActive = false ; // Simplified - no active state tracking
547+ const isEditing = editingWorkspaceId === workspaceId ;
548+
549+ return (
550+ < WorkspaceItem
551+ key = { workspace . path }
552+ selected = { selectedWorkspace ?. workspacePath === workspace . path }
553+ onClick = { ( ) =>
554+ onSelectWorkspace ( {
555+ projectPath,
556+ projectName,
557+ workspacePath : workspace . path ,
558+ workspaceId,
559+ } )
560+ }
560561 >
561- ×
562- </ WorkspaceRemoveBtn >
563- < Tooltip className = "tooltip" align = "right" >
564- Remove workspace
565- </ Tooltip >
566- </ TooltipWrapper >
567- { isEditing && renameError && (
568- < WorkspaceErrorContainer > { renameError } </ WorkspaceErrorContainer >
569- ) }
570- { ! isEditing && removeError ?. workspaceId === workspaceId && (
571- < WorkspaceErrorContainer > { removeError . error } </ WorkspaceErrorContainer >
572- ) }
573- </ WorkspaceItem >
574- ) ;
575- } ) }
576- </ WorkspacesContainer >
577- ) }
578- </ ProjectGroup >
579- ) )
580- ) }
581- </ ProjectsList >
562+ < StatusIndicator active = { isActive } title = "AI Assistant" />
563+ < BranchIcon > ⎇</ BranchIcon >
564+ { isEditing ? (
565+ < WorkspaceNameInput
566+ value = { editingName }
567+ onChange = { ( e ) => setEditingName ( e . target . value ) }
568+ onKeyDown = { ( e ) => handleRenameKeyDown ( e , workspaceId ) }
569+ onBlur = { ( ) => void confirmRename ( workspaceId ) }
570+ autoFocus
571+ onClick = { ( e ) => e . stopPropagation ( ) }
572+ />
573+ ) : (
574+ < WorkspaceName
575+ onDoubleClick = { ( e ) => {
576+ e . stopPropagation ( ) ;
577+ startRenaming ( workspaceId , displayName ) ;
578+ } }
579+ title = "Double-click to rename"
580+ >
581+ { displayName }
582+ </ WorkspaceName >
583+ ) }
584+ < TooltipWrapper inline >
585+ < WorkspaceRemoveBtn
586+ onClick = { ( e ) => {
587+ e . stopPropagation ( ) ;
588+ void handleRemoveWorkspace ( workspaceId ) ;
589+ } }
590+ >
591+ ×
592+ </ WorkspaceRemoveBtn >
593+ < Tooltip className = "tooltip" align = "right" >
594+ Remove workspace
595+ </ Tooltip >
596+ </ TooltipWrapper >
597+ { isEditing && renameError && (
598+ < WorkspaceErrorContainer > { renameError } </ WorkspaceErrorContainer >
599+ ) }
600+ { ! isEditing && removeError ?. workspaceId === workspaceId && (
601+ < WorkspaceErrorContainer > { removeError . error } </ WorkspaceErrorContainer >
602+ ) }
603+ </ WorkspaceItem >
604+ ) ;
605+ } ) }
606+ </ WorkspacesContainer >
607+ ) }
608+ </ ProjectGroup >
609+ ) )
610+ ) }
611+ </ ProjectsList >
612+ </ >
613+ ) }
614+ < TooltipWrapper inline >
615+ < CollapseButton onClick = { onToggleCollapsed } > { collapsed ? "»" : "«" } </ CollapseButton >
616+ < Tooltip className = "tooltip" align = "center" >
617+ { collapsed ? "Expand sidebar" : "Collapse sidebar" } (
618+ { formatKeybind ( KEYBINDS . TOGGLE_SIDEBAR ) } )
619+ </ Tooltip >
620+ </ TooltipWrapper >
582621 </ SidebarContainer >
583622 ) ;
584623} ;
0 commit comments