You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
4.2 KiB
136 lines
4.2 KiB
package templates
|
|
|
|
templ Index() {
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Derby Race Timer</title>
|
|
<link href="/static/css/tailwind.css" rel="stylesheet" />
|
|
<script src="/static/js/htmx.min.js"></script>
|
|
</head>
|
|
<body class="bg-gray-100 min-h-screen">
|
|
<div class="container mx-auto px-4 py-8">
|
|
<header class="mb-8">
|
|
<h1 class="text-3xl font-bold text-center">Derby Race Timer</h1>
|
|
</header>
|
|
|
|
<div class="mb-6 flex justify-center">
|
|
<div id="race-status" class="px-4 py-2 rounded-full text-white bg-blue-600">Ready</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
|
|
@laneComponents()
|
|
</div>
|
|
|
|
<div class="flex justify-center space-x-4">
|
|
<button
|
|
hx-post="/api/reset"
|
|
hx-swap="none"
|
|
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
|
|
Reset Race
|
|
</button>
|
|
<button
|
|
hx-post="/api/force-end"
|
|
hx-swap="none"
|
|
class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded">
|
|
Force End Race
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
console.log("Setting up SSE connection...");
|
|
|
|
// Set up SSE connection
|
|
const eventSource = new EventSource('/api/events');
|
|
|
|
eventSource.onopen = function() {
|
|
console.log("SSE connection opened");
|
|
};
|
|
|
|
eventSource.onerror = function(error) {
|
|
console.error("SSE connection error:", error);
|
|
};
|
|
|
|
eventSource.addEventListener('debug', function(event) {
|
|
console.log("Debug event received:", event.data);
|
|
});
|
|
|
|
eventSource.addEventListener('lane-finish', function(event) {
|
|
console.log("Lane finish event received:", event.data);
|
|
try {
|
|
const laneFinishData = JSON.parse(event.data);
|
|
const lane = document.getElementById(`lane-${laneFinishData.lane}`);
|
|
if (lane) {
|
|
console.log(`Updating lane ${laneFinishData.lane} with time ${laneFinishData.time}`);
|
|
lane.classList.add('finished');
|
|
lane.querySelector('.time').textContent = laneFinishData.time.toFixed(4);
|
|
|
|
const placeEl = lane.querySelector('.place');
|
|
placeEl.textContent = `${getOrdinal(laneFinishData.place)} Place`;
|
|
placeEl.classList.remove('hidden');
|
|
} else {
|
|
console.error(`Lane element not found for lane ${laneFinishData.lane}`);
|
|
}
|
|
} catch (error) {
|
|
console.error("Error processing lane finish event:", error);
|
|
}
|
|
});
|
|
|
|
eventSource.addEventListener('status', function(event) {
|
|
console.log("Status event received:", event.data);
|
|
try {
|
|
const statusData = JSON.parse(event.data);
|
|
let statusText = 'Unknown';
|
|
let statusClass = 'bg-gray-500';
|
|
|
|
if (statusData.status === 'idle') {
|
|
statusText = 'Ready';
|
|
statusClass = 'bg-blue-600';
|
|
|
|
// Reset all lanes
|
|
document.querySelectorAll('.lane').forEach(lane => {
|
|
lane.classList.remove('finished');
|
|
lane.querySelector('.time').textContent = '--.--.---';
|
|
lane.querySelector('.place').classList.add('hidden');
|
|
});
|
|
} else if (statusData.status === 'running') {
|
|
statusText = 'Race Running';
|
|
statusClass = 'bg-green-600';
|
|
} else if (statusData.status === 'finished') {
|
|
statusText = 'Race Complete';
|
|
statusClass = 'bg-purple-600';
|
|
}
|
|
|
|
document.getElementById('race-status').textContent = statusText;
|
|
document.getElementById('race-status').className = `px-4 py-2 rounded-full text-white ${statusClass}`;
|
|
} catch (error) {
|
|
console.error("Error processing status event:", error);
|
|
}
|
|
});
|
|
|
|
function getOrdinal(n) {
|
|
const s = ["th", "st", "nd", "rd"];
|
|
const v = n % 100;
|
|
return n + (s[(v-20)%10] || s[v] || s[0]);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|
|
}
|
|
|
|
templ laneComponents() {
|
|
for i := 1; i <= 4; i++ {
|
|
@laneComponent(i)
|
|
}
|
|
}
|
|
|
|
templ laneComponent(lane int) {
|
|
<div id={ "lane-" + string(rune('0' + lane)) } class="lane bg-white p-4 rounded shadow">
|
|
<h2 class="text-xl font-semibold mb-2">Lane { string(rune('0' + lane)) }</h2>
|
|
<div class="text-3xl font-mono mb-2 time">--.--.---</div>
|
|
<div class="place text-lg font-bold text-green-600 hidden"></div>
|
|
</div>
|
|
} |