feat(All): 第一版项目

This commit is contained in:
2025-12-19 09:33:04 +08:00
parent 154132f17e
commit 2f6831336e
35 changed files with 5120 additions and 0 deletions

58
src/client/App.tsx Normal file
View File

@@ -0,0 +1,58 @@
import { useState, useCallback } from 'react'
import { ThemeProvider } from './contexts/ThemeContext'
import ThemeSwitcher from './components/ThemeSwitcher'
import IpInput from './components/IpInput'
import LatencyMap from './components/LatencyMap'
import ResultsPanel from './components/ResultsPanel'
import { testAllNodes } from './api/latency'
import { LatencyResult } from '@shared/types'
import './styles/index.css'
function AppContent() {
const [results, setResults] = useState<Map<string, LatencyResult>>(new Map())
const [testing, setTesting] = useState(false)
const handleTest = useCallback(async (ip: string) => {
setTesting(true)
setResults(new Map())
await testAllNodes(ip, (result) => {
setResults((prev) => new Map(prev).set(result.nodeId, result))
})
setTesting(false)
}, [])
return (
<div className="app">
<header className="app-header">
<h1 className="app-title">
<span className="title-icon">🌐</span>
Latency Test
</h1>
<ThemeSwitcher />
</header>
<main className="app-main">
<p className="app-description">
Test network latency from global locations to any IP address
</p>
<IpInput onTest={handleTest} testing={testing} />
<LatencyMap results={results} />
<ResultsPanel results={results} />
</main>
<footer className="app-footer">
<p>Latency thresholds: <span className="excellent"></span> &lt;50ms <span className="good"></span> 50-150ms <span className="poor"></span> &gt;150ms</p>
</footer>
</div>
)
}
export default function App() {
return (
<ThemeProvider>
<AppContent />
</ThemeProvider>
)
}