From 10d6bbbbdd282193639711c995668ad824e1c41e Mon Sep 17 00:00:00 2001 From: Nico Date: Wed, 13 May 2026 17:50:13 +0200 Subject: [PATCH 1/3] fix(ui): make layout responsive across all desktop resolutions (960px to ultrawide) - Fix viewport meta: remove hardcoded width=1366 lock - Add text-2xs (0.625rem) token for proper rem-based font scaling - Wrap tables in overflow-x-auto to prevent horizontal clipping - Replace all text-[Npx] with rem-based Tailwind tokens (342 replacements) - Replace hardcoded min-w-[Npx] with theme tokens - Expand containers proportionally (w-[92%] max-w-[2000px]) at >1920px - Add 2xl: grid breakpoints for multi-column layouts on large screens - Add responsive breakpoints to ChampionDraft outer containers - CompactTier verified: no clipping at 960px minimum window Closes #220 --- .gitignore | 15 ++ index.html | 2 +- src/App.css | 1 + src/components/EndOfSeasonScreen.tsx | 4 +- src/components/NegotiationFeedbackPanel.tsx | 6 +- src/components/NextMatchDisplay.tsx | 2 +- src/components/TraitBadge.tsx | 6 +- src/components/champions/ChampionProfile.tsx | 4 +- src/components/champions/ChampionsTab.tsx | 26 +- .../dashboard/DashboardBlockerModal.tsx | 2 +- src/components/dashboard/DashboardSidebar.tsx | 6 +- src/components/finances/FinancesTab.tsx | 2 +- src/components/home/HomeLatestNewsCard.tsx | 6 +- src/components/home/HomeLeagueDigestCard.tsx | 2 +- .../home/HomeLeaguePositionCard.tsx | 4 +- src/components/home/HomeNextOpponentCard.tsx | 2 +- .../home/HomePlayerMomentumCard.tsx | 4 +- .../home/HomeRecentMessagesCard.tsx | 2 +- src/components/home/HomeRecentResultsCard.tsx | 2 +- src/components/home/HomeRosterLineupCard.tsx | 8 +- src/components/home/HomeSeasonStatusCard.tsx | 4 +- src/components/home/HomeTab.tsx | 2 +- src/components/home/HomeThisWeekCard.tsx | 6 +- src/components/home/HomeTodayPlanCard.tsx | 4 +- src/components/inbox/InboxTab.tsx | 2 +- src/components/manager/ManagerTab.tsx | 58 ++-- src/components/match/ChampionDraft.tsx | 124 ++++----- src/components/match/DraftResultScreen.tsx | 24 +- src/components/match/HalfTimeBreak.tsx | 4 +- src/components/match/LolLiveMap.tsx | 10 +- src/components/match/LolMatchLive.tsx | 52 ++-- src/components/match/LolResultScreen.tsx | 10 +- src/components/match/MatchLive.tsx | 6 +- src/components/match/MatchPanels.tsx | 20 +- src/components/match/PostMatchHelpers.tsx | 6 +- src/components/match/PostMatchScreen.tsx | 14 +- src/components/match/PreMatchLineup.tsx | 38 +-- src/components/match/PreMatchSetup.tsx | 2 +- src/components/match/SubPanel.tsx | 248 +++++++++++++----- .../match/lol-prototype/ui/panels.tsx | 28 +- src/components/news/NewsTab.tsx | 22 +- .../playerProfile/PlayerProfile.tsx | 4 +- .../PlayerProfileAttributesCard.tsx | 2 +- .../PlayerProfileChampionsCard.tsx | 4 +- .../playerProfile/PlayerProfileHeroCard.tsx | 2 +- src/components/players/PlayersListTab.tsx | 4 +- .../playoffs/PlayoffBracketBoard.tsx | 12 +- .../schedule/ScheduleCalendarView.tsx | 20 +- src/components/schedule/ScheduleTab.tsx | 2 +- .../scouting/ScoutingPlayerSearchCard.tsx | 4 +- .../scouting/ScoutingScoutDetailsCard.tsx | 6 +- src/components/scouting/ScoutingTab.tsx | 2 +- src/components/scrims/ScrimPlanningCard.tsx | 14 +- src/components/scrims/ScrimsTab.tsx | 22 +- src/components/social/SocialEditor.tsx | 22 +- src/components/social/SocialTab.tsx | 2 +- src/components/squad/SquadRosterView.tsx | 32 +-- src/components/staff/StaffTab.tsx | 10 +- src/components/tactics/TacticsTab.tsx | 8 +- src/components/teamProfile/TeamProfile.tsx | 2 +- .../teamProfile/TeamProfileHistoryCard.tsx | 120 ++++----- .../TeamProfileRecentMatchesCard.tsx | 6 +- src/components/teams/TeamsListTab.tsx | 2 +- src/components/tournaments/TournamentsTab.tsx | 196 +++++++------- .../training/TrainingGroupsCard.tsx | 10 +- .../training/TrainingSettingsPanel.tsx | 6 +- src/components/training/TrainingTab.tsx | 4 +- src/components/transfers/TransferBidModal.tsx | 2 +- .../transfers/TransferNegotiationHistory.tsx | 2 +- src/components/transfers/TransfersTab.tsx | 2 +- src/components/ui/Select.tsx | 4 +- src/components/worldEditor/WorldEditorTab.tsx | 6 +- .../youthAcademy/YouthAcademyTab.tsx | 136 +++++----- src/pages/ChampionPage.tsx | 2 +- src/pages/Settings.tsx | 4 +- 75 files changed, 802 insertions(+), 664 deletions(-) diff --git a/.gitignore b/.gitignore index 5191c5da3..2c76f4414 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,18 @@ Thumbs.db # Tauri mobile generated files (optional, Tauri v2) # ========================= src-tauri/gen/ + +# ========================= +# Engram local memory +# ========================= +.engram/ + +# ========================= +# Scraper tool +# ========================= +scraper/ + +# ========================= +# SDD planning artifacts +# ========================= +openspec/ diff --git a/index.html b/index.html index 16bfb5567..a68be3393 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,7 @@ Open League Manager diff --git a/src/App.css b/src/App.css index 8c18f67a6..f33e4c02e 100644 --- a/src/App.css +++ b/src/App.css @@ -28,6 +28,7 @@ /* Typography */ --font-sans: "Inter", "Avenir", "Helvetica", "Arial", sans-serif; --font-heading: "Barlow Condensed", "Inter", "Arial Narrow", sans-serif; + --text-2xs: 0.625rem; /* Primary: Emerald Green */ --color-primary-50: #ecfdf5; diff --git a/src/components/EndOfSeasonScreen.tsx b/src/components/EndOfSeasonScreen.tsx index 8e3a734da..e2c153e86 100644 --- a/src/components/EndOfSeasonScreen.tsx +++ b/src/components/EndOfSeasonScreen.tsx @@ -100,7 +100,7 @@ export default function EndOfSeasonScreen({ gameState, onGameUpdate }: EndOfSeas }; return ( -
+
{step === "review" && ( <> {/* Hero */} @@ -131,7 +131,7 @@ export default function EndOfSeasonScreen({ gameState, onGameUpdate }: EndOfSeas

{userTeam?.name}

-

+

{t("endOfSeason.regularPhaseSummary")}

diff --git a/src/components/NegotiationFeedbackPanel.tsx b/src/components/NegotiationFeedbackPanel.tsx index 9da0d3413..49704088e 100644 --- a/src/components/NegotiationFeedbackPanel.tsx +++ b/src/components/NegotiationFeedbackPanel.tsx @@ -41,7 +41,7 @@ export default function NegotiationFeedbackPanel({ >
-

+

{t(titleKey)}

@@ -70,13 +70,13 @@ export default function NegotiationFeedbackPanel({

-

+

{t(patienceKey)}

-

+

{t(tensionKey)}

diff --git a/src/components/NextMatchDisplay.tsx b/src/components/NextMatchDisplay.tsx index 866b813a4..e7e76ebc7 100644 --- a/src/components/NextMatchDisplay.tsx +++ b/src/components/NextMatchDisplay.tsx @@ -233,7 +233,7 @@ export default function NextMatchDisplay({

{countdown}d

-

+

{t("home.daysUntilMatch")}

diff --git a/src/components/TraitBadge.tsx b/src/components/TraitBadge.tsx index c851b9a92..15bf514c0 100644 --- a/src/components/TraitBadge.tsx +++ b/src/components/TraitBadge.tsx @@ -47,8 +47,8 @@ export function TraitBadge({ trait: traitName, size = "sm" }: { trait: string; s if (!meta) return null; const sizeClasses = size === "xs" - ? "text-[9px] px-1.5 py-0.5 gap-0.5" - : "text-[10px] px-2 py-0.5 gap-1"; + ? "text-2xs px-1.5 py-0.5 gap-0.5" + : "text-2xs px-2 py-0.5 gap-1"; return ( {displayed.map(t => )} {remaining > 0 && ( - +{remaining} + +{remaining} )}
); diff --git a/src/components/champions/ChampionProfile.tsx b/src/components/champions/ChampionProfile.tsx index e6c5eb3b7..da5b23fca 100644 --- a/src/components/champions/ChampionProfile.tsx +++ b/src/components/champions/ChampionProfile.tsx @@ -332,7 +332,7 @@ export default function ChampionProfile({ champion, onClose }: ChampionProfilePr {cp.champion_name || champKey}

{cp.role && ( -

+

{cp.role}

)} @@ -383,7 +383,7 @@ export default function ChampionProfile({ champion, onClose }: ChampionProfilePr {syn.champion_name || champKey}

{syn.role && ( -

+

{syn.role}

)} diff --git a/src/components/champions/ChampionsTab.tsx b/src/components/champions/ChampionsTab.tsx index 5cc08a3ad..f30c9013a 100644 --- a/src/components/champions/ChampionsTab.tsx +++ b/src/components/champions/ChampionsTab.tsx @@ -436,7 +436,7 @@ export default function ChampionsTab({ gameState, onGameUpdate }: ChampionsTabPr
-

+

{t("champions.patchLabel", "Patch")}

@@ -452,7 +452,7 @@ export default function ChampionsTab({ gameState, onGameUpdate }: ChampionsTabPr

-
+
{t("champions.discoveryProgress", "Meta descubierto")} @@ -461,7 +461,7 @@ export default function ChampionsTab({ gameState, onGameUpdate }: ChampionsTabPr
-

+

{t("champions.staffMetaImpact", "Scout read")}: {formatStaffEffectPercent(staffEffects.metaDiscovery)} · {t("champions.staffMasteryImpact", "mastery learning")}: {formatStaffEffectPercent(staffEffects.development)}

@@ -477,7 +477,7 @@ export default function ChampionsTab({ gameState, onGameUpdate }: ChampionsTabPr @@ -613,16 +613,16 @@ export default function ChampionsTab({ gameState, onGameUpdate }: ChampionsTabPr
-

+

{soloQ.tier}

-

+

{soloQ.lp} LP = 0 ? "text-emerald-300" : "text-rose-300"}`}> {soloQ.delta >= 0 ? `+${soloQ.delta}` : soloQ.delta}

-

x{soloQMult.toFixed(1)} mastery

+

x{soloQMult.toFixed(1)} mastery

-

+

P{slotIndex + 1}

{slotTitle}

-

+

{t("champions.gain")} {gainHint.label}

-

{slotDesc}

+

{slotDesc}

setSearchTerm(event.target.value)} - className="rounded-md bg-[#111318] border border-white/15 px-2 py-1 text-[11px] md:py-1.5 md:text-xs w-36 md:w-44" + className="rounded-md bg-[#111318] border border-white/15 px-2 py-1 text-xs md:py-1.5 md:text-xs w-36 md:w-44" placeholder={t("match.draft.searchPlaceholder")} /> @@ -2966,7 +2966,7 @@ export default function ChampionDraft({ @@ -2982,7 +2982,7 @@ export default function ChampionDraft({ {!finished && isUserTurn ? (
-

+

{pendingChampionId ? `${t("match.draft.selected")}: ${championById.get(pendingChampionId)?.name ?? pendingChampionId}` : t("match.draft.selectThenConfirm")} @@ -2991,7 +2991,7 @@ export default function ChampionDraft({ type="button" onClick={handleConfirmPendingAction} disabled={!pendingChampionId} - className="rounded-md bg-orange-500 hover:bg-orange-400 disabled:opacity-40 disabled:cursor-not-allowed text-navy-900 px-3 py-1 text-[11px] font-heading font-bold uppercase tracking-wide" + className="rounded-md bg-orange-500 hover:bg-orange-400 disabled:opacity-40 disabled:cursor-not-allowed text-navy-900 px-3 py-1 text-xs font-heading font-bold uppercase tracking-wide" > {currentStep?.type === "ban" ? t("match.draft.actions.ban") @@ -3010,7 +3010,7 @@ export default function ChampionDraft({ ) : visibleChampions.length === 0 ? (

{t("match.draft.noChampionsForFilters")}

) : ( -
+
{visibleChampions.map((champion) => { const isUsed = usedChampionIds.has(champion.id); const showMastery = roleFilter !== "ALL"; @@ -3035,12 +3035,12 @@ export default function ChampionDraft({ loading="lazy" />

{champion.name}

-
+
{metaTier} {showMastery ? {mastery} : null}
@@ -3061,16 +3061,16 @@ export default function ChampionDraft({
-
-

+

{t("match.draft.counterIntelPros", { defaultValue: "In your favor" })}

{selectedChampionCounterIntel.favorable.length === 0 ? ( -
+
{t("match.draft.counterIntelNoPros", { defaultValue: "No clear favorable counters detected." })}
) : null} @@ -3113,23 +3113,23 @@ export default function ChampionDraft({
{row.champion.name}
-

{row.champion.name}

-

+

{row.champion.name}

+

{row.isPicked ? t("match.draft.counterIntelPicked", { defaultValue: "Already picked by rival" }) : t("match.draft.counterIntelPotential", { defaultValue: "Potential rival pick" })}

-

+{row.value}

+

+{row.value}

))} -

+

{t("match.draft.counterIntelCons", { defaultValue: "Against your pick" })}

{selectedChampionCounterIntel.risky.length === 0 ? ( -
+
{t("match.draft.counterIntelNoCons", { defaultValue: "No immediate hard counters found." })}
) : null} @@ -3141,14 +3141,14 @@ export default function ChampionDraft({
{row.champion.name}
-

{row.champion.name}

-

+

{row.champion.name}

+

{row.isPicked ? t("match.draft.counterIntelPicked", { defaultValue: "Already picked by rival" }) : t("match.draft.counterIntelPotential", { defaultValue: "Potential rival pick" })}

-

-{row.value}

+

-{row.value}

))} @@ -3156,12 +3156,12 @@ export default function ChampionDraft({ ) : ( <> -

+

{t("match.draft.enemyComfortTitle")}

{rivalMasteryDisplay.length === 0 ? ( -
+
{t("match.draft.enemyComfortUnknown")}
) : null} @@ -3175,9 +3175,9 @@ export default function ChampionDraft({ loading="lazy" />
-

{champion.name}

-

{playerName}

-

+

{champion.name}

+

{playerName}

+

{source === "insignia" ? t("match.draft.masterySourceSignature") : source === "scouting" @@ -3188,7 +3188,7 @@ export default function ChampionDraft({

-

{mastery}

+

{mastery}

))} @@ -3279,7 +3279,7 @@ function DraftSlot({ className={`absolute inset-y-0 ${side === "blue" ? "left-0 border-r border-r-cyan-300/40" : "right-0 border-l border-l-orange-400/45"} ${compact ? "w-5" : "w-8"} bg-black/65 border-white/25 z-20 flex items-center justify-center`} > {playerName} @@ -3299,7 +3299,7 @@ function DraftSlot({ event.stopPropagation(); onSwapArm(); }} - className={`w-5 h-5 rounded border text-[10px] leading-none text-white ${swapArmed ? "bg-cyan-500/35 border-cyan-300/80" : "bg-black/65 border-white/25"}`} + className={`w-5 h-5 rounded border text-2xs leading-none text-white ${swapArmed ? "bg-cyan-500/35 border-cyan-300/80" : "bg-black/65 border-white/25"}`} title={t("match.draft.swapTargetTitle")} > ▲ @@ -3310,7 +3310,7 @@ function DraftSlot({ event.stopPropagation(); onSwapArm(); }} - className={`w-5 h-5 rounded border text-[10px] leading-none text-white ${swapArmed ? "bg-cyan-500/35 border-cyan-300/80" : "bg-black/65 border-white/25"}`} + className={`w-5 h-5 rounded border text-2xs leading-none text-white ${swapArmed ? "bg-cyan-500/35 border-cyan-300/80" : "bg-black/65 border-white/25"}`} title={t("match.draft.swapTargetTitle")} > ▼ diff --git a/src/components/match/DraftResultScreen.tsx b/src/components/match/DraftResultScreen.tsx index 1910f82aa..569ba4810 100644 --- a/src/components/match/DraftResultScreen.tsx +++ b/src/components/match/DraftResultScreen.tsx @@ -288,7 +288,7 @@ export default function DraftResultScreen({
-

{t("match.draftResult.performance")}

+

{t("match.draftResult.performance")}

{blueTri}

@@ -516,7 +516,7 @@ export default function DraftResultScreen({
-

{t("match.draftResult.gameTimeline")}

+

{t("match.draftResult.gameTimeline")}

diff --git a/src/components/match/HalfTimeBreak.tsx b/src/components/match/HalfTimeBreak.tsx index 7d522fa1e..7b25df3af 100644 --- a/src/components/match/HalfTimeBreak.tsx +++ b/src/components/match/HalfTimeBreak.tsx @@ -244,7 +244,7 @@ export default function HalfTimeBreak({ {/* Main Content */}
-
+
{/* Left: First Half Summary */}
@@ -326,7 +326,7 @@ export default function HalfTimeBreak({ > {opt.label}

-

+

{opt.description}

diff --git a/src/components/match/LolLiveMap.tsx b/src/components/match/LolLiveMap.tsx index b52a4b5ac..e6bb78fd5 100644 --- a/src/components/match/LolLiveMap.tsx +++ b/src/components/match/LolLiveMap.tsx @@ -166,7 +166,7 @@ export default function LolLiveMap({ snapshot, championSelections }: LolLiveMapP title={`${label} · ${unit.role} · ${unit.task}`} >
+ {respawnLeft ?? "X"} ) : null} @@ -190,9 +190,9 @@ export default function LolLiveMap({ snapshot, championSelections }: LolLiveMapP
{snapshot.lol_map ? ( -
+
-

{t("match.liveMap.dragon")}

+

{t("match.liveMap.dragon")}

{snapshot.lol_map.objectives.dragon.alive ? t("match.liveMap.aliveWithKind", { @@ -204,7 +204,7 @@ export default function LolLiveMap({ snapshot, championSelections }: LolLiveMapP

-

{t("match.liveMap.baron")}

+

{t("match.liveMap.baron")}

{snapshot.lol_map.objectives.baron.alive ? t("match.liveMap.alive") diff --git a/src/components/match/LolMatchLive.tsx b/src/components/match/LolMatchLive.tsx index 066b0c128..b02c49f7d 100644 --- a/src/components/match/LolMatchLive.tsx +++ b/src/components/match/LolMatchLive.tsx @@ -991,10 +991,10 @@ export default function LolMatchLive({ gameState, snapshot, championSelections, {blueBrand.logo ? {`${snapshot.home_team.name} : null}

- {blueBrand.tag || blueTag} - {t("match.live")} + {blueBrand.tag || blueTag} + {t("match.live")}
-
+
{t("match.liveA11y.towerIcon")} {blueTowers} {t("match.liveA11y.goldIcon")} @@ -1003,21 +1003,21 @@ export default function LolMatchLive({ gameState, snapshot, championSelections,
- {blueKills} + {blueKills} {t("match.liveA11y.lecLogo")} - {redKills} + {redKills}
-
+
{redGold} {t("match.liveA11y.goldIcon")} {redTowers} {t("match.liveA11y.towerIcon")}
- {redBrand.tag || redTag} - {t("match.live")} + {redBrand.tag || redTag} + {t("match.live")}
{redBrand.logo ? {`${snapshot.away_team.name} : null} @@ -1035,16 +1035,16 @@ export default function LolMatchLive({ gameState, snapshot, championSelections, {t("match.liveA11y.dragonIcon")} )) : {t("match.liveA11y.dragonIcon")}} -
+
{t("match.liveA11y.voidgrubIcon")} {blueVoidgrubs}
-
{clock}
+
{clock}
-
+
{redVoidgrubs} {t("match.liveA11y.voidgrubIcon")}
@@ -1072,15 +1072,15 @@ export default function LolMatchLive({ gameState, snapshot, championSelections,
{entry.killerIcon ? {t("match.liveA11y.killerIcon")} - :
{actorInitials(entry.killerLabel, "K")}
} + :
{actorInitials(entry.killerLabel, "K")}
}
-
+
{entry.victimIcon ? {t("match.liveA11y.victimIcon")} - :
{actorInitials(entry.victimLabel, "V")}
} + :
{actorInitials(entry.victimLabel, "V")}
}
- {entry.minute}' + {entry.minute}'
) : (
@@ -1090,16 +1090,16 @@ export default function LolMatchLive({ gameState, snapshot, championSelections, : null}
- {entry.type} - {entry.text} + {entry.type} + {entry.text}
- {entry.minute}' + {entry.minute}'
)}
)) : ( -
+
{t("match.waitingFirstSkirmish")}
)} @@ -1116,10 +1116,10 @@ export default function LolMatchLive({ gameState, snapshot, championSelections,
-
+
{t("match.liveControls")}
-
+
@@ -1158,10 +1158,10 @@ export default function LolMatchLive({ gameState, snapshot, championSelections, {skipWarningOpen && !isSkipping ? (
-

+

{t("match.skipWarningTitle")}

-

+

{t( "match.skipWarningBody", "Skip Match now re-simulates from minute 0. You will lose all progress from this live match.", @@ -1169,13 +1169,13 @@ export default function LolMatchLive({ gameState, snapshot, championSelections,

))}
@@ -342,7 +342,7 @@ export default function MatchLive({ {t('match.subs')} ({userSide === "Home" ? snapshot.home_subs_made : snapshot.away_subs_made}/{snapshot.max_subs})
-

{t('match.formation')}

+

{t('match.formation')}

{["4-4-2", "4-3-3", "3-5-2", "4-5-1", "4-2-3-1", "3-4-3"].map(f => { const cur = userSide === "Home" ? snapshot.home_team.formation : snapshot.away_team.formation; @@ -355,7 +355,7 @@ export default function MatchLive({
-

{t('match.playStyle')}

+

{t('match.playStyle')}

{[ { id: "Balanced", icon: }, diff --git a/src/components/match/MatchPanels.tsx b/src/components/match/MatchPanels.tsx index 6f6ac87c8..81ef4d645 100644 --- a/src/components/match/MatchPanels.tsx +++ b/src/components/match/MatchPanels.tsx @@ -139,7 +139,7 @@ export function MatchStats({ snapshot }: { snapshot: MatchSnapshot }) { {stat.home} - + {stat.label} @@ -198,7 +198,7 @@ export function Lineups({ snapshot }: { snapshot: MatchSnapshot }) { if (players.length === 0) return null; return (
-

+

{pos}s

{players.map((p) => { @@ -217,7 +217,7 @@ export function Lineups({ snapshot }: { snapshot: MatchSnapshot }) { className={`flex items-center gap-2 py-1 px-2 rounded text-xs ${isOff ? "opacity-40" : ""}`} > {isSubOn && ( - + )} {yc > 0 && ( - + {yc > 1 ? yc : ""} )} @@ -239,7 +239,7 @@ export function Lineups({ snapshot }: { snapshot: MatchSnapshot }) { style={{ width: `${p.condition}%` }} />
- + {Math.round(p.condition)}
@@ -253,7 +253,7 @@ export function Lineups({ snapshot }: { snapshot: MatchSnapshot }) { {/* Bench */} {bench.length > 0 && (
-

+

{t("match.bench")}

{bench.map((p) => { @@ -264,7 +264,7 @@ export function Lineups({ snapshot }: { snapshot: MatchSnapshot }) { className={`flex items-center gap-2 py-1 px-2 rounded text-xs ${wasSubbedOff ? "opacity-50" : ""}`} > {wasSubbedOff && ( - + )} {p.name} @@ -272,7 +272,7 @@ export function Lineups({ snapshot }: { snapshot: MatchSnapshot }) { {translatePositionAbbreviation(t, p.role ?? "")} - + {Math.round(p.condition)}
@@ -284,7 +284,7 @@ export function Lineups({ snapshot }: { snapshot: MatchSnapshot }) { {/* Sub History */} {snapshot.substitutions.filter((s) => s.side === side).length > 0 && (
-

+

{t("match.substitutions")}

{snapshot.substitutions @@ -292,7 +292,7 @@ export function Lineups({ snapshot }: { snapshot: MatchSnapshot }) { .map((sub, i) => (
{sub.minute}' diff --git a/src/components/match/PostMatchHelpers.tsx b/src/components/match/PostMatchHelpers.tsx index 67e59b674..ee9635ce1 100644 --- a/src/components/match/PostMatchHelpers.tsx +++ b/src/components/match/PostMatchHelpers.tsx @@ -31,7 +31,7 @@ export function QuickStat({ {home} - + {label} @@ -69,7 +69,7 @@ export function renderScorers( return (

@@ -213,7 +213,7 @@ export function PlayerRatingsPanel({ {p.rating.toFixed(1)} {p.name} - + {translatePositionAbbreviation(t, p.role ?? "")}

diff --git a/src/components/match/PostMatchScreen.tsx b/src/components/match/PostMatchScreen.tsx index b7e8238de..2ddf29979 100644 --- a/src/components/match/PostMatchScreen.tsx +++ b/src/components/match/PostMatchScreen.tsx @@ -375,7 +375,7 @@ export default function PostMatchScreen({ {/* Main Content */}
-
+
{/* Left: Match Events */}
@@ -486,19 +486,19 @@ export default function PostMatchScreen({ entry.fixture.id, ) } - className="shrink-0 rounded-md px-2 py-1 text-[10px] font-heading font-bold uppercase tracking-widest text-accent-400 hover:bg-gray-200 dark:hover:bg-navy-600/60 transition-colors" + className="shrink-0 rounded-md px-2 py-1 text-2xs font-heading font-bold uppercase tracking-widest text-accent-400 hover:bg-gray-200 dark:hover:bg-navy-600/60 transition-colors" > {t("match.viewDetails")} )}
{scorerSummary && ( -

+

{scorerSummary}

)} {statSummary && ( -

+

{statSummary}

)} @@ -514,7 +514,7 @@ export default function PostMatchScreen({ {isLeagueFixture && roundSummary && ( <>
-

+

{t("home.leagueTable")}

@@ -537,7 +537,7 @@ export default function PostMatchScreen({
-

+

{t("home.topScorers")}

@@ -626,7 +626,7 @@ export default function PostMatchScreen({ )}
-

+

{opt.description}

diff --git a/src/components/match/PreMatchLineup.tsx b/src/components/match/PreMatchLineup.tsx index bb248747f..f0a70039a 100644 --- a/src/components/match/PreMatchLineup.tsx +++ b/src/components/match/PreMatchLineup.tsx @@ -135,7 +135,7 @@ export default function PreMatchLineup({
- + {t("match.formationFit")} {LOL_ROLE_ORDER.map((role) => { @@ -143,7 +143,7 @@ export default function PreMatchLineup({ const ok = actual === 1; return (
- + {role === "JUNGLE" ? "JG" : role} onSelectStarter(null)} - className="text-[10px] text-gray-500 hover:text-gray-800 dark:hover:text-gray-300 font-heading uppercase tracking-wider" + className="text-2xs text-gray-500 hover:text-gray-800 dark:hover:text-gray-300 font-heading uppercase tracking-wider" > {t("match.cancel")} @@ -191,7 +191,7 @@ export default function PreMatchLineup({
{selectedStarterId && ( -

+

{t("match.swapPrompt")}

)} @@ -203,36 +203,36 @@ export default function PreMatchLineup({
-

+

{role === "JUNGLE" ? "JG" : role}

{players.length !== 1 && ( - {players.length}/1 + {players.length}/1 )}
- + OVR {keyStats.map((s) => ( {s.label} ))} - + FIT
{players.length === 0 ? ( -
+
{t("match.noBenchAvailable2")}
) : ( @@ -258,7 +258,7 @@ export default function PreMatchLineup({ /> ) : (
}
= 70 ? "text-primary-400" : ovr >= 50 ? "text-gray-300" : "text-red-400" }`} > @@ -282,7 +282,7 @@ export default function PreMatchLineup({ {keyStats.map((s) => ( @@ -318,13 +318,13 @@ export default function PreMatchLineup({
- + POS - + {t("match.keyStats")} - + FIT
@@ -350,7 +350,7 @@ export default function PreMatchLineup({ loading="lazy" /> ) : ( -
+
{bp.name.substring(0, 1).toUpperCase()}
)} @@ -364,7 +364,7 @@ export default function PreMatchLineup({ {keyStats.map((s) => ( @@ -418,7 +418,7 @@ export default function PreMatchLineup({ loading="lazy" /> ) : ( -
+
{player.name.substring(0, 1).toUpperCase()}
)} diff --git a/src/components/match/PreMatchSetup.tsx b/src/components/match/PreMatchSetup.tsx index 33c5cc78b..a62b6a03b 100644 --- a/src/components/match/PreMatchSetup.tsx +++ b/src/components/match/PreMatchSetup.tsx @@ -235,7 +235,7 @@ export default function PreMatchSetup({ } > -
+
e.stopPropagation()} > {/* Header */} @@ -234,7 +234,7 @@ export function SubPanel({ className={`flex flex-col items-center gap-0.5 transition-all cursor-pointer hover:scale-110 ${isSelected ? "scale-110" : ""}`} >
{Math.round(p.condition)}
- + {p.name.split(" ").pop()} @@ -257,67 +257,99 @@ export function SubPanel({ {/* On-field player table */}
- - - - - - - - - - - {team.players - .filter((p) => !snapshot.sent_off.includes(p.id)) - .sort((a, b) => { - const posOrd: Record = { - Goalkeeper: 1, - Defender: 2, - Midfielder: 3, - Forward: 4, - }; - return ( - (posOrd[a.role ?? ""] || 99) - - (posOrd[b.role ?? ""] || 99) || - a.name.localeCompare(b.name) - ); - }) - .map((p) => { - const isSelected = selectedOff === p.id; - const isSubOn = subbedOnIds.has(p.id); - const ovr = getOvr(p); - return ( - { - handleSelectOffPlayer(p.id); - }} - className={`cursor-pointer transition-colors text-sm ${ - isSelected - ? "bg-red-500/10" - : "hover:bg-gray-100 dark:hover:bg-navy-700/50" - }`} - > - - - - - diff --git a/src/components/training/TrainingSettingsPanel.tsx b/src/components/training/TrainingSettingsPanel.tsx index 80766f976..926bca809 100644 --- a/src/components/training/TrainingSettingsPanel.tsx +++ b/src/components/training/TrainingSettingsPanel.tsx @@ -72,7 +72,7 @@ export default function TrainingSettingsPanel({

{t(`training.schedules.${scheduleId}.label`)}

-

+

{t(`training.schedules.${scheduleId}.desc`)}

@@ -123,7 +123,7 @@ export default function TrainingSettingsPanel({ {trainingFocusAttrs[focusId].map((attribute) => ( {statLabel(attribute)} @@ -157,7 +157,7 @@ export default function TrainingSettingsPanel({ > {t(`training.intensities.${intensityId}.label`)}

-

+

{t(`training.intensities.${intensityId}.desc`)}

diff --git a/src/components/training/TrainingTab.tsx b/src/components/training/TrainingTab.tsx index 039117e38..c22c73186 100644 --- a/src/components/training/TrainingTab.tsx +++ b/src/components/training/TrainingTab.tsx @@ -308,7 +308,7 @@ export default function TrainingTab({ ]; return ( -
+
{staffAdvice ? (
{player.match_name}

-

+

{soloQ.tier} · {soloQ.lp} LP = 0 ? "text-emerald-300" : "text-rose-300"}`}> {soloQ.delta >= 0 ? `+${soloQ.delta}` : soloQ.delta} diff --git a/src/components/transfers/TransferBidModal.tsx b/src/components/transfers/TransferBidModal.tsx index 78450c414..2d05670c2 100644 --- a/src/components/transfers/TransferBidModal.tsx +++ b/src/components/transfers/TransferBidModal.tsx @@ -144,7 +144,7 @@ export default function TransferBidModal({ /> {myTeam && bidFee !== null && bidProjection ? (

-

+

{t("transfers.bidImpactTitle", { defaultValue: "Projected impact", })} diff --git a/src/components/transfers/TransferNegotiationHistory.tsx b/src/components/transfers/TransferNegotiationHistory.tsx index a5e88538e..ebf13a23d 100644 --- a/src/components/transfers/TransferNegotiationHistory.tsx +++ b/src/components/transfers/TransferNegotiationHistory.tsx @@ -31,7 +31,7 @@ export default function TransferNegotiationHistory({ return (

-

+

{t("transfers.negotiationHistory")}

{managerFee !== null && managerFee !== undefined ? ( diff --git a/src/components/transfers/TransfersTab.tsx b/src/components/transfers/TransfersTab.tsx index 456090ebf..352375424 100644 --- a/src/components/transfers/TransfersTab.tsx +++ b/src/components/transfers/TransfersTab.tsx @@ -415,7 +415,7 @@ export default function TransfersTab({ bidProjection.exceeds_finance; return ( -
+
{/* Budget header */} {myTeam && ( diff --git a/src/components/ui/Select.tsx b/src/components/ui/Select.tsx index d29b85ed6..ec28f211f 100644 --- a/src/components/ui/Select.tsx +++ b/src/components/ui/Select.tsx @@ -238,7 +238,7 @@ export function Select({ }; const sizes = { - xs: "py-0.5 text-[10px]", + xs: "py-0.5 text-2xs", sm: "py-1.5 text-xs", md: "py-2 text-sm", }; @@ -255,7 +255,7 @@ export function Select({ const chevronSize = { xs: "w-3 h-3", sm: "w-4 h-4", md: "w-4 h-4" }[ selectSize ]; - const optionTextSize = { xs: "text-[10px]", sm: "text-xs", md: "text-sm" }[ + const optionTextSize = { xs: "text-2xs", sm: "text-xs", md: "text-sm" }[ selectSize ]; diff --git a/src/components/worldEditor/WorldEditorTab.tsx b/src/components/worldEditor/WorldEditorTab.tsx index 857817016..31fe9bde9 100644 --- a/src/components/worldEditor/WorldEditorTab.tsx +++ b/src/components/worldEditor/WorldEditorTab.tsx @@ -532,7 +532,7 @@ export default function WorldEditorTab({ onBack }: WorldEditorTabProps) { return (
-
+
{onBack ? ( @@ -615,7 +615,7 @@ export default function WorldEditorTab({ onBack }: WorldEditorTabProps) { -

Busca por nombre in-game exacto normalizado. Ignora medias calculadas del Excel.

+

Busca por nombre in-game exacto normalizado. Ignora medias calculadas del Excel.

) : null}
@@ -752,7 +752,7 @@ function ModeButton({ active, onClick, children }: { active: boolean; onClick: ( } function ScopeButton({ active, onClick, children }: { active: boolean; onClick: () => void; children: ReactNode }) { - return ; + return ; } function DeleteButton({ onClick, children }: { onClick: () => void; children: ReactNode }) { diff --git a/src/components/youthAcademy/YouthAcademyTab.tsx b/src/components/youthAcademy/YouthAcademyTab.tsx index 76403913e..cc2880a50 100644 --- a/src/components/youthAcademy/YouthAcademyTab.tsx +++ b/src/components/youthAcademy/YouthAcademyTab.tsx @@ -149,7 +149,7 @@ export default function YouthAcademyTab({ gameState, onSelectPlayer, onGameUpdat

{youthPlayers.length}

-

+

{t("youthAcademy.academyPlayersStartingMayus")}

@@ -160,7 +160,7 @@ export default function YouthAcademyTab({ gameState, onSelectPlayer, onGameUpdat

{avgOvr}

-

+

{t("youthAcademy.avgOvr")}

@@ -171,7 +171,7 @@ export default function YouthAcademyTab({ gameState, onSelectPlayer, onGameUpdat

{avgPotential ?? "??"}

-

+

{t("youthAcademy.avgPotential")}

@@ -182,7 +182,7 @@ export default function YouthAcademyTab({ gameState, onSelectPlayer, onGameUpdat

{highPotential}

-

+

{t("youthAcademy.highPotential")}

@@ -262,7 +262,7 @@ export default function YouthAcademyTab({ gameState, onSelectPlayer, onGameUpdat loading="lazy" /> ) : ( - {option.source_team_short_name} + {option.source_team_short_name} )}
@@ -317,70 +317,72 @@ export default function YouthAcademyTab({ gameState, onSelectPlayer, onGameUpdat

{t("youthAcademy.noYouthPlayers")}

) : ( -
{t("match.player")} - {t("common.position")} - - {t("common.ovr")} - {t("match.fitness")}
-
- {isSelected && ( - - )} - {isSubOn && ( - - ▲ +
+ + + + + + + + + + + {team.players + .filter((p) => !snapshot.sent_off.includes(p.id)) + .sort((a, b) => { + const posOrd: Record = { + Goalkeeper: 1, + Defender: 2, + Midfielder: 3, + Forward: 4, + }; + return ( + (posOrd[a.role ?? ""] || 99) - + (posOrd[b.role ?? ""] || 99) || + a.name.localeCompare(b.name) + ); + }) + .map((p) => { + const isSelected = selectedOff === p.id; + const isSubOn = subbedOnIds.has(p.id); + const ovr = getOvr(p); + return ( + { + handleSelectOffPlayer(p.id); + }} + className={`cursor-pointer transition-colors text-sm ${ + isSelected + ? "bg-red-500/10" + : "hover:bg-gray-100 dark:hover:bg-navy-700/50" + }`} + > + + + + + + ); + })} + +
{t("match.player")} + {t("common.position")} + + {t("common.ovr")} + {t("match.fitness")}
+
+ {isSelected && ( + + )} + {isSubOn && ( + + ▲ + + )} + + {p.name} - )} - - {p.name} +
+
+ + {translatePositionAbbreviation(t, p.role ?? "")} - + + {ovr} + +
+
+
+
+ + {Math.round(p.condition)} + +
+
+
+
@@ -366,15 +398,15 @@ export function SubPanel({
- + {selectedPlayer.name}
- + {t("common.vs")}
- + {comparedPlayer.name} @@ -449,10 +481,90 @@ export function SubPanel({
{t("match.noBenchAvailable")}
+ ) : ( +
+ + + + + + + + + + + {availableBench.map((p) => { + const ovr = getOvr(p); + // Off-position indicator: compare with selected player's position + const posMatch = selectedPlayer + ? (p.role ?? "") === (selectedPlayer.role ?? "") + : true; + return ( + { + handleSelectBenchPlayer(p.id); + }} + className={`transition-colors text-sm ${ + selectedOff + ? selectedBench === p.id + ? "cursor-pointer bg-green-500/15 ring-1 ring-green-500/30" + : "cursor-pointer hover:bg-green-500/10" + : "opacity-60" + }`} + > + + + + + + ); + })} + +
{t("match.player")} + {t("common.position")} + + {t("common.ovr")} + {t("match.fitness")}
+
+ {selectedOff && ( + + )} + + {p.name} + +
+
+ + {translatePositionAbbreviation(t, p.role ?? "")} + {!posMatch && selectedOff && " !"} + + + {ovr} + +
+
+
+
+ + {Math.round(p.condition)} + +
+
+
+ )} +
) : ( - + + + {history.map((record, index) => { + const decisiveGames = record.won + record.lost; + const winRate = decisiveGames > 0 + ? `${Math.round((record.won / decisiveGames) * 100)}%` + : "0%"; + + return ( + + + + + + + + + + )})} + +
{t("match.player")} {t("common.position")} @@ -532,7 +644,7 @@ export function SubPanel({ {snapshot.substitutions.filter((s) => s.side === side).length > 0 && (
-

+

{t("match.history")}

{snapshot.substitutions @@ -540,7 +652,7 @@ export function SubPanel({ .map((sub, i) => (
{sub.minute}' diff --git a/src/components/match/lol-prototype/ui/panels.tsx b/src/components/match/lol-prototype/ui/panels.tsx index ddb157b3e..4006d7b52 100644 --- a/src/components/match/lol-prototype/ui/panels.tsx +++ b/src/components/match/lol-prototype/ui/panels.tsx @@ -132,7 +132,7 @@ function Slot({ className = "h-4 w-4", trinket = false, goldBorder = false, item
{effectiveIcon ? {itemKey : null} {shouldShowCd ? ( -
+
{cooldownText}
) : null} @@ -215,7 +215,7 @@ function SidePane({ champion, team, championByPlayerId, timeSec }: {
{red && (
-
+
{name}{banished ? " (Realm)" : ""} {cs}
@@ -223,7 +223,7 @@ function SidePane({ champion, team, championByPlayerId, timeSec }: {
-
{kda}
+
{kda}
)} @@ -248,16 +248,16 @@ function SidePane({ champion, team, championByPlayerId, timeSec }: {
{icon ? {name} : null} {champion && !champion.alive && respawnText && ( -
+
{respawnText}
)} {banished && ( -
+
REALM
)} -
+
{level}
@@ -266,7 +266,7 @@ function SidePane({ champion, team, championByPlayerId, timeSec }: { {!red && (
-
+
{name}{banished ? " (Realm)" : ""} {cs}
@@ -274,7 +274,7 @@ function SidePane({ champion, team, championByPlayerId, timeSec }: {
-
{kda}
+
{kda}
)} @@ -283,16 +283,16 @@ function SidePane({ champion, team, championByPlayerId, timeSec }: {
{icon ? {name} : null} {champion && !champion.alive && respawnText && ( -
+
{respawnText}
)} {banished && ( -
+
REALM
)} -
+
{level}
@@ -342,9 +342,9 @@ export function LecLowerThirdPanel({ champions, championByPlayerId, timeSec = 0
- - {diffLabel} - + + {diffLabel} +
diff --git a/src/components/news/NewsTab.tsx b/src/components/news/NewsTab.tsx index b29378e2e..9f6c8b917 100644 --- a/src/components/news/NewsTab.tsx +++ b/src/components/news/NewsTab.tsx @@ -120,7 +120,7 @@ export default function NewsTab({ gameState, onSelectTeam }: NewsTabProps) { } return ( -
+
{/* Filters row */}
{/* Category pills */} @@ -263,12 +263,12 @@ function HeroArticle({
{meta.icon} {meta.label} - + {formatNewsDate(article.date)} @@ -299,7 +299,7 @@ function HeroArticle({

-

+

— {article.source}

{article.team_ids.length > 0 && onSelectTeam && ( @@ -311,7 +311,7 @@ function HeroArticle({ e.stopPropagation(); onSelectTeam(tid); }} - className="text-[10px] font-heading font-bold uppercase tracking-wider text-primary-500 hover:text-primary-600 dark:hover:text-primary-400 bg-primary-500/5 hover:bg-primary-500/10 px-2 py-0.5 rounded-md transition-colors cursor-pointer" + className="text-2xs font-heading font-bold uppercase tracking-wider text-primary-500 hover:text-primary-600 dark:hover:text-primary-400 bg-primary-500/5 hover:bg-primary-500/10 px-2 py-0.5 rounded-md transition-colors cursor-pointer" > {getTeamName(gameState.teams, tid)} @@ -350,7 +350,7 @@ function ArticleCard({
{meta.icon} {meta.label} @@ -381,10 +381,10 @@ function ArticleCard({

- + {article.source} - + {formatNewsDate(article.date)} @@ -429,7 +429,7 @@ function ArticleDetail({ {/* Category + date */}
{meta.icon} {meta.label} @@ -478,7 +478,7 @@ function ArticleDetail({ {/* Footer */}
-

+

— {article.source}

{article.team_ids.length > 0 && onSelectTeam && ( @@ -487,7 +487,7 @@ function ArticleDetail({ diff --git a/src/components/playerProfile/PlayerProfile.tsx b/src/components/playerProfile/PlayerProfile.tsx index dd33a41da..5cf00063d 100644 --- a/src/components/playerProfile/PlayerProfile.tsx +++ b/src/components/playerProfile/PlayerProfile.tsx @@ -791,7 +791,7 @@ export default function PlayerProfile({ } return ( -
+
-

+

{score ? `${score.home} - ${score.away}` : t("tournaments.scheduled")}

@@ -176,13 +176,13 @@ export default function PlayoffBracketBoard({
-

{t("tournaments.upperBracket")}

+

{t("tournaments.upperBracket")}

{upperRounds.map((round, i) => renderRound(round, i, rounds.indexOf(round)))}
{lowerRounds.length > 0 ? (
-

{t("tournaments.lowerBracket")}

+

{t("tournaments.lowerBracket")}

{lowerRounds.map((round, i) => renderRound(round, i, rounds.indexOf(round)))}
) : null} diff --git a/src/components/schedule/ScheduleCalendarView.tsx b/src/components/schedule/ScheduleCalendarView.tsx index 5a802fabe..4e89d5425 100644 --- a/src/components/schedule/ScheduleCalendarView.tsx +++ b/src/components/schedule/ScheduleCalendarView.tsx @@ -194,7 +194,7 @@ function FixtureChip({ ) : null} {score ? `${score.home}-${score.away}` : "vs"} @@ -220,7 +220,7 @@ function FixtureChip({ className={ isFull ? "ml-auto" - : "ml-auto !text-[8px] !px-1 !py-0" + : "ml-auto !text-2xs !px-1 !py-0" } > BO{bo} @@ -258,7 +258,7 @@ function ScrimChip({ scrim, gameState, size = "compact" }: ScrimChipProps) { loading="lazy" /> ) : null} - + {t("schedule.scrimVs", { team: opponentName, defaultValue: "Scrim vs {{team}}" })}
@@ -373,7 +373,7 @@ export default function ScheduleCalendarView({ > -

+

{monthLabel}

@@ -500,7 +500,7 @@ export default function ScheduleCalendarView({ diff --git a/src/components/schedule/ScheduleTab.tsx b/src/components/schedule/ScheduleTab.tsx index e69c385ce..ced17565f 100644 --- a/src/components/schedule/ScheduleTab.tsx +++ b/src/components/schedule/ScheduleTab.tsx @@ -151,7 +151,7 @@ export default function ScheduleTab({ ); return ( -
+
{isPreseason && ( diff --git a/src/components/scouting/ScoutingPlayerSearchCard.tsx b/src/components/scouting/ScoutingPlayerSearchCard.tsx index 60b6f5c30..95522ae9d 100644 --- a/src/components/scouting/ScoutingPlayerSearchCard.tsx +++ b/src/components/scouting/ScoutingPlayerSearchCard.tsx @@ -125,10 +125,10 @@ export default function ScoutingPlayerSearchCard({ > {player.match_name} -
+
{player.full_name}
-
+
{scout.first_name} {scout.last_name}

-
+
-

+

{t("scouting.judgingAbility")}

-

+

{t("scouting.judgingPotential")}

+
{/* Header */}
diff --git a/src/components/scrims/ScrimPlanningCard.tsx b/src/components/scrims/ScrimPlanningCard.tsx index 9b1a0fea3..089c63991 100644 --- a/src/components/scrims/ScrimPlanningCard.tsx +++ b/src/components/scrims/ScrimPlanningCard.tsx @@ -130,17 +130,17 @@ export default function ScrimPlanningCard({

- + {t("training.scrims.weekCapacity")}: {slots} - + {t("training.scrims.lossStreak")}: {streak}
-

+

{t("training.scrims.slot", "Slot")} {index + 1}

@@ -190,12 +190,12 @@ export default function ScrimPlanningCard({ ) : null} {hasResult ? ( {slotContext?.resultWon ? "Win" : "Loss"} ) : ( - + {t("training.scrims.pending", "Pendiente")} )} @@ -212,7 +212,7 @@ export default function ScrimPlanningCard({ return (

-
+ {record.season}/{record.season + 1} + + #{record.league_position} + + {record.played} + + {record.won} + + {record.lost} + + {winRate} + + {record.points} +
+
); diff --git a/src/components/teamProfile/TeamProfileRecentMatchesCard.tsx b/src/components/teamProfile/TeamProfileRecentMatchesCard.tsx index 01265a544..596e17ef3 100644 --- a/src/components/teamProfile/TeamProfileRecentMatchesCard.tsx +++ b/src/components/teamProfile/TeamProfileRecentMatchesCard.tsx @@ -49,7 +49,7 @@ export default function TeamProfileRecentMatchesCard({
-

+

{sideLabel}

@@ -58,7 +58,7 @@ export default function TeamProfileRecentMatchesCard({

-

+

{scoreLabel}

@@ -67,7 +67,7 @@ export default function TeamProfileRecentMatchesCard({

-

+

{economyLabel}

diff --git a/src/components/teams/TeamsListTab.tsx b/src/components/teams/TeamsListTab.tsx index 07e97806d..f81fa8d2e 100644 --- a/src/components/teams/TeamsListTab.tsx +++ b/src/components/teams/TeamsListTab.tsx @@ -42,7 +42,7 @@ export default function TeamsListTab({ gameState, onSelectTeam }: TeamsListTabPr }).sort((a, b) => a.leaguePos - b.leaguePos); return ( -

+
{teamsData.map(({ team, roster, avgOvr, totalValue, leaguePos, standing }) => { const isUser = team.id === userTeamId; diff --git a/src/components/tournaments/TournamentsTab.tsx b/src/components/tournaments/TournamentsTab.tsx index 26c001cd7..a17125450 100644 --- a/src/components/tournaments/TournamentsTab.tsx +++ b/src/components/tournaments/TournamentsTab.tsx @@ -35,7 +35,7 @@ export default function TournamentsTab({ if (!league) { return ( -
+

{t("tournaments.noActive")} @@ -91,7 +91,7 @@ export default function TournamentsTab({ const hasAcademyPlayoffsStarted = academyPlayoffFixtures.length > 0; return ( -

+
{isPreseason && ( @@ -222,63 +222,65 @@ export default function TournamentsTab({

) : ( - - - - - - - - - - - - - {standings.map((entry, idx) => { - const isUser = entry.team_id === userTeamId; - return ( - onSelectTeam(entry.team_id)} - className={`cursor-pointer transition-colors ${isUser ? "bg-primary-50 dark:bg-primary-500/10" : "hover:bg-gray-50 dark:hover:bg-navy-700/50"}`} - > - - + + + + + + + ); + })} + +
- # - - {t("common.team")} - - {t("common.played")} - - {t("common.won")} - - {t("common.lost")} - - {t("tournaments.mapScore")} -
- {idx + 1} - + + + + + + + + + + + + + {standings.map((entry, idx) => { + const isUser = entry.team_id === userTeamId; + return ( + onSelectTeam(entry.team_id)} + className={`cursor-pointer transition-colors ${isUser ? "bg-primary-50 dark:bg-primary-500/10" : "hover:bg-gray-50 dark:hover:bg-navy-700/50"}`} > - {getTeamName(gameState.teams, entry.team_id)} - - - - - - - ); - })} - -
+ # + + {t("common.team")} + + {t("common.played")} + + {t("common.won")} + + {t("common.lost")} + + {t("tournaments.mapScore")} +
- {entry.played} - - {entry.won} - - {entry.lost} - - {entry.goals_for}-{entry.goals_against} -
+
+ {idx + 1} + + {getTeamName(gameState.teams, entry.team_id)} + + {entry.played} + + {entry.won} + + {entry.lost} + + {entry.goals_for}-{entry.goals_against} +
+
)} @@ -296,7 +298,7 @@ export default function TournamentsTab({ const first = fixtures[0]; return (
-

+

{first.competition === "Playoffs" ? `${t("schedule.playoffs")} · ${t("schedule.round", { number: md })}` : t("schedule.matchday", { number: md })} @@ -338,43 +340,45 @@ export default function TournamentsTab({ {t("tournaments.leagueTable")} - - - - - - - - - - - - - {academyStandings.map((entry, idx) => { - const isUserAcademy = gameState.manager.team_id - ? gameState.teams.some( - (team) => - team.id === entry.team_id && - team.parent_team_id === gameState.manager.team_id, - ) - : false; - return ( - onSelectTeam(entry.team_id)} - className={`cursor-pointer transition-colors ${isUserAcademy ? "bg-primary-50 dark:bg-primary-500/10" : "hover:bg-gray-50 dark:hover:bg-navy-700/50"}`} - > - - - - - - - - ); - })} - -
#{t("common.team")}{t("common.played")}{t("common.won")}{t("common.lost")}{t("tournaments.mapScore")}
{idx + 1}{getTeamName(gameState.teams, entry.team_id)}{entry.played}{entry.won}{entry.lost}{entry.goals_for}-{entry.goals_against}
+

+ + + + + + + + + + + + + {academyStandings.map((entry, idx) => { + const isUserAcademy = gameState.manager.team_id + ? gameState.teams.some( + (team) => + team.id === entry.team_id && + team.parent_team_id === gameState.manager.team_id, + ) + : false; + return ( + onSelectTeam(entry.team_id)} + className={`cursor-pointer transition-colors ${isUserAcademy ? "bg-primary-50 dark:bg-primary-500/10" : "hover:bg-gray-50 dark:hover:bg-navy-700/50"}`} + > + + + + + + + + ); + })} + +
#{t("common.team")}{t("common.played")}{t("common.won")}{t("common.lost")}{t("tournaments.mapScore")}
{idx + 1}{getTeamName(gameState.teams, entry.team_id)}{entry.played}{entry.won}{entry.lost}{entry.goals_for}-{entry.goals_against}
+
diff --git a/src/components/training/TrainingGroupsCard.tsx b/src/components/training/TrainingGroupsCard.tsx index a8c98cf1e..9292a2f1f 100644 --- a/src/components/training/TrainingGroupsCard.tsx +++ b/src/components/training/TrainingGroupsCard.tsx @@ -194,7 +194,7 @@ export default function TrainingGroupsCard({ ))} - + {count}
+ {t("common.player")} + {t("common.position")} + {t("training.groups.group")} + {t("training.effectiveFocus")}
- - - - - - - - - - - - - {youthPlayers.map((player) => { - return ( - onSelectPlayer?.(player.id)} - className="hover:bg-gray-50 dark:hover:bg-navy-700/50 cursor-pointer transition-colors" - > - +
+
{t("youthAcademy.player")}{t("youthAcademy.pos")}{t("youthAcademy.age")}{t("youthAcademy.ovr")}{t("youthAcademy.potential")}{t("youthAcademy.condition")} - {t("common.actions")} -
-
-

{player.match_name || player.id}

-

{player.full_name}

-
-
+ + + + + + + + + + + + + {youthPlayers.map((player) => { + return ( + onSelectPlayer?.(player.id)} + className="hover:bg-gray-50 dark:hover:bg-navy-700/50 cursor-pointer transition-colors" + > + + + + - - - - - - - ); - })} - -
{t("youthAcademy.player")}{t("youthAcademy.pos")}{t("youthAcademy.age")}{t("youthAcademy.ovr")}{t("youthAcademy.potential")}{t("youthAcademy.condition")} + {t("common.actions")} +
- +
+

{player.match_name || player.id}

+

{player.full_name}

+
+
+ + {player.age} + {player.ovr} + + {player.potential ?? "??"} {player.age} - {player.ovr} - - {player.potential ?? "??"} - - {player.condition}% - - -
+ + {player.condition}% + + + + + + ); + })} + + +
)} diff --git a/src/pages/ChampionPage.tsx b/src/pages/ChampionPage.tsx index 19681a7ba..75eb64f88 100644 --- a/src/pages/ChampionPage.tsx +++ b/src/pages/ChampionPage.tsx @@ -428,7 +428,7 @@ export default function ChampionPage({ championKey, onClose }: ChampionPageProps {champKey}

{item.value !== undefined && ( -

+

{item.value} {item.value === 1 ? "game" : "games"}

)} diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx index f47d20ec2..3e988be5a 100644 --- a/src/pages/Settings.tsx +++ b/src/pages/Settings.tsx @@ -260,7 +260,7 @@ export default function Settings() { }} /> {isAndroid ? ( - + {t("settings.uiScaleAndroidLocked", "Bloqueado en XS en Android")} ) : null} @@ -522,7 +522,7 @@ export default function Settings() { {t("app.version")}

- + Sturdy Robot
From 6fb17d617099ad41ae29f50141b7e6b906559de0 Mon Sep 17 00:00:00 2001 From: Nico Date: Wed, 13 May 2026 18:03:13 +0200 Subject: [PATCH 2/3] fix(db): correct team upsert column/value mismatch (47 columns, 47 values) --- src-tauri/crates/db/src/repositories/team_repo.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-tauri/crates/db/src/repositories/team_repo.rs b/src-tauri/crates/db/src/repositories/team_repo.rs index 20df12704..3eff0d5ea 100644 --- a/src-tauri/crates/db/src/repositories/team_repo.rs +++ b/src-tauri/crates/db/src/repositories/team_repo.rs @@ -56,7 +56,7 @@ pub fn upsert_team(conn: &Connection, t: &Team) -> Result<(), String> { founded_year, colors_primary, colors_secondary, starting_xi_ids, team_roles, form, history, training_groups, weekly_scrim_opponent_ids, weekly_scrim_plan_team_ids, scrim_weekly_objective, scrim_weekly_slots, scrim_setup_locked_week_key, scrim_reputation, scrim_weekly_cancellations, scrim_loss_streak, scrim_weekly_played, scrim_weekly_wins, scrim_weekly_losses, scrim_slot_results, scrim_reports, financial_ledger, sponsorship, facilities, team_kind, parent_team_id, academy_team_id, academy_metadata) - VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29, ?30, ?31, ?32, ?33, ?34, ?35, ?36, ?37, ?38, ?39, ?40, ?41, ?42, ?43, ?44, ?45, ?46, ?47, ?48)", + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29, ?30, ?31, ?32, ?33, ?34, ?35, ?36, ?37, ?38, ?39, ?40, ?41, ?42, ?43, ?44, ?45, ?46, ?47)", params![ t.id, t.name, From 6e0a8e0100fd4f2dae179ecd4e2cd71e1ceed34b Mon Sep 17 00:00:00 2001 From: Nico Date: Wed, 13 May 2026 18:18:44 +0200 Subject: [PATCH 3/3] fix(ui): repair broken JSX in SubPanel from overflow-x-auto insertion --- src/components/match/SubPanel.tsx | 108 ------------------------------ 1 file changed, 108 deletions(-) diff --git a/src/components/match/SubPanel.tsx b/src/components/match/SubPanel.tsx index ff4a6f0ef..6f3a22c8b 100644 --- a/src/components/match/SubPanel.tsx +++ b/src/components/match/SubPanel.tsx @@ -350,37 +350,6 @@ export function SubPanel({
- - - - {translatePositionAbbreviation(t, p.role ?? "")} - - - - {ovr} - - -
-
-
-
- - {Math.round(p.condition)} - -
- - - ); - })} - - -
-
{/* Right: Bench Players + Comparison */}
@@ -561,83 +530,6 @@ export function SubPanel({
)}
- ) : ( - - - - - - - - - - - {availableBench.map((p) => { - const ovr = getOvr(p); - // Off-position indicator: compare with selected player's position - const posMatch = selectedPlayer - ? (p.role ?? "") === (selectedPlayer.role ?? "") - : true; - return ( - { - handleSelectBenchPlayer(p.id); - }} - className={`transition-colors text-sm ${ - selectedOff - ? selectedBench === p.id - ? "cursor-pointer bg-green-500/15 ring-1 ring-green-500/30" - : "cursor-pointer hover:bg-green-500/10" - : "opacity-60" - }`} - > - - - - - - ); - })} - -
{t("match.player")} - {t("common.position")} - - {t("common.ovr")} - {t("match.fitness")}
-
- {selectedOff && ( - - )} - - {p.name} - -
-
- - {translatePositionAbbreviation(t, p.role ?? "")} - {!posMatch && selectedOff && " !"} - - - {ovr} - -
-
-
-
- - {Math.round(p.condition)} - -
-
- )}
{/* Sub History */}