|
1 | 1 | import React, { useState, useEffect } from "react"; |
2 | 2 | import { Search, Filter, X } from "lucide-react"; |
3 | 3 | import { useSearch, useFavorites, useDebounce } from "../../hooks"; |
4 | | -import { useSettingsStore } from "../../stores/appStore"; |
5 | 4 | import SearchResultCard from "../ui/SearchResultCard"; |
6 | 5 | import SearchInput from "../ui/SearchInput"; |
7 | 6 | import LoadingSpinner from "../ui/LoadingSpinner"; |
8 | | -import EmptyState from "../ui/EmptyState"; |
9 | 7 | import Pagination from "../ui/Pagination"; |
10 | 8 | import CategoryFilter from "../ui/CategoryFilter"; |
| 9 | +import { |
| 10 | + PageLayout, |
| 11 | + PageHeader, |
| 12 | + PageContent, |
| 13 | + WelcomeState, |
| 14 | +} from "../ui/PageLayout"; |
| 15 | +import { useSettingsStore } from "../../stores/appStore"; |
11 | 16 |
|
12 | 17 | const SearchTab: React.FC = () => { |
13 | 18 | const [query, setQuery] = useState(""); |
@@ -61,20 +66,26 @@ const SearchTab: React.FC = () => { |
61 | 66 | const validationError = query ? validateQuery(query) : null; |
62 | 67 |
|
63 | 68 | return ( |
64 | | - <div className="h-full flex flex-col"> |
65 | | - {/* Enhanced Search Header - Fixed at top */} |
66 | | - <div className="px-6 py-4 bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700"> |
67 | | - <div className="flex items-center justify-between mb-4"> |
68 | | - <div className="flex items-center space-x-3"> |
69 | | - <div className="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-gradient-to-r from-blue-100 to-indigo-100 dark:from-blue-900/30 dark:to-indigo-900/30"> |
70 | | - <Search className="w-4 h-4 text-blue-600 dark:text-blue-400" /> |
| 69 | + <PageLayout> |
| 70 | + <PageHeader |
| 71 | + icon={Search} |
| 72 | + title="Search" |
| 73 | + subtitle="Find tools, libraries, and resources from awesome lists" |
| 74 | + colorTheme="blue" |
| 75 | + actions={ |
| 76 | + settings?.usePreprocessedSearch && ( |
| 77 | + <div className="flex items-center space-x-2 text-sm"> |
| 78 | + <div className="w-2 h-2 rounded-full bg-green-500 animate-pulse"></div> |
| 79 | + <span className="text-gray-600 dark:text-gray-400 font-medium"> |
| 80 | + Fast Search Enabled |
| 81 | + </span> |
71 | 82 | </div> |
72 | | - <h2 className="text-xl font-semibold bg-gradient-to-r from-gray-900 to-gray-700 dark:from-white dark:to-gray-200 bg-clip-text text-transparent"> |
73 | | - Search |
74 | | - </h2> |
75 | | - </div> |
76 | | - </div> |
| 83 | + ) |
| 84 | + } |
| 85 | + /> |
77 | 86 |
|
| 87 | + {/* Search Input Section */} |
| 88 | + <div className="px-6 py-4 bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700"> |
78 | 89 | <SearchInput |
79 | 90 | value={query} |
80 | 91 | onChange={setQuery} |
@@ -127,37 +138,34 @@ const SearchTab: React.FC = () => { |
127 | 138 | )} |
128 | 139 | </div> |
129 | 140 |
|
130 | | - {/* Main Content Area - Scrollable */} |
131 | | - <div className="flex-1 overflow-hidden"> |
| 141 | + <PageContent> |
132 | 142 | {/* Search Results */} |
133 | 143 | {showResults && ( |
134 | | - <div className="h-full overflow-y-auto px-6 py-6"> |
| 144 | + <> |
135 | 145 | {isLoading && ( |
136 | 146 | <div className="flex justify-center py-12"> |
137 | 147 | <LoadingSpinner size="lg" /> |
138 | 148 | </div> |
139 | 149 | )} |
140 | 150 |
|
141 | 151 | {isError && ( |
142 | | - <div className="text-center py-12"> |
143 | | - <div className="inline-flex items-center justify-center w-12 h-12 rounded-full bg-red-100 dark:bg-red-900/30 mb-4"> |
144 | | - <X className="w-6 h-6 text-red-600 dark:text-red-400" /> |
145 | | - </div> |
146 | | - <h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2"> |
147 | | - Search Error |
148 | | - </h3> |
149 | | - <p className="text-gray-600 dark:text-gray-400"> |
150 | | - {error?.message || |
151 | | - "Something went wrong while searching. Please try again."} |
152 | | - </p> |
153 | | - </div> |
| 152 | + <WelcomeState |
| 153 | + icon={X} |
| 154 | + title="Search Error" |
| 155 | + description={ |
| 156 | + error?.message || |
| 157 | + "Something went wrong while searching. Please try again." |
| 158 | + } |
| 159 | + colorTheme="red" |
| 160 | + /> |
154 | 161 | )} |
155 | 162 |
|
156 | 163 | {!isLoading && !isError && !hasResults && ( |
157 | | - <EmptyState |
158 | | - icon={<Search className="w-12 h-12" />} |
| 164 | + <WelcomeState |
| 165 | + icon={Search} |
159 | 166 | title="No results found" |
160 | 167 | description={`No results found for "${debouncedQuery}". Try adjusting your search terms or removing filters.`} |
| 168 | + colorTheme="blue" |
161 | 169 | /> |
162 | 170 | )} |
163 | 171 |
|
@@ -210,53 +218,30 @@ const SearchTab: React.FC = () => { |
210 | 218 | )} |
211 | 219 | </> |
212 | 220 | )} |
213 | | - </div> |
| 221 | + </> |
214 | 222 | )} |
215 | 223 |
|
216 | 224 | {/* Enhanced Welcome State */} |
217 | 225 | {!debouncedQuery && ( |
218 | | - <div className="h-full flex items-center justify-center px-6 py-6"> |
219 | | - <div className="text-center space-y-8 max-w-2xl"> |
220 | | - <div className="inline-flex items-center justify-center w-24 h-24 rounded-2xl bg-gradient-to-br from-blue-100 to-indigo-100 dark:from-blue-900/30 dark:to-indigo-900/30 border border-blue-200/50 dark:border-blue-700/50 shadow-lg"> |
221 | | - <Search className="w-12 h-12 text-blue-600 dark:text-blue-400" /> |
222 | | - </div> |
223 | | - <div> |
224 | | - <h3 className="text-2xl font-bold bg-gradient-to-r from-gray-900 to-gray-700 dark:from-white dark:to-gray-200 bg-clip-text text-transparent mb-3"> |
225 | | - Start searching |
226 | | - </h3> |
227 | | - <p className="text-gray-600 dark:text-gray-400 text-lg leading-relaxed"> |
228 | | - Enter a search query above to find tools, libraries, and |
229 | | - resources from awesome lists. |
230 | | - </p> |
231 | | - </div> |
232 | | - |
233 | | - <div className="flex flex-col items-center gap-4"> |
234 | | - <span className="text-sm font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wide"> |
235 | | - Try searching for: |
236 | | - </span> |
237 | | - <div className="flex flex-wrap justify-center gap-3"> |
238 | | - {[ |
239 | | - "React", |
240 | | - "Python", |
241 | | - "Machine Learning", |
242 | | - "DevOps", |
243 | | - "Design", |
244 | | - ].map((term) => ( |
245 | | - <button |
246 | | - key={term} |
247 | | - onClick={() => setQuery(term)} |
248 | | - className="px-4 py-2 bg-gradient-to-r from-gray-100 to-gray-200 dark:from-gray-800 dark:to-gray-700 text-gray-700 dark:text-gray-300 rounded-xl hover:from-blue-100 hover:to-indigo-100 dark:hover:from-blue-900/30 dark:hover:to-indigo-900/30 hover:text-blue-700 dark:hover:text-blue-300 transition-all duration-200 font-medium shadow-sm hover:shadow-md border border-gray-200/50 dark:border-gray-600/50" |
249 | | - > |
250 | | - {term} |
251 | | - </button> |
252 | | - ))} |
253 | | - </div> |
254 | | - </div> |
255 | | - </div> |
256 | | - </div> |
| 226 | + <WelcomeState |
| 227 | + icon={Search} |
| 228 | + title="Start searching" |
| 229 | + description="Enter a search query above to find tools, libraries, and resources from awesome lists." |
| 230 | + colorTheme="blue" |
| 231 | + suggestions={[ |
| 232 | + { label: "React", onClick: () => setQuery("React") }, |
| 233 | + { label: "Python", onClick: () => setQuery("Python") }, |
| 234 | + { |
| 235 | + label: "Machine Learning", |
| 236 | + onClick: () => setQuery("Machine Learning"), |
| 237 | + }, |
| 238 | + { label: "DevOps", onClick: () => setQuery("DevOps") }, |
| 239 | + { label: "Design", onClick: () => setQuery("Design") }, |
| 240 | + ]} |
| 241 | + /> |
257 | 242 | )} |
258 | | - </div> |
259 | | - </div> |
| 243 | + </PageContent> |
| 244 | + </PageLayout> |
260 | 245 | ); |
261 | 246 | }; |
262 | 247 |
|
|
0 commit comments