1- import { useState } from 'react'
2- import { toast } from 'sonner'
3- import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
4- import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism'
5- import type { SearchResult } from '../types'
1+ import { useState } from 'react' ;
2+ import { toast } from 'sonner' ;
3+ import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' ;
4+ import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism' ;
5+ import { SearchBox } from './search' ;
6+ import type { SearchResult } from '../types' ;
67
78interface SearchPanelProps {
8- repoId : string
9- apiUrl : string
10- apiKey : string
9+ repoId : string ;
10+ apiUrl : string ;
11+ apiKey : string ;
1112}
1213
1314export function SearchPanel ( { repoId, apiUrl, apiKey } : SearchPanelProps ) {
14- const [ query , setQuery ] = useState ( '' )
15- const [ results , setResults ] = useState < SearchResult [ ] > ( [ ] )
16- const [ loading , setLoading ] = useState ( false )
17- const [ searchTime , setSearchTime ] = useState < number | null > ( null )
18- const [ cached , setCached ] = useState ( false )
15+ const [ query , setQuery ] = useState ( '' ) ;
16+ const [ results , setResults ] = useState < SearchResult [ ] > ( [ ] ) ;
17+ const [ loading , setLoading ] = useState ( false ) ;
18+ const [ searchTime , setSearchTime ] = useState < number | null > ( null ) ;
19+ const [ cached , setCached ] = useState ( false ) ;
1920
20- const handleSearch = async ( e : React . FormEvent ) => {
21- e . preventDefault ( )
22- if ( ! query . trim ( ) ) return
21+ const handleSearch = async ( ) => {
22+ if ( ! query . trim ( ) ) return ;
2323
24- setLoading ( true )
25- const startTime = Date . now ( )
24+ setLoading ( true ) ;
25+ const startTime = Date . now ( ) ;
2626
2727 try {
2828 const response = await fetch ( `${ apiUrl } /search` , {
2929 method : 'POST' ,
3030 headers : {
31- ' Authorization' : `Bearer ${ apiKey } ` ,
32- 'Content-Type' : 'application/json'
31+ Authorization : `Bearer ${ apiKey } ` ,
32+ 'Content-Type' : 'application/json' ,
3333 } ,
3434 body : JSON . stringify ( {
3535 query,
3636 repo_id : repoId ,
37- max_results : 10
38- } )
39- } )
37+ max_results : 10 ,
38+ } ) ,
39+ } ) ;
4040
41- const data = await response . json ( )
42- setResults ( data . results || [ ] )
43- setSearchTime ( Date . now ( ) - startTime )
44- setCached ( data . cached || false )
41+ const data = await response . json ( ) ;
42+ setResults ( data . results || [ ] ) ;
43+ setSearchTime ( Date . now ( ) - startTime ) ;
44+ setCached ( data . cached || false ) ;
4545 } catch ( error ) {
46- console . error ( 'Search error:' , error )
46+ console . error ( 'Search error:' , error ) ;
4747 toast . error ( 'Search failed' , {
48- description : 'Please check your query and try again'
49- } )
48+ description : 'Please check your query and try again' ,
49+ } ) ;
5050 } finally {
51- setLoading ( false )
51+ setLoading ( false ) ;
5252 }
53- }
53+ } ;
5454
5555 return (
5656 < div className = "p-6 space-y-6" >
57- { /* Search */ }
58- < div className = "bg-[#0a0a0c] border border-white/5 rounded-xl p-5" >
59- < form onSubmit = { handleSearch } >
60- < div className = "flex gap-3" >
61- < input
62- type = "text"
63- value = { query }
64- onChange = { ( e ) => setQuery ( e . target . value ) }
65- placeholder = "e.g., authentication middleware, React hooks, database queries..."
66- className = "flex-1 px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white placeholder:text-gray-500 focus:outline-none focus:border-blue-500/50 focus:ring-1 focus:ring-blue-500/20 transition-all"
67- disabled = { loading }
68- autoFocus
69- />
70- < button
71- type = "submit"
72- className = "px-6 py-3 bg-gradient-to-r from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700 text-white font-medium rounded-xl transition-all disabled:opacity-50"
73- disabled = { loading }
74- >
75- { loading ? 'Searching...' : 'Search' }
76- </ button >
77- </ div >
78- < p className = "mt-3 text-xs text-gray-500" >
79- Powered by semantic embeddings - finds code by meaning, not just keywords
80- </ p >
81- </ form >
57+ { /* Search Box */ }
58+ < div className = "card p-5" >
59+ < SearchBox
60+ value = { query }
61+ onChange = { setQuery }
62+ onSubmit = { handleSearch }
63+ loading = { loading }
64+ autoFocus
65+ />
8266
8367 { searchTime !== null && (
84- < div className = "mt-4 pt-4 border-t border-white/5 flex items-center gap-4 text-sm text-gray-400 " >
68+ < div className = "mt-4 pt-4 border-t border-border flex items-center gap-4 text-sm text-text-secondary " >
8569 < span >
86- < span className = "font-semibold text-white " > { results . length } </ span > results
70+ < span className = "font-semibold text-text-primary " > { results . length } </ span > results
8771 </ span >
88- < span className = "text-gray-600 " > •</ span >
72+ < span className = "text-text-muted " > •</ span >
8973 < span >
90- < span className = "font-mono font-semibold text-white " > { searchTime } ms</ span >
74+ < span className = "font-mono font-semibold text-text-primary " > { searchTime } ms</ span >
9175 </ span >
9276 { cached && (
9377 < >
94- < span className = "text-gray-600" > •</ span >
95- < span className = "text-xs bg-green-500/10 text-green-400 border border-green-500/20 px-2 py-0.5 rounded-md" >
96- ⚡ Cached
97- </ span >
78+ < span className = "text-text-muted" > •</ span >
79+ < span className = "badge-success" > ⚡ Cached</ span >
9880 </ >
9981 ) }
10082 </ div >
@@ -104,45 +86,48 @@ export function SearchPanel({ repoId, apiUrl, apiKey }: SearchPanelProps) {
10486 { /* Results */ }
10587 < div className = "space-y-4" >
10688 { results . map ( ( result , idx ) => (
107- < div key = { idx } className = "bg-[#0a0a0c] border border-white/5 rounded-xl p-5 hover:border-white/10 transition-all group" >
89+ < div
90+ key = { idx }
91+ className = "card p-5 hover:border-border-accent transition-all duration-normal group"
92+ >
10893 { /* Header */ }
10994 < div className = "flex items-start justify-between mb-4" >
11095 < div className = "flex-1" >
11196 < div className = "flex items-center gap-2 mb-1" >
112- < h3 className = "font-mono font-semibold text-sm text-white " >
97+ < h3 className = "font-mono font-semibold text-sm text-text-primary " >
11398 { result . name }
11499 </ h3 >
115- < span className = "px-2 py-0.5 text-[10px] uppercase tracking-wide bg-white/5 text-gray-400 border border-white/10 rounded " >
100+ < span className = "badge-neutral text-[10px] uppercase tracking-wide" >
116101 { result . type . replace ( '_' , ' ' ) }
117102 </ span >
118103 </ div >
119- < p className = "text-xs text-gray-500 font-mono" >
104+ < p className = "text-xs text-text-muted font-mono" >
120105 { result . file_path . split ( '/' ) . slice ( - 3 ) . join ( '/' ) }
121106 </ p >
122107 </ div >
123-
108+
124109 < div className = "flex items-center gap-3" >
125110 < div className = "text-right" >
126- < div className = "text-xs font-mono text-gray-500 " > Match</ div >
127- < div className = "text-sm font-mono font-semibold text-blue-400 " >
111+ < div className = "text-xs font-mono text-text-muted " > Match</ div >
112+ < div className = "text-sm font-mono font-semibold text-accent " >
128113 { ( result . score * 100 ) . toFixed ( 0 ) } %
129114 </ div >
130115 </ div >
131116 < button
132117 onClick = { ( e ) => {
133- e . stopPropagation ( )
134- navigator . clipboard . writeText ( result . code )
135- toast . success ( 'Code copied!' )
118+ e . stopPropagation ( ) ;
119+ navigator . clipboard . writeText ( result . code ) ;
120+ toast . success ( 'Code copied!' ) ;
136121 } }
137- className = "px-3 py-1.5 text-sm text-gray-400 hover:text-white bg-white/5 hover:bg-white/10 rounded-lg opacity-0 group-hover:opacity-100 transition-all "
122+ className = "btn-ghost px-3 py-1.5 text-sm opacity-0 group-hover:opacity-100"
138123 title = "Copy code"
139124 >
140125 Copy
141126 </ button >
142127 </ div >
143128 </ div >
144129
145- { /* Code with Syntax Highlighting */ }
130+ { /* Code */ }
146131 < div className = "relative rounded-lg overflow-hidden" >
147132 < SyntaxHighlighter
148133 language = { result . language }
@@ -152,47 +137,45 @@ export function SearchPanel({ repoId, apiUrl, apiKey }: SearchPanelProps) {
152137 borderRadius : '0.5rem' ,
153138 fontSize : '0.75rem' ,
154139 lineHeight : '1.5' ,
155- background : '#0d0d0f ' ,
140+ background : 'var(--color-bg-secondary) ' ,
156141 } }
157142 showLineNumbers
158143 startingLineNumber = { result . line_start }
159144 >
160145 { result . code }
161146 </ SyntaxHighlighter >
162-
147+
163148 < div className = "absolute top-3 right-3" >
164- < span className = "px-2 py-0.5 text-[10px] font-mono uppercase bg-black/50 text-gray-400 backdrop-blur rounded" >
149+ < span className = "px-2 py-0.5 text-[10px] font-mono uppercase glass text-text-muted rounded" >
165150 { result . language }
166151 </ span >
167152 </ div >
168153 </ div >
169154
170- { /* Metadata */ }
171- < div className = "mt-3 flex items-center gap-3 text-xs text-gray-500 " >
155+ { /* Footer */ }
156+ < div className = "mt-3 flex items-center gap-3 text-xs text-text-muted " >
172157 < span className = "font-mono" >
173158 Lines { result . line_start } –{ result . line_end }
174159 </ span >
175- < span className = "text-gray-600" > •</ span >
176- < span className = "text-gray-500 truncate" >
177- { result . file_path }
178- </ span >
160+ < span > •</ span >
161+ < span className = "truncate" > { result . file_path } </ span >
179162 </ div >
180163 </ div >
181164 ) ) }
182165 </ div >
183166
184167 { /* Empty State */ }
185168 { results . length === 0 && query && ! loading && (
186- < div className = "bg-[#0a0a0c] border border-white/5 rounded-xl p-16 text-center" >
187- < div className = "w-20 h-20 mx-auto mb-4 rounded-2xl bg-white/5 flex items-center justify-center" >
169+ < div className = "card p-16 text-center" >
170+ < div className = "w-20 h-20 mx-auto mb-4 rounded-2xl glass flex items-center justify-center" >
188171 < span className = "text-4xl" > 🔍</ span >
189172 </ div >
190- < h3 className = "text-base font-semibold mb-2 text-white " > No results found</ h3 >
191- < p className = "text-sm text-gray-400 " >
173+ < h3 className = "text-base font-semibold mb-2 text-text-primary " > No results found</ h3 >
174+ < p className = "text-sm text-text-secondary " >
192175 Try a different query or check if the repository is fully indexed
193176 </ p >
194177 </ div >
195178 ) }
196179 </ div >
197- )
180+ ) ;
198181}
0 commit comments