anycoder-f91ecd1a / components /SearchEngine.js
00Boobs00's picture
Upload components/SearchEngine.js with huggingface_hub
6cb2d31 verified
import { useState } from 'react';
import { Search, Globe, Zap, ExternalLink } from 'lucide-react';
export default function SearchEngine() {
const [query, setQuery] = useState('');
const [engine, setEngine] = useState('tavily');
const [results, setResults] = useState([]);
const [loading, setLoading] = useState(false);
const handleSearch = async (e) => {
e.preventDefault();
if (!query.trim()) return;
setLoading(true);
setResults([]);
try {
const res = await fetch('/api/search', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, engine }),
});
const data = await res.json();
setResults(data.results || []);
} catch (err) {
console.error('Search failed', err);
setResults([]);
} finally {
setLoading(false);
}
};
return (
<div className="bg-slate-800 rounded-xl p-6 shadow-xl border border-slate-700">
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between mb-4 gap-3">
<div className="flex items-center gap-2">
<Search className="w-5 h-5 text-yellow-500" />
<h2 className="text-lg font-semibold text-white">Unified Search</h2>
</div>
<div className="flex bg-slate-900 rounded-lg p-1 border border-slate-600 w-full sm:w-auto">
<button
onClick={() => setEngine('tavily')}
className={`flex-1 sm:flex-none px-3 py-1.5 rounded-md text-sm flex items-center justify-center gap-1.5 transition-all ${
engine === 'tavily'
? 'bg-yellow-600 text-white shadow-md'
: 'text-slate-400 hover:text-white hover:bg-slate-800'
}`}
>
<Zap className="w-3 h-3" /> Tavily
</button>
<button
onClick={() => setEngine('searxng')}
className={`flex-1 sm:flex-none px-3 py-1.5 rounded-md text-sm flex items-center justify-center gap-1.5 transition-all ${
engine === 'searxng'
? 'bg-yellow-600 text-white shadow-md'
: 'text-slate-400 hover:text-white hover:bg-slate-800'
}`}
>
<Globe className="w-3 h-3" /> SearXNG
</button>
</div>
</div>
<form onSubmit={handleSearch} className="relative mb-6">
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder={`Search using ${engine === 'tavily' ? 'Tavily AI' : 'SearXNG'}...`}
className="w-full bg-slate-900 border border-slate-600 rounded-lg pl-10 pr-4 py-3 text-white placeholder-slate-500 focus:ring-2 focus:ring-yellow-500 focus:border-transparent outline-none transition-all"
/>
<button
type="submit"
disabled={loading}
className="absolute right-2 top-2 bg-yellow-600 hover:bg-yellow-500 text-white p-1.5 rounded-md transition-colors disabled:opacity-50"
>
<Search className="w-5 h-5" />
</button>
</form>
<div className="space-y-3 max-h-96 overflow-y-auto pr-2">
{loading ? (
<div className="flex flex-col items-center justify-center py-12 text-slate-400 gap-2">
<div className="w-8 h-8 border-4 border-slate-700 border-t-yellow-500 rounded-full animate-spin" />
<span className="text-sm">Searching the web...</span>
</div>
) : results.length > 0 ? (
results.map((result, i) => (
<a
key={i}
href={result.url}
target="_blank"
rel="noopener noreferrer"
className="block p-4 bg-slate-900 rounded-lg border border-slate-700 hover:border-yellow-600/50 hover:bg-slate-850 hover:shadow-lg hover:shadow-yellow-900/10 transition-all group"
>
<div className="flex items-start justify-between gap-2">
<h3 className="text-blue-400 font-medium group-hover