22import Link from "next/link" ;
33import { usePathname } from "next/navigation" ;
44import { cn } from "./cn.js" ;
5+ import { useState } from "react" ;
6+ import { ChevronRight } from "lucide-react" ;
57
6- export function Sidebar ( { docs, onLinkClick} ) {
8+ function NavItem ( { doc, isActive, onClick} ) {
9+ return (
10+ < Link
11+ href = { `/docs/${ doc . slug } ` }
12+ className = { cn ( "block px-3 py-2 rounded-md hover:bg-gray-100" , isActive ( doc . slug ) && "bg-gray-100" ) }
13+ onClick = { onClick }
14+ >
15+ < li > { doc . title } </ li >
16+ </ Link >
17+ ) ;
18+ }
19+
20+ function NavGroup ( { group, docsMap, isActive, onClick} ) {
21+ const pathname = usePathname ( ) ;
22+ const isGroupActive = group . slug === pathname . split ( "/docs/" ) [ 1 ] || group . items . some ( ( item ) => isActive ( item . slug ) ) ;
23+ const [ isOpen , setIsOpen ] = useState ( true ) ;
24+
25+ return (
26+ < div >
27+ < div className = { cn ( isActive ( group . slug ) && "bg-gray-100" , "flex items-center rounded-md hover:bg-gray-100" ) } >
28+ { group . slug ? (
29+ < Link href = { `/docs/${ group . slug } ` } className = { cn ( "flex-1 px-3 py-2" ) } onClick = { onClick } >
30+ < span className = "font-medium" > { group . title } </ span >
31+ </ Link >
32+ ) : (
33+ < span className = "font-medium cursor-pointer px-3 py-2 flex-1" onClick = { ( ) => setIsOpen ( ! isOpen ) } >
34+ { group . title }
35+ </ span >
36+ ) }
37+ < button
38+ onClick = { ( ) => setIsOpen ( ! isOpen ) }
39+ className = { cn ( "px-2 py-2 " ) }
40+ aria-label = { isOpen ? "Collapse section" : "Expand section" }
41+ >
42+ < ChevronRight className = { cn ( "w-4 h-4 transition-transform" , isOpen && "rotate-90" ) } />
43+ </ button >
44+ </ div >
45+ { isOpen && (
46+ < ul className = "ml-4" >
47+ { group . items . map ( ( item ) => {
48+ const doc = docsMap [ item . slug ] ;
49+ if ( ! doc ) return null ;
50+ return < NavItem key = { doc . slug } doc = { doc } isActive = { isActive } onClick = { onClick } /> ;
51+ } ) }
52+ </ ul >
53+ ) }
54+ </ div >
55+ ) ;
56+ }
57+
58+ export function Sidebar ( { navStructure, docsMap, onLinkClick} ) {
759 const pathname = usePathname ( ) ;
860 const isActive = ( slug ) => pathname . startsWith ( `/docs/${ slug } ` ) ;
961 const handleLinkClick = ( ) => {
@@ -13,18 +65,23 @@ export function Sidebar({docs, onLinkClick}) {
1365 } ;
1466 return (
1567 < ul className = { cn ( "h-full" , "overflow-auto px-4 w-full" ) } >
16- { docs
17- . sort ( ( a , b ) => a . order - b . order )
18- . map ( ( doc ) => (
19- < Link
20- href = { `/docs/${ doc . slug } ` }
21- key = { doc . title }
22- className = { cn ( "block px-3 py-2 rounded-md hover:bg-gray-100" , isActive ( doc . slug ) && "bg-gray-100" ) }
23- onClick = { handleLinkClick }
24- >
25- < li > { doc . title } </ li >
26- </ Link >
27- ) ) }
68+ { navStructure . map ( ( item ) => {
69+ if ( item . type === "group" ) {
70+ return (
71+ < NavGroup
72+ key = { item . slug || item . title }
73+ group = { item }
74+ docsMap = { docsMap }
75+ isActive = { isActive }
76+ onClick = { handleLinkClick }
77+ />
78+ ) ;
79+ } else {
80+ const doc = docsMap [ item . slug ] ;
81+ if ( ! doc ) return null ;
82+ return < NavItem key = { doc . slug } doc = { doc } isActive = { isActive } onClick = { handleLinkClick } /> ;
83+ }
84+ } ) }
2885 </ ul >
2986 ) ;
3087}
0 commit comments