style: badges as row above flags, centered over each team
Build & Deploy Tippspiel / build (push) Successful in 51s
Build & Deploy Tippspiel / build (push) Successful in 51s
Badge row uses same flex proportions as match row (flex:1 | spacer | flex:1) so left badge centers over left flag, right badge over right flag. Full team names restored (no more truncation from 5-column layout). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -21,21 +21,21 @@
|
|||||||
inset 0 1px 0 rgba(255,255,255,0.07) !important;
|
inset 0 1px 0 rgba(255,255,255,0.07) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Badge columns — vertically centered to flags */
|
/* Badge row — same flex proportions as matchRow so badges align over flags */
|
||||||
.badgeLeft, .badgeRight {
|
.badgeRow {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
align-self: flex-start;
|
margin-bottom: 8px;
|
||||||
height: 56px; /* match flag height */
|
|
||||||
min-width: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.badgeLeft {
|
.badgeSlot {
|
||||||
justify-content: flex-start;
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.badgeRight {
|
.badgeSpacer {
|
||||||
justify-content: flex-end;
|
min-width: 60px; /* matches scoreBox width */
|
||||||
}
|
}
|
||||||
|
|
||||||
.status {
|
.status {
|
||||||
@@ -123,12 +123,12 @@
|
|||||||
0 0 16px rgba(254, 174, 50, 0.25);
|
0 0 16px rgba(254, 174, 50, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Match block — badges + teams + time/score */
|
/* Match row — Teams + time/score */
|
||||||
.matchBlock {
|
.matchRow {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 6px;
|
gap: 10px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,16 +34,6 @@ function useCountdown(minutesUntilKickoff: number) {
|
|||||||
return remaining;
|
return remaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
const STATUS_LABELS: Record<string, string> = {
|
|
||||||
SCHEDULED: 'Geplant',
|
|
||||||
TIMED: 'Terminiert',
|
|
||||||
IN_PLAY: 'Live',
|
|
||||||
PAUSED: 'Pause',
|
|
||||||
FINISHED: 'Beendet',
|
|
||||||
POSTPONED: 'Verschoben',
|
|
||||||
CANCELLED: 'Abgesagt',
|
|
||||||
};
|
|
||||||
|
|
||||||
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',
|
||||||
@@ -84,24 +74,49 @@ 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}`}>
|
||||||
|
|
||||||
{/* Main layout: badges + teams + time/score in one block */}
|
{/* Badge row — centered above each flag */}
|
||||||
<div className={styles.matchBlock}>
|
<div className={styles.badgeRow}>
|
||||||
{/* Left badge — group */}
|
<span className={styles.badgeSlot}>
|
||||||
<div className={styles.badgeLeft}>
|
|
||||||
{match.group && (
|
{match.group && (
|
||||||
<span className={styles.group}>
|
<span className={styles.group}>
|
||||||
{match.group.replace('GROUP_', 'Gr. ')}
|
{match.group.replace('GROUP_', 'Gruppe ')}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</span>
|
||||||
|
<span className={styles.badgeSpacer} />
|
||||||
|
<span className={styles.badgeSlot}>
|
||||||
|
{isLive && (
|
||||||
|
<span className={styles.liveBadge}>
|
||||||
|
<span className={styles.liveDot} />
|
||||||
|
LIVE
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{isFinished && (
|
||||||
|
<span className={styles.finishedBadge}>Beendet</span>
|
||||||
|
)}
|
||||||
|
{(state === 'open' || state === 'tipped') && match.tippable && (
|
||||||
|
<span className={`${styles.countdownBadge} ${remainingMins < 60 ? styles.countdownUrgent : ''}`}>
|
||||||
|
{match.minutesUntilKickoff < 60
|
||||||
|
? `Noch ${remainingMins} Min!`
|
||||||
|
: (() => {
|
||||||
|
const h = Math.floor(match.minutesUntilKickoff / 60);
|
||||||
|
if (h < 24) return `in ${h}h`;
|
||||||
|
const d = Math.floor(h / 24);
|
||||||
|
return `in ${d} Tag${d > 1 ? 'en' : ''}`;
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Home team */}
|
{/* Teams + Center (time or score) */}
|
||||||
|
<div className={styles.matchRow}>
|
||||||
<div className={styles.teamHome}>
|
<div className={styles.teamHome}>
|
||||||
<FlagBox crest={match.homeTeam.crest} name={match.homeTeam.name} />
|
<FlagBox crest={match.homeTeam.crest} name={match.homeTeam.name} />
|
||||||
<span className={styles.teamName}>{match.homeTeam.shortName}</span>
|
<span className={styles.teamName}>{match.homeTeam.shortName}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Center: LED time or Score */}
|
|
||||||
<div className={styles.scoreBox}>
|
<div className={styles.scoreBox}>
|
||||||
{isFinished || isLive ? (
|
{isFinished || isLive ? (
|
||||||
<span className={`${styles.score} ${isLive ? styles.scoreLive : ''}`}>
|
<span className={`${styles.score} ${isLive ? styles.scoreLive : ''}`}>
|
||||||
@@ -112,37 +127,10 @@ export default function MatchCard({ match, onTip }: Props) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Away team */}
|
|
||||||
<div className={styles.teamAway}>
|
<div className={styles.teamAway}>
|
||||||
<FlagBox crest={match.awayTeam.crest} name={match.awayTeam.name} />
|
<FlagBox crest={match.awayTeam.crest} name={match.awayTeam.name} />
|
||||||
<span className={styles.teamName}>{match.awayTeam.shortName}</span>
|
<span className={styles.teamName}>{match.awayTeam.shortName}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right badge — status/countdown */}
|
|
||||||
<div className={styles.badgeRight}>
|
|
||||||
{isLive && (
|
|
||||||
<span className={styles.liveBadge}>
|
|
||||||
<span className={styles.liveDot} />
|
|
||||||
LIVE
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
{isFinished && (
|
|
||||||
<span className={styles.finishedBadge}>{STATUS_LABELS[match.status] ?? match.status}</span>
|
|
||||||
)}
|
|
||||||
{(state === 'open' || state === 'tipped') && match.tippable && (
|
|
||||||
<span className={`${styles.countdownBadge} ${remainingMins < 60 ? styles.countdownUrgent : ''}`}>
|
|
||||||
{match.minutesUntilKickoff < 60
|
|
||||||
? `${remainingMins}m`
|
|
||||||
: (() => {
|
|
||||||
const h = Math.floor(match.minutesUntilKickoff / 60);
|
|
||||||
if (h < 24) return `${h}h`;
|
|
||||||
const d = Math.floor(h / 24);
|
|
||||||
return `${d}d`;
|
|
||||||
})()
|
|
||||||
}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Tipp area — wird zum farbigen Banner wenn Punkte ausgewertet */}
|
{/* Tipp area — wird zum farbigen Banner wenn Punkte ausgewertet */}
|
||||||
|
|||||||
Reference in New Issue
Block a user