This commit is contained in:
2026-02-16 19:34:35 +00:00
commit 9ab0940ca4
784 changed files with 41710 additions and 0 deletions
+70
View File
@@ -0,0 +1,70 @@
import { useRef, useState } from 'react';
import { Button } from '@/components/ui/button';
import { Search as SearchIcon, X as ClearIcon } from 'lucide-react';
import { Input } from '@/components/ui/input';
import { cn } from 'helpers/cn';
type SearchInputProps = {
className?: string;
handleSearch: (value: string) => void;
value?: string;
placeholder?: string;
};
export function SearchInput(props: SearchInputProps) {
const { className, handleSearch, value = '', placeholder = 'Search' } = props;
const [isMobileSearchOpen, setIsMobileSearchOpen] = useState(false);
const inputRef = useRef<HTMLInputElement | null>(null);
return (
<div className={cn(isMobileSearchOpen && 'h-24 md:h-auto')}>
<Button
type="button"
variant="outline"
size="icon"
aria-label={isMobileSearchOpen ? 'Close search' : 'Open search'}
onClick={() => {
setIsMobileSearchOpen((v) => !v);
if (!isMobileSearchOpen) {
setTimeout(() => inputRef.current?.focus(), 160);
}
}}
className="ml-auto shrink-0 md:hidden"
>
{isMobileSearchOpen ? <ClearIcon className="h-5 w-5" /> : <SearchIcon className="h-5 w-5" />}
</Button>
<div
className={cn(
'relative w-fit max-w-lg',
isMobileSearchOpen
? 'absolute left-0 mt-4 block w-full md:relative md:mt-0 md:w-fit'
: 'hidden w-auto md:block',
className,
)}
>
{!!value ? (
<button
type="button"
aria-label="Clear search"
onClick={() => handleSearch('')}
className="absolute left-3 top-1/2 -translate-y-1/2 z-10 rounded p-1 hover:bg-muted"
>
<ClearIcon className="h-4 w-4 text-muted-foreground" />
</button>
) : (
<span className="pointer-events-none absolute left-3 top-1/2 z-10 -translate-y-1/2">
<SearchIcon className="text-muted-foreground h-4 w-4" />
</span>
)}
<Input
ref={inputRef}
placeholder={placeholder}
value={value}
onChange={(ev) => handleSearch(ev.target.value)}
className="pl-10 pr-4 text-sm"
/>
</div>
</div>
);
}