22
33import * as React from "react" ;
44import { useStore } from "@tanstack/react-store" ;
5- import { ChevronDownIcon , PanelLeftIcon } from "lucide-react" ;
5+ import { PanelLeftIcon } from "lucide-react" ;
66import { cn } from "@/lib/utils" ;
77import { Button } from "@/components/ui/button" ;
88import {
@@ -24,7 +24,6 @@ import {
2424 PopoverTrigger ,
2525} from "@/components/ui/popover" ;
2626import { sidebarStore , sidebarActions } from "./sidebar-store" ;
27- import { Skeleton } from "@/components/ui/skeleton" ;
2827import { IconChevronRight } from "@tabler/icons-react" ;
2928
3029const SIDEBAR_WIDTH = "16rem" ;
@@ -103,29 +102,53 @@ export function Sidebar({
103102 // Register sidebar on mount
104103 React . useEffect ( ( ) => {
105104 if ( hasRegistered . current ) return ;
106-
105+
106+ const normalizedShortcut =
107+ keyboardShortcut && keyboardShortcut . length === 1
108+ ? `mod+${ keyboardShortcut } `
109+ : keyboardShortcut ;
110+
107111 const existing = sidebarStore . state . sidebars [ id ] ;
108112 if ( ! existing ) {
109113 sidebarActions . registerSidebar ( id , {
110114 open : defaultOpen ,
111115 variant,
112116 side,
113117 openMobile : false ,
114- keyboardShortcut,
118+ keyboardShortcut : normalizedShortcut ,
115119 } ) ;
116- } else if ( keyboardShortcut !== existing . keyboardShortcut ) {
120+ } else if ( normalizedShortcut !== existing . keyboardShortcut ) {
117121 // Update keyboard shortcut if changed
118- sidebarActions . setKeyboardShortcut ( id , keyboardShortcut ) ;
122+ sidebarActions . setKeyboardShortcut ( id , normalizedShortcut ) ;
119123 }
120-
124+
121125 hasRegistered . current = true ;
122-
126+
123127 return ( ) => {
124128 hasRegistered . current = false ;
125129 sidebarActions . unregisterSidebar ( id ) ;
126130 } ;
127131 } , [ id , defaultOpen , variant , side , keyboardShortcut ] ) ;
128132
133+ // Keyboard shortcut handler
134+ React . useEffect ( ( ) => {
135+ if ( ! keyboardShortcut ) return ;
136+
137+ const handleKeyDown = ( event : KeyboardEvent ) => {
138+ // Only support mod+key for now
139+ if ( ! event . metaKey && ! event . ctrlKey ) return ;
140+
141+ const key = keyboardShortcut . replace ( / m o d \+ / i, "" ) . toLowerCase ( ) ;
142+ if ( event . key . toLowerCase ( ) === key ) {
143+ event . preventDefault ( ) ;
144+ sidebarActions . toggleSidebar ( id ) ;
145+ }
146+ } ;
147+
148+ window . addEventListener ( "keydown" , handleKeyDown ) ;
149+ return ( ) => window . removeEventListener ( "keydown" , handleKeyDown ) ;
150+ } , [ id , keyboardShortcut ] ) ;
151+
129152 // Update CSS variable when sidebar state changes
130153 React . useEffect ( ( ) => {
131154 if ( sidebar ) {
@@ -189,16 +212,12 @@ export function Sidebar({
189212 minWidth : `var(--sidebar-${ id } -width, ${ defaultOpen ? width : collapsedWidth } )` ,
190213 maxWidth : `var(--sidebar-${ id } -width, ${ defaultOpen ? width : collapsedWidth } )`
191214 } }
192- className = { cn ( baseStyles , variantStyles [ variant ] , className , "animate-pulse border-transparent " ) }
215+ className = { cn ( baseStyles , variantStyles [ variant ] , className , "" ) }
193216 { ...props }
194217 >
195218 { /* Skeleton - no content on server */ }
196219 < div className = "flex h-full flex-col overflow-hidden" style = { { width : `var(--sidebar-${ id } -width, ${ defaultOpen ? width : collapsedWidth } )` } } >
197- < div className = "flex flex-col gap-0.5 p-2" >
198- < Skeleton className = "w-full h-9 opacity-10" />
199- < Skeleton className = "w-full h-9 opacity-10" />
200- < Skeleton className = "w-full h-9 opacity-10" />
201- </ div >
220+
202221 </ div >
203222 </ aside >
204223 </ div >
0 commit comments