Spaces:
Running
Running
now make a log in page where the user must put their name, section and grade level. so after taking the test their name section and grade will be added at the leaderboard
Browse files- components/header.js +3 -2
- index.html +9 -3
- leaderboard.html +6 -2
- login.html +87 -0
- script.js +60 -10
components/header.js
CHANGED
|
@@ -32,8 +32,9 @@ class CustomHeader extends HTMLElement {
|
|
| 32 |
<nav class="hidden md:flex space-x-6">
|
| 33 |
<a href="/" class="nav-link">Home</a>
|
| 34 |
<a href="/leaderboard.html" class="nav-link">Leaderboard</a>
|
| 35 |
-
</nav>
|
| 36 |
-
<
|
|
|
|
| 37 |
<i data-feather="menu"></i>
|
| 38 |
</button>
|
| 39 |
</div>
|
|
|
|
| 32 |
<nav class="hidden md:flex space-x-6">
|
| 33 |
<a href="/" class="nav-link">Home</a>
|
| 34 |
<a href="/leaderboard.html" class="nav-link">Leaderboard</a>
|
| 35 |
+
<a href="/login.html" class="nav-link">Login</a>
|
| 36 |
+
</nav>
|
| 37 |
+
<button class="md:hidden">
|
| 38 |
<i data-feather="menu"></i>
|
| 39 |
</button>
|
| 40 |
</div>
|
index.html
CHANGED
|
@@ -91,11 +91,17 @@
|
|
| 91 |
<script src="components/header.js"></script>
|
| 92 |
<script src="components/footer.js"></script>
|
| 93 |
<script src="script.js"></script>
|
| 94 |
-
|
| 95 |
<script>
|
| 96 |
feather.replace();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
</script>
|
| 98 |
-
|
| 99 |
-
<script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
|
| 100 |
</body>
|
| 101 |
</html>
|
|
|
|
| 91 |
<script src="components/header.js"></script>
|
| 92 |
<script src="components/footer.js"></script>
|
| 93 |
<script src="script.js"></script>
|
|
|
|
| 94 |
<script>
|
| 95 |
feather.replace();
|
| 96 |
+
|
| 97 |
+
// Check if user is logged in
|
| 98 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 99 |
+
const userInfo = localStorage.getItem('userInfo');
|
| 100 |
+
if (!userInfo) {
|
| 101 |
+
window.location.href = '/login.html';
|
| 102 |
+
}
|
| 103 |
+
});
|
| 104 |
</script>
|
| 105 |
+
<script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
|
|
|
|
| 106 |
</body>
|
| 107 |
</html>
|
leaderboard.html
CHANGED
|
@@ -22,12 +22,14 @@
|
|
| 22 |
<thead>
|
| 23 |
<tr>
|
| 24 |
<th class="px-6 py-3 text-left text-xs font-medium text-indigo-300 uppercase tracking-wider">Rank</th>
|
|
|
|
|
|
|
| 25 |
<th class="px-6 py-3 text-left text-xs font-medium text-indigo-300 uppercase tracking-wider">Language</th>
|
| 26 |
<th class="px-6 py-3 text-left text-xs font-medium text-indigo-300 uppercase tracking-wider">WPM</th>
|
| 27 |
<th class="px-6 py-3 text-left text-xs font-medium text-indigo-300 uppercase tracking-wider">Accuracy</th>
|
| 28 |
<th class="px-6 py-3 text-left text-xs font-medium text-indigo-300 uppercase tracking-wider">Time</th>
|
| 29 |
<th class="px-6 py-3 text-left text-xs font-medium text-indigo-300 uppercase tracking-wider">Date</th>
|
| 30 |
-
|
| 31 |
</thead>
|
| 32 |
<tbody id="leaderboard-body" class="divide-y divide-gray-700">
|
| 33 |
<!-- Leaderboard data will be inserted here -->
|
|
@@ -54,12 +56,14 @@
|
|
| 54 |
const row = document.createElement('tr');
|
| 55 |
row.innerHTML = `
|
| 56 |
<td class="px-6 py-4 whitespace-nowrap">${index + 1}</td>
|
|
|
|
|
|
|
| 57 |
<td class="px-6 py-4 whitespace-nowrap">${entry.language.toUpperCase()}</td>
|
| 58 |
<td class="px-6 py-4 whitespace-nowrap">${entry.wpm}</td>
|
| 59 |
<td class="px-6 py-4 whitespace-nowrap">${entry.accuracy}%</td>
|
| 60 |
<td class="px-6 py-4 whitespace-nowrap">${entry.time_taken}s</td>
|
| 61 |
<td class="px-6 py-4 whitespace-nowrap">${new Date(entry.created_at).toLocaleString()}</td>
|
| 62 |
-
|
| 63 |
tbody.appendChild(row);
|
| 64 |
});
|
| 65 |
}
|
|
|
|
| 22 |
<thead>
|
| 23 |
<tr>
|
| 24 |
<th class="px-6 py-3 text-left text-xs font-medium text-indigo-300 uppercase tracking-wider">Rank</th>
|
| 25 |
+
<th class="px-6 py-3 text-left text-xs font-medium text-indigo-300 uppercase tracking-wider">Name</th>
|
| 26 |
+
<th class="px-6 py-3 text-left text-xs font-medium text-indigo-300 uppercase tracking-wider">Grade & Section</th>
|
| 27 |
<th class="px-6 py-3 text-left text-xs font-medium text-indigo-300 uppercase tracking-wider">Language</th>
|
| 28 |
<th class="px-6 py-3 text-left text-xs font-medium text-indigo-300 uppercase tracking-wider">WPM</th>
|
| 29 |
<th class="px-6 py-3 text-left text-xs font-medium text-indigo-300 uppercase tracking-wider">Accuracy</th>
|
| 30 |
<th class="px-6 py-3 text-left text-xs font-medium text-indigo-300 uppercase tracking-wider">Time</th>
|
| 31 |
<th class="px-6 py-3 text-left text-xs font-medium text-indigo-300 uppercase tracking-wider">Date</th>
|
| 32 |
+
</tr>
|
| 33 |
</thead>
|
| 34 |
<tbody id="leaderboard-body" class="divide-y divide-gray-700">
|
| 35 |
<!-- Leaderboard data will be inserted here -->
|
|
|
|
| 56 |
const row = document.createElement('tr');
|
| 57 |
row.innerHTML = `
|
| 58 |
<td class="px-6 py-4 whitespace-nowrap">${index + 1}</td>
|
| 59 |
+
<td class="px-6 py-4 whitespace-nowrap">${entry.name}</td>
|
| 60 |
+
<td class="px-6 py-4 whitespace-nowrap">${entry.grade} - ${entry.section}</td>
|
| 61 |
<td class="px-6 py-4 whitespace-nowrap">${entry.language.toUpperCase()}</td>
|
| 62 |
<td class="px-6 py-4 whitespace-nowrap">${entry.wpm}</td>
|
| 63 |
<td class="px-6 py-4 whitespace-nowrap">${entry.accuracy}%</td>
|
| 64 |
<td class="px-6 py-4 whitespace-nowrap">${entry.time_taken}s</td>
|
| 65 |
<td class="px-6 py-4 whitespace-nowrap">${new Date(entry.created_at).toLocaleString()}</td>
|
| 66 |
+
`;
|
| 67 |
tbody.appendChild(row);
|
| 68 |
});
|
| 69 |
}
|
login.html
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Login - CodeFlow Typing Challenge</title>
|
| 7 |
+
<link rel="stylesheet" href="style.css">
|
| 8 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
+
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
| 10 |
+
</head>
|
| 11 |
+
<body class="bg-gray-900 text-gray-100 min-h-screen">
|
| 12 |
+
<custom-header></custom-header>
|
| 13 |
+
<main class="container mx-auto px-4 py-8 max-w-md">
|
| 14 |
+
<div class="text-center mb-12">
|
| 15 |
+
<h1 class="text-4xl font-bold mb-2 text-indigo-400">Enter Your Details</h1>
|
| 16 |
+
<p class="text-lg text-gray-400">Your information will appear on the leaderboard</p>
|
| 17 |
+
</div>
|
| 18 |
+
|
| 19 |
+
<div class="bg-gray-800 rounded-xl p-6 shadow-lg">
|
| 20 |
+
<form id="login-form" class="space-y-6">
|
| 21 |
+
<div>
|
| 22 |
+
<label for="name" class="block text-sm font-medium text-gray-300 mb-1">Full Name</label>
|
| 23 |
+
<input type="text" id="name" required
|
| 24 |
+
class="w-full bg-gray-900 border border-gray-700 rounded-lg p-3 focus:border-indigo-500 focus:outline-none">
|
| 25 |
+
</div>
|
| 26 |
+
|
| 27 |
+
<div>
|
| 28 |
+
<label for="grade" class="block text-sm font-medium text-gray-300 mb-1">Grade Level</label>
|
| 29 |
+
<select id="grade" required
|
| 30 |
+
class="w-full bg-gray-900 border border-gray-700 rounded-lg p-3 focus:border-indigo-500 focus:outline-none">
|
| 31 |
+
<option value="">Select Grade</option>
|
| 32 |
+
<option value="7">Grade 7</option>
|
| 33 |
+
<option value="8">Grade 8</option>
|
| 34 |
+
<option value="9">Grade 9</option>
|
| 35 |
+
<option value="10">Grade 10</option>
|
| 36 |
+
<option value="11">Grade 11</option>
|
| 37 |
+
<option value="12">Grade 12</option>
|
| 38 |
+
<option value="college">College</option>
|
| 39 |
+
</select>
|
| 40 |
+
</div>
|
| 41 |
+
|
| 42 |
+
<div>
|
| 43 |
+
<label for="section" class="block text-sm font-medium text-gray-300 mb-1">Section</label>
|
| 44 |
+
<input type="text" id="section" required
|
| 45 |
+
class="w-full bg-gray-900 border border-gray-700 rounded-lg p-3 focus:border-indigo-500 focus:outline-none">
|
| 46 |
+
</div>
|
| 47 |
+
|
| 48 |
+
<button type="submit"
|
| 49 |
+
class="w-full bg-indigo-600 hover:bg-indigo-700 px-6 py-3 rounded-lg text-lg transition">
|
| 50 |
+
Start Typing Test
|
| 51 |
+
</button>
|
| 52 |
+
</form>
|
| 53 |
+
</div>
|
| 54 |
+
</main>
|
| 55 |
+
|
| 56 |
+
<custom-footer></custom-footer>
|
| 57 |
+
|
| 58 |
+
<script src="components/header.js"></script>
|
| 59 |
+
<script src="components/footer.js"></script>
|
| 60 |
+
<script>
|
| 61 |
+
feather.replace();
|
| 62 |
+
|
| 63 |
+
document.getElementById('login-form').addEventListener('submit', function(e) {
|
| 64 |
+
e.preventDefault();
|
| 65 |
+
|
| 66 |
+
const name = document.getElementById('name').value.trim();
|
| 67 |
+
const grade = document.getElementById('grade').value;
|
| 68 |
+
const section = document.getElementById('section').value.trim();
|
| 69 |
+
|
| 70 |
+
if (!name || !grade || !section) {
|
| 71 |
+
alert('Please fill in all fields');
|
| 72 |
+
return;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
// Store user info in localStorage
|
| 76 |
+
localStorage.setItem('userInfo', JSON.stringify({
|
| 77 |
+
name,
|
| 78 |
+
grade,
|
| 79 |
+
section
|
| 80 |
+
}));
|
| 81 |
+
|
| 82 |
+
// Redirect to test page
|
| 83 |
+
window.location.href = '/';
|
| 84 |
+
});
|
| 85 |
+
</script>
|
| 86 |
+
</body>
|
| 87 |
+
</html>
|
script.js
CHANGED
|
@@ -299,22 +299,72 @@ resultsSection.classList.remove('hidden');
|
|
| 299 |
}
|
| 300 |
// Mock save results function for local testing
|
| 301 |
async function saveResults(language, wpm, accuracy, timeTaken) {
|
| 302 |
-
|
|
|
|
|
|
|
| 303 |
language,
|
| 304 |
wpm,
|
| 305 |
accuracy,
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 310 |
|
|
|
|
|
|
|
| 311 |
// Mock leaderboard data for local testing
|
| 312 |
async function fetchLeaderboard() {
|
| 313 |
-
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 318 |
}
|
| 319 |
// Event listeners
|
| 320 |
inputField.addEventListener('input', updateDisplay);
|
|
|
|
| 299 |
}
|
| 300 |
// Mock save results function for local testing
|
| 301 |
async function saveResults(language, wpm, accuracy, timeTaken) {
|
| 302 |
+
const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}');
|
| 303 |
+
|
| 304 |
+
const result = {
|
| 305 |
language,
|
| 306 |
wpm,
|
| 307 |
accuracy,
|
| 308 |
+
time_taken: timeTaken,
|
| 309 |
+
name: userInfo.name || 'Anonymous',
|
| 310 |
+
grade: userInfo.grade || 'N/A',
|
| 311 |
+
section: userInfo.section || 'N/A',
|
| 312 |
+
created_at: new Date().toISOString()
|
| 313 |
+
};
|
| 314 |
+
|
| 315 |
+
console.log('Results would be saved:', result);
|
| 316 |
+
|
| 317 |
+
// In a real app, you would send this to your backend
|
| 318 |
+
// await fetch('/api/results', {
|
| 319 |
+
// method: 'POST',
|
| 320 |
+
// headers: { 'Content-Type': 'application/json' },
|
| 321 |
+
// body: JSON.stringify(result)
|
| 322 |
+
// });
|
| 323 |
|
| 324 |
+
return { success: true, data: result };
|
| 325 |
+
}
|
| 326 |
// Mock leaderboard data for local testing
|
| 327 |
async function fetchLeaderboard() {
|
| 328 |
+
// Try to get from localStorage if no backend
|
| 329 |
+
const savedResults = JSON.parse(localStorage.getItem('savedResults') || '[]');
|
| 330 |
+
|
| 331 |
+
// Add some sample data if empty
|
| 332 |
+
if (savedResults.length === 0) {
|
| 333 |
+
return [
|
| 334 |
+
{
|
| 335 |
+
name: 'John Doe',
|
| 336 |
+
grade: '10',
|
| 337 |
+
section: 'A',
|
| 338 |
+
language: 'javascript',
|
| 339 |
+
wpm: 85,
|
| 340 |
+
accuracy: 98,
|
| 341 |
+
time_taken: 120,
|
| 342 |
+
created_at: new Date().toISOString()
|
| 343 |
+
},
|
| 344 |
+
{
|
| 345 |
+
name: 'Jane Smith',
|
| 346 |
+
grade: '11',
|
| 347 |
+
section: 'B',
|
| 348 |
+
language: 'html',
|
| 349 |
+
wpm: 75,
|
| 350 |
+
accuracy: 95,
|
| 351 |
+
time_taken: 180,
|
| 352 |
+
created_at: new Date().toISOString()
|
| 353 |
+
},
|
| 354 |
+
{
|
| 355 |
+
name: 'Alex Johnson',
|
| 356 |
+
grade: '9',
|
| 357 |
+
section: 'C',
|
| 358 |
+
language: 'css',
|
| 359 |
+
wpm: 65,
|
| 360 |
+
accuracy: 92,
|
| 361 |
+
time_taken: 150,
|
| 362 |
+
created_at: new Date().toISOString()
|
| 363 |
+
}
|
| 364 |
+
];
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
return savedResults;
|
| 368 |
}
|
| 369 |
// Event listeners
|
| 370 |
inputField.addEventListener('input', updateDisplay);
|