55 lines
2.3 KiB
TypeScript
55 lines
2.3 KiB
TypeScript
import { useState, useRef, useEffect } from 'react';
|
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
import { SearchDropdown } from './search-dropdown';
|
|
import { MagnifyingGlassIcon, XMarkIcon } from '@heroicons/react/24/outline';
|
|
import { useClickOutside } from '@web/src/hooks/useClickOutside';
|
|
|
|
interface SearchBarProps {
|
|
recentSearches: string[];
|
|
}
|
|
|
|
export function SearchBar({ recentSearches }: SearchBarProps) {
|
|
const [searchFocused, setSearchFocused] = useState(false);
|
|
const [searchQuery, setSearchQuery] = useState('');
|
|
const searchRef = useRef<HTMLDivElement>(null);
|
|
useClickOutside(searchRef, () => setSearchFocused(false))
|
|
return (
|
|
<div ref={searchRef} className="relative max-w-xl w-full px-4">
|
|
<div className={`
|
|
relative flex items-center w-full h-10 rounded-full
|
|
transition-all duration-300 ease-in-out
|
|
${searchFocused
|
|
? 'bg-white shadow-md ring-2 ring-blue-500'
|
|
: 'bg-gray-100 hover:bg-gray-200'
|
|
}
|
|
`}>
|
|
<MagnifyingGlassIcon className="h-5 w-5 ml-3 text-gray-500" />
|
|
<input
|
|
type="text"
|
|
placeholder="Search for courses, topics, or instructors..."
|
|
className="w-full h-full bg-transparent px-3 outline-none text-sm"
|
|
onFocus={() => setSearchFocused(true)}
|
|
value={searchQuery}
|
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
/>
|
|
{searchQuery && (
|
|
<motion.button
|
|
initial={{ opacity: 0, scale: 0.8 }}
|
|
animate={{ opacity: 1, scale: 1 }}
|
|
exit={{ opacity: 0, scale: 0.8 }}
|
|
className="p-1.5 mr-2 rounded-full hover:bg-gray-200"
|
|
onClick={() => setSearchQuery('')}
|
|
>
|
|
<XMarkIcon className="h-4 w-4 text-gray-500" />
|
|
</motion.button>
|
|
)}
|
|
</div>
|
|
<SearchDropdown
|
|
searchFocused={searchFocused}
|
|
searchQuery={searchQuery}
|
|
recentSearches={recentSearches}
|
|
setSearchQuery={setSearchQuery}
|
|
/>
|
|
</div>
|
|
);
|
|
} |