@@ -11,6 +11,7 @@ import {
1111 Container ,
1212 Group ,
1313 Stack ,
14+ Table ,
1415 Text ,
1516 Title ,
1617} from "@mantine/core" ;
@@ -21,16 +22,13 @@ import {
2122} from "@tabler/icons-react" ;
2223import { useQuery , useQueryClient } from "@tanstack/react-query" ;
2324import { createLazyFileRoute , useSearch } from "@tanstack/react-router" ;
24- import type { ColumnDef } from "@tanstack/react-table" ;
2525import { useEffect , useMemo , useState } from "react" ;
2626
2727import { BORDER_STYLE_GRAY_3 , ICON_SIZE , SEARCH , TIME_MS } from '@/config/style-constants' ;
2828import { useUserInteractions } from "@/hooks/use-user-interactions" ;
2929
3030import { SearchInterface } from "../components/search/SearchInterface" ;
31- import { SearchResultPreview , useSearchResultHover } from "../components/search/SearchResultPreview" ;
3231import { SearchResultsSkeleton } from "../components/search/SearchResultsSkeleton" ;
33- import { BaseTable } from "../components/tables/BaseTable" ;
3432import { pageDescription , pageTitle } from "../styles/layout.css" ;
3533
3634interface SearchFilters {
@@ -133,113 +131,6 @@ const getEntityTypeColor = (entityType: AutocompleteResult["entity_type"]) => {
133131 return "gray" ;
134132} ;
135133
136- /**
137- * Name cell component - extracted to use hooks properly
138- * React hooks must be called at the top level of a component, not in render functions
139- */
140- const SearchResultNameCell = ( { result } : { result : AutocompleteResult } ) => {
141- const entityUrl = convertToRelativeUrl ( result . id ) ;
142- const hover = useSearchResultHover ( result ) ;
143-
144- return (
145- < >
146- < div { ...hover . props } >
147- { entityUrl ? (
148- < Anchor
149- href = { entityUrl }
150- size = "sm"
151- fw = { 500 }
152- style = { { textDecoration : "none" } }
153- aria-label = { `View ${ result . entity_type } ${ result . display_name } ` }
154- >
155- { result . display_name }
156- </ Anchor >
157- ) : (
158- < Text fw = { 500 } size = "sm" >
159- { result . display_name }
160- </ Text >
161- ) }
162- { result . hint && (
163- < Text size = "xs" c = "dimmed" lineClamp = { 1 } >
164- { result . hint }
165- </ Text >
166- ) }
167- { result . external_id && (
168- < Text size = "xs" c = "dimmed" >
169- { result . external_id }
170- </ Text >
171- ) }
172- </ div >
173-
174- { /* Hover preview card */ }
175- < SearchResultPreview
176- entity = { result }
177- opened = { hover . opened }
178- onToggle = { hover . toggle }
179- targetElement = { hover . targetElement }
180- />
181- </ >
182- ) ;
183- } ;
184-
185- // Extract column definitions to reduce complexity
186- const createSearchColumns = ( ) : ColumnDef < AutocompleteResult > [ ] => [
187- {
188- accessorKey : "entity_type" ,
189- header : "Type" ,
190- size : 100 ,
191- cell : ( { row } ) => {
192- const result = row . original ;
193- return (
194- < Badge
195- size = "sm"
196- color = { getEntityTypeColor ( result . entity_type ) }
197- variant = "light"
198- >
199- { result . entity_type }
200- </ Badge >
201- ) ;
202- } ,
203- } ,
204- {
205- accessorKey : "display_name" ,
206- header : "Name" ,
207- cell : ( { row } ) => < SearchResultNameCell result = { row . original } /> ,
208- } ,
209- {
210- accessorKey : "cited_by_count" ,
211- header : "Citations" ,
212- size : 120 ,
213- cell : ( { row } ) => {
214- const count = row . original . cited_by_count ;
215- return count ? (
216- < Text size = "sm" fw = { 500 } >
217- { formatLargeNumber ( count ) }
218- </ Text >
219- ) : (
220- < Text size = "sm" c = "dimmed" >
221- —
222- </ Text >
223- ) ;
224- } ,
225- } ,
226- {
227- accessorKey : "works_count" ,
228- header : "Works" ,
229- size : 100 ,
230- cell : ( { row } ) => {
231- const count = row . original . works_count ;
232- return count ? (
233- < Text size = "sm" > { formatLargeNumber ( count ) } </ Text >
234- ) : (
235- < Text size = "sm" c = "dimmed" >
236- —
237- </ Text >
238- ) ;
239- } ,
240- } ,
241- ] ;
242-
243134const SearchPage = ( ) => {
244135 const searchParams = useSearch ( { from : "/search" } ) ;
245136 const queryClient = useQueryClient ( ) ;
@@ -293,8 +184,6 @@ const SearchPage = () => {
293184 staleTime : TIME_MS . SEARCH_STALE_TIME ,
294185 } ) ;
295186
296- const columns = createSearchColumns ( ) ;
297-
298187 const handleSearch = async ( filters : SearchFilters ) => {
299188 setSearchFilters ( filters ) ;
300189 // Auto-tracking in useUserInteractions will handle page visit recording
@@ -451,24 +340,64 @@ const SearchPage = () => {
451340 ) }
452341 </ Group >
453342
454- < BaseTable
455- data = { searchResults }
456- columns = { columns }
457- searchable = { false } // Search is handled by the SearchInterface
458- onRowClick = { ( result ) => {
459- logger . debug (
460- "ui" ,
461- "Search result clicked" ,
462- {
463- id : result . id ,
464- name : result . display_name ,
465- type : result . entity_type ,
466- } ,
467- "SearchPage" ,
468- ) ;
469- // Navigation is handled by the entity links in the table
470- } }
471- />
343+ { /* Using Mantine Table directly due to TanStack Table hook compatibility
344+ issues with lazy-loaded routes. BaseTable's useReactTable/useVirtualizer
345+ hooks cause "Invalid hook call" errors in this lazy route context. */ }
346+ < Table striped highlightOnHover withTableBorder >
347+ < Table . Thead >
348+ < Table . Tr >
349+ < Table . Th w = { 100 } > Type</ Table . Th >
350+ < Table . Th > Name</ Table . Th >
351+ < Table . Th w = { 100 } > Citations</ Table . Th >
352+ < Table . Th w = { 100 } > Works</ Table . Th >
353+ </ Table . Tr >
354+ </ Table . Thead >
355+ < Table . Tbody >
356+ { searchResults . map ( ( result ) => {
357+ const entityUrl = convertToRelativeUrl ( result . id ) ;
358+ return (
359+ < Table . Tr key = { result . id } >
360+ < Table . Td >
361+ < Badge size = "sm" color = { getEntityTypeColor ( result . entity_type ) } variant = "light" >
362+ { result . entity_type }
363+ </ Badge >
364+ </ Table . Td >
365+ < Table . Td >
366+ < Stack gap = { 2 } >
367+ { entityUrl ? (
368+ < Anchor
369+ href = { entityUrl }
370+ size = "sm"
371+ fw = { 500 }
372+ style = { { textDecoration : "none" } }
373+ >
374+ { result . display_name }
375+ </ Anchor >
376+ ) : (
377+ < Text size = "sm" fw = { 500 } > { result . display_name } </ Text >
378+ ) }
379+ { result . hint && (
380+ < Text size = "xs" c = "dimmed" lineClamp = { 1 } >
381+ { result . hint }
382+ </ Text >
383+ ) }
384+ </ Stack >
385+ </ Table . Td >
386+ < Table . Td >
387+ < Text size = "sm" fw = { 500 } >
388+ { result . cited_by_count ? formatLargeNumber ( result . cited_by_count ) : '—' }
389+ </ Text >
390+ </ Table . Td >
391+ < Table . Td >
392+ < Text size = "sm" >
393+ { result . works_count ? formatLargeNumber ( result . works_count ) : '—' }
394+ </ Text >
395+ </ Table . Td >
396+ </ Table . Tr >
397+ ) ;
398+ } ) }
399+ </ Table . Tbody >
400+ </ Table >
472401 </ Stack >
473402 ) ;
474403 } ;
0 commit comments