fix: kickoff time centered without 'Uhr', unified countdown badge, DevPanel close button
Build & Deploy Tippspiel / build (push) Successful in 50s

- Kickoff: centered "21:00" above flags (no 'Uhr' suffix)
- Countdown: always rendered as badge (was unstyled span for <60min)
- DevPanel: added close button (✕) in panel header for reliable closing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ronny
2026-04-11 22:46:53 +02:00
parent ea5018ab09
commit e175bb8804
4 changed files with 47 additions and 26 deletions
@@ -46,6 +46,23 @@
padding: 12px 16px; padding: 12px 16px;
background: rgba(254,174,50,0.08); background: rgba(254,174,50,0.08);
border-bottom: 1px solid rgba(254,174,50,0.15); border-bottom: 1px solid rgba(254,174,50,0.15);
display: flex;
align-items: center;
justify-content: space-between;
}
.closeBtn {
background: none;
border: none;
color: var(--text-muted);
font-size: 16px;
cursor: pointer;
padding: 4px 8px;
border-radius: 6px;
}
.closeBtn:hover {
background: rgba(255,255,255,0.1);
color: var(--text-primary);
} }
.panelTitle { .panelTitle {
+1
View File
@@ -131,6 +131,7 @@ export default function DevPanel({ currentUser, onUserChange, matches, onRefresh
<div className={styles.panel}> <div className={styles.panel}>
<div className={styles.panelHeader}> <div className={styles.panelHeader}>
<span className={styles.panelTitle}>🧪 Simulations-Modus</span> <span className={styles.panelTitle}>🧪 Simulations-Modus</span>
<button className={styles.closeBtn} onClick={() => setOpen(false)}></button>
</div> </div>
{/* User Switcher */} {/* User Switcher */}
+9 -4
View File
@@ -77,12 +77,17 @@
border: 1px solid rgba(75,183,248,0.15); border: 1px solid rgba(75,183,248,0.15);
} }
/* Kickoff badge in header row */ /* Kickoff time — centered above flags */
.kickoffBadge { .kickoffRow {
font-size: 12px; text-align: center;
margin-bottom: 6px;
}
.kickoffTime {
font-size: 13px;
font-weight: 700; font-weight: 700;
color: var(--text-secondary); color: var(--text-secondary);
letter-spacing: 0.02em; letter-spacing: 0.05em;
} }
.topRowSpacer { .topRowSpacer {
+20 -22
View File
@@ -47,17 +47,7 @@ const STATUS_LABELS: Record<string, string> = {
function formatKickoff(utcDate: string): string { function formatKickoff(utcDate: string): string {
return new Date(utcDate).toLocaleString('de-DE', { return new Date(utcDate).toLocaleString('de-DE', {
hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Berlin', hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Berlin',
}) + ' Uhr'; });
}
function CountdownBadge({ minutes }: { minutes: number }) {
if (minutes <= 0) return null;
if (minutes < 60) return <span className={styles.badgeUrgent}> in {minutes} Min.</span>;
const h = Math.floor(minutes / 60);
const m = minutes % 60;
if (h < 24) return <span className={styles.badge}>in {h}h{m > 0 ? ` ${m}m` : ''}</span>;
const d = Math.floor(h / 24);
return <span className={styles.badge}>in {d} Tag{d > 1 ? 'en' : ''}</span>;
} }
function FlagBox({ crest, name }: { crest: string | null; name: string }) { function FlagBox({ crest, name }: { crest: string | null; name: string }) {
@@ -94,7 +84,7 @@ export default function MatchCard({ match, onTip }: Props) {
return ( return (
<div className={`card ${styles.card} ${styles[`card_${state}`]} ${isLive ? styles.live : ''} ${glowClass}`}> <div className={`card ${styles.card} ${styles[`card_${state}`]} ${isLive ? styles.live : ''} ${glowClass}`}>
{/* Top row: Group + Kickoff + Countdown */} {/* Top row: Group + Countdown */}
<div className={styles.topRow}> <div className={styles.topRow}>
{(isLive || isFinished) && ( {(isLive || isFinished) && (
<span className={`${styles.status} ${isLive ? styles.statusLive : ''}`}> <span className={`${styles.status} ${isLive ? styles.statusLive : ''}`}>
@@ -107,21 +97,29 @@ export default function MatchCard({ match, onTip }: Props) {
{match.group.replace('GROUP_', 'Gruppe ')} {match.group.replace('GROUP_', 'Gruppe ')}
</span> </span>
)} )}
{!isFinished && !isLive && (
<span className={styles.kickoffBadge}>{formatKickoff(match.utcDate)}</span>
)}
<span className={styles.topRowSpacer} /> <span className={styles.topRowSpacer} />
{(state === 'open' || state === 'tipped') && match.tippable && ( {(state === 'open' || state === 'tipped') && match.tippable && (
match.minutesUntilKickoff < 60 ? ( <span className={`${styles.badge} ${remainingMins < 60 ? styles.badgeUrgent : ''} ${remainingMins < 5 ? styles.countdownUrgent : ''}`}>
<span className={`${styles.countdown} ${remainingMins < 5 ? styles.countdownUrgent : ''}`}> {match.minutesUntilKickoff < 60
Noch {remainingMins} Min! ? `Noch ${remainingMins} Min!`
</span> : (() => {
) : ( const h = Math.floor(match.minutesUntilKickoff / 60);
<CountdownBadge minutes={match.minutesUntilKickoff} /> if (h < 24) return `in ${h}h`;
) const d = Math.floor(h / 24);
return `in ${d} Tag${d > 1 ? 'en' : ''}`;
})()
}
</span>
)} )}
</div> </div>
{/* Kickoff time — centered above flags */}
{!isFinished && !isLive && (
<div className={styles.kickoffRow}>
<span className={styles.kickoffTime}>{formatKickoff(match.utcDate)}</span>
</div>
)}
{/* Teams + Score */} {/* Teams + Score */}
<div className={styles.matchRow}> <div className={styles.matchRow}>
{/* Home */} {/* Home */}