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:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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}>
|
||||||
{match.group && (
|
{/* Left badge — group */}
|
||||||
<span className={styles.group}>
|
<div className={styles.badgeLeft}>
|
||||||
{match.group.replace('GROUP_', 'Gruppe ')}
|
{match.group && (
|
||||||
</span>
|
<span className={styles.group}>
|
||||||
)}
|
{match.group.replace('GROUP_', 'Gr. ')}
|
||||||
<span style={{ flex: 1 }} />
|
</span>
|
||||||
{isLive && (
|
)}
|
||||||
<span className={styles.liveBadge}>
|
</div>
|
||||||
<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>
|
|
||||||
)}
|
|
||||||
</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 */}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user