style: badges centered to flags, wider dashboard, mobile header actions

MatchCard:
- Badges (group, countdown, LIVE, BEENDET) now vertically centered
  to flag height, positioned left/right of the teams
- Removed separate topRow — all in one matchBlock flex layout

Dashboard:
- max-width increased to 800px (matches spielplan width)

Header:
- Theme toggle + admin link moved to headerActions (always visible)
- Theme toggle icon in gold color (was too dark in dark mode)
- Admin link brighter (text-secondary instead of text-muted)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ronny
2026-04-12 13:55:00 +02:00
parent 0e1675fe90
commit 799239dcc1
5 changed files with 70 additions and 51 deletions
+11 -4
View File
@@ -85,8 +85,8 @@
font-size: 16px; font-size: 16px;
cursor: pointer; cursor: pointer;
transition: background 0.15s, transform 0.1s; transition: background 0.15s, transform 0.1s;
margin-left: 6px;
flex-shrink: 0; flex-shrink: 0;
color: var(--gold);
} }
.themeToggle:hover { background: var(--primary-dim); } .themeToggle:hover { background: var(--primary-dim); }
.themeToggle:active { transform: scale(0.92); } .themeToggle:active { transform: scale(0.92); }
@@ -106,19 +106,26 @@
} }
} }
/* Hide header nav on mobile */ /* Header actions — always visible (theme toggle + admin) */
.headerActions {
display: flex;
align-items: center;
gap: 4px;
}
/* Hide header nav on mobile, keep actions */
@media (max-width: 767px) { @media (max-width: 767px) {
.nav { .nav {
display: none; display: none;
} }
} }
/* Admin link: icon only, subtle */ /* Admin link: icon only */
.adminLink { .adminLink {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 4px; padding: 4px;
color: var(--text-muted); color: var(--text-secondary);
text-decoration: none; text-decoration: none;
transition: color 0.2s; transition: color 0.2s;
} }
+3 -1
View File
@@ -93,6 +93,8 @@ export default function App() {
<NavLink to="/profil" className={({ isActive }) => isActive ? styles.navLinkActive : styles.navLink}> <NavLink to="/profil" className={({ isActive }) => isActive ? styles.navLinkActive : styles.navLink}>
Mein Profil Mein Profil
</NavLink> </NavLink>
</nav>
<div className={styles.headerActions}>
<NavLink to="/admin" className={styles.adminLink} title="Admin"> <NavLink to="/admin" className={styles.adminLink} title="Admin">
<Settings size={16} /> <Settings size={16} />
</NavLink> </NavLink>
@@ -104,7 +106,7 @@ export default function App() {
> >
{theme === 'dark' ? <Sun size={16} /> : <Moon size={16} />} {theme === 'dark' ? <Sun size={16} /> : <Moon size={16} />}
</button> </button>
</nav> </div>
</div> </div>
</header> </header>
+16 -9
View File
@@ -21,14 +21,21 @@
inset 0 1px 0 rgba(255,255,255,0.07) !important; inset 0 1px 0 rgba(255,255,255,0.07) !important;
} }
/* Top row — badges inset to align near flag inner edges */ /* Badge columns — vertically centered to flags */
.topRow { .badgeLeft, .badgeRight {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; align-self: flex-start;
margin-bottom: 12px; height: 56px; /* match flag height */
margin-left: 8px; min-width: 0;
margin-right: 8px; }
.badgeLeft {
justify-content: flex-start;
}
.badgeRight {
justify-content: flex-end;
} }
.status { .status {
@@ -116,12 +123,12 @@
0 0 16px rgba(254, 174, 50, 0.25); 0 0 16px rgba(254, 174, 50, 0.25);
} }
/* Match row — Teams + Score/Time */ /* Match block — badges + teams + time/score */
.matchRow { .matchBlock {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
justify-content: center; justify-content: center;
gap: 10px; gap: 6px;
margin-bottom: 16px; margin-bottom: 16px;
} }
+33 -30
View File
@@ -84,41 +84,18 @@ 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 left + Status/Countdown right */} {/* Main layout: badges + teams + time/score in one block */}
<div className={styles.topRow}> <div className={styles.matchBlock}>
{/* Left badge — group */}
<div className={styles.badgeLeft}>
{match.group && ( {match.group && (
<span className={styles.group}> <span className={styles.group}>
{match.group.replace('GROUP_', 'Gruppe ')} {match.group.replace('GROUP_', 'Gr. ')}
</span>
)}
<span style={{ flex: 1 }} />
{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
? `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> </div>
{/* Teams + Center (time or score) */} {/* Home team */}
<div className={styles.matchRow}>
{/* Home */}
<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>
@@ -135,11 +112,37 @@ export default function MatchCard({ match, onTip }: Props) {
)} )}
</div> </div>
{/* Away */} {/* 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 */}
+2 -2
View File
@@ -1,6 +1,6 @@
.dashboard { .dashboard {
padding: 16px; padding: 12px;
max-width: 600px; max-width: 800px;
margin: 0 auto; margin: 0 auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;