@@ -4,7 +4,7 @@ import { SearchResults } from "@/components/SearchResults";
44import { LoadingState } from "@/components/LoadingState" ;
55import { ErrorState } from "@/components/ErrorState" ;
66import { useToast } from "@/hooks/use-toast" ;
7- import { ChevronLeft , ChevronRight } from "lucide-react" ;
7+ import { ChevronLeft , ChevronRight , Settings } from "lucide-react" ;
88import seekrLogo from "@/assets/seekr-logo.png" ;
99import { mockResults } from "@/mock/searchResults" ;
1010
@@ -23,6 +23,8 @@ const Index = () => {
2323 const [ currentQuery , setCurrentQuery ] = useState ( "" ) ;
2424 const { toast } = useToast ( ) ;
2525 const [ currentText , setCurrentText ] = useState ( "" ) ;
26+ const [ limit , setLimit ] = useState ( 10 ) ;
27+ const [ showSettings , setShowSettings ] = useState ( false ) ;
2628
2729 const RESULTS_PER_PAGE = 10 ;
2830
@@ -40,29 +42,34 @@ const Index = () => {
4042 const params = new URLSearchParams ( window . location . search ) ;
4143 const page = parseInt ( params . get ( "page" ) || "1" ) ;
4244 const query = params . get ( "q" ) || "" ;
45+ const urlLimit = parseInt ( params . get ( "limit" ) || "10" ) ;
4346
4447 if ( page > 1 ) setCurrentPage ( page ) ;
48+ if ( urlLimit ) setLimit ( urlLimit ) ;
4549 if ( query ) {
4650 setCurrentQuery ( query ) ;
4751 setHasSearched ( true ) ;
48- handleSearch ( query ) ;
52+ handleSearch ( query , urlLimit ) ;
4953 }
5054 } , [ ] ) ;
5155
52- // Update URL when page changes
56+ // Update URL when page or limit changes
5357 useEffect ( ( ) => {
5458 if ( hasSearched && currentQuery ) {
5559 const params = new URLSearchParams ( ) ;
5660 params . set ( "q" , currentQuery ) ;
5761 if ( currentPage > 1 ) {
5862 params . set ( "page" , currentPage . toString ( ) ) ;
5963 }
64+ if ( limit !== 10 ) {
65+ params . set ( "limit" , limit . toString ( ) ) ;
66+ }
6067 window . history . pushState ( { } , "" , `?${ params . toString ( ) } ` ) ;
6168
6269 // Scroll to top when page changes
6370 window . scrollTo ( { top : 0 , behavior : "smooth" } ) ;
6471 }
65- } , [ currentPage , hasSearched , currentQuery ] ) ;
72+ } , [ currentPage , limit , hasSearched , currentQuery ] ) ;
6673
6774 // Typing animation effect
6875 useEffect ( ( ) => {
@@ -104,31 +111,30 @@ const Index = () => {
104111 } ;
105112 } , [ hasSearched ] ) ;
106113
107- const handleSearch = async ( query : string ) => {
114+ const handleSearch = async ( query : string , customLimit = limit ) => {
108115 setIsLoading ( true ) ;
109116 setError ( null ) ;
110117 setHasSearched ( true ) ;
111118 setCurrentQuery ( query ) ;
112- setCurrentPage ( 1 ) ; // Reset to page 1 on new search
119+ setCurrentPage ( 1 ) ;
113120 setAllResults ( [ ] ) ;
114-
115- // Scroll to top when searching
121+ setLimit ( customLimit ) ;
122+
116123 window . scrollTo ( { top : 0 , behavior : "smooth" } ) ;
117-
124+
118125 try {
119126 const response = await fetch (
120- `https ://127.0.0.1:8000/search?q=${ encodeURIComponent ( query ) } `
127+ `http ://127.0.0.1:8000/search?q=${ encodeURIComponent ( query ) } &limit= ${ customLimit } `
121128 ) ;
122-
129+
123130 if ( ! response . ok ) {
124131 throw new Error ( `Search failed: ${ response . statusText } ` ) ;
125132 }
126-
133+
127134 const data = await response . json ( ) ;
128-
129135 const searchResults = Array . isArray ( data ) ? data : data . results || [ ] ;
130136 setAllResults ( searchResults ) ;
131-
137+
132138 if ( searchResults . length === 0 ) {
133139 toast ( {
134140 title : "No results found" ,
@@ -138,12 +144,11 @@ const Index = () => {
138144 } catch ( err ) {
139145 const errorMessage =
140146 err instanceof Error ? err . message : "An unknown error occurred while searching" ;
141-
147+
142148 console . error ( "Search error:" , errorMessage ) ;
143-
144149 setError ( errorMessage ) ;
145150 setAllResults ( mockResults ) ;
146-
151+
147152 toast ( {
148153 title : "Search failed — showing mock results" ,
149154 description : "Backend request failed. Displaying demo data instead." ,
@@ -154,6 +159,14 @@ const Index = () => {
154159 }
155160 } ;
156161
162+ const handleLimitChange = ( newLimit : number ) => {
163+ setLimit ( newLimit ) ;
164+ if ( hasSearched && currentQuery ) {
165+ handleSearch ( currentQuery , newLimit ) ;
166+ }
167+ setShowSettings ( false ) ;
168+ } ;
169+
157170 const handlePageChange = ( newPage : number ) => {
158171 if ( newPage < 1 || newPage > totalPages ) return ;
159172 setCurrentPage ( newPage ) ;
@@ -197,6 +210,57 @@ const Index = () => {
197210
198211 return (
199212 < div className = "min-h-screen bg-background" >
213+ { /* Settings Button - Fixed Position */ }
214+ { hasSearched && (
215+ < div className = "fixed top-4 right-4 z-50" >
216+ < button
217+ onClick = { ( ) => setShowSettings ( ! showSettings ) }
218+ className = "p-2.5 rounded-lg bg-background border border-input hover:bg-accent transition-colors shadow-sm"
219+ aria-label = "Settings"
220+ >
221+ < Settings className = "h-5 w-5" />
222+ </ button >
223+
224+ { /* Settings Dropdown */ }
225+ { showSettings && (
226+ < >
227+ { /* Backdrop */ }
228+ < div
229+ className = "fixed inset-0 z-40"
230+ onClick = { ( ) => setShowSettings ( false ) }
231+ />
232+
233+ { /* Settings Panel */ }
234+ < div className = "absolute right-0 mt-2 w-64 bg-background border border-input rounded-lg shadow-lg p-4 z-50" >
235+ < h3 className = "font-semibold text-sm mb-3" > Search Settings</ h3 >
236+
237+ < div className = "space-y-2" >
238+ < label className = "text-sm text-muted-foreground" >
239+ Max. total results
240+ </ label >
241+ < div className = "grid grid-cols-2 gap-2" >
242+ { [ 10 , 25 , 50 , 100 ] . map ( ( l ) => (
243+ < button
244+ key = { l }
245+ onClick = { ( ) => handleLimitChange ( l ) }
246+ disabled = { isLoading }
247+ className = { `px-3 py-2 text-sm rounded-lg border transition-colors ${
248+ limit === l
249+ ? "bg-primary text-primary-foreground border-primary"
250+ : "border-input hover:bg-accent"
251+ } disabled:opacity-50 disabled:cursor-not-allowed`}
252+ >
253+ { l }
254+ </ button >
255+ ) ) }
256+ </ div >
257+ </ div >
258+ </ div >
259+ </ >
260+ ) }
261+ </ div >
262+ ) }
263+
200264 { /* Centered Landing View */ }
201265 { ! hasSearched && (
202266 < div className = "flex items-center justify-center min-h-screen px-4" >
0 commit comments