Lokal Leaderboard

This commit is contained in:
Carsten Graf
2025-09-20 19:14:41 +02:00
parent 7e9705902e
commit 9de327bfb3
8 changed files with 419 additions and 36 deletions

View File

@@ -353,7 +353,7 @@ body {
}
.status {
font-size: clamp(3rem, 1.8vw, 1.2rem);
font-size: clamp(1.5rem, 3vw, 3rem);
margin: clamp(8px, 1vh, 12px) 0;
padding: clamp(6px, 1vh, 10px) clamp(12px, 2vw, 18px);
border-radius: 20px;
@@ -455,6 +455,61 @@ body {
border-radius: 8px;
}
/* Leaderboard Styles */
#leaderboard-container {
text-align: left;
}
.leaderboard-entry {
display: flex;
justify-content: space-between;
align-items: center;
margin: clamp(8px, 1vh, 12px) 0;
font-size: clamp(1.1rem, 2.2vw, 1.4rem);
font-weight: 600;
background: rgba(255, 255, 255, 0.15);
padding: clamp(8px, 1.5vh, 12px) clamp(12px, 2vw, 16px);
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.3);
transition: all 0.3s ease;
}
.leaderboard-entry:hover {
background: rgba(255, 255, 255, 0.25);
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
.leaderboard-entry .rank {
color: #ffd700;
font-weight: bold;
min-width: 30px;
font-size: clamp(1.2rem, 2.4vw, 1.5rem);
}
.leaderboard-entry .name {
flex: 1;
margin: 0 15px;
color: #ffffff;
font-weight: 600;
}
.leaderboard-entry .time {
color: #00ff88;
font-weight: bold;
font-family: 'Courier New', monospace;
min-width: 80px;
text-align: right;
}
.no-times {
text-align: center;
color: rgba(255, 255, 255, 0.7);
font-style: italic;
font-size: clamp(0.9rem, 1.8vw, 1.1rem);
padding: 20px;
}
.learning-mode {
background: rgba(245, 157, 15, 0.2);
border: 2px solid #f59d0f;

View File

@@ -72,14 +72,33 @@
</div>
<div class="best-times">
<h3>🏆 Deine Bestzeiten heute</h3>
<div class="best-time-row">
<span>Bahn 1:</span>
<span id="best1">--.-</span>
</div>
<div class="best-time-row">
<span>Bahn 2:</span>
<span id="best2">--.-</span>
<h3>🏆 Lokales Leaderboard</h3>
<div id="leaderboard-container">
<div class="leaderboard-entry">
<span class="rank">1.</span>
<span class="name">Max Mustermann</span>
<span class="time">23.45</span>
</div>
<div class="leaderboard-entry">
<span class="rank">2.</span>
<span class="name">Anna Schmidt</span>
<span class="time">24.67</span>
</div>
<div class="leaderboard-entry">
<span class="rank">3.</span>
<span class="name">Tom Weber</span>
<span class="time">25.89</span>
</div>
<div class="leaderboard-entry">
<span class="rank">4.</span>
<span class="name">Lisa Müller</span>
<span class="time">26.12</span>
</div>
<div class="leaderboard-entry">
<span class="rank">5.</span>
<span class="name">Paul Fischer</span>
<span class="time">27.34</span>
</div>
</div>
</div>
@@ -96,6 +115,7 @@
let learningButton = "";
let name1 = "";
let name2 = "";
let leaderboardData = [];
// Lane Configuration
let laneConfigType = 0; // 0=Identical, 1=Different
@@ -336,7 +356,67 @@
function formatTime(seconds) {
if (seconds === 0) return "00.00";
return seconds.toFixed(2);
const totalSeconds = Math.floor(seconds);
const minutes = Math.floor(totalSeconds / 60);
const remainingSeconds = totalSeconds % 60;
const milliseconds = Math.floor((seconds - totalSeconds) * 100);
// Zeige Minuten nur wenn über 60 Sekunden
if (totalSeconds >= 60) {
return `${minutes.toString().padStart(2, "0")}:${remainingSeconds
.toString()
.padStart(2, "0")}.${milliseconds.toString().padStart(2, "0")}`;
} else {
return `${remainingSeconds.toString().padStart(2, "0")}.${milliseconds
.toString()
.padStart(2, "0")}`;
}
}
// Leaderboard Funktionen
async function loadLeaderboard() {
try {
const response = await fetch("/api/leaderboard");
const data = await response.json();
leaderboardData = data.leaderboard || [];
updateLeaderboardDisplay();
} catch (error) {
console.error("Fehler beim Laden des Leaderboards:", error);
}
}
function updateLeaderboardDisplay() {
const container = document.getElementById("leaderboard-container");
container.innerHTML = "";
if (leaderboardData.length === 0) {
container.innerHTML =
'<div class="no-times">Noch keine Zeiten erfasst</div>';
return;
}
leaderboardData.forEach((entry, index) => {
const entryDiv = document.createElement("div");
entryDiv.className = "leaderboard-entry";
const rankSpan = document.createElement("span");
rankSpan.className = "rank";
rankSpan.textContent = entry.rank + ".";
const nameSpan = document.createElement("span");
nameSpan.className = "name";
nameSpan.textContent = entry.name;
const timeSpan = document.createElement("span");
timeSpan.className = "time";
timeSpan.textContent = entry.timeFormatted;
entryDiv.appendChild(rankSpan);
entryDiv.appendChild(nameSpan);
entryDiv.appendChild(timeSpan);
container.appendChild(entryDiv);
});
}
function updateDisplay() {
@@ -411,10 +491,7 @@
}
}
document.getElementById("best1").textContent =
best1 > 0 ? formatTime(best1) + "s" : "--.-";
document.getElementById("best2").textContent =
best2 > 0 ? formatTime(best2) + "s" : "--.-";
// Leaderboard wird separat geladen
// Namen anzeigen/verstecken
const name1Element = document.getElementById("name1");
@@ -528,6 +605,10 @@
// Initial load
syncFromBackend();
loadLaneConfig();
loadLeaderboard();
// Leaderboard alle 5 Sekunden aktualisieren
setInterval(loadLeaderboard, 5000);
</script>
</body>
</html>