@@ -7,8 +7,11 @@ import {
77 Box ,
88 Chip ,
99 Stack ,
10+ Collapse ,
11+ Typography ,
12+ Tooltip ,
1013} from '@mui/material' ;
11- import { Search , Clear } from '@mui/icons-material' ;
14+ import { Search , Clear , FilterList } from '@mui/icons-material' ;
1215import { trackSearch , trackFilter } from '../utils/analytics.js' ;
1316
1417const SearchAndFilter = ( {
@@ -20,6 +23,7 @@ const SearchAndFilter = ({
2023 specialLabels = [ ] ,
2124} ) => {
2225 const [ localSearchQuery , setLocalSearchQuery ] = useState ( searchQuery ) ;
26+ const [ isKeywordSelectOpen , setIsKeywordSelectOpen ] = useState ( false ) ;
2327
2428 // Update local state when external searchQuery changes
2529 useEffect ( ( ) => {
@@ -50,7 +54,7 @@ const SearchAndFilter = ({
5054 onSearchChange ( '' ) ;
5155 } ;
5256 return (
53- < Box sx = { { mb : 2 } } >
57+ < Box >
5458 < Stack spacing = { 1.5 } >
5559 { /* Compact Search Bar */ }
5660 < TextField
@@ -68,11 +72,43 @@ const SearchAndFilter = ({
6872 ) ,
6973 endAdornment : (
7074 < InputAdornment position = "end" >
71- { localSearchQuery && (
72- < IconButton edge = "end" onClick = { handleClear } size = "small" >
73- < Clear sx = { { fontSize : 18 } } />
74- </ IconButton >
75- ) }
75+ < Stack direction = "row" spacing = { 0.5 } alignItems = "center" >
76+ { /* Quick Keyword Select Toggle - Now visible on all devices */ }
77+ { ( availableLabels . length > 0 || specialLabels . length > 0 ) && (
78+ < Tooltip
79+ title = {
80+ isKeywordSelectOpen
81+ ? 'Hide keyword filters'
82+ : 'Show keyword filters'
83+ }
84+ >
85+ < IconButton
86+ edge = "end"
87+ onClick = { ( ) =>
88+ setIsKeywordSelectOpen ( ! isKeywordSelectOpen )
89+ }
90+ size = "small"
91+ sx = { {
92+ color : isKeywordSelectOpen
93+ ? 'primary.main'
94+ : 'action.active' ,
95+ '&:hover' : {
96+ color : 'primary.main' ,
97+ bgcolor : 'action.hover' ,
98+ } ,
99+ } }
100+ >
101+ < FilterList sx = { { fontSize : 20 } } />
102+ </ IconButton >
103+ </ Tooltip >
104+ ) }
105+
106+ { localSearchQuery && (
107+ < IconButton edge = "end" onClick = { handleClear } size = "small" >
108+ < Clear sx = { { fontSize : 18 } } />
109+ </ IconButton >
110+ ) }
111+ </ Stack >
76112 </ InputAdornment >
77113 ) ,
78114 } }
@@ -90,95 +126,156 @@ const SearchAndFilter = ({
90126 } }
91127 />
92128
93- { /* Topic Filter Labels */ }
129+ { /* Topic Filter Labels - Now visible on all devices when toggled */ }
94130 { ( availableLabels . length > 0 || specialLabels . length > 0 ) && (
95- < Box
96- sx = { {
97- p : 1.5 ,
98- bgcolor : 'background.paper' ,
99- borderRadius : 2 ,
100- border : theme => `1px solid ${ theme . palette . divider } ` ,
101- boxShadow : 1 ,
102- } }
103- >
104- < Stack
105- direction = "row"
106- spacing = { 0.5 }
107- flexWrap = "wrap"
108- sx = { { gap : 0.5 } }
109- >
110- { /* Special Labels First */ }
111- { specialLabels . map ( label => {
112- const isSelected = selectedLabels . includes ( label ) ;
113- const labelColor =
114- label === 'prior / related work' ? 'default' : 'typeLabels' ;
115- return (
116- < Chip
117- key = { label }
118- label = { label }
119- size = "small"
120- clickable
121- color = { labelColor }
122- variant = { isSelected ? 'filled' : 'outlined' }
123- onClick = { ( ) => {
124- if ( isSelected ) {
125- onLabelsChange ( selectedLabels . filter ( l => l !== label ) ) ;
126- trackFilter ( 'special_label' , `remove_${ label } ` ) ;
127- } else {
128- onLabelsChange ( [ ...selectedLabels , label ] ) ;
129- trackFilter ( 'special_label' , `add_${ label } ` ) ;
130- }
131- } }
132- sx = { {
133- height : 26 ,
134- fontSize : '0.7rem' ,
135- borderRadius : 2 ,
136- '& .MuiChip-label' : { px : 1.5 } ,
137- transition : 'all 0.2s ease' ,
138- '&:hover' : {
139- transform : 'translateY(-1px)' ,
140- boxShadow : 2 ,
141- } ,
142- } }
143- />
144- ) ;
145- } ) }
131+ < Box >
132+ < Collapse in = { isKeywordSelectOpen } >
133+ < Box
134+ sx = { {
135+ p : 2 ,
136+ bgcolor : 'background.paper' ,
137+ borderRadius : 2 ,
138+ border : theme => `1px solid ${ theme . palette . divider } ` ,
139+ boxShadow : 1 ,
140+ } }
141+ >
142+ < Stack spacing = { 1.5 } >
143+ { /* Special Labels Section */ }
144+ { specialLabels . length > 0 && (
145+ < Box >
146+ < Typography
147+ variant = "caption"
148+ sx = { {
149+ display : 'block' ,
150+ mb : 0.75 ,
151+ color : 'text.secondary' ,
152+ fontWeight : 600 ,
153+ textTransform : 'uppercase' ,
154+ fontSize : '0.65rem' ,
155+ letterSpacing : '0.5px' ,
156+ } }
157+ >
158+ Paper Types
159+ </ Typography >
160+ < Stack
161+ direction = "row"
162+ spacing = { 0.5 }
163+ flexWrap = "wrap"
164+ sx = { { gap : 0.5 } }
165+ >
166+ { specialLabels . map ( label => {
167+ const isSelected = selectedLabels . includes ( label ) ;
168+ const labelColor =
169+ label === 'prior / related work'
170+ ? 'default'
171+ : 'typeLabels' ;
172+ return (
173+ < Chip
174+ key = { label }
175+ label = { label }
176+ size = "small"
177+ clickable
178+ color = { labelColor }
179+ variant = { isSelected ? 'filled' : 'outlined' }
180+ onClick = { ( ) => {
181+ if ( isSelected ) {
182+ onLabelsChange (
183+ selectedLabels . filter ( l => l !== label )
184+ ) ;
185+ trackFilter (
186+ 'special_label' ,
187+ `remove_${ label } `
188+ ) ;
189+ } else {
190+ onLabelsChange ( [ ...selectedLabels , label ] ) ;
191+ trackFilter ( 'special_label' , `add_${ label } ` ) ;
192+ }
193+ } }
194+ sx = { {
195+ height : 28 ,
196+ fontSize : '0.75rem' ,
197+ borderRadius : 2 ,
198+ '& .MuiChip-label' : { px : 1.5 } ,
199+ transition : 'all 0.2s ease' ,
200+ '&:hover' : {
201+ transform : 'translateY(-1px)' ,
202+ boxShadow : 2 ,
203+ } ,
204+ } }
205+ />
206+ ) ;
207+ } ) }
208+ </ Stack >
209+ </ Box >
210+ ) }
146211
147- { /* Regular Labels - Show All */ }
148- { availableLabels . map ( label => {
149- const isSelected = selectedLabels . includes ( label ) ;
150- return (
151- < Chip
152- key = { label }
153- label = { label }
154- size = "small"
155- clickable
156- color = "labels"
157- variant = { isSelected ? 'filled' : 'outlined' }
158- onClick = { ( ) => {
159- if ( isSelected ) {
160- onLabelsChange ( selectedLabels . filter ( l => l !== label ) ) ;
161- trackFilter ( 'regular_label' , `remove_${ label } ` ) ;
162- } else {
163- onLabelsChange ( [ ...selectedLabels , label ] ) ;
164- trackFilter ( 'regular_label' , `add_${ label } ` ) ;
165- }
166- } }
167- sx = { {
168- height : 26 ,
169- fontSize : '0.7rem' ,
170- borderRadius : 2 ,
171- '& .MuiChip-label' : { px : 1.5 } ,
172- transition : 'all 0.2s ease' ,
173- '&:hover' : {
174- transform : 'translateY(-1px)' ,
175- boxShadow : 2 ,
176- } ,
177- } }
178- />
179- ) ;
180- } ) }
181- </ Stack >
212+ { /* Regular Labels Section */ }
213+ { availableLabels . length > 0 && (
214+ < Box >
215+ < Typography
216+ variant = "caption"
217+ sx = { {
218+ display : 'block' ,
219+ mb : 0.75 ,
220+ color : 'text.secondary' ,
221+ fontWeight : 600 ,
222+ textTransform : 'uppercase' ,
223+ fontSize : '0.65rem' ,
224+ letterSpacing : '0.5px' ,
225+ } }
226+ >
227+ Topics & Keywords
228+ </ Typography >
229+ < Stack
230+ direction = "row"
231+ spacing = { 0.5 }
232+ flexWrap = "wrap"
233+ sx = { { gap : 0.5 } }
234+ >
235+ { availableLabels . map ( label => {
236+ const isSelected = selectedLabels . includes ( label ) ;
237+ return (
238+ < Chip
239+ key = { label }
240+ label = { label }
241+ size = "small"
242+ clickable
243+ color = "labels"
244+ variant = { isSelected ? 'filled' : 'outlined' }
245+ onClick = { ( ) => {
246+ if ( isSelected ) {
247+ onLabelsChange (
248+ selectedLabels . filter ( l => l !== label )
249+ ) ;
250+ trackFilter (
251+ 'regular_label' ,
252+ `remove_${ label } `
253+ ) ;
254+ } else {
255+ onLabelsChange ( [ ...selectedLabels , label ] ) ;
256+ trackFilter ( 'regular_label' , `add_${ label } ` ) ;
257+ }
258+ } }
259+ sx = { {
260+ height : 28 ,
261+ fontSize : '0.75rem' ,
262+ borderRadius : 2 ,
263+ '& .MuiChip-label' : { px : 1.5 } ,
264+ transition : 'all 0.2s ease' ,
265+ '&:hover' : {
266+ transform : 'translateY(-1px)' ,
267+ boxShadow : 2 ,
268+ } ,
269+ } }
270+ />
271+ ) ;
272+ } ) }
273+ </ Stack >
274+ </ Box >
275+ ) }
276+ </ Stack >
277+ </ Box >
278+ </ Collapse >
182279 </ Box >
183280 ) }
184281 </ Stack >
0 commit comments