speedtest / templates /index.html
triflix's picture
Upload 6 files
38dfb36 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Speed Test - Glassmorphism UI</title>
<!-- Optional: Font Awesome for icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- Google Font for a clean, modern feel -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap">
<style>
/* -----------------------------
BASIC RESET & BODY STYLING
------------------------------*/
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
background: linear-gradient(to right, #0a0b0d, #17181b);
color: #fff;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: flex-start;
padding: 2rem;
}
/* -----------------------------
DASHBOARD GRID
------------------------------*/
.dashboard {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 1.5rem;
max-width: 1200px;
width: 100%;
}
/* -----------------------------
GLASSMORPHISM CARD BASE
------------------------------*/
.card {
position: relative;
background: rgba(255, 255, 255, 0.05);
border-radius: 1rem;
overflow: hidden;
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
box-shadow: 0 8px 32px rgba(0,0,0,0.4);
display: flex;
flex-direction: column;
padding: 1.5rem;
}
.card::before {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.02), rgba(255, 153, 0, 0.08));
pointer-events: none;
mix-blend-mode: overlay;
}
.card h2, .card h3, .card h4, .card h5, .card p {
position: relative;
margin-bottom: 0.4rem;
}
.card h2, .card h3 {
font-weight: 500;
}
/* -----------------------------
1) DOWNLOAD SPEED CARD
------------------------------*/
.download-card .metric-value {
font-size: 2rem;
font-weight: 700;
margin-bottom: 0.2rem;
}
.download-card .sub-info {
font-size: 0.85rem;
opacity: 0.7;
margin-bottom: 0.6rem;
}
.download-card .download-icon {
font-size: 2rem;
color: #ff9900;
margin-bottom: 1rem;
}
/* -----------------------------
2) UPLOAD SPEED CARD
------------------------------*/
.upload-card .metric-value {
font-size: 2rem;
font-weight: 700;
margin-bottom: 0.2rem;
}
.upload-card .sub-info {
font-size: 0.85rem;
opacity: 0.7;
margin-bottom: 0.6rem;
}
.upload-card .upload-icon {
font-size: 2rem;
color: #ff9900;
margin-bottom: 1rem;
}
/* -----------------------------
3) PING CARD
------------------------------*/
.ping-card .metric-value {
font-size: 2rem;
font-weight: 700;
margin-bottom: 0.2rem;
}
.ping-card .sub-info {
font-size: 0.85rem;
opacity: 0.7;
margin-bottom: 0.6rem;
}
.ping-card .ping-icon {
font-size: 2rem;
color: #ff9900;
margin-bottom: 1rem;
}
/* -----------------------------
4) START TEST CARD (Large, center focus)
------------------------------*/
.start-test-card {
background: url('https://via.placeholder.com/300x400?text=SpeedTest+Blur') center/cover no-repeat;
background-blend-mode: overlay;
background-color: rgba(0,0,0,0.5);
display: flex;
flex-direction: column;
justify-content: flex-end;
color: #fff;
text-align: center;
padding: 2rem;
}
.start-test-card h3 {
font-size: 1.3rem;
margin-bottom: 0.4rem;
}
.start-test-card p {
font-size: 0.9rem;
opacity: 0.8;
margin-bottom: 1.2rem;
}
.start-btn {
display: inline-block;
background-color: rgba(255,255,255,0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
padding: 0.8rem 1.2rem;
border-radius: 0.5rem;
color: #fff;
font-size: 1rem;
cursor: pointer;
transition: background 0.3s;
}
.start-btn:hover {
background-color: rgba(255, 153, 0, 0.2);
}
/* -----------------------------
5) CLOCK CARD / STATUS CARD
------------------------------*/
.clock-card {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.clock-card h4 {
margin-top: 1rem;
font-size: 1.2rem;
margin-bottom: 0.5rem;
}
.clock-face {
margin-top: 1rem;
width: 80px;
height: 80px;
border: 4px solid rgba(255,255,255,0.3);
border-radius: 50%;
position: relative;
}
.clock-face::before {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 4px;
height: 20px;
background: #ff9900;
transform: translate(-50%, -90%);
border-radius: 2px;
}
/* -----------------------------
6) PROGRESS CARD
------------------------------*/
.progress-card .progress-icon {
font-size: 2rem;
color: #ff9900;
margin-bottom: 1rem;
}
.progress-card .progress-value {
font-size: 1.6rem;
font-weight: 600;
margin-bottom: 0.2rem;
}
.progress-card .small-text {
font-size: 0.85rem;
opacity: 0.7;
}
/* -----------------------------
7) RESULTS / INFO CARD
------------------------------*/
.results-card {
text-align: center;
}
.results-card h4 {
font-size: 1.2rem;
margin-bottom: 0.8rem;
}
.results-card .summary {
font-size: 0.9rem;
opacity: 0.8;
}
</style>
</head>
<body>
<div class="dashboard">
<!-- 1) DOWNLOAD SPEED CARD -->
<div class="card download-card">
<i class="fas fa-download download-icon"></i>
<h3>Download Speed</h3>
<div class="metric-value" id="downloadValue">--</div>
<p class="sub-info">Mbps</p>
<p class="sub-info">(<span id="downloadMBps">--</span> MB/s)</p>
</div>
<!-- 2) UPLOAD SPEED CARD -->
<div class="card upload-card">
<i class="fas fa-upload upload-icon"></i>
<h3>Upload Speed</h3>
<div class="metric-value" id="uploadValue">--</div>
<p class="sub-info">Mbps</p>
<p class="sub-info">(<span id="uploadMBps">--</span> MB/s)</p>
</div>
<!-- 3) PING CARD -->
<div class="card ping-card">
<i class="fas fa-stopwatch ping-icon"></i>
<h3>Ping</h3>
<div class="metric-value" id="pingValue">--</div>
<p class="sub-info">ms</p>
<p class="sub-info">Rating: <span id="pingRating">--</span></p>
</div>
<!-- 4) START TEST CARD -->
<div class="card start-test-card">
<h3>Speed Test Ready</h3>
<p>Tap below to begin measuring your connection.</p>
<button class="start-btn" id="startTest">Start Test</button>
</div>
<!-- 5) CLOCK CARD / STATUS CARD -->
<div class="card clock-card">
<h4>Test Status</h4>
<div class="clock-face"></div>
<p id="statusText" style="margin-top:1rem; opacity:0.8;">Not started</p>
</div>
<!-- 6) PROGRESS CARD -->
<div class="card progress-card">
<i class="fas fa-spinner progress-icon"></i>
<h4>Progress</h4>
<div class="progress-value" id="progressPercent">0%</div>
<p class="small-text">Current Step</p>
</div>
<!-- 7) RESULTS CARD -->
<div class="card results-card">
<h4>Test Summary</h4>
<p class="summary" id="resultSummary">No data yet.</p>
</div>
</div>
<script>
const startBtn = document.getElementById('startTest');
const statusText = document.getElementById('statusText');
const progressPercent = document.getElementById('progressPercent');
const downloadValue = document.getElementById('downloadValue');
const uploadValue = document.getElementById('uploadValue');
const pingValue = document.getElementById('pingValue');
const downloadMBps = document.getElementById('downloadMBps');
const pingRating = document.getElementById('pingRating');
const resultSummary = document.getElementById('resultSummary');
let testId = null;
let pollInterval = null;
startBtn.addEventListener('click', async () => {
// Reset UI
statusText.textContent = "Starting test...";
progressPercent.textContent = "0%";
downloadValue.textContent = "--";
uploadValue.textContent = "--";
pingValue.textContent = "--";
pingRating.textContent = "--";
downloadMBps.textContent = "--";
resultSummary.textContent = "Measuring your connection...";
// Start test by calling the backend
try {
const res = await fetch('/start-test', { method: 'POST' });
const data = await res.json();
testId = data.test_id;
// Begin polling for test status every 1 second
pollInterval = setInterval(fetchTestStatus, 1000);
} catch (error) {
statusText.textContent = "Error starting test.";
console.error("Error:", error);
}
});
async function fetchTestStatus() {
if (!testId) return;
try {
const res = await fetch(`/test-status/${testId}`);
if (res.status !== 200) {
statusText.textContent = "Test not found.";
clearInterval(pollInterval);
return;
}
const result = await res.json();
// Update UI based on backend response
statusText.textContent = result.status;
progressPercent.textContent = result.progress + "%";
if (result.download_mbps) {
downloadValue.textContent = result.download_mbps;
downloadMBps.textContent = result.download_MBps;
}
if (result.upload_mbps) {
uploadValue.textContent = result.upload_mbps;
document.getElementById('uploadMBps').textContent = result.upload_MBps;
}
if (result.ping) {
pingValue.textContent = result.ping;
pingRating.textContent = result.ping <= 20 ? "Excellent" :
result.ping <= 50 ? "Good" :
result.ping <= 100 ? "Average" : "Poor";
}
if (result.progress === 100 || result.progress < 0) {
// Test complete or encountered error
clearInterval(pollInterval);
resultSummary.textContent = `Download: ${result.download_mbps} Mbps, Upload: ${result.upload_mbps} Mbps, Ping: ${result.ping} ms`;
}
} catch (error) {
console.error("Error fetching test status:", error);
}
}
</script>
</body>
</html>