From dc3c375081d3a339a1b864a739e34041b8fcd93f Mon Sep 17 00:00:00 2001 From: Nils Briggen Date: Fri, 12 Jun 2026 00:30:48 +0200 Subject: [PATCH] Mobile overhaul: round-picker bracket, 5-tab nav + More sheet, real icons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Bracket on phones: a segmented round picker with full-width cards replaces the 1040px sideways scroll; desktop keeps the columns. - Odds table: sticky team column; the three lowest-value columns hide on phones so Team/QF/SF/Final/Champion fit without scrolling. - Bottom nav: 4 primary tabs + a More sheet (vs Markt, Modell, Story, Teams, Daten, plus language & theme toggles) — 7 tabs were cramped. - Emoji → icons: timeline events use a ball icon, card-shaped color chips and substitution arrows; unknown-team fallbacks use a shield. Country-flag emojis stay (intentional). - Readability: bigger scores on match cards, minimum text sizes bumped, probability-number triple hides on the narrowest screens (the bar carries the information). Co-Authored-By: Claude Fable 5 --- src/app/RootLayout.tsx | 108 +++++++++++++++++---- src/components/MatchCard.tsx | 4 +- src/components/OddsTable.tsx | 21 ++-- src/features/bracket/BracketPage.tsx | 79 +++++++++++---- src/features/match/MatchPreviewPage.tsx | 22 +++-- src/features/scoreboard/ScoreboardPage.tsx | 5 +- src/features/team/TeamProfilePage.tsx | 4 +- 7 files changed, 183 insertions(+), 60 deletions(-) diff --git a/src/app/RootLayout.tsx b/src/app/RootLayout.tsx index 20b8423..eb2843b 100644 --- a/src/app/RootLayout.tsx +++ b/src/app/RootLayout.tsx @@ -1,6 +1,6 @@ -import { useEffect } from 'react'; -import { Link, Outlet } from '@tanstack/react-router'; -import { Gauge, GitMerge, Languages, Moon, Radio, Scale, Sparkles, Sun, Table, TrendingUp, Trophy } from 'lucide-react'; +import { useEffect, useState } from 'react'; +import { Link, Outlet, useRouterState } from '@tanstack/react-router'; +import { Database, Gauge, GitMerge, Languages, Menu, Moon, Radio, Scale, Sparkles, Sun, Table, TrendingUp, Trophy, Users } from 'lucide-react'; import type { LucideIcon } from 'lucide-react'; import { useUiStore } from '@/stores/uiStore'; import { useLocaleStore } from '@/stores/localeStore'; @@ -8,7 +8,9 @@ import { useTournamentStore } from '@/stores/tournamentStore'; import { useT, type Dict } from '@/lib/i18n'; import { cn } from '@/lib/cn'; -const NAV: { to: string; label: (t: Dict) => string; exact: boolean; icon: LucideIcon }[] = [ +interface NavItem { to: string; label: (t: Dict) => string; exact: boolean; icon: LucideIcon } + +const NAV: NavItem[] = [ { to: '/', label: (t) => t.nav.live, exact: true, icon: Radio }, { to: '/groups', label: (t) => t.nav.groups, exact: false, icon: Table }, { to: '/bracket', label: (t) => t.nav.bracket, exact: false, icon: GitMerge }, @@ -18,6 +20,14 @@ const NAV: { to: string; label: (t: Dict) => string; exact: boolean; icon: Lucid { to: '/story', label: (t) => t.nav.story, exact: false, icon: Sparkles }, ]; +// Phones get four primary tabs + a "More" sheet (7 tabs were unusably cramped). +const MOBILE_PRIMARY: NavItem[] = NAV.slice(0, 4); +const MOBILE_MORE: NavItem[] = [ + ...NAV.slice(4), + { to: '/teams', label: (t) => t.nav.teams, exact: false, icon: Users }, + { to: '/data', label: (t) => t.nav.data, exact: false, icon: Database }, +]; + function ConnectionStatus() { const t = useT(); const status = useTournamentStore((s) => s.status); @@ -76,6 +86,78 @@ export function LanguageToggle() { ); } +function MobileNav() { + const t = useT(); + const [moreOpen, setMoreOpen] = useState(false); + const pathname = useRouterState({ select: (s) => s.location.pathname }); + const moreActive = MOBILE_MORE.some((i) => pathname.startsWith(i.to)); + + useEffect(() => setMoreOpen(false), [pathname]); + + return ( + <> + {moreOpen && ( + + + + ); +} + export function RootLayout() { const t = useT(); useEffect(() => { @@ -119,23 +201,7 @@ export function RootLayout() { - {/* Mobile bottom tab bar */} - +