@@ -42,13 +42,19 @@ <h1 class="page-title">Leaderboard</h1>
4242
4343
4444 < div class ="search-container ">
45- < input
46- type ="text "
47- id ="leaderboard-search "
48- class ="search-input "
49- placeholder ="./search_by_name_or_leetcode_id "
50- autocomplete ="off "
51- >
45+ < div class ="search-bar ">
46+ < span class ="search-prefix "> $ grep -i</ span >
47+ < input
48+ type ="text "
49+ id ="leaderboard-search "
50+ class ="search-input "
51+ placeholder ="pattern "
52+ autocomplete ="off "
53+ spellcheck ="false "
54+ >
55+ < span class ="search-result-count " id ="search-result-count "> </ span >
56+ < kbd class ="search-shortcut " id ="search-shortcut "> Ctrl+K</ kbd >
57+ </ div >
5258 </ div >
5359
5460 < div class ="leaderboard ">
@@ -107,12 +113,37 @@ <h1 class="page-title">Leaderboard</h1>
107113 } ) ;
108114
109115 const searchInput = document . getElementById ( 'leaderboard-search' ) ;
116+ const shortcutBadge = document . getElementById ( 'search-shortcut' ) ;
110117
111118 searchInput . addEventListener ( 'input' , ( e ) => {
112119 currentSearchTerm = e . target . value . toLowerCase ( ) . trim ( ) ;
113120 applyFiltersAndRender ( ) ;
114121 } ) ;
115122
123+ searchInput . addEventListener ( 'focus' , ( ) => {
124+ shortcutBadge . style . opacity = '0' ;
125+ } ) ;
126+
127+ searchInput . addEventListener ( 'blur' , ( ) => {
128+ if ( ! searchInput . value ) {
129+ shortcutBadge . style . opacity = '1' ;
130+ }
131+ } ) ;
132+
133+ // Ctrl+K / Cmd+K keyboard shortcut
134+ document . addEventListener ( 'keydown' , ( e ) => {
135+ if ( ( e . ctrlKey || e . metaKey ) && e . key === 'k' ) {
136+ e . preventDefault ( ) ;
137+ searchInput . focus ( ) ;
138+ }
139+ if ( e . key === 'Escape' && document . activeElement === searchInput ) {
140+ searchInput . value = '' ;
141+ currentSearchTerm = '' ;
142+ searchInput . blur ( ) ;
143+ applyFiltersAndRender ( ) ;
144+ }
145+ } ) ;
146+
116147 fetchLeaderboardData ( ) ;
117148 } ) ;
118149
@@ -214,12 +245,25 @@ <h1 class="page-title">Leaderboard</h1>
214245 } ) ) ;
215246
216247 const filteredData = rankedData . filter ( user => {
248+ if ( ! currentSearchTerm ) return true ;
217249 return (
218250 user . name . toLowerCase ( ) . includes ( currentSearchTerm ) ||
219251 user . id . toLowerCase ( ) . includes ( currentSearchTerm )
220252 ) ;
221253 } ) ;
222254
255+ // Update result count
256+ const countEl = document . getElementById ( 'search-result-count' ) ;
257+ if ( currentSearchTerm ) {
258+ const total = originalData . length ;
259+ const matched = filteredData . length ;
260+ countEl . textContent = `${ matched } /${ total } ` ;
261+ countEl . style . opacity = '1' ;
262+ } else {
263+ countEl . textContent = '' ;
264+ countEl . style . opacity = '0' ;
265+ }
266+
223267 renderLeaderboard ( filteredData ) ;
224268 }
225269
@@ -309,7 +353,7 @@ <h1 class="page-title">Leaderboard</h1>
309353 mobileCards . appendChild ( card ) ;
310354 } ) ;
311355
312- if ( data . length > currentDisplayLimit ) {
356+ if ( ! isSearching && data . length > currentDisplayLimit ) {
313357 document . getElementById ( 'load-more-btn' ) . style . display = 'inline-block' ;
314358 document . getElementById ( 'scroll-top-btn' ) . style . display = 'none' ;
315359
@@ -323,7 +367,7 @@ <h1 class="page-title">Leaderboard</h1>
323367 }
324368 } else {
325369 document . getElementById ( 'load-more-btn' ) . style . display = 'none' ;
326- document . getElementById ( 'scroll-top-btn' ) . style . display = 'inline-block' ;
370+ document . getElementById ( 'scroll-top-btn' ) . style . display = isSearching ? 'none' : 'inline-block' ;
327371 }
328372 }
329373
0 commit comments