2026-02-06 23:01:30 -05:00

78 lines
2.0 KiB
TypeScript

'use client';
import { useState, useEffect, useRef, useCallback } from 'react';
import { Search, X } from 'lucide-react';
interface TemplateSearchProps {
onSearch: (query: string) => void;
placeholder?: string;
initialValue?: string;
}
export function TemplateSearch({
onSearch,
placeholder = 'Search templates...',
initialValue = '',
}: TemplateSearchProps) {
const [value, setValue] = useState(initialValue);
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const inputRef = useRef<HTMLInputElement>(null);
const debouncedSearch = useCallback(
(q: string) => {
if (timerRef.current) clearTimeout(timerRef.current);
timerRef.current = setTimeout(() => {
onSearch(q);
}, 300);
},
[onSearch],
);
useEffect(() => {
return () => {
if (timerRef.current) clearTimeout(timerRef.current);
};
}, []);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const q = e.target.value;
setValue(q);
debouncedSearch(q);
};
const handleClear = () => {
setValue('');
onSearch('');
inputRef.current?.focus();
};
return (
<div className="relative w-full">
<Search className="absolute left-4 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-500 pointer-events-none" />
<input
ref={inputRef}
type="text"
value={value}
onChange={handleChange}
placeholder={placeholder}
className="
w-full pl-11 pr-10 py-3 rounded-full
bg-gray-800 border border-gray-700
text-gray-100 placeholder-gray-500
focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent
transition-all duration-200
"
/>
{value && (
<button
onClick={handleClear}
className="absolute right-3 top-1/2 -translate-y-1/2 p-1 rounded-full
text-gray-500 hover:text-gray-300 hover:bg-gray-700 transition-colors"
>
<X className="h-4 w-4" />
</button>
)}
</div>
);
}