@@ -12,6 +12,7 @@ import {
1212 Container ,
1313 Group ,
1414 Paper ,
15+ Select ,
1516 SegmentedControl ,
1617 SimpleGrid ,
1718 Stack ,
@@ -47,6 +48,16 @@ interface SearchFilters {
4748
4849type ViewMode = "table" | "card" | "list" ;
4950
51+ type SortOption = "relevance" | "citations" | "works" | "name" | "type" ;
52+
53+ const SORT_OPTIONS : { value : SortOption ; label : string } [ ] = [
54+ { value : "relevance" , label : "Relevance" } ,
55+ { value : "citations" , label : "Most Cited" } ,
56+ { value : "works" , label : "Most Works" } ,
57+ { value : "name" , label : "Name (A-Z)" } ,
58+ { value : "type" , label : "Entity Type" } ,
59+ ] ;
60+
5061// Calculate entity type breakdown from results
5162const getEntityTypeBreakdown = ( results : AutocompleteResult [ ] ) => {
5263 const breakdown = results . reduce ( ( acc , result ) => {
@@ -190,6 +201,9 @@ const SearchPage = () => {
190201 // View mode state
191202 const [ viewMode , setViewMode ] = useState < ViewMode > ( "table" ) ;
192203
204+ // Sort state
205+ const [ sortBy , setSortBy ] = useState < SortOption > ( "relevance" ) ;
206+
193207 // Entity type filter state
194208 const [ selectedTypes , setSelectedTypes ] = useState < string [ ] > ( [ ] ) ;
195209
@@ -409,6 +423,25 @@ const SearchPage = () => {
409423 return searchResults . filter ( result => selectedTypes . includes ( result . entity_type ) ) ;
410424 } , [ searchResults , selectedTypes ] ) ;
411425
426+ // Sort and filter results by selected sort option
427+ const sortedResults = useMemo ( ( ) => {
428+ let results = filteredResults ;
429+
430+ switch ( sortBy ) {
431+ case "citations" :
432+ return [ ...results ] . sort ( ( a , b ) => ( b . cited_by_count || 0 ) - ( a . cited_by_count || 0 ) ) ;
433+ case "works" :
434+ return [ ...results ] . sort ( ( a , b ) => ( b . works_count || 0 ) - ( a . works_count || 0 ) ) ;
435+ case "name" :
436+ return [ ...results ] . sort ( ( a , b ) => a . display_name . localeCompare ( b . display_name ) ) ;
437+ case "type" :
438+ return [ ...results ] . sort ( ( a , b ) => a . entity_type . localeCompare ( b . entity_type ) ) ;
439+ case "relevance" :
440+ default :
441+ return results ; // Keep original order from API (relevance-sorted)
442+ }
443+ } , [ filteredResults , sortBy ] ) ;
444+
412445 // Calculate entity type breakdown
413446 const entityTypeBreakdown = useMemo ( ( ) => {
414447 return searchResults ? getEntityTypeBreakdown ( searchResults ) : [ ] ;
@@ -433,8 +466,6 @@ const SearchPage = () => {
433466 ) ;
434467 if ( ! hasResults ) return renderNoResultsState ( searchFilters . query , handleQuickSearch ) ;
435468
436- const displayResults = selectedTypes . length > 0 ? filteredResults : searchResults ;
437-
438469 return (
439470 < Stack >
440471 { /* Enhanced Results Header */ }
@@ -443,7 +474,7 @@ const SearchPage = () => {
443474 < Group justify = "space-between" align = "center" wrap = "nowrap" >
444475 < Group gap = "md" align = "center" >
445476 < Text size = "sm" fw = { 500 } >
446- { displayResults . length } { displayResults . length === 1 ? 'result' : 'results' }
477+ { sortedResults . length } { sortedResults . length === 1 ? 'result' : 'results' }
447478 { selectedTypes . length > 0 && ` (filtered from ${ searchResults . length } )` }
448479 </ Text >
449480 { searchDuration > 0 && (
@@ -455,32 +486,42 @@ const SearchPage = () => {
455486 ) }
456487 </ Group >
457488
458- { /* View mode toggle */ }
459- < SegmentedControl
460- value = { viewMode }
461- onChange = { ( value ) => setViewMode ( value as ViewMode ) }
462- data = { [
463- {
464- value : 'table' ,
465- label : (
466- < Tooltip label = "Table view" > < IconTable size = { ICON_SIZE . SM } /> </ Tooltip >
467- )
468- } ,
469- {
470- value : 'card' ,
471- label : (
472- < Tooltip label = "Card view" > < IconLayoutGrid size = { ICON_SIZE . SM } /> </ Tooltip >
473- )
474- } ,
475- {
476- value : 'list' ,
477- label : (
478- < Tooltip label = "List view" > < IconList size = { ICON_SIZE . SM } /> </ Tooltip >
479- )
480- } ,
481- ] }
482- size = "xs"
483- />
489+ { /* View mode toggle and sort selector */ }
490+ < Group gap = "sm" >
491+ < Select
492+ size = "xs"
493+ value = { sortBy }
494+ onChange = { ( value ) => setSortBy ( value as SortOption ) }
495+ data = { SORT_OPTIONS }
496+ style = { { width : 140 } }
497+ allowDeselect = { false }
498+ />
499+ < SegmentedControl
500+ value = { viewMode }
501+ onChange = { ( value ) => setViewMode ( value as ViewMode ) }
502+ data = { [
503+ {
504+ value : 'table' ,
505+ label : (
506+ < Tooltip label = "Table view" > < IconTable size = { ICON_SIZE . SM } /> </ Tooltip >
507+ )
508+ } ,
509+ {
510+ value : 'card' ,
511+ label : (
512+ < Tooltip label = "Card view" > < IconLayoutGrid size = { ICON_SIZE . SM } /> </ Tooltip >
513+ )
514+ } ,
515+ {
516+ value : 'list' ,
517+ label : (
518+ < Tooltip label = "List view" > < IconList size = { ICON_SIZE . SM } /> </ Tooltip >
519+ )
520+ } ,
521+ ] }
522+ size = "xs"
523+ />
524+ </ Group >
484525 </ Group >
485526
486527 { /* Entity type breakdown and filter chips */ }
@@ -600,7 +641,7 @@ const SearchPage = () => {
600641 </ Table . Tr >
601642 </ Table . Thead >
602643 < Table . Tbody >
603- { displayResults . map ( ( result ) => {
644+ { sortedResults . map ( ( result ) => {
604645 const entityUrl = convertToRelativeUrl ( result . id ) ;
605646 const inGraph = isInGraph ( result . id ) ;
606647 return (
@@ -664,7 +705,7 @@ const SearchPage = () => {
664705
665706 { viewMode === "card" && (
666707 < SimpleGrid cols = { { base : 1 , xs : 2 , sm : 2 , md : 3 , lg : 4 } } spacing = "md" >
667- { displayResults . map ( ( result ) => {
708+ { sortedResults . map ( ( result ) => {
668709 const entityUrl = convertToRelativeUrl ( result . id ) ;
669710 const inGraph = isInGraph ( result . id ) ;
670711 return (
@@ -717,7 +758,7 @@ const SearchPage = () => {
717758
718759 { viewMode === "list" && (
719760 < Stack gap = "xs" >
720- { displayResults . map ( ( result ) => {
761+ { sortedResults . map ( ( result ) => {
721762 const entityUrl = convertToRelativeUrl ( result . id ) ;
722763 const inGraph = isInGraph ( result . id ) ;
723764 return (
0 commit comments