| 86 | className="flex-col border-r border-border" |
| 87 | > |
| 88 | {/* Header Row */} |
| 89 | <div |
| 90 | className={ |
| 91 | isCollapsed |
| 92 | ? 'flex flex-col items-center gap-1 px-2 pt-3' |
| 93 | : 'flex h-14 items-center justify-between gap-1 px-3' |
| 94 | } |
| 95 | > |
| 96 | <button |
| 97 | type="button" |
| 98 | onClick={() => router.push('/')} |
| 99 | aria-label="CodeFox home" |
| 100 | tabIndex={-1} |
| 101 | className="flex h-9 items-center rounded-md transition-opacity hover:opacity-80" |
| 102 | > |
| 103 | {isCollapsed ? ( |
| 104 | <FoxMark className="h-5 w-5 text-foreground" /> |
| 105 | ) : ( |
| 106 | <Wordmark /> |
| 107 | )} |
| 108 | </button> |
| 109 | |
| 110 | {/* Always reachable — collapsing must be reversible. */} |
| 111 | <SidebarTrigger |
| 112 | className="flex h-9 w-9 shrink-0 items-center justify-center rounded-md transition-colors hover:bg-accent" |
| 113 | onClick={() => setIsCollapsed(!isCollapsed)} |
| 114 | /> |
| 115 | </div> |
| 116 | |
| 117 | <div className="w-full border-t border-border" /> |
| 118 | |
| 119 | {/* Primary action */} |
| 120 | <div |
| 121 | className={`mt-2 ${isCollapsed ? 'flex justify-center px-2' : 'px-3'}`} |
| 122 | > |
| 123 | <button |
| 124 | type="button" |
| 125 | onClick={() => router.push('/')} |
| 126 | title="New project" |
| 127 | className={cn( |
| 128 | 'flex h-9 items-center rounded-md text-sm font-medium transition-colors hover:bg-accent', |
| 129 | isCollapsed ? 'w-9 justify-center' : 'w-full justify-start' |
| 130 | )} |
| 131 | > |
| 132 | <span className="flex w-5 shrink-0 justify-center"> |
| 133 | <PlusIcon |
| 134 | className="h-5 w-5" |
| 135 | style={{ color: 'hsl(var(--primary))' }} |
| 136 | /> |
| 137 | </span> |
| 138 | {!isCollapsed && <span className="ml-2">New project</span>} |
| 139 | </button> |
| 140 | </div> |
| 141 | |
| 142 | {/* Chat list. A plain scroll container: the virtualized version sized |
| 143 | itself from `window.innerHeight - 300`, which was wrong at every |
| 144 | viewport but one and never updated on resize. */} |
| 145 | <SidebarContent className="mt-3"> |