Skip to content

Commit b3e1048

Browse files
committed
refactor(Search): improve search UX with loader timing and state management
Enhance the search experience by ensuring the loader is displayed for a minimum duration to avoid flickering. Additionally, introduce a `hasSearched` state to accurately display "No results found" only after a search has been performed.
1 parent fcaf8f6 commit b3e1048

File tree

1 file changed

+15
-4
lines changed

1 file changed

+15
-4
lines changed

app/components/workbench/Search.tsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import type { TextSearchOptions, TextSearchOnProgressCallback, WebContainer } fr
33
import { workbenchStore } from '~/lib/stores/workbench';
44
import { webcontainer } from '~/lib/webcontainer';
55
import { WORK_DIR } from '~/utils/constants';
6-
import { Loader2 } from 'lucide-react';
76
import { debounce } from '~/utils/debounce';
87

98
interface DisplayMatch {
@@ -94,6 +93,7 @@ export function Search() {
9493
const [searchResults, setSearchResults] = useState<DisplayMatch[]>([]);
9594
const [isSearching, setIsSearching] = useState(false);
9695
const [expandedFiles, setExpandedFiles] = useState<Record<string, boolean>>({});
96+
const [hasSearched, setHasSearched] = useState(false);
9797

9898
const groupedResults = useMemo(() => groupResultsByFile(searchResults), [searchResults]);
9999

@@ -112,13 +112,18 @@ export function Search() {
112112
setSearchResults([]);
113113
setIsSearching(false);
114114
setExpandedFiles({});
115+
setHasSearched(false);
115116

116117
return;
117118
}
118119

119120
setIsSearching(true);
120121
setSearchResults([]);
121122
setExpandedFiles({});
123+
setHasSearched(true);
124+
125+
const minLoaderTime = 300; // ms
126+
const start = Date.now();
122127

123128
try {
124129
const instance = await webcontainer;
@@ -144,7 +149,13 @@ export function Search() {
144149
} catch (error) {
145150
console.error('Failed to initiate search:', error);
146151
} finally {
147-
setIsSearching(false);
152+
const elapsed = Date.now() - start;
153+
154+
if (elapsed < minLoaderTime) {
155+
setTimeout(() => setIsSearching(false), minLoaderTime - elapsed);
156+
} else {
157+
setIsSearching(false);
158+
}
148159
}
149160
}, []);
150161

@@ -178,10 +189,10 @@ export function Search() {
178189
<div className="flex-1 overflow-auto py-2">
179190
{isSearching && (
180191
<div className="flex items-center justify-center h-32 text-bolt-elements-textTertiary">
181-
<Loader2 className="animate-spin mr-2" /> Searching...
192+
<div className="i-ph:circle-notch animate-spin mr-2" /> Searching...
182193
</div>
183194
)}
184-
{!isSearching && searchResults.length === 0 && (
195+
{!isSearching && hasSearched && searchResults.length === 0 && searchQuery.trim() !== '' && (
185196
<div className="flex items-center justify-center h-32 text-gray-500">No results found.</div>
186197
)}
187198
{!isSearching &&

0 commit comments

Comments
 (0)