11'use client' ;
2+
23import { Button } from '@/components/ui/button' ;
34import Image from 'next/image' ;
45import { memo , useCallback , useContext , useState } from 'react' ;
5- import { SquarePen } from 'lucide-react' ;
66import SidebarSkeleton from './sidebar-skeleton' ;
77import UserSettings from './user-settings' ;
88import { SideBarItem } from './sidebar-item' ;
@@ -22,9 +22,9 @@ import {
2222import { ProjectContext } from './chat/code-engine/project-context' ;
2323
2424interface SidebarProps {
25- setIsModalOpen : ( value : boolean ) => void ; // Parent setter to update collapse state
25+ setIsModalOpen : ( value : boolean ) => void ;
2626 isCollapsed : boolean ;
27- setIsCollapsed : ( value : boolean ) => void ; // Parent setter to update collapse state
27+ setIsCollapsed : ( value : boolean ) => void ;
2828 isMobile : boolean ;
2929 currentChatId ?: string ;
3030 chatListUpdated : boolean ;
@@ -44,11 +44,10 @@ export function ChatSideBar({
4444 error,
4545 onRefetch,
4646} : SidebarProps ) {
47- // Use a local state only for the currently selected chat.
4847 const router = useRouter ( ) ;
4948 const [ currentChatid , setCurrentChatid ] = useState ( '' ) ;
5049 const { setCurProject, pollChatProject } = useContext ( ProjectContext ) ;
51- // Handler for starting a new chat.
50+
5251 const handleNewChat = useCallback ( ( ) => {
5352 window . history . replaceState ( { } , '' , '/' ) ;
5453 setCurrentChatid ( '' ) ;
@@ -64,86 +63,97 @@ export function ChatSideBar({
6463 return (
6564 < div
6665 data-collapsed = { isCollapsed }
67- className = "relative justify-between group lg:bg-accent/0 lg:dark:bg-card/0 flex flex-col h-full "
66+ className = "relative flex flex-col h-full justify-between group lg:bg-accent/0 lg:dark:bg-card/0"
6867 >
6968 < Sidebar collapsible = "icon" side = "left" >
70- { /* Toggle button: Clicking this will toggle the collapse state */ }
71- < SidebarTrigger
72- className = "lg:flex items-center justify-center cursor-pointer p-2 ml-3.5 mt-2"
73- onClick = { ( ) => setIsCollapsed ( ! isCollapsed ) }
74- />
75- < Button
76- onClick = { ( ) => router . push ( '/' ) }
77- variant = "ghost"
78- className = "
79- w-full
80- h-14
81- flex
82- items-center
83- justify-start
84- px-4
85- gap-2
86- text-sm
87- xl:text-lg
88- font-normal
89- rounded-md
90- hover:bg-yellow-50
91- transition-all
92- duration-200
93- ease-in-out
94- "
69+ { /* Header Row: Fox Logo (clickable) on the left, SidebarTrigger on the right */ }
70+ < div
71+ className = { `flex items-center ${ isCollapsed ? 'justify-center w-full px-0' : 'justify-between px-3' } pt-3` }
9572 >
96- < Image
97- src = "/codefox.svg"
98- alt = "CodeFox Logo"
99- width = { 32 }
100- height = { 32 }
101- className = "flex-shrink-0 dark:invert"
102- />
10373 { ! isCollapsed && (
104- < span className = "text-primary-500 font-semibold text-lg" >
105- CodeFox
106- </ span >
74+ < div className = "flex flex-1 items-center justify-between" >
75+ < Button
76+ onClick = { ( ) => router . push ( '/' ) }
77+ variant = "ghost"
78+ className = "inline-flex items-center gap-2 pl-0
79+ rounded-md ease-in-out"
80+ >
81+ < Image
82+ src = "/codefox.svg"
83+ alt = "CodeFox Logo"
84+ width = { 40 }
85+ height = { 40 }
86+ className = "dark:invert"
87+ />
88+ < span className = "text-primary-500 font-semibold text-base" >
89+ CodeFox
90+ </ span >
91+ </ Button >
92+
93+ { /* SidebarTrigger 保证在 CodeFox 按钮的中间 */ }
94+ < SidebarTrigger
95+ className = "flex items-center justify-center w-12 h-12 "
96+ onClick = { ( ) => setIsCollapsed ( ! isCollapsed ) }
97+ />
98+ </ div >
99+ ) }
100+
101+ { isCollapsed && (
102+ < SidebarTrigger
103+ className = "flex items-center justify-center w-full p-2 mt"
104+ onClick = { ( ) => setIsCollapsed ( ! isCollapsed ) }
105+ />
107106 ) }
108- </ Button >
107+ </ div >
109108
110109 { /* Divider Line */ }
111110 < div className = "border-t border-dotted border-gray-300 my-2 w-full mx-auto" />
112111
113- < Button
114- onClick = { ( ) => setIsModalOpen ( true ) }
115- size = "setting"
116- variant = "ghost"
117- className = "flex items-center justify-start w-[85%] h-14 text-xs xl:text-sm font-normal gap-2 pl-4 hover:bg-yellow-50 rounded-md transition-all duration-200 ease-in-out"
112+ { /* New Project 按钮 - 依然占据整行 */ }
113+ < div
114+ className = { `flex ${ isCollapsed ? 'justify-center items-center w-full px-0' : '' } w-full mt-4` }
118115 >
119- < div className = "flex items-center gap-2" >
116+ < Button
117+ onClick = { ( ) => {
118+ if ( isCollapsed ) {
119+ router . push ( '/' ) ;
120+ } else {
121+ setIsModalOpen ( true ) ;
122+ }
123+ } }
124+ variant = "ghost"
125+ className = { `h-7 w-7 flex items-center justify-center rounded-md ease-in-out ${
126+ ! isCollapsed && 'w-full gap-2 pl-4 justify-start'
127+ } `}
128+ >
120129 < svg
130+ data-name = "Layer 1"
131+ viewBox = "0 0 32 32"
132+ preserveAspectRatio = "xMidYMid meet"
121133 xmlns = "http://www.w3.org/2000/svg"
122- fill = "none"
123- viewBox = "0 0 24 24"
124- strokeWidth = "1.5"
125- stroke = "currentColor"
126- className = "w-5 h-5 text-yellow-500"
134+ className = {
135+ isCollapsed
136+ ? 'w-8 h-8 min-w-[32px] min-h-[32px] ml-[-5px] mt-[-10px]'
137+ : 'w-10 h-10 min-w-[32px] min-h-[32px] mr-1'
138+ }
139+ strokeWidth = "0.1"
127140 >
128- < path
129- strokeLinecap = "round"
130- strokeLinejoin = "round"
131- d = "M12 18v-5.25m0 0a6.01 6.01 0 0 0 1.5-.189m-1.5.189a6.01 6.01 0 0 1-1.5-.189m3.75 7.478a12.06 12.06 0 0 1-4.5 0m3.75 2.383a14.406 14.406 0 0 1-3 0M14.25 18v-.192c0-.983.658-1.823 1.508-2.316a7.5 7.5 0 1 0-7.517 0c.85.493 1.509 1.333 1.509 2.316V18"
132- />
141+ < g transform = "scale(-1,1) translate(-32,0)" >
142+ < path
143+ d = "M5,8A1,1,0,0,0,7,8V7H8A1,1,0,0,0,8,5H7V4A1,1,0,0,0,5,4V5H4A1,1,0,0,0,4,7H5ZM18,5H12a1,1,0,0,0,0,2h6a1,1,0,0,1,1,1v9.72l-1.57-1.45a1,1,0,0,0-.68-.27H8a1,1,0,0,1-1-1V12a1,1,0,0,0-2,0v3a3,3,0,0,0,3,3h8.36l3,2.73A1,1,0,0,0,20,21a1.1,1.1,0,0,0,.4-.08A1,1,0,0,0,21,20V8A3,3,0,0,0,18,5Z"
144+ fill = "#808080"
145+ />
146+ </ g >
133147 </ svg >
134-
135148 { ! isCollapsed && (
136- < span className = "text-primary -600 hover:text-primary -800 transition-colors text-sm" >
149+ < span className = "text-gray -600 hover:text-gray -800 font-semibold text-sm relative -top-0.5 " >
137150 New Project
138151 </ span >
139152 ) }
153+ </ Button >
154+ </ div >
140155
141- { ! isCollapsed && (
142- < SquarePen className = "text-primary-400 hover:text-primary-600 transition-colors w-4 h-4" />
143- ) }
144- </ div >
145- </ Button >
146-
156+ { /* 聊天列表 */ }
147157 < SidebarContent >
148158 < SidebarGroup >
149159 < SidebarGroupContent >
@@ -171,12 +181,14 @@ export function ChatSideBar({
171181 </ SidebarGroup >
172182 </ SidebarContent >
173183
174- < SidebarFooter >
184+ { /* 底部设置 */ }
185+ < SidebarFooter
186+ className = { `mt-auto ${ isCollapsed ? 'flex justify-center px-0' : '' } ` }
187+ >
175188 < UserSettings isSimple = { false } />
176189 </ SidebarFooter >
177190
178191 < SidebarRail
179- // Optional: Provide a secondary trigger if needed.
180192 setIsSimple = { ( ) => setIsCollapsed ( ! isCollapsed ) }
181193 isSimple = { false }
182194 />
0 commit comments