File size: 5,044 Bytes
42bbfb1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
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:text-blue-300 group-hover:underline mb-1 line-clamp-1">
                  {result.title}
                </h3>
                <ExternalLink className="w-4 h-4 text-slate-600 flex-shrink-0 mt-1" />
              </div>
              <p className="text-sm text-slate-400 line-clamp-2 leading-relaxed">
                {result.content || result.snippet}
              </p>
              <span className="text-xs text-slate-600 mt-2 block truncate">
                {result.url}
              </span>
            </a>
          ))
        ) : query === '' ? (
          <div className="text-center py-12">
            <Search className="w-12 h-12 text-slate-700 mx-auto mb-3" />
            <p className="text-slate-500 text-sm">Enter a query to search the web.</p>
          </div>
        ) : (
          <div className="text-center py-12">
            <p className="text-slate-500 text-sm">No results found.</p>
          </div>
        )}
      </div>
    </div>
  );
}