A quick vibe-coded site to test response times of PLC.directory mirrors (over 3 attempts)
1import { useState } from "react";
2import { Button } from "@/components/ui/button";
3import { Input } from "@/components/ui/input";
4import { BenchmarkTable } from "@/components/BenchmarkTable";
5import { mirrors } from "@/config/mirrors";
6import { benchmarkAllMirrors } from "@/utils/benchmark";
7import { BenchmarkResult } from "@/types/benchmark";
8import { toast } from "sonner";
9import { Activity, Zap } from "lucide-react";
10
11const Index = () => {
12 const [did, setDid] = useState("");
13 const [loading, setLoading] = useState(false);
14 const [results, setResults] = useState<BenchmarkResult[]>([]);
15
16 const handleBenchmark = async () => {
17 if (!did.trim()) {
18 toast.error("Please enter a DID");
19 return;
20 }
21
22 setLoading(true);
23 setResults([]);
24
25 try {
26 const benchmarkResults = await benchmarkAllMirrors(mirrors, did.trim());
27 setResults(benchmarkResults);
28
29 const successCount = benchmarkResults.filter(r => r.status === "success").length;
30 toast.success(`Benchmark complete! ${successCount}/${benchmarkResults.length} mirrors responded`);
31 } catch (error) {
32 toast.error("Failed to run benchmark");
33 console.error(error);
34 } finally {
35 setLoading(false);
36 }
37 };
38
39 const handleKeyPress = (e: React.KeyboardEvent) => {
40 if (e.key === "Enter" && !loading) {
41 handleBenchmark();
42 }
43 };
44
45 return (
46 <div className="min-h-screen bg-background py-8 px-4">
47 <div className="max-w-6xl mx-auto space-y-8">
48 {/* Header */}
49 <header className="text-center space-y-3">
50 <div className="flex items-center justify-center gap-2 text-primary">
51 <Activity className="w-8 h-8" />
52 <h1 className="text-4xl font-bold">PLC Mirror Benchmark</h1>
53 </div>
54 <p className="text-muted-foreground text-lg max-w-2xl mx-auto">
55 Test and compare response times across different PLC.directory mirrors
56 </p>
57 </header>
58
59 {/* Input Section */}
60 <div className="bg-card border border-border rounded-lg p-6 shadow-sm">
61 <div className="space-y-4">
62 <div>
63 <label htmlFor="did-input" className="block text-sm font-medium mb-2">
64 ATProto DID
65 </label>
66 <div className="flex gap-3">
67 <Input
68 id="did-input"
69 type="text"
70 placeholder="did:plc:example123..."
71 value={did}
72 onChange={(e) => setDid(e.target.value)}
73 onKeyPress={handleKeyPress}
74 className="flex-1 font-mono"
75 disabled={loading}
76 />
77 <Button
78 onClick={handleBenchmark}
79 disabled={loading || !did.trim()}
80 className="gap-2"
81 >
82 <Zap className="w-4 h-4" />
83 {loading ? "Benchmarking..." : "Run Benchmark"}
84 </Button>
85 </div>
86 </div>
87 <div className="text-sm text-muted-foreground">
88 Testing {mirrors.length} mirrors with 3 attempts each
89 </div>
90 </div>
91 </div>
92
93 {/* Results Section */}
94 {(results.length > 0 || loading) && (
95 <div className="space-y-4">
96 <h2 className="text-2xl font-semibold">Results</h2>
97 {loading ? (
98 <div className="bg-card border border-border rounded-lg p-12 text-center">
99 <div className="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-primary mb-4"></div>
100 <p className="text-muted-foreground">Benchmarking mirrors...</p>
101 </div>
102 ) : (
103 <BenchmarkTable results={results} />
104 )}
105 </div>
106 )}
107
108 {/* Info Section */}
109 {results.length === 0 && !loading && (
110 <div className="bg-muted/30 border border-border rounded-lg p-6">
111 <h3 className="font-semibold mb-2">How to use:</h3>
112 <ol className="list-decimal list-inside space-y-1 text-sm text-muted-foreground">
113 <li>Enter an ATProto DID (e.g., did:plc:z72i7hdynmk6r22z27h6tvur)</li>
114 <li>Click "Run Benchmark" or press Enter</li>
115 <li>View response times and status for each mirror</li>
116 </ol>
117 <div className="mt-4 pt-4 border-t border-border">
118 <p className="text-sm text-muted-foreground">
119 Mirrors can be configured in <code className="bg-background px-2 py-1 rounded text-mono">src/config/mirrors.ts</code>
120 </p>
121 </div>
122 </div>
123 )}
124 </div>
125 </div>
126 );
127};
128
129export default Index;