@@ -83,10 +83,19 @@ export function Sidebar({
8383 }
8484 } ;
8585
86+ // listen for ESC key and close the sidebar
87+ const handleEscape = ( event : KeyboardEvent ) => {
88+ if ( event . key === 'Escape' ) {
89+ closeSidebar ( ) ;
90+ }
91+ } ;
92+
8693 document . addEventListener ( 'mousedown' , handleClickOutside ) ;
94+ document . addEventListener ( 'keydown' , handleEscape ) ;
8795
8896 return ( ) => {
8997 document . removeEventListener ( 'mousedown' , handleClickOutside ) ;
98+ document . removeEventListener ( 'keydown' , handleEscape ) ;
9099 } ;
91100 } , [ sidebarRef ] ) ;
92101
@@ -129,6 +138,30 @@ export function Sidebar({
129138 [ courseId , findPathToContent , fullCourseContent ] ,
130139 ) ;
131140
141+ const activeItemRef = useRef < HTMLDivElement | HTMLAnchorElement | null > ( null ) ;
142+
143+ useEffect ( ( ) => {
144+ if ( sidebarOpen && activeItemRef . current ) {
145+ activeItemRef . current . scrollIntoView ( {
146+ behavior : 'smooth' ,
147+ block : 'center' ,
148+ } ) ;
149+ // focus on the active item
150+ if ( activeItemRef . current instanceof HTMLAnchorElement ) {
151+ activeItemRef . current . focus ( ) ;
152+ } else if ( activeItemRef . current instanceof HTMLDivElement ) {
153+ // check for the first focusable element and focus on it
154+ const firstFocusableElement =
155+ activeItemRef . current . querySelector ( 'button, a' ) ;
156+ if ( firstFocusableElement ) {
157+ (
158+ firstFocusableElement as HTMLButtonElement | HTMLAnchorElement
159+ ) . focus ( ) ;
160+ }
161+ }
162+ }
163+ } , [ sidebarOpen ] ) ;
164+
132165 const renderContent = useCallback (
133166 ( contents : FullCourseContent [ ] ) => {
134167 return contents . map ( ( content ) => {
@@ -140,6 +173,11 @@ export function Sidebar({
140173 key = { content . id }
141174 value = { `item-${ content . id } ` }
142175 className = { `rounded-md border-none ${ isActiveContent ? 'bg-primary/5' : '' } ` }
176+ ref = {
177+ isActiveContent
178+ ? ( activeItemRef as React . RefObject < HTMLDivElement > )
179+ : null
180+ }
143181 >
144182 < AccordionTrigger className = "rounded-md px-4 text-lg font-medium capitalize" >
145183 { content . title }
@@ -156,6 +194,11 @@ export function Sidebar({
156194 key = { content . id }
157195 href = { navigateToContent ( content . id ) || '#' }
158196 className = { `flex w-full cursor-pointer items-center rounded-md p-4 tracking-tight hover:bg-primary/10 ${ isActiveContent ? 'bg-primary/10' : '' } ` }
197+ ref = {
198+ isActiveContent
199+ ? ( activeItemRef as React . RefObject < HTMLAnchorElement > )
200+ : null
201+ }
159202 >
160203 < div className = "flex w-full items-center justify-between gap-2" >
161204 < div className = "flex items-center gap-2" >
@@ -186,10 +229,7 @@ export function Sidebar({
186229 ) ;
187230
188231 return (
189-
190- < div className = "sticky top-[55px] z-20 bg-background py-2" >
191-
192-
232+ < div className = "sticky top-[72px] z-20 bg-background py-2" >
193233 < Button
194234 ref = { buttonRef }
195235 onClick = { ( ) => setSidebarOpen ( ( s ) => ! s ) }
@@ -209,11 +249,9 @@ export function Sidebar({
209249 variants = { sidebarVariants }
210250 className = "fixed right-0 top-0 z-[99999] flex h-screen w-full flex-col gap-4 overflow-y-auto rounded-r-lg border-l border-primary/10 bg-neutral-50 dark:bg-neutral-900 md:max-w-[30vw]"
211251 >
212-
213252 < div className = "sticky top-0 z-10 flex items-center justify-between border-b border-primary/10 bg-neutral-50 p-5 dark:bg-neutral-900" >
214253 { ' ' }
215254 < h4 className = "text-xl font-bold tracking-tighter text-primary lg:text-2xl" >
216-
217255 Course Content
218256 </ h4 >
219257 < Button
@@ -224,7 +262,11 @@ export function Sidebar({
224262 < X className = "size-5" />
225263 </ Button >
226264 </ div >
227- < Accordion type = "multiple" className = "w-full px-4 pb-20 capitalize" >
265+ < Accordion
266+ type = "multiple"
267+ defaultValue = { currentActiveContentIds . map ( ( num ) => `item-${ num } ` ) }
268+ className = "w-full px-4 capitalize"
269+ >
228270 { memoizedContent }
229271 </ Accordion >
230272 </ motion . div >
0 commit comments