initial commit
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
let rennplanData = {};
|
||||
let resultsData = {};
|
||||
let messageData = {};
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
initTabs();
|
||||
loadData();
|
||||
|
||||
setInterval(loadData, CONFIG.REFRESH_INTERVAL);
|
||||
});
|
||||
|
||||
function initTabs() {
|
||||
const rennplanBtn = document.getElementById("tab-rennplan");
|
||||
const resultsBtn = document.getElementById("tab-ergebnisse");
|
||||
|
||||
const rennplanView = document.getElementById("rennplan-view");
|
||||
const resultsView = document.getElementById("ergebnisse-view");
|
||||
|
||||
rennplanBtn.addEventListener("click", () => {
|
||||
rennplanView.classList.remove("hidden");
|
||||
resultsView.classList.add("hidden");
|
||||
|
||||
setTabActive(rennplanBtn, resultsBtn);
|
||||
});
|
||||
|
||||
resultsBtn.addEventListener("click", () => {
|
||||
resultsView.classList.remove("hidden");
|
||||
rennplanView.classList.add("hidden");
|
||||
|
||||
setTabActive(resultsBtn, rennplanBtn);
|
||||
});
|
||||
}
|
||||
|
||||
function setTabActive(active, inactive) {
|
||||
active.className =
|
||||
"flex-1 py-4 text-indigo-600 border-b-4 border-indigo-600 font-medium";
|
||||
|
||||
inactive.className =
|
||||
"flex-1 py-4 text-slate-500 font-medium";
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
try {
|
||||
const scrollY = window.scrollY;
|
||||
|
||||
const [rennplanRes, resultsRes, messageRes] = await Promise.all([
|
||||
fetch(CONFIG.RENNPLAN_URL),
|
||||
fetch(CONFIG.RESULTS_URL),
|
||||
fetch(CONFIG.MESSAGE_URL)
|
||||
]);
|
||||
|
||||
rennplanData = await rennplanRes.json();
|
||||
resultsData = await resultsRes.json();
|
||||
messageData = await messageRes.json();
|
||||
|
||||
renderMessage();
|
||||
renderRennplan();
|
||||
renderResults();
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
window.scrollTo(0, scrollY);
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.error("API Fehler:", err);
|
||||
}
|
||||
}
|
||||
|
||||
function renderMessage() {
|
||||
const box = document.getElementById("message-box");
|
||||
|
||||
if (!messageData?.message) {
|
||||
box.classList.add("hidden");
|
||||
return;
|
||||
}
|
||||
|
||||
let style = "";
|
||||
|
||||
switch (messageData.type) {
|
||||
case "danger":
|
||||
style = "bg-red-50 border-red-400 text-red-900";
|
||||
break;
|
||||
case "warning":
|
||||
style = "bg-amber-50 border-amber-400 text-amber-900";
|
||||
break;
|
||||
default:
|
||||
style = "bg-blue-50 border-blue-400 text-blue-900";
|
||||
}
|
||||
|
||||
box.className = `border-l-4 p-4 rounded-xl shadow-sm ${style}`;
|
||||
box.innerHTML = `<div class="font-medium">${messageData.message}</div>`;
|
||||
box.classList.remove("hidden");
|
||||
}
|
||||
|
||||
function renderRennplan() {
|
||||
const container = document.getElementById("rennplan-content");
|
||||
container.innerHTML = "";
|
||||
|
||||
const rennplan = rennplanData.rennplan || {};
|
||||
|
||||
const sortedLaeufe = Object.keys(rennplan)
|
||||
.sort((a, b) => {
|
||||
return parseInt(b.replace("lauf", "")) - parseInt(a.replace("lauf", ""));
|
||||
});
|
||||
|
||||
sortedLaeufe.forEach(laufKey => {
|
||||
|
||||
const laufNum = laufKey.replace("lauf", "");
|
||||
|
||||
const races = Object.entries(rennplan[laufKey])
|
||||
.sort((a, b) => Number(a[0]) - Number(b[0]));
|
||||
|
||||
container.innerHTML += `
|
||||
<section class="space-y-4">
|
||||
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
<div class="h-10 w-10 rounded-full bg-indigo-600 text-white flex items-center justify-center font-semibold">
|
||||
${laufNum}
|
||||
</div>
|
||||
|
||||
<h2 class="text-xl font-medium text-slate-800">
|
||||
Lauf ${laufNum}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
${races.map(([_, race]) => `
|
||||
<div class="bg-white rounded-2xl shadow-sm overflow-hidden">
|
||||
|
||||
<div class="bg-indigo-50 px-5 py-4 flex justify-between">
|
||||
<div>
|
||||
<div class="text-lg font-medium">${race.name}</div>
|
||||
<div class="text-sm text-slate-500">${race.art}</div>
|
||||
</div>
|
||||
|
||||
<div class="text-indigo-600 font-semibold">
|
||||
${race.zeit}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-5 flex flex-wrap gap-2 text-sm">
|
||||
<span class="bg-slate-100 px-3 py-1 rounded-full">
|
||||
Bahn 1 · ${race.bahn1}
|
||||
</span>
|
||||
|
||||
<span class="bg-slate-100 px-3 py-1 rounded-full">
|
||||
Bahn 2 · ${race.bahn2}
|
||||
</span>
|
||||
|
||||
<span class="bg-slate-100 px-3 py-1 rounded-full">
|
||||
Bahn 3 · ${race.bahn3}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
`).join("")}
|
||||
|
||||
</section>`;
|
||||
});
|
||||
}
|
||||
|
||||
function renderResults() {
|
||||
const container = document.getElementById("results-content");
|
||||
container.innerHTML = "";
|
||||
|
||||
const races = Object.entries(resultsData.ergebnisse || {})
|
||||
.sort((a, b) => Number(b[0]) - Number(a[0]));
|
||||
|
||||
races.forEach(([_, race]) => {
|
||||
|
||||
const lane = (key, data, winner) => {
|
||||
const isWinner = race.winner === key;
|
||||
|
||||
return `
|
||||
<div class="
|
||||
p-4 rounded-xl border
|
||||
${isWinner ? "bg-green-50 border-green-400" : "bg-slate-50 border-slate-200"}
|
||||
">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="font-medium">${data.boot}</div>
|
||||
|
||||
${isWinner ? `
|
||||
<span class="bg-green-600 text-white text-xs px-2 py-1 rounded-full">
|
||||
Sieger
|
||||
</span>` : ""}
|
||||
</div>
|
||||
|
||||
<div class="text-sm text-slate-500 mt-1">
|
||||
${data.zeit}
|
||||
</div>
|
||||
|
||||
<div class="text-xs text-slate-400 mt-1">
|
||||
${formatLaneLabel(key)}
|
||||
</div>
|
||||
</div>`;
|
||||
};
|
||||
|
||||
container.innerHTML += `
|
||||
<div class="bg-white rounded-3xl shadow-sm overflow-hidden">
|
||||
|
||||
<div class="bg-indigo-600 text-white p-5">
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
<div class="text-lg font-medium">${race.title}</div>
|
||||
<div class="text-indigo-100 text-sm">${race.art}</div>
|
||||
</div>
|
||||
|
||||
<div class="text-sm">
|
||||
Lauf ${race.lauf}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-indigo-100 text-sm mt-2">
|
||||
${formatDateTime(race.start)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-5 grid gap-3 md:grid-cols-3">
|
||||
${lane("bahn1", race.bahn1)}
|
||||
${lane("bahn2", race.bahn2)}
|
||||
${lane("bahn3", race.bahn3)}
|
||||
</div>
|
||||
|
||||
</div>`;
|
||||
});
|
||||
}
|
||||
|
||||
function formatLaneLabel(key) {
|
||||
const map = {
|
||||
bahn1: "Bahn 1",
|
||||
bahn2: "Bahn 2",
|
||||
bahn3: "Bahn 3"
|
||||
};
|
||||
|
||||
return map[key] || key;
|
||||
}
|
||||
|
||||
function formatDateTime(dateString) {
|
||||
const match = dateString.match(
|
||||
/^(\d{4})-(\d{2})-(\d{2})-(\d{2}):(\d{2}):(\d{2})$/
|
||||
);
|
||||
|
||||
if (!match) return dateString;
|
||||
|
||||
const [, y, m, d, h, i, s] = match;
|
||||
|
||||
const date = new Date(y, m - 1, d, h, i, s);
|
||||
|
||||
return date.toLocaleString("de-DE", {
|
||||
day: "2-digit",
|
||||
month: "2-digit",
|
||||
year: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit"
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user