init
This commit is contained in:
commit
ce1095bb24
27 changed files with 621 additions and 0 deletions
102
app/static/css/styles.css
Normal file
102
app/static/css/styles.css
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
background-color: #f7f7f7;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
color: #222;
|
||||
}
|
||||
|
||||
form {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
input, select, button {
|
||||
padding: 8px;
|
||||
margin: 5px;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
button {
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 10px 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button.green {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
}
|
||||
|
||||
button.red {
|
||||
background-color: #e53935;
|
||||
color: white;
|
||||
}
|
||||
|
||||
button.orange {
|
||||
background-color: orange;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.fahrer-eintrag {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.licht {
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin: 10px;
|
||||
border-radius: 50%;
|
||||
background-color: grey;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.licht.rot.aktiv {
|
||||
background-color: red;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.licht.gruen {
|
||||
background-color: green !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(10, 10, 10, 0.9);
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
color: white;
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.ampel-klein {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 10px auto;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.ergebnis {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.fahrerbox {
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
color: white;
|
||||
flex: 1 1 200px;
|
||||
}
|
||||
30
app/static/js/admin.js
Normal file
30
app/static/js/admin.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
function systemCommand(cmd) {
|
||||
fetch(`/admin/${cmd}`, { method: "POST" })
|
||||
.then(res => res.text())
|
||||
.then(alert);
|
||||
}
|
||||
|
||||
function fetchLogs() {
|
||||
fetch("/admin/logs")
|
||||
.then(res => res.text())
|
||||
.then(data => {
|
||||
document.getElementById("logs").innerText = data;
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById("adminForm").addEventListener("submit", function(e) {
|
||||
e.preventDefault();
|
||||
const data = new FormData(e.target);
|
||||
const json = {};
|
||||
for (let [k, v] of data.entries()) {
|
||||
json[k] = v;
|
||||
}
|
||||
json["ziel_aktiviert"] = data.get("ziel_aktiviert") === "on";
|
||||
|
||||
fetch("/admin/save", {
|
||||
method: "POST",
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(json)
|
||||
}).then(res => res.text())
|
||||
.then(alert);
|
||||
});
|
||||
17
app/static/js/fahrer.js
Normal file
17
app/static/js/fahrer.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
function addFahrer() {
|
||||
const fahrerListe = document.getElementById("fahrerListe");
|
||||
const index = fahrerListe.children.length + 1;
|
||||
const farben = ["#ff0000", "#00ff00", "#0000ff", "#ffa500"];
|
||||
const neueFarbe = farben[index % farben.length];
|
||||
|
||||
const div = document.createElement("div");
|
||||
div.className = "fahrer-eintrag";
|
||||
div.innerHTML = `
|
||||
<label>Fahrer ${index}:
|
||||
<input type="text" name="name" value="Fahrer ${index}">
|
||||
<input type="number" name="nummer" value="${10 + index}">
|
||||
<input type="color" name="farbe" value="${neueFarbe}">
|
||||
</label>
|
||||
`;
|
||||
fahrerListe.appendChild(div);
|
||||
}
|
||||
31
app/static/js/main.js
Normal file
31
app/static/js/main.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
function startCountdown() {
|
||||
const beep = new Audio("/static/sounds/beep.wav");
|
||||
const go = new Audio("/static/sounds/go.wav");
|
||||
|
||||
setTimeout(() => {
|
||||
document.getElementById("licht1").classList.add("aktiv");
|
||||
beep.play();
|
||||
}, 1000);
|
||||
|
||||
setTimeout(() => {
|
||||
document.getElementById("licht2").classList.add("aktiv");
|
||||
beep.play();
|
||||
}, 2000);
|
||||
|
||||
setTimeout(() => {
|
||||
document.getElementById("licht3").classList.add("aktiv");
|
||||
beep.play();
|
||||
}, 3000);
|
||||
|
||||
setTimeout(() => {
|
||||
document.querySelectorAll(".licht").forEach(el => {
|
||||
el.classList.remove("rot");
|
||||
el.classList.add("gruen");
|
||||
});
|
||||
go.play();
|
||||
}, 4000);
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.href = "/rennen";
|
||||
}, 7000);
|
||||
}
|
||||
20
app/static/js/zuordnen.js
Normal file
20
app/static/js/zuordnen.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
document.getElementById("zuordnungForm").addEventListener("submit", function(e) {
|
||||
e.preventDefault();
|
||||
const zuordnungen = [];
|
||||
|
||||
document.querySelectorAll(".zuordnung").forEach(row => {
|
||||
const zeit = row.querySelector("span").innerText;
|
||||
const fahrer = row.querySelector("select").value;
|
||||
if (fahrer) {
|
||||
zuordnungen.push({ zeit: zeit, fahrer: fahrer });
|
||||
}
|
||||
});
|
||||
|
||||
fetch("/zeit_zuordnen", {
|
||||
method: "POST",
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ zuordnungen: zuordnungen })
|
||||
}).then(() => {
|
||||
window.location.href = "/ergebnis";
|
||||
});
|
||||
});
|
||||
BIN
app/static/sounds/beep.wav
Normal file
BIN
app/static/sounds/beep.wav
Normal file
Binary file not shown.
BIN
app/static/sounds/go.wav
Normal file
BIN
app/static/sounds/go.wav
Normal file
Binary file not shown.
Reference in a new issue