@@ -18,7 +18,6 @@ const NavItem = styled(NavLink)<{ $isExpanded: boolean }>`
1818 padding: ${ props => props . $isExpanded ? '8px' : '1px' } ;
1919 margin: 4px 0;
2020 color: #e04bff;
21- text-decoration: none;
2221 white-space: nowrap;
2322 overflow: hidden;
2423 text-overflow: ellipsis;
@@ -44,21 +43,51 @@ const NavItem = styled(NavLink)<{ $isExpanded: boolean }>`
4443 }
4544
4645 &.hovered:after {
47- color: #535bf2 ;
46+ color: rgb(125, 225, 253) ;
4847 content: ']';
4948 }
5049 &.hovered:before {
51- color: #535bf2 ;
50+ color: rgb(125, 225, 253) ;
5251 content: '[';
5352 }
5453`
5554
55+ interface NavItemType {
56+ to : string ;
57+ label : string ;
58+ shortcutKey : string ;
59+ }
60+
5661export const Sidebar = ( ) => {
5762 const [ focusedIndex , setFocusedIndex ] = useState ( - 1 ) ;
5863 const [ isExpanded , setIsExpanded ] = useState ( false ) ;
5964 const [ isMobile , setIsMobile ] = useState ( window . innerWidth < 768 ) ;
6065
61- const navItems = [
66+ // Helper function to determine shortcut keys
67+ const determineShortcutKeys = ( items : { to : string ; label : string } [ ] ) : NavItemType [ ] => {
68+ const usedKeys = new Set < string > ( ) ;
69+ return items . map ( item => {
70+ const label = item . label . toLowerCase ( ) ;
71+ let shortcutKey = '' ;
72+
73+ // Try to find first available character
74+ for ( const char of label ) {
75+ if ( ! usedKeys . has ( char ) ) {
76+ shortcutKey = char ;
77+ usedKeys . add ( char ) ;
78+ break ;
79+ }
80+ }
81+
82+ return {
83+ to : item . to ,
84+ label : item . label ,
85+ shortcutKey
86+ } ;
87+ } ) ;
88+ } ;
89+
90+ const baseNavItems = [
6291 { to : "/" , label : "Home" } ,
6392 { to : "/accounts" , label : "Accounts" } ,
6493 { to : "/agents" , label : "Agents" } ,
@@ -67,6 +96,9 @@ export const Sidebar = () => {
6796 { to : "/extrinsics" , label : "Extrinsics" } ,
6897 { to : "/events" , label : "Events" }
6998 ] ;
99+
100+ const navItems = determineShortcutKeys ( baseNavItems ) ;
101+
70102 // Add mobile detection
71103 useEffect ( ( ) => {
72104 const handleResize = ( ) => {
@@ -80,18 +112,53 @@ export const Sidebar = () => {
80112 return ( ) => window . removeEventListener ( 'resize' , handleResize ) ;
81113 } , [ ] ) ;
82114
115+ // Global keyboard shortcuts
116+ useEffect ( ( ) => {
117+ const handleGlobalKeyDown = ( e : KeyboardEvent ) => {
118+ // Don't trigger shortcuts if user is typing in an input or textarea
119+ if ( e . target instanceof HTMLInputElement || e . target instanceof HTMLTextAreaElement ) {
120+ return ;
121+ }
122+
123+ if ( ! isMobile ) {
124+ const pressedKey = e . key . toLowerCase ( ) ;
125+ const matchingItem = navItems . find ( item => item . shortcutKey === pressedKey ) ;
126+ if ( matchingItem ) {
127+ setFocusedIndex ( navItems . indexOf ( matchingItem ) ) ;
128+ const link = document . querySelector ( `a[href="${ matchingItem . to } "]` ) as HTMLElement ;
129+ link ?. click ( ) ;
130+ }
131+ }
132+ } ;
133+
134+ document . addEventListener ( 'keydown' , handleGlobalKeyDown ) ;
135+ return ( ) => document . removeEventListener ( 'keydown' , handleGlobalKeyDown ) ;
136+ } , [ navItems , isMobile ] ) ;
137+
83138 const handleKeyDown = ( e : React . KeyboardEvent ) => {
84139 if ( e . key === 'ArrowDown' ) {
85140 setFocusedIndex ( prev => ( prev + 1 ) % navItems . length ) ;
86141 } else if ( e . key === 'ArrowUp' ) {
87142 setFocusedIndex ( prev => ( prev - 1 + navItems . length ) % navItems . length ) ;
88143 } else if ( e . key === 'Enter' ) {
89- // setFocusedIndex(-1);
90144 const link = document . getElementById ( `nav-item-${ focusedIndex } ` ) ;
91145 link ?. click ( ) ;
92146 }
93147 } ;
94148
149+ const renderLabel = ( label : string , shortcutKey : string ) => {
150+ const index = label . toLowerCase ( ) . indexOf ( shortcutKey ) ;
151+ if ( index === - 1 ) return label ;
152+
153+ return (
154+ < >
155+ { label . slice ( 0 , index ) }
156+ < span style = { { color : "aqua" } } > { label . charAt ( index ) } </ span >
157+ { label . slice ( index + 1 ) }
158+ </ >
159+ ) ;
160+ } ;
161+
95162 return (
96163 < SidebarContainer
97164 onKeyDown = { handleKeyDown }
@@ -105,10 +172,10 @@ export const Sidebar = () => {
105172 onClick = { ( e ) => { if ( ! isExpanded && isMobile ) { e . preventDefault ( ) } } }
106173 to = { item . to }
107174 id = { `nav-item-${ index } ` }
108- className = { focusedIndex === index ? `hovered` : '' }
175+ className = { focusedIndex === index && ( ( isMobile && isExpanded ) || ! isMobile ) ? `hovered` : '' }
109176 $isExpanded = { isExpanded || ! isMobile }
110177 >
111- { isMobile && ! isExpanded ? item . label : item . label }
178+ { isMobile && ! isExpanded ? item . label : renderLabel ( item . label , item . shortcutKey ) }
112179 </ NavItem >
113180 ) ) }
114181 </ SidebarContainer >
0 commit comments