Private
Public Access
1
0
Files
it232Abschied/secure/admin.html
Sebastian Unterschütz cf2e6e1c94 bug fixes
2025-11-26 18:56:59 +01:00

248 lines
8.8 KiB
HTML

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Lehrer Zimmer (Admin)</title>
<style>
body { font-family: sans-serif; background: #222; color: #ddd; padding: 20px; max-width: 800px; margin: 0 auto; }
/* Header & Suche */
.header { display: flex; justify-content: space-between; align-items: center; border-bottom: 2px solid #555; padding-bottom: 20px; margin-bottom: 20px; }
h1 { margin: 0; color: #ffcc00; }
input[type="text"] {
padding: 10px; font-size: 16px; width: 250px;
background: #333; border: 1px solid #666; color: white; outline: none;
}
/* Tabs */
.tabs { display: flex; gap: 10px; margin-bottom: 20px; }
.tab-btn {
flex: 1; padding: 15px; cursor: pointer; background: #333; border: none; color: #888; font-weight: bold; font-size: 16px;
}
.tab-btn.active { background: #4caf50; color: white; }
.tab-btn#tab-public.active { background: #2196F3; } /* Blau für Public */
.tab-btn#tab-badwords.active { background: #f44336; } /* Rot für Badwords */
/* Normale Liste */
.entry {
background: #333; padding: 15px; margin-bottom: 8px;
display: flex; justify-content: space-between; align-items: center;
border-left: 5px solid #555;
}
.entry.highlight { border-left-color: #ffeb3b; background: #444; }
.info { font-size: 1.1em; }
.meta { font-size: 0.85em; color: #aaa; margin-top: 4px; font-family: monospace; }
.code { color: #00e5ff; font-weight: bold; font-size: 1.1em; letter-spacing: 1px; }
/* Buttons */
button { cursor: pointer; padding: 8px 15px; border: none; font-weight: bold; color: white; border-radius: 4px; }
.btn-delete { background: #f44336; }
.btn-delete:hover { background: #d32f2f; }
/* BADWORD STYLES (Tags) */
#badword-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
padding: 20px;
background: #333;
border: 1px solid #555;
}
.badword-tag {
background: #222;
padding: 8px 15px;
border-radius: 20px;
display: flex;
align-items: center;
gap: 10px;
border: 1px solid #f44336;
color: #ff8a80;
font-weight: bold;
}
.badword-remove {
cursor: pointer;
color: #f44336;
font-weight: bold;
background: rgba(255,255,255,0.1);
width: 20px; height: 20px;
display: flex; align-items: center; justify-content: center;
border-radius: 50%;
}
.badword-remove:hover { background: #f44336; color: white; }
.empty { text-align: center; padding: 40px; color: #666; font-style: italic; }
</style>
</head>
<body>
<div class="header">
<h1>👨‍🏫 Lehrer Zimmer</h1>
<input type="text" id="searchInput" placeholder="Suche Code oder Name..." onkeyup="filterList()">
</div>
<div class="tabs">
<button id="tab-public" class="tab-btn active" onclick="switchTab('public')">🏆 Bestenliste</button>
<button id="tab-badwords" class="tab-btn" onclick="switchTab('badwords')">🤬 Badwords</button>
</div>
<div id="list-section">
<div id="list">Lade...</div>
</div>
<div id="badword-section" style="display:none;">
<div style="margin-bottom: 20px; display:flex; gap:10px;">
<input type="text" id="newBadword" placeholder="Neues Wort hinzufügen...">
<button onclick="addBadword()" style="background:#f44336; color:white; border:none; padding:10px 20px; cursor:pointer;">+ Hinzufügen</button>
</div>
<h3>Aktuelle Liste:</h3>
<div id="badword-container">
</div>
</div>
<script>
let currentTab = 'public';
let allEntries = [];
// Initial laden
loadList();
// --- FUNKTIONEN FÜR BESTENLISTE ---
async function loadList() {
const listEl = document.getElementById('list');
listEl.innerHTML = '<div style="text-align:center">Lade Daten...</div>';
try {
const res = await fetch('/api/admin/list?type=public');
allEntries = await res.json();
renderList(allEntries);
} catch(e) {
listEl.innerHTML = '<div class="empty">Fehler beim Laden.</div>';
}
}
function renderList(data) {
const listEl = document.getElementById('list');
if (!data || data.length === 0) {
listEl.innerHTML = "<div class='empty'>Liste ist leer.</div>";
return;
}
let html = "";
data.forEach(entry => {
html += `
<div class="entry">
<div class="info">
<strong>${entry.name || 'Unbekannt'}</strong>
<span style="color:#ffcc00; font-weight:bold; margin-left:10px;">${entry.score} Pkt</span>
<div class="meta">
CODE: <span class="code">${entry.code || '---'}</span> | ${entry.time || '?'}
</div>
</div>
<div class="actions">
<button class="btn-delete" onclick="decide('${entry.sessionId}', 'delete')">🗑 Löschen</button>
</div>
</div>`;
});
listEl.innerHTML = html;
filterList(); // Suche anwenden falls Text drin steht
}
async function decide(sid, action) {
if(!confirm("Eintrag endgültig löschen?")) return;
await fetch('/api/admin/action', {
method: 'POST', headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ sessionId: sid, action: action })
});
loadList();
}
function filterList() {
const term = document.getElementById('searchInput').value.toUpperCase();
const entries = document.querySelectorAll('.entry');
entries.forEach(div => {
if (div.innerText.toUpperCase().includes(term)) {
div.style.display = "flex";
if(term.length > 0) div.classList.add("highlight"); else div.classList.remove("highlight");
} else { div.style.display = "none"; }
});
}
// --- FUNKTIONEN FÜR BADWORDS ---
async function loadBadwords() {
try {
const res = await fetch('/api/admin/badwords');
const words = await res.json(); // Array von Strings
const container = document.getElementById('badword-container');
container.innerHTML = '';
if (!words || words.length === 0) {
container.innerHTML = "<div class='empty'>Keine Badwords definiert.</div>";
return;
}
// Tags generieren
words.forEach(w => {
container.innerHTML += `
<div class="badword-tag">
${w}
<span class="badword-remove" onclick="removeBadword('${w}')" title="Löschen">✖</span>
</div>`;
});
} catch(e) {
document.getElementById('badword-container').innerHTML = "Fehler beim Laden.";
}
}
async function addBadword() {
const input = document.getElementById('newBadword');
const word = input.value.trim();
if(!word) return;
await fetch('/api/admin/badwords', {
method: 'POST', headers: {'Content-Type':'application/json'},
body: JSON.stringify({ action: 'add', word: word })
});
input.value = "";
loadBadwords();
}
async function removeBadword(word) {
if(!confirm(`Das Wort "${word}" von der Liste entfernen?`)) return;
await fetch('/api/admin/badwords', {
method: 'POST', headers: {'Content-Type':'application/json'},
body: JSON.stringify({ action: 'remove', word: word })
});
loadBadwords();
}
// --- TAB UMSCHALTEN ---
function switchTab(tab) {
currentTab = tab;
// Buttons stylen
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
document.getElementById('tab-' + tab).classList.add('active');
// Ansicht wechseln
if (tab === 'badwords') {
document.getElementById('list-section').style.display = 'none';
document.getElementById('badword-section').style.display = 'block';
document.getElementById('searchInput').style.display = 'none';
loadBadwords();
} else {
document.getElementById('list-section').style.display = 'block';
document.getElementById('badword-section').style.display = 'none';
document.getElementById('searchInput').style.display = 'block';
loadList();
}
}
</script>
</body>
</html>