@@ -259,6 +259,24 @@ const cardHoverVariants = {
259259}
260260
261261function ResultCard ( { result, index } : { result : SearchResult ; index : number } ) {
262+ const [ expanded , setExpanded ] = useState ( false )
263+ const codeLines = result . code . split ( '\n' )
264+ const isLongCode = codeLines . length > 8
265+ const displayCode = expanded ? result . code : codeLines . slice ( 0 , 8 ) . join ( '\n' )
266+
267+ // Color based on match score
268+ const scoreColor = result . score >= 0.7
269+ ? 'from-emerald-400 to-green-500'
270+ : result . score >= 0.5
271+ ? 'from-blue-400 to-indigo-500'
272+ : 'from-amber-400 to-orange-500'
273+
274+ const scoreBg = result . score >= 0.7
275+ ? 'bg-emerald-500/10 border-emerald-500/20'
276+ : result . score >= 0.5
277+ ? 'bg-blue-500/10 border-blue-500/20'
278+ : 'bg-amber-500/10 border-amber-500/20'
279+
262280 return (
263281 < motion . div
264282 variants = { resultCardVariants }
@@ -274,35 +292,79 @@ function ResultCard({ result, index }: { result: SearchResult; index: number })
274292 initial = "rest"
275293 whileHover = "hover"
276294 >
277- < Card
278- className = "bg-[#111113] border-white/5 overflow-hidden hover:border-blue-500/30 transition-colors duration-300 cursor-pointer"
279- >
280- < div className = "px-5 py-4 border-b border-white/5 flex items-start justify-between" >
281- < div >
282- < div className = "flex items-center gap-3" >
283- < h3 className = "font-mono font-semibold" > { result . name } </ h3 >
284- < Badge variant = "outline" className = "text-[10px] text-gray-400 border-gray-700" >
285- { result . type . replace ( '_' , ' ' ) }
286- </ Badge >
295+ < Card className = "bg-[#0c0c0e] border-white/[0.06] overflow-hidden hover:border-white/10 transition-all duration-300 cursor-pointer group" >
296+ { /* Header - Clean and Spacious */ }
297+ < div className = "px-6 py-5 flex items-start justify-between gap-6" >
298+ { /* Left: Function info */ }
299+ < div className = "flex-1 min-w-0" >
300+ < div className = "flex items-center gap-3 mb-2" >
301+ < h3 className = "font-mono text-lg font-semibold text-white truncate group-hover:text-blue-400 transition-colors" >
302+ { result . name }
303+ </ h3 >
304+ < span className = "px-2 py-0.5 text-[10px] font-medium uppercase tracking-wider text-gray-500 bg-white/5 rounded" >
305+ { result . type . replace ( '_' , ' ' ) }
306+ </ span >
307+ </ div >
308+ < p className = "text-sm text-gray-500 font-mono truncate" >
309+ { result . file_path }
310+ </ p >
311+ </ div >
312+
313+ { /* Right: Match Score - THE HERO */ }
314+ < div className = { cn ( "flex flex-col items-center px-4 py-3 rounded-xl border" , scoreBg ) } >
315+ < div className = { cn ( "text-3xl font-bold bg-gradient-to-r bg-clip-text text-transparent" , scoreColor ) } >
316+ { ( result . score * 100 ) . toFixed ( 0 ) } %
317+ </ div >
318+ < div className = "text-[10px] text-gray-500 uppercase tracking-widest mt-0.5" > match</ div >
287319 </ div >
288- < p className = "text-sm text-gray-500 font-mono mt-1" >
289- { result . file_path . split ( '/' ) . slice ( - 2 ) . join ( '/' ) }
290- </ p >
291320 </ div >
292- < div className = "text-right" >
293- < div className = "text-2xl font-bold text-blue-400" > { ( result . score * 100 ) . toFixed ( 0 ) } %</ div >
294- < div className = "text-[10px] text-gray-500 uppercase tracking-wider" > match</ div >
321+
322+ { /* Code Block - Contained with gradient fade */ }
323+ < div className = "relative" >
324+ < div className = { cn (
325+ "transition-all duration-300" ,
326+ ! expanded && isLongCode && "max-h-[200px] overflow-hidden"
327+ ) } >
328+ < SyntaxHighlighter
329+ language = { result . language || 'python' }
330+ style = { oneDark }
331+ customStyle = { {
332+ margin : 0 ,
333+ borderRadius : 0 ,
334+ fontSize : '0.8rem' ,
335+ background : '#08080a' ,
336+ padding : '1rem 1.5rem' ,
337+ } }
338+ showLineNumbers
339+ startingLineNumber = { result . line_start || 1 }
340+ >
341+ { displayCode }
342+ </ SyntaxHighlighter >
343+ </ div >
344+
345+ { /* Gradient fade + expand button */ }
346+ { isLongCode && ! expanded && (
347+ < div className = "absolute bottom-0 left-0 right-0 h-20 bg-gradient-to-t from-[#08080a] to-transparent flex items-end justify-center pb-3" >
348+ < button
349+ onClick = { ( e ) => { e . stopPropagation ( ) ; setExpanded ( true ) ; } }
350+ className = "px-4 py-1.5 text-xs font-medium text-gray-400 bg-white/5 hover:bg-white/10 rounded-full border border-white/10 hover:border-white/20 transition-all"
351+ >
352+ Show { codeLines . length - 8 } more lines
353+ </ button >
354+ </ div >
355+ ) }
356+
357+ { isLongCode && expanded && (
358+ < div className = "flex justify-center py-3 bg-[#08080a] border-t border-white/5" >
359+ < button
360+ onClick = { ( e ) => { e . stopPropagation ( ) ; setExpanded ( false ) ; } }
361+ className = "px-4 py-1.5 text-xs font-medium text-gray-400 bg-white/5 hover:bg-white/10 rounded-full border border-white/10 hover:border-white/20 transition-all"
362+ >
363+ Show less
364+ </ button >
365+ </ div >
366+ ) }
295367 </ div >
296- </ div >
297- < SyntaxHighlighter
298- language = { result . language || 'python' }
299- style = { oneDark }
300- customStyle = { { margin : 0 , borderRadius : 0 , fontSize : '0.8rem' , background : '#0d0d0f' } }
301- showLineNumbers
302- startingLineNumber = { result . line_start || 1 }
303- >
304- { result . code }
305- </ SyntaxHighlighter >
306368 </ Card >
307369 </ motion . div >
308370 </ motion . div >
@@ -319,16 +381,21 @@ export function LandingPage() {
319381 const [ hasSearched , setHasSearched ] = useState ( false )
320382 const [ availableRepos , setAvailableRepos ] = useState < string [ ] > ( [ ] )
321383 const [ rateLimitError , setRateLimitError ] = useState < string | null > ( null )
322- const [ lastQuery , setLastQuery ] = useState ( '' )
384+ const [ searchedQuery , setSearchedQuery ] = useState ( '' ) // What was actually searched
385+ const [ inputQuery , setInputQuery ] = useState ( '' ) // What user is typing
323386 const [ currentRepoId , setCurrentRepoId ] = useState ( '' )
324387 const [ isCustomRepo , setIsCustomRepo ] = useState ( false )
325388
389+ // Check if results are stale (user typed something different)
390+ const isStale = hasSearched && ! loading && inputQuery . trim ( ) !== searchedQuery . trim ( ) && inputQuery . trim ( ) !== ''
391+
326392 // Reset to hero state
327393 const handleNewSearch = ( ) => {
328394 setHasSearched ( false )
329395 setResults ( [ ] )
330396 setSearchTime ( null )
331- setLastQuery ( '' )
397+ setSearchedQuery ( '' )
398+ setInputQuery ( '' )
332399 window . scrollTo ( { top : 0 , behavior : 'smooth' } )
333400 }
334401
@@ -359,7 +426,8 @@ export function LandingPage() {
359426
360427 setLoading ( true )
361428 setHasSearched ( true )
362- setLastQuery ( query )
429+ setSearchedQuery ( query ) // Track what was actually searched
430+ setInputQuery ( query ) // Sync input with searched
363431 setCurrentRepoId ( repoId )
364432 setIsCustomRepo ( isCustom )
365433 setRateLimitError ( null )
@@ -396,8 +464,8 @@ export function LandingPage() {
396464
397465 // Re-search with updated query (from compact search bar)
398466 const handleReSearch = ( ) => {
399- if ( lastQuery . trim ( ) && currentRepoId ) {
400- handleSearch ( lastQuery , currentRepoId , isCustomRepo )
467+ if ( inputQuery . trim ( ) && currentRepoId ) {
468+ handleSearch ( inputQuery , currentRepoId , isCustomRepo )
401469 }
402470 }
403471
@@ -435,8 +503,8 @@ export function LandingPage() {
435503 < div className = "min-h-screen pt-16" >
436504 { /* Compact Search Bar - sticky below nav */ }
437505 < CompactSearchBar
438- query = { lastQuery }
439- onQueryChange = { setLastQuery }
506+ query = { inputQuery }
507+ onQueryChange = { setInputQuery }
440508 onSearch = { handleReSearch }
441509 onNewSearch = { handleNewSearch }
442510 loading = { loading }
@@ -450,12 +518,26 @@ export function LandingPage() {
450518 < div className = "flex items-center justify-between mb-6 animate-in fade-in duration-300" >
451519 { loading ? (
452520 < span className = "text-gray-400 text-sm" >
453- Searching for "< span className = "text-blue-400" > { lastQuery } </ span > "...
521+ Searching for "< span className = "text-blue-400" > { inputQuery } </ span > "...
454522 </ span >
523+ ) : isStale ? (
524+ < motion . div
525+ className = "flex items-center gap-3"
526+ initial = { { opacity : 0 , y : - 10 } }
527+ animate = { { opacity : 1 , y : 0 } }
528+ >
529+ < span className = "text-amber-400 text-sm flex items-center gap-2" >
530+ < span className = "w-2 h-2 bg-amber-400 rounded-full animate-pulse" />
531+ Press Enter to search for "< span className = "text-white" > { inputQuery } </ span > "
532+ </ span >
533+ < span className = "text-gray-600 text-xs" >
534+ (showing results for "{ searchedQuery } ")
535+ </ span >
536+ </ motion . div >
455537 ) : (
456538 < div className = "flex items-center gap-4" >
457539 < span className = "text-gray-400 text-sm" >
458- < span className = "text-white font-semibold" > { results . length } </ span > results for "< span className = "text-blue-400" > { lastQuery } </ span > "
540+ < span className = "text-white font-semibold" > { results . length } </ span > results for "< span className = "text-blue-400" > { searchedQuery } </ span > "
459541 </ span >
460542 { searchTime && (
461543 < span className = "font-mono text-sm text-green-400" >
@@ -495,11 +577,16 @@ export function LandingPage() {
495577
496578 < AnimatePresence mode = "wait" >
497579 < motion . div
498- key = { lastQuery }
499- className = "space-y-4 "
580+ key = { searchedQuery }
581+ className = "space-y-6 "
500582 initial = { { opacity : 0 } }
501- animate = { { opacity : 1 } }
583+ animate = { {
584+ opacity : isStale ? 0.4 : 1 ,
585+ filter : isStale ? 'blur(2px)' : 'blur(0px)' ,
586+ scale : isStale ? 0.98 : 1 ,
587+ } }
502588 exit = { { opacity : 0 } }
589+ transition = { { duration : 0.3 } }
503590 >
504591 { results . map ( ( result , idx ) => (
505592 < ResultCard key = { `${ result . file_path } -${ result . name } -${ idx } ` } result = { result } index = { idx } />
0 commit comments