33import React , { useState } from "react" ;
44import Link from "next/link" ;
55import SidebarItem from "../sidebar/SidebarItem" ;
6- import { usePathname , useRouter } from "next/navigation" ;
6+ import { useRouter } from "next/navigation" ;
77import { IconWrapper } from "../ui/IconWrapper" ;
8+ import { motion , AnimatePresence } from "framer-motion" ;
89import {
910 XMarkIcon ,
1011 HomeIcon ,
1112 FolderIcon ,
1213 ArrowRightOnRectangleIcon ,
13- ChevronDoubleLeftIcon ,
14- ChevronDoubleRightIcon ,
1514 SparklesIcon ,
1615 StarIcon ,
1716 DocumentTextIcon ,
@@ -22,6 +21,7 @@ import { signOut, useSession } from "next-auth/react";
2221import { ProfilePic } from "./ProfilePic" ;
2322import { useSubscription } from "@/hooks/useSubscription" ;
2423import { OpensoxProBadge } from "../sheet/OpensoxProBadge" ;
24+ import { ChevronLeftIcon , ChevronRightIcon } from 'lucide-react' ;
2525
2626const SIDEBAR_ROUTES = [
2727 {
@@ -41,15 +41,8 @@ const SIDEBAR_ROUTES = [
4141 } ,
4242] ;
4343
44- const getSidebarLinkClassName = ( currentPath : string , routePath : string ) => {
45- const isActive = currentPath === routePath ;
46- return `${ isActive ? "text-ox-purple" : "text-ox-white" } ` ;
47- } ;
48-
49- export default function Sidebar ( ) {
50- const { showSidebar, setShowSidebar, isCollapsed, toggleCollapsed } =
51- useShowSidebar ( ) ;
52- const pathname = usePathname ( ) ;
44+ export default function Sidebar ( { overlay = false } : { overlay ?: boolean } ) {
45+ const { setShowSidebar, isCollapsed, toggleCollapsed } = useShowSidebar ( ) ;
5346 const router = useRouter ( ) ;
5447 const { isPaidUser } = useSubscription ( ) ;
5548
@@ -64,17 +57,22 @@ export default function Sidebar() {
6457 router . push ( "/pricing" ) ;
6558 }
6659 } ;
60+ const desktopWidth = isCollapsed ? 80 : 288 ;
61+ const mobileWidth = desktopWidth ;
6762
6863 return (
69- < div
70- className = { `h-screen ${
71- isCollapsed ? "w-20" : "w-72"
72- } flex flex-col bg-ox-sidebar border-r border-ox-header z-50 transition-all duration-300 ease-out ${
73- showSidebar ? "fixed xl:relative left-0 top-0 bottom-0" : ""
64+ < motion . div
65+ className = { `h-screen flex flex-col bg-ox-sidebar border-r border-ox-header z-50 ${
66+ overlay ? "fixed left-0 top-0 bottom-0 xl:hidden" : ""
7467 } `}
68+ initial = { overlay ? { x : - 400 , width : mobileWidth } : { width : desktopWidth } }
69+ animate = { overlay ? { x : 0 , width : mobileWidth } : { width : desktopWidth } }
70+ exit = { overlay ? { x : - 400 , width : mobileWidth } : undefined }
71+ transition = { { type : "spring" , stiffness : 260 , damping : 30 } }
72+ style = { { width : overlay ? mobileWidth : desktopWidth } }
7573 >
7674 { /* Mobile header */ }
77- < div className = "flex justify-between px-4 py- 4 border-b border-ox-header xl:hidden bg-ox-sidebar " >
75+ < div className = "flex justify-between items-center h-16 px- 4 border-b border-ox-header xl:hidden bg-ox-sideba " >
7876 < div className = "flex items-center" >
7977 < Link
8078 href = "/"
@@ -103,18 +101,17 @@ export default function Sidebar() {
103101 className = { isCollapsed ? "w-full flex justify-center" : "" }
104102 >
105103 { isCollapsed ? (
106- < ChevronDoubleRightIcon className = "size-5 text-ox-purple" />
104+ < ChevronRightIcon className = "size-5 text-ox-purple" />
107105 ) : (
108- < ChevronDoubleLeftIcon className = "size-5 text-ox-purple" />
106+ < ChevronLeftIcon className = "size-5 text-ox-purple" />
109107 ) }
110108 </ IconWrapper >
111109 </ div >
112110
113- < div className = "sidebar-body flex-grow flex-col overflow-y-auto px-3 py-4 space-y-1 " >
111+ < div className = "sidebar-body flex-grow flex-col overflow-y-auto px-3 py-4" >
114112 { SIDEBAR_ROUTES . map ( ( route ) => {
115- const activeClass = getSidebarLinkClassName ( pathname , route . path ) ;
116113 return (
117- < Link href = { route . path } className = { activeClass } key = { route . path } >
114+ < Link href = { route . path } key = { route . path } >
118115 < SidebarItem
119116 itemName = { route . label }
120117 icon = { route . icon }
@@ -131,14 +128,14 @@ export default function Sidebar() {
131128 />
132129 { ! isCollapsed && ! isPaidUser ? (
133130 < div
134- className = "w-full h-[44px] flex items-center rounded-md cursor-pointer transition-colors px-2 gap-3 pl-3 hover:bg-[#121214] "
131+ className = "w-full h-[44px] flex items-center rounded-md cursor-pointer transition-colors px-2 gap-3 pl-3 hover:bg-[#292929] group "
135132 onClick = { proClickHandler }
136133 >
137- < span className = "shrink-0 text-[#eaeaea]" >
134+ < span className = "shrink-0 text-[#eaeaea] group-hover:text-white transition-colors " >
138135 < StarIcon className = "size-5" />
139136 </ span >
140137 < div className = "flex items-center gap-1" >
141- < h1 className = "text-xs font-medium text-[#c8c8c8] group-hover:text-ox-purple " >
138+ < h1 className = "text-xs font-medium text-[#c8c8c8] group-hover:text-white transition-colors " >
142139 Opensox Pro
143140 </ h1 >
144141 < OpensoxProBadge className = "px-1.5 py-0.5 scale-75" />
@@ -156,7 +153,7 @@ export default function Sidebar() {
156153
157154 { /* Bottom profile */ }
158155 < ProfileMenu isCollapsed = { isCollapsed } />
159- </ div >
156+ </ motion . div >
160157 ) ;
161158}
162159
@@ -189,7 +186,7 @@ function ProfileMenu({ isCollapsed }: { isCollapsed: boolean }) {
189186 return (
190187 < div className = "px-3 py-4 border-t border-ox-header bg-ox-sidebar relative profile-menu-container" >
191188 < div
192- className = { `group flex items-center rounded-md bg-ox-content border border-ox-header p-2 transition-all duration-300 ease-out cursor-pointer ${
189+ className = { `group flex items-center rounded-md bg-ox-profile-card border border-ox-header p-2 transition-all duration-300 ease-out cursor-pointer ${
193190 isCollapsed ? "justify-center" : "gap-3"
194191 } `}
195192 onClick = { ( ) => setOpen ( ( s ) => ! s ) }
@@ -203,53 +200,62 @@ function ProfileMenu({ isCollapsed }: { isCollapsed: boolean }) {
203200 </ span >
204201 < span className = "text-[10px] text-zinc-400" > { userEmail } </ span >
205202 </ div >
206- < ChevronDoubleLeftIcon
203+ < ChevronLeftIcon
207204 className = { `size-4 text-zinc-400 transition-transform ${ open ? "rotate-90" : "-rotate-90" } ` }
208205 />
209206 </ div >
210207 ) }
211208 </ div >
212209 { /* Profile Card Dropdown */ }
213- { ! isCollapsed && open && (
214- < div className = "absolute bottom-full left-3 right-3 mb-2 bg-ox-content border border-ox-header rounded-lg shadow-xl overflow-hidden z-50" >
215- { /* User Info Section */ }
216- < div className = "p-3 border-b border-ox-header" >
217- < div className = "flex items-center gap-3" >
218- < ProfilePic imageUrl = { userImage } />
219- < div className = "flex flex-col" >
220- < span className = "text-sm text-white font-semibold" >
221- { fullName }
222- </ span >
223- < span className = "text-xs text-zinc-400" > { userEmail } </ span >
210+ < AnimatePresence >
211+ { ! isCollapsed && open && (
212+ < motion . div
213+ key = "profile-dropdown"
214+ initial = { { opacity : 0 , y : 8 } }
215+ animate = { { opacity : 1 , y : 0 } }
216+ exit = { { opacity : 0 , y : 8 } }
217+ transition = { { duration : 0.18 } }
218+ className = "absolute bottom-full left-3 right-3 mb-2 bg-ox-profile-card border border-ox-header rounded-lg shadow-xl overflow-hidden z-50"
219+ >
220+ { /* User Info Section */ }
221+ < div className = "p-3 border-b border-ox-header" >
222+ < div className = "flex items-center gap-3" >
223+ < ProfilePic imageUrl = { userImage } />
224+ < div className = "flex flex-col" >
225+ < span className = "text-sm text-white font-semibold" >
226+ { fullName }
227+ </ span >
228+ < span className = "text-xs text-zinc-400" > { userEmail } </ span >
229+ </ div >
224230 </ div >
225231 </ div >
226- </ div >
227232
228- { /* Menu Items */ }
229- < div className = "py-1" >
230- < button
231- onClick = { ( ) => {
232- router . push ( "/dashboard/account" ) ;
233- setOpen ( false ) ;
234- } }
235- className = "w-full flex items-center gap-3 px-3 py-2 text-sm text-[#eaeaea] hover:bg-ox-sidebar transition-colors"
236- >
237- < Cog6ToothIcon className = "size-4" />
238- < span > Account Settings</ span >
239- </ button >
240- < button
241- onClick = { ( ) => {
242- signOut ( { callbackUrl : "/" } ) ;
243- setOpen ( false ) ;
244- } }
245- className = "w-full flex items-center gap-3 px-3 py-2 text-sm text-[#eaeaea] hover:bg-ox-sidebar transition-colors"
246- >
247- < ArrowRightOnRectangleIcon className = "size-4" />
248- < span > Logout</ span >
249- </ button >
250- </ div >
251- </ div >
252- ) }
233+ { /* Menu Items */ }
234+ < div className = "py-1" >
235+ < button
236+ onClick = { ( ) => {
237+ router . push ( "/dashboard/account" ) ;
238+ setOpen ( false ) ;
239+ } }
240+ className = "w-full flex items-center gap-3 px-3 py-2 text-sm text-[#eaeaea] hover:bg-ox-sidebar transition-colors"
241+ >
242+ < Cog6ToothIcon className = "size-4" />
243+ < span > Account Settings</ span >
244+ </ button >
245+ < button
246+ onClick = { ( ) => {
247+ signOut ( { callbackUrl : "/" } ) ;
248+ setOpen ( false ) ;
249+ } }
250+ className = "w-full flex items-center gap-3 px-3 py-2 text-sm text-[#eaeaea] hover:bg-ox-sidebar transition-colors"
251+ >
252+ < ArrowRightOnRectangleIcon className = "size-4" />
253+ < span > Logout</ span >
254+ </ button >
255+ </ div >
256+ </ motion . div >
257+ ) }
258+ </ AnimatePresence >
253259 </ div >
254260 ) ;
255261}
0 commit comments