1
1
'use client' ;
2
+
2
3
import { Button } from '@/components/ui/button' ;
3
4
import Image from 'next/image' ;
4
5
import { memo , useCallback , useContext , useState } from 'react' ;
5
- import { SquarePen } from 'lucide-react' ;
6
6
import SidebarSkeleton from './sidebar-skeleton' ;
7
7
import UserSettings from './user-settings' ;
8
8
import { SideBarItem } from './sidebar-item' ;
@@ -22,9 +22,9 @@ import {
22
22
import { ProjectContext } from './chat/code-engine/project-context' ;
23
23
24
24
interface SidebarProps {
25
- setIsModalOpen : ( value : boolean ) => void ; // Parent setter to update collapse state
25
+ setIsModalOpen : ( value : boolean ) => void ;
26
26
isCollapsed : boolean ;
27
- setIsCollapsed : ( value : boolean ) => void ; // Parent setter to update collapse state
27
+ setIsCollapsed : ( value : boolean ) => void ;
28
28
isMobile : boolean ;
29
29
currentChatId ?: string ;
30
30
chatListUpdated : boolean ;
@@ -44,11 +44,10 @@ export function ChatSideBar({
44
44
error,
45
45
onRefetch,
46
46
} : SidebarProps ) {
47
- // Use a local state only for the currently selected chat.
48
47
const router = useRouter ( ) ;
49
48
const [ currentChatid , setCurrentChatid ] = useState ( '' ) ;
50
49
const { setCurProject, pollChatProject } = useContext ( ProjectContext ) ;
51
- // Handler for starting a new chat.
50
+
52
51
const handleNewChat = useCallback ( ( ) => {
53
52
window . history . replaceState ( { } , '' , '/' ) ;
54
53
setCurrentChatid ( '' ) ;
@@ -64,86 +63,97 @@ export function ChatSideBar({
64
63
return (
65
64
< div
66
65
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"
68
67
>
69
68
< 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` }
95
72
>
96
- < Image
97
- src = "/codefox.svg"
98
- alt = "CodeFox Logo"
99
- width = { 32 }
100
- height = { 32 }
101
- className = "flex-shrink-0 dark:invert"
102
- />
103
73
{ ! 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
+ />
107
106
) }
108
- </ Button >
107
+ </ div >
109
108
110
109
{ /* Divider Line */ }
111
110
< div className = "border-t border-dotted border-gray-300 my-2 w-full mx-auto" />
112
111
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` }
118
115
>
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
+ >
120
129
< svg
130
+ data-name = "Layer 1"
131
+ viewBox = "0 0 32 32"
132
+ preserveAspectRatio = "xMidYMid meet"
121
133
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"
127
140
>
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 >
133
147
</ svg >
134
-
135
148
{ ! 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 " >
137
150
New Project
138
151
</ span >
139
152
) }
153
+ </ Button >
154
+ </ div >
140
155
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
+ { /* 聊天列表 */ }
147
157
< SidebarContent >
148
158
< SidebarGroup >
149
159
< SidebarGroupContent >
@@ -171,12 +181,14 @@ export function ChatSideBar({
171
181
</ SidebarGroup >
172
182
</ SidebarContent >
173
183
174
- < SidebarFooter >
184
+ { /* 底部设置 */ }
185
+ < SidebarFooter
186
+ className = { `mt-auto ${ isCollapsed ? 'flex justify-center px-0' : '' } ` }
187
+ >
175
188
< UserSettings isSimple = { false } />
176
189
</ SidebarFooter >
177
190
178
191
< SidebarRail
179
- // Optional: Provide a secondary trigger if needed.
180
192
setIsSimple = { ( ) => setIsCollapsed ( ! isCollapsed ) }
181
193
isSimple = { false }
182
194
/>
0 commit comments