diff --git a/frontend/src/components/bounty/SearchBar.tsx b/frontend/src/components/bounty/SearchBar.tsx new file mode 100644 index 000000000..b0fdd64a8 --- /dev/null +++ b/frontend/src/components/bounty/SearchBar.tsx @@ -0,0 +1,86 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { Search, X } from 'lucide-react'; +import { motion, AnimatePresence } from 'framer-motion'; + +interface SearchBarProps { + placeholder?: string; + onSearch: (query: string) => void; + suggestions?: string[]; + className?: string; +} + +export function SearchBar({ placeholder = 'Search bounties...', onSearch, suggestions = [], className = '' }: SearchBarProps) { + const [query, setQuery] = useState(''); + const [showSuggestions, setShowSuggestions] = useState(false); + const [filteredSuggestions, setFilteredSuggestions] = useState([]); + const inputRef = useRef(null); + const wrapperRef = useRef(null); + + useEffect(() => { + const handler = (e: MouseEvent) => { + if (wrapperRef.current && !wrapperRef.current.contains(e.target as Node)) { + setShowSuggestions(false); + } + }; + document.addEventListener('mousedown', handler); + return () => document.removeEventListener('mousedown', handler); + }, []); + + useEffect(() => { + if (query.length > 0 && suggestions.length > 0) { + setFilteredSuggestions(suggestions.filter(s => s.toLowerCase().includes(query.toLowerCase())).slice(0, 5)); + setShowSuggestions(true); + } else { + setShowSuggestions(false); + } + }, [query, suggestions]); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + onSearch(query); + setShowSuggestions(false); + }; + + const selectSuggestion = (s: string) => { + setQuery(s); + onSearch(s); + setShowSuggestions(false); + }; + + return ( +
+
+ + setQuery(e.target.value)} + placeholder={placeholder} + className="w-full bg-forge-900 border border-border rounded-lg pl-10 pr-10 py-2.5 text-sm text-text-primary placeholder-text-muted focus:outline-none focus:border-emerald/50 focus:ring-1 focus:ring-emerald/20 transition-colors" + /> + {query && ( + + )} + + + {showSuggestions && filteredSuggestions.length > 0 && ( + + {filteredSuggestions.map((s) => ( + + ))} + + )} + +
+ ); +} \ No newline at end of file