- Stream-Übersicht unter /stream/<Zuschauercode> (1920x1080, Lobby, Veto, Spielstand) - Live-Stand, Rundenverlauf und Serienstand auf Match-Seite und Übersicht - Parser mit echten AMP-Logs geprüft: Game Over mit leerer Map-Gruppe, Match_Start vor der Aufwärmphase, veraltete Seitenzuordnung nach der Halbzeit - Nach Map-Ende automatisch nächste Map bzw. Abschluss der entschiedenen Serie - LOG_DEBUG zur Fehlersuche, README und .env.example ergänzt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
54 lines
2.4 KiB
React
54 lines
2.4 KiB
React
// Rundenverlauf einer Map: ein Feld pro Runde in der Farbe des Siegerteams,
|
|
// mit Symbol für den Grund. Nach der Halbzeit (und jeder Verlängerungshälfte) ein Trenner.
|
|
|
|
export const REASON_LABEL = {
|
|
bomb: 'Bombe explodiert',
|
|
defuse: 'Bombe entschärft',
|
|
time: 'Zeit abgelaufen',
|
|
elimination: 'Alle ausgeschaltet',
|
|
surrender: 'Aufgegeben',
|
|
other: 'Runde gewonnen',
|
|
};
|
|
|
|
export function ReasonIcon({ reason, size = 12 }) {
|
|
const common = { width: size, height: size, viewBox: '0 0 16 16', 'aria-hidden': true, className: 'reason-icon' };
|
|
switch (reason) {
|
|
case 'bomb':
|
|
return (
|
|
<svg {...common}><circle cx="7" cy="9.5" r="5" fill="currentColor" /><path d="M10.5 5.5 13 3" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" /><circle cx="13.6" cy="2.4" r="1.4" fill="currentColor" /></svg>
|
|
);
|
|
case 'defuse':
|
|
return (
|
|
<svg {...common}><path d="M3 13 9.5 6.5M6.5 3.5 12.5 9.5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" /><circle cx="11.5" cy="4.5" r="2.5" fill="none" stroke="currentColor" strokeWidth="1.8" /></svg>
|
|
);
|
|
case 'time':
|
|
return (
|
|
<svg {...common}><circle cx="8" cy="8" r="6" fill="none" stroke="currentColor" strokeWidth="1.8" /><path d="M8 4.5V8l2.5 1.8" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" /></svg>
|
|
);
|
|
case 'elimination':
|
|
return (
|
|
<svg {...common}><circle cx="8" cy="8" r="5.5" fill="none" stroke="currentColor" strokeWidth="1.6" /><path d="M8 1v4M8 11v4M1 8h4M11 8h4" stroke="currentColor" strokeWidth="1.6" /></svg>
|
|
);
|
|
default:
|
|
return <svg {...common}><circle cx="8" cy="8" r="3" fill="currentColor" /></svg>;
|
|
}
|
|
}
|
|
|
|
export default function RoundStrip({ rounds = [], maxRounds = 24, teams, size = 'md' }) {
|
|
const half = maxRounds / 2;
|
|
const total = Math.max(rounds.length, maxRounds);
|
|
const cells = [];
|
|
for (let i = 1; i <= total; i++) {
|
|
const r = rounds.find((x) => x.number === i);
|
|
const breakBefore = i > 1 && (i - 1 === half || (i - 1 > maxRounds && (i - 1 - maxRounds) % 3 === 0));
|
|
cells.push(
|
|
<li key={i}
|
|
className={`round ${r ? `won-${r.winner}` : 'open'} ${breakBefore ? 'break' : ''}`}
|
|
title={r ? `Runde ${i}: ${teams[r.winner].name} (${REASON_LABEL[r.reason] ?? ''})` : `Runde ${i}`}>
|
|
{r ? <ReasonIcon reason={r.reason} /> : null}
|
|
</li>,
|
|
);
|
|
}
|
|
return <ol className={`round-strip round-strip-${size}`} aria-label="Rundenverlauf">{cells}</ol>;
|
|
}
|