UI Refresh & Logic Updates: New answer color scheme, improved Boolean/Number handling for results, and localized formatting.

This commit is contained in:
2026-04-16 20:40:27 +02:00
parent 604d23bcdf
commit 2c352b2392
5 changed files with 41 additions and 55 deletions
+11 -16
View File
@@ -16,23 +16,22 @@
background: #111111 url('/img/bg.png') center/cover fixed;
}
/* Answer button base colors */
.answer-a {
background: #dc2626;
}
.answer-a:hover {
background: #b91c1c;
}
.answer-b {
background: #2563eb;
}
.answer-b:hover {
.answer-a:hover {
background: #1d4ed8;
}
.answer-b {
background: #7c3aed;
}
.answer-b:hover {
background: #6d28d9;
}
.answer-c {
background: #d97706;
}
@@ -42,14 +41,13 @@
}
.answer-d {
background: #16a34a;
background: #0891b2;
}
.answer-d:hover {
background: #15803d;
background: #0e7490;
}
/* Selected state */
.answer-a.selected,
.answer-b.selected,
.answer-c.selected,
@@ -58,7 +56,6 @@
transform: scale(1.03);
}
/* Disabled state */
.answer-a.disabled,
.answer-b.disabled,
.answer-c.disabled,
@@ -67,7 +64,6 @@
cursor: not-allowed;
}
/* Ensure Tailwind doesn't override answer button styles */
button.answer-a,
button.answer-b,
button.answer-c,
@@ -83,7 +79,6 @@
transform: scale(1.03);
}
/* Fire gradient for headings */
.fire-gradient {
background: linear-gradient(135deg, #dc2626, #f59e0b);
-webkit-background-clip: text;
+20 -30
View File
@@ -158,8 +158,9 @@ function StatsPage() {
const u = a['Nutzername'] || 'Unbekannt';
if (!users[u]) users[u] = { total: 0, correct: 0, points: 0 };
users[u].total++;
if (a['Richtig']) users[u].correct++;
users[u].points += a['Punkte'] || 0;
const richtig = a['Richtig'];
if (richtig === true || richtig === 'true' || richtig === 1) users[u].correct++;
users[u].points += Number(a['Punkte']) || 0;
});
return (
@@ -167,21 +168,11 @@ function StatsPage() {
<div className="bg-white rounded-xl shadow p-6">
<h2 className="text-xl font-bold mb-4">📊 Übersicht</h2>
<div className="grid grid-cols-3 gap-4 text-center">
<div className="bg-red-50 rounded-lg p-4">
<div className="text-2xl font-bold text-red-600">{Object.keys(sessions).length}</div>
<div className="text-sm text-gray-500">Sessions</div>
</div>
<div className="bg-amber-50 rounded-lg p-4">
<div className="text-2xl font-bold text-amber-600">{Object.keys(users).length}</div>
<div className="text-sm text-gray-500">Teilnehmer</div>
</div>
<div className="bg-orange-50 rounded-lg p-4">
<div className="text-2xl font-bold text-orange-600">{data.answers.length}</div>
<div className="text-sm text-gray-500">Antworten</div>
</div>
<div className="bg-red-50 rounded-lg p-4"><div className="text-2xl font-bold text-red-600">{Object.keys(sessions).length}</div><div className="text-sm text-gray-500">Sessions</div></div>
<div className="bg-amber-50 rounded-lg p-4"><div className="text-2xl font-bold text-amber-600">{Object.keys(users).length}</div><div className="text-sm text-gray-500">Teilnehmer</div></div>
<div className="bg-orange-50 rounded-lg p-4"><div className="text-2xl font-bold text-orange-600">{data.answers.length}</div><div className="text-sm text-gray-500">Antworten</div></div>
</div>
</div>
<div className="bg-white rounded-xl shadow p-6">
<h3 className="text-lg font-bold mb-3">👤 Pro Teilnehmer</h3>
<input className="w-full p-2 border rounded-lg mb-3 focus:border-red-500 outline-none" placeholder="Filtern..." value={filter} onChange={(e) => setFilter(e.target.value)} />
@@ -189,28 +180,27 @@ function StatsPage() {
<table className="w-full text-sm">
<thead><tr className="border-b"><th className="text-left py-2">Name</th><th>Richtig</th><th>Gesamt</th><th>Quote</th><th>Punkte</th></tr></thead>
<tbody>
{Object.entries(users)
.filter(([u]) => !filter || u.toLowerCase().includes(filter.toLowerCase()))
.sort(([, a], [, b]) => b.points - a.points)
.map(([u, v]) => (
<tr key={u} className="border-b last:border-0">
<td className="py-2 font-medium">{u}</td>
<td className="text-center text-green-600">{v.correct}</td>
<td className="text-center">{v.total}</td>
<td className="text-center">{Math.round((v.correct / v.total) * 100)}%</td>
<td className="text-center font-bold">{v.points}</td>
</tr>
))}
{Object.entries(users).filter(([u]) => !filter || u.toLowerCase().includes(filter.toLowerCase())).sort(([, a], [, b]) => b.points - a.points).map(([u, v]) => (
<tr key={u} className="border-b last:border-0">
<td className="py-2 font-medium">{u}</td>
<td className="text-center text-green-600">{v.correct}</td>
<td className="text-center">{v.total}</td>
<td className="text-center">{Math.round((v.correct / v.total) * 100)}%</td>
<td className="text-center font-bold">{v.points.toLocaleString('de')}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
<div className="bg-white rounded-xl shadow p-6">
<h3 className="text-lg font-bold mb-3">📁 Sessions</h3>
{Object.entries(sessions).reverse().map(([sid, s]) => {
const total = s.answers.length;
const correct = s.answers.filter((a) => a['Richtig']).length;
const correct = s.answers.filter((a) => {
const v = a['Richtig'];
return v === true || v === 'true' || v === 1;
}).length;
const uniqueUsers = new Set(s.answers.map((a) => a['Nutzername'])).size;
return (
<div key={sid} className="border-b last:border-0 py-3">
@@ -485,7 +475,7 @@ function LiveControlPage({ token, code, ws, initialSession }) {
{result?.stats && (
<div className="grid grid-cols-2 gap-2 mb-4">
{Object.entries(result.stats).map(([k, v]) => (
<div key={k} className={`p-2 rounded-lg text-white text-center ${k === 'A' ? 'bg-red-500' : k === 'B' ? 'bg-blue-500' : k === 'C' ? 'bg-amber-500' : 'bg-green-500'}`}>
<div key={k} className={`p-2 rounded-lg text-white text-center ${k === 'A' ? 'bg-blue-500' : k === 'B' ? 'bg-purple-500' : k === 'C' ? 'bg-amber-500' : 'bg-cyan-500'}`}>
{k}: <strong>{v}</strong>
</div>
))}
+6 -3
View File
@@ -705,8 +705,11 @@ function MyResultsPage({ navigate }) {
<div className="w-full max-w-md mt-6 space-y-4">
{Object.entries(sessions).reverse().map(([sid, s]) => {
const total = s.answers.length;
const cor = s.answers.filter((a) => a['Richtig']).length;
const points = s.answers.reduce((sum, a) => sum + (a['Punkte'] || 0), 0);
const cor = s.answers.filter((a) => {
const v = a['Richtig'];
return v === true || v === 'true' || v === 1;
}).length;
const points = s.answers.reduce((sum, a) => sum + (Number(a['Punkte']) || 0), 0);
return (
<div key={sid} className="bg-gray-800 rounded-xl p-4">
<div className="flex justify-between items-start mb-2">
@@ -716,7 +719,7 @@ function MyResultsPage({ navigate }) {
</div>
<span className="text-sm text-gray-400">{s.date ? new Date(s.date).toLocaleDateString('de') : ''}</span>
</div>
<p>{cor}/{total} richtig {points} Punkte</p>
<p>{cor}/{total} richtig {points.toLocaleString('de')} Punkte</p>
</div>
);
})}
+1 -1
View File
@@ -113,7 +113,7 @@ function PresentApp() {
{question?.typ?.toLowerCase() !== 'freitext' && (
<div className="grid grid-cols-2 gap-4 flex-1 max-h-96">
{(question?.antworten || []).map((a) => {
const colors = { A: 'bg-red-600', B: 'bg-blue-600', C: 'bg-amber-600', D: 'bg-green-600' };
const colors = { A: 'bg-blue-600', B: 'bg-purple-600', C: 'bg-amber-600', D: 'bg-cyan-600' };
return (
<div key={a.key} className={`${colors[a.key] || 'bg-gray-600'} rounded-2xl flex items-center justify-center p-6 text-2xl font-bold`}>{a.text}</div>
);
+3 -5
View File
@@ -16,13 +16,12 @@
background: #111111 url('/img/bg.png') center/cover fixed;
}
/* Answer colors for presentation view */
.answer-a {
background: #dc2626;
background: #2563eb;
}
.answer-b {
background: #2563eb;
background: #7c3aed;
}
.answer-c {
@@ -30,10 +29,9 @@
}
.answer-d {
background: #16a34a;
background: #0891b2;
}
/* Fire gradient for headings */
.fire-gradient {
background: linear-gradient(135deg, #dc2626, #f59e0b);
-webkit-background-clip: text;