@@ -4,31 +4,136 @@ import {
44 SidebarMenu ,
55 SidebarMenuButton ,
66 SidebarMenuItem ,
7+ useSidebar ,
78} from '@/components/ui/sidebar' ;
89import { resolveUrl } from '@/lib/utils' ;
910import { type NavItem } from '@/types' ;
1011import { Link , usePage } from '@inertiajs/react' ;
12+ import { ChevronDownIcon } from 'lucide-react' ;
13+ import { useEffect , useId , useRef , useState } from 'react' ;
1114
12- export function NavMain ( { items = [ ] } : { items : NavItem [ ] } ) {
15+ export function NavMain ( { lable = "Platform" , items = [ ] , openSubmenu, setOpenSubmenu } : {
16+ lable ?: string ;
17+ items : NavItem [ ] ;
18+ openSubmenu : { id : string ; index : number } | null ;
19+ setOpenSubmenu : React . Dispatch < React . SetStateAction < { id : string ; index : number } | null > > ;
20+ } ) {
1321 const page = usePage ( ) ;
22+
23+ const id = useRef < string > ( useId ( ) ) ;
24+
25+ const { isMobile, state, openMobile } = useSidebar ( ) ;
26+
27+ const subMenuRefs = useRef < Record < string , HTMLDivElement | null > > ( { } ) ;
28+
29+ const [ subMenuHeight , setSubMenuHeight ] = useState < Record < string , number > > (
30+ { }
31+ ) ;
32+
33+ const handleSubmenuToggle = ( index : number , id : string ) => {
34+ setOpenSubmenu ( ( prevOpenSubmenu ) => {
35+ if (
36+ prevOpenSubmenu &&
37+ prevOpenSubmenu . id === id &&
38+ prevOpenSubmenu . index === index
39+ ) {
40+ return null ;
41+ }
42+ return { id, index } ;
43+ } ) ;
44+ }
45+
46+ useEffect ( ( ) => {
47+ if ( openSubmenu !== null ) {
48+ const key = `${ openSubmenu . id } -${ openSubmenu . index } ` ;
49+ if ( subMenuRefs . current [ key ] ) {
50+ setSubMenuHeight ( ( prevHeights ) => ( {
51+ ...prevHeights ,
52+ [ key ] : subMenuRefs . current [ key ] ?. scrollHeight || 0 ,
53+ } ) ) ;
54+ }
55+ }
56+ } , [ openSubmenu ] ) ;
57+
58+ const activeGroup = ( navItem : NavItem ) => {
59+ let foundItem = items . find ( ( item ) => {
60+ if ( navItem . href && page . url . startsWith ( resolveUrl ( navItem . href ) ) ) {
61+ return item ;
62+ }
63+ } ) ;
64+
65+ if ( foundItem ) return true ;
66+ else return false ;
67+ }
68+
1469 return (
1570 < SidebarGroup className = "px-2 py-0" >
16- < SidebarGroupLabel > Platform </ SidebarGroupLabel >
71+ < SidebarGroupLabel > { lable } </ SidebarGroupLabel >
1772 < SidebarMenu >
18- { items . map ( ( item ) => (
73+ { items . map ( ( item , index ) => (
1974 < SidebarMenuItem key = { item . title } >
20- < SidebarMenuButton
21- asChild
22- isActive = { page . url . startsWith (
23- resolveUrl ( item . href ) ,
24- ) }
25- tooltip = { { children : item . title } }
26- >
27- < Link href = { item . href } prefetch >
75+ { item . subItems ? ( < >
76+ < SidebarMenuButton
77+ isActive = { activeGroup ( item ) }
78+ className = "cursor-pointer"
79+ tooltip = { { children : item . title } }
80+ onClick = { ( ) => handleSubmenuToggle ( index , id . current ) }
81+ >
2882 { item . icon && < item . icon /> }
2983 < span > { item . title } </ span >
30- </ Link >
31- </ SidebarMenuButton >
84+ < ChevronDownIcon
85+ className = { `ms-auto h-4 w-4 shrink-0 opacity-50 transition-all duration-300 ${ openSubmenu ?. id === id . current && openSubmenu ?. index === index ? "rotate-180" : "" } ` }
86+ />
87+ </ SidebarMenuButton >
88+
89+ { ( state === "expanded" || ( isMobile && openMobile ) ) && (
90+ < div
91+ ref = { ( el ) => {
92+ subMenuRefs . current [ `${ id . current } -${ index } ` ] = el ;
93+ } }
94+ className = "overflow-hidden transition-all duration-300"
95+ style = { {
96+ height :
97+ openSubmenu ?. id === id . current && openSubmenu ?. index === index
98+ ? `${ subMenuHeight [ `${ id . current } -${ index } ` ] } px`
99+ : "0px" ,
100+ } }
101+ >
102+ < SidebarMenu className = "mt-2 ms-6 w-auto" >
103+ { item . subItems . map ( ( subItem ) => (
104+ < SidebarMenuItem key = { subItem . title } >
105+ < SidebarMenuButton
106+
107+ asChild
108+ isActive = { subItem . href ? page . url . startsWith (
109+ resolveUrl ( subItem . href ) ,
110+ ) : false }
111+ tooltip = { { children : subItem . title } }
112+ >
113+ < Link href = { subItem . href ! } prefetch >
114+ { subItem . icon && < subItem . icon /> }
115+ < span > { subItem . title } </ span >
116+ </ Link >
117+ </ SidebarMenuButton >
118+ </ SidebarMenuItem >
119+ ) ) }
120+ </ SidebarMenu >
121+ </ div >
122+ ) }
123+ </ > ) : (
124+ < SidebarMenuButton
125+ asChild
126+ isActive = { item . href ? page . url . startsWith (
127+ resolveUrl ( item . href ) ,
128+ ) : false }
129+ tooltip = { { children : item . title } }
130+ >
131+ < Link href = { item . href } prefetch >
132+ { item . icon && < item . icon /> }
133+ < span > { item . title } </ span >
134+ </ Link >
135+ </ SidebarMenuButton >
136+ ) }
32137 </ SidebarMenuItem >
33138 ) ) }
34139 </ SidebarMenu >
0 commit comments