File size: 3,937 Bytes
3270c21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import { useState } from 'react';
import { Search, Globe, Zap } from 'lucide-react';

export default function SearchEngine() {
  const [query, setQuery] = useState('');
  const [engine, setEngine] = useState('tavily'); // 'tavily' or 'searxng'
  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);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="bg-slate-800 rounded-xl p-6 shadow-xl border border-slate-700">
      <div className="flex items-center justify-between mb-4">
        <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">
          <button
            onClick={() => setEngine('tavily')}
            className={`px-3 py-1 rounded-md text-sm flex items-center gap-1.5 transition-all ${
              engine === 'tavily' 
                ? 'bg-yellow-600 text-white' 
                : 'text-slate-400 hover:text-white'
            }`}
          >
            <Zap className="w-3 h-3" /> Tavily
          </button>
          <button
            onClick={() => setEngine('searxng')}
            className={`px-3 py-1 rounded-md text-sm flex items-center gap-1.5 transition-all ${
              engine === 'searxng' 
                ? 'bg-yellow-600 text-white' 
                : 'text-slate-400 hover:text-white'
            }`}
          >
            <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"
        />
        <Search className="absolute left-3 top-3.5 w-5 h-5 text-slate-500" />
      </form>

      <div className="space-y-3 max-h-80 overflow-y-auto pr-2 custom-scrollbar">
        {loading ? (
          <div className="flex items-center justify-center py-8 text-slate-400">
            Searching...
          </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-slate-500 hover:bg-slate-850 transition-all group"
            >
              <h3 className="text-blue-400 font-medium group-hover:underline mb-1">
                {result.title}
              </h3>
              <p className="text-sm text-slate-400 line-clamp-2">
                {result.content || result.snippet}
              </p>
              <span className="text-xs text-slate-600 mt-2 block truncate">
                {result.url}
              </span>
            </a>
          ))
        ) : (
          <p className="text-slate-500 text-sm text-center py-4">
            Enter a query to search the web.
          </p>
        )}
      </div>
    </div>
  );
}