@@ -32,6 +32,105 @@ const navItems = [
3232 { href : "/settings" , label : "Настройки" , icon : Settings } ,
3333]
3434
35+ interface SidebarContentProps {
36+ sidebarOpen : boolean
37+ setSidebarOpen : ( open : boolean ) => void
38+ location : ReturnType < typeof useLocation >
39+ user : ReturnType < typeof useAuth > [ "user" ]
40+ logout : ReturnType < typeof useLogout >
41+ toggleTheme : ( ) => void
42+ resolvedTheme : string
43+ }
44+
45+ const SidebarContent = ( {
46+ setSidebarOpen,
47+ location,
48+ user,
49+ logout,
50+ toggleTheme,
51+ resolvedTheme,
52+ } : SidebarContentProps ) => (
53+ < >
54+ < div className = "h-16 border-b flex items-center justify-between px-6" >
55+ < div className = "flex items-center gap-3" >
56+ < div className = "w-8 h-8 bg-primary/10 rounded-lg flex items-center justify-center" >
57+ < span className = "text-primary font-bold" > A</ span >
58+ </ div >
59+ < h1 className = "text-xl font-bold" > Admin Panel</ h1 >
60+ </ div >
61+ < Button
62+ variant = "ghost"
63+ size = "icon"
64+ className = "lg:hidden"
65+ onClick = { ( ) => setSidebarOpen ( false ) }
66+ >
67+ < X className = "h-5 w-5" />
68+ </ Button >
69+ </ div >
70+
71+ < nav className = "flex-1 p-4 space-y-2" >
72+ { navItems . map ( ( item ) => {
73+ const isActive = location . pathname === item . href ||
74+ location . pathname . startsWith ( item . href + "/" )
75+ const Icon = item . icon
76+
77+ return (
78+ < Link key = { item . href } to = { item . href } onClick = { ( ) => setSidebarOpen ( false ) } >
79+ < Button
80+ variant = { isActive ? "secondary" : "ghost" }
81+ className = { cn (
82+ "w-full justify-start" ,
83+ isActive && "bg-primary/10 text-primary hover:bg-primary/20"
84+ ) }
85+ >
86+ < Icon className = "mr-2 h-4 w-4" />
87+ { item . label }
88+ </ Button >
89+ </ Link >
90+ )
91+ } ) }
92+ </ nav >
93+
94+ < div className = "p-4 border-t space-y-3" >
95+ { /* Theme Toggle */ }
96+ < Button
97+ variant = "outline"
98+ className = "w-full justify-start"
99+ onClick = { toggleTheme }
100+ >
101+ { resolvedTheme === 'dark' ? (
102+ < >
103+ < Sun className = "mr-2 h-4 w-4" />
104+ Светлая тема
105+ </ >
106+ ) : (
107+ < >
108+ < Moon className = "mr-2 h-4 w-4" />
109+ Тёмная тема
110+ </ >
111+ ) }
112+ </ Button >
113+
114+ { /* User Info */ }
115+ < div className = "text-sm" >
116+ < div className = "font-medium" > { user ?. first_name || user ?. username || "Admin" } </ div >
117+ < div className = "text-xs text-muted-foreground" > Администратор</ div >
118+ </ div >
119+
120+ { /* Logout */ }
121+ < Button
122+ variant = "outline"
123+ className = "w-full justify-start text-destructive hover:text-destructive"
124+ onClick = { ( ) => logout . mutate ( ) }
125+ disabled = { logout . isPending }
126+ >
127+ < LogOut className = "mr-2 h-4 w-4" />
128+ Выйти
129+ </ Button >
130+ </ div >
131+ </ >
132+ )
133+
35134export const MainLayout = ( { children } : MainLayoutProps ) => {
36135 const { user } = useAuth ( )
37136 const logout = useLogout ( )
@@ -43,93 +142,21 @@ export const MainLayout = ({ children }: MainLayoutProps) => {
43142 setTheme ( resolvedTheme === 'dark' ? 'light' : 'dark' )
44143 }
45144
46- const SidebarContent = ( ) => (
47- < >
48- < div className = "h-16 border-b flex items-center justify-between px-6" >
49- < div className = "flex items-center gap-3" >
50- < div className = "w-8 h-8 bg-primary/10 rounded-lg flex items-center justify-center" >
51- < span className = "text-primary font-bold" > A</ span >
52- </ div >
53- < h1 className = "text-xl font-bold" > Admin Panel</ h1 >
54- </ div >
55- < Button
56- variant = "ghost"
57- size = "icon"
58- className = "lg:hidden"
59- onClick = { ( ) => setSidebarOpen ( false ) }
60- >
61- < X className = "h-5 w-5" />
62- </ Button >
63- </ div >
64-
65- < nav className = "flex-1 p-4 space-y-2" >
66- { navItems . map ( ( item ) => {
67- const isActive = location . pathname === item . href ||
68- location . pathname . startsWith ( item . href + "/" )
69- const Icon = item . icon
70-
71- return (
72- < Link key = { item . href } to = { item . href } onClick = { ( ) => setSidebarOpen ( false ) } >
73- < Button
74- variant = { isActive ? "secondary" : "ghost" }
75- className = { cn (
76- "w-full justify-start" ,
77- isActive && "bg-primary/10 text-primary hover:bg-primary/20"
78- ) }
79- >
80- < Icon className = "mr-2 h-4 w-4" />
81- { item . label }
82- </ Button >
83- </ Link >
84- )
85- } ) }
86- </ nav >
87-
88- < div className = "p-4 border-t space-y-3" >
89- { /* Theme Toggle */ }
90- < Button
91- variant = "outline"
92- className = "w-full justify-start"
93- onClick = { toggleTheme }
94- >
95- { resolvedTheme === 'dark' ? (
96- < >
97- < Sun className = "mr-2 h-4 w-4" />
98- Светлая тема
99- </ >
100- ) : (
101- < >
102- < Moon className = "mr-2 h-4 w-4" />
103- Тёмная тема
104- </ >
105- ) }
106- </ Button >
107-
108- { /* User Info */ }
109- < div className = "text-sm" >
110- < div className = "font-medium" > { user ?. first_name || user ?. username || "Admin" } </ div >
111- < div className = "text-xs text-muted-foreground" > Администратор</ div >
112- </ div >
113-
114- { /* Logout */ }
115- < Button
116- variant = "outline"
117- className = "w-full justify-start text-destructive hover:text-destructive"
118- onClick = { ( ) => logout . mutate ( ) }
119- disabled = { logout . isPending }
120- >
121- < LogOut className = "mr-2 h-4 w-4" />
122- Выйти
123- </ Button >
124- </ div >
125- </ >
126- )
145+ const sidebarProps : SidebarContentProps = {
146+ sidebarOpen,
147+ setSidebarOpen,
148+ location,
149+ user,
150+ logout,
151+ toggleTheme,
152+ resolvedTheme,
153+ }
127154
128155 return (
129156 < div className = "min-h-screen bg-background flex" >
130157 { /* Desktop Sidebar */ }
131158 < aside className = "hidden lg:flex w-64 border-r bg-card flex-col" >
132- < SidebarContent />
159+ < SidebarContent { ... sidebarProps } />
133160 </ aside >
134161
135162 { /* Mobile Sidebar Overlay */ }
@@ -150,7 +177,7 @@ export const MainLayout = ({ children }: MainLayoutProps) => {
150177 transition = { { type : "spring" , damping : 25 , stiffness : 200 } }
151178 className = "fixed left-0 top-0 bottom-0 w-64 border-r bg-card flex flex-col z-50 lg:hidden"
152179 >
153- < SidebarContent />
180+ < SidebarContent { ... sidebarProps } />
154181 </ motion . aside >
155182 </ >
156183 ) }
0 commit comments