mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 18:26:38 +00:00
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.
This commit is contained in:
parent
fcaf8f66f0
commit
b3e1048fa4
@ -3,7 +3,6 @@ import type { TextSearchOptions, TextSearchOnProgressCallback, WebContainer } fr
|
|||||||
import { workbenchStore } from '~/lib/stores/workbench';
|
import { workbenchStore } from '~/lib/stores/workbench';
|
||||||
import { webcontainer } from '~/lib/webcontainer';
|
import { webcontainer } from '~/lib/webcontainer';
|
||||||
import { WORK_DIR } from '~/utils/constants';
|
import { WORK_DIR } from '~/utils/constants';
|
||||||
import { Loader2 } from 'lucide-react';
|
|
||||||
import { debounce } from '~/utils/debounce';
|
import { debounce } from '~/utils/debounce';
|
||||||
|
|
||||||
interface DisplayMatch {
|
interface DisplayMatch {
|
||||||
@ -94,6 +93,7 @@ export function Search() {
|
|||||||
const [searchResults, setSearchResults] = useState<DisplayMatch[]>([]);
|
const [searchResults, setSearchResults] = useState<DisplayMatch[]>([]);
|
||||||
const [isSearching, setIsSearching] = useState(false);
|
const [isSearching, setIsSearching] = useState(false);
|
||||||
const [expandedFiles, setExpandedFiles] = useState<Record<string, boolean>>({});
|
const [expandedFiles, setExpandedFiles] = useState<Record<string, boolean>>({});
|
||||||
|
const [hasSearched, setHasSearched] = useState(false);
|
||||||
|
|
||||||
const groupedResults = useMemo(() => groupResultsByFile(searchResults), [searchResults]);
|
const groupedResults = useMemo(() => groupResultsByFile(searchResults), [searchResults]);
|
||||||
|
|
||||||
@ -112,6 +112,7 @@ export function Search() {
|
|||||||
setSearchResults([]);
|
setSearchResults([]);
|
||||||
setIsSearching(false);
|
setIsSearching(false);
|
||||||
setExpandedFiles({});
|
setExpandedFiles({});
|
||||||
|
setHasSearched(false);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -119,6 +120,10 @@ export function Search() {
|
|||||||
setIsSearching(true);
|
setIsSearching(true);
|
||||||
setSearchResults([]);
|
setSearchResults([]);
|
||||||
setExpandedFiles({});
|
setExpandedFiles({});
|
||||||
|
setHasSearched(true);
|
||||||
|
|
||||||
|
const minLoaderTime = 300; // ms
|
||||||
|
const start = Date.now();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const instance = await webcontainer;
|
const instance = await webcontainer;
|
||||||
@ -144,8 +149,14 @@ export function Search() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to initiate search:', error);
|
console.error('Failed to initiate search:', error);
|
||||||
} finally {
|
} finally {
|
||||||
|
const elapsed = Date.now() - start;
|
||||||
|
|
||||||
|
if (elapsed < minLoaderTime) {
|
||||||
|
setTimeout(() => setIsSearching(false), minLoaderTime - elapsed);
|
||||||
|
} else {
|
||||||
setIsSearching(false);
|
setIsSearching(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const debouncedSearch = useCallback(debounce(handleSearch, 300), [handleSearch]);
|
const debouncedSearch = useCallback(debounce(handleSearch, 300), [handleSearch]);
|
||||||
@ -178,10 +189,10 @@ export function Search() {
|
|||||||
<div className="flex-1 overflow-auto py-2">
|
<div className="flex-1 overflow-auto py-2">
|
||||||
{isSearching && (
|
{isSearching && (
|
||||||
<div className="flex items-center justify-center h-32 text-bolt-elements-textTertiary">
|
<div className="flex items-center justify-center h-32 text-bolt-elements-textTertiary">
|
||||||
<Loader2 className="animate-spin mr-2" /> Searching...
|
<div className="i-ph:circle-notch animate-spin mr-2" /> Searching...
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!isSearching && searchResults.length === 0 && (
|
{!isSearching && hasSearched && searchResults.length === 0 && searchQuery.trim() !== '' && (
|
||||||
<div className="flex items-center justify-center h-32 text-gray-500">No results found.</div>
|
<div className="flex items-center justify-center h-32 text-gray-500">No results found.</div>
|
||||||
)}
|
)}
|
||||||
{!isSearching &&
|
{!isSearching &&
|
||||||
|
Loading…
Reference in New Issue
Block a user