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 9b65da2fa..e74cf60ae 100644 --- a/src/components/EndOfSeasonScreen.tsx +++ b/src/components/EndOfSeasonScreen.tsx @@ -98,7 +98,7 @@ export default function EndOfSeasonScreen({ gameState, onGameUpdate }: EndOfSeas }; return ( -
+
{step === "review" && ( <> {/* Hero */} @@ -129,7 +129,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 a6e078d3b..45d99f122 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/ChampionsTab.tsx b/src/components/champions/ChampionsTab.tsx index fb8923ee2..e28af5733 100644 --- a/src/components/champions/ChampionsTab.tsx +++ b/src/components/champions/ChampionsTab.tsx @@ -432,8 +432,8 @@ export default function ChampionsTab({ gameState, onGameUpdate, onViewChampion }
-

- {t("champions.patchLabel")} +

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

{patch?.current_patch_label || t("champions.patchFallback")} @@ -448,7 +448,7 @@ export default function ChampionsTab({ gameState, onGameUpdate, onViewChampion }

-
+
{t("champions.discoveryProgress")} @@ -457,8 +457,8 @@ export default function ChampionsTab({ gameState, onGameUpdate, onViewChampion }
-

- {t("champions.staffMetaImpact")}: {formatStaffEffectPercent(staffEffects.metaDiscovery)} · {t("champions.staffMasteryImpact")}: {formatStaffEffectPercent(staffEffects.development)} +

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

@@ -473,7 +473,7 @@ export default function ChampionsTab({ gameState, onGameUpdate, onViewChampion } @@ -625,16 +625,16 @@ export default function ChampionsTab({ gameState, onGameUpdate, onViewChampion }
-

+

{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")} /> @@ -2999,7 +2999,7 @@ export default function ChampionDraft({ @@ -3015,7 +3015,7 @@ export default function ChampionDraft({ {!finished && isUserTurn ? (
-

+

{pendingChampionId ? `${t("match.draft.selected")}: ${championById.get(pendingChampionId)?.name ?? pendingChampionId}` : t("match.draft.selectThenConfirm")} @@ -3024,7 +3024,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") @@ -3043,7 +3043,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"; @@ -3068,12 +3068,12 @@ export default function ChampionDraft({ loading="lazy" />

{champion.name}

-
+
{metaTier} {showMastery ? {mastery} : null}
@@ -3094,16 +3094,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} @@ -3146,23 +3146,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} @@ -3174,14 +3174,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}

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

+

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

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

{champion.name}

-

{playerName}

-

+

{champion.name}

+

{playerName}

+

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

-

{mastery}

+

{mastery}

))} @@ -3312,7 +3312,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} @@ -3332,7 +3332,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")} > ▲ @@ -3343,7 +3343,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 0228fcc20..46833e9c0 100644 --- a/src/components/match/DraftResultScreen.tsx +++ b/src/components/match/DraftResultScreen.tsx @@ -352,7 +352,7 @@ export default function DraftResultScreen({
diff --git a/src/components/match/HalfTimeBreak.tsx b/src/components/match/HalfTimeBreak.tsx index a5565365a..91002ea3f 100644 --- a/src/components/match/HalfTimeBreak.tsx +++ b/src/components/match/HalfTimeBreak.tsx @@ -232,7 +232,7 @@ export default function HalfTimeBreak({ {/* Main Content */}
-
+
{/* Left: First Half Summary */}
@@ -314,7 +314,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 e7c92ec8b..4185bd351 100644 --- a/src/components/match/LolMatchLive.tsx +++ b/src/components/match/LolMatchLive.tsx @@ -997,10 +997,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")} @@ -1009,21 +1009,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} @@ -1041,16 +1041,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")}
@@ -1078,15 +1078,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}'
) : (
@@ -1096,16 +1096,16 @@ export default function LolMatchLive({ gameState, snapshot, championSelections, : null}
- {entry.type} - {entry.text} + {entry.type} + {entry.text}
- {entry.minute}' + {entry.minute}'
)}
)) : ( -
+
{t("match.waitingFirstSkirmish")}
)} @@ -1122,10 +1122,10 @@ export default function LolMatchLive({ gameState, snapshot, championSelections,
-
+
{t("match.liveControls")}
-
+
@@ -1165,10 +1165,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.", @@ -1176,13 +1176,13 @@ export default function LolMatchLive({ gameState, snapshot, championSelections,

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

{t('match.draftStrategy')}

+

{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; + return ( + + ); + })} +
+
+
+

{t('match.playStyle')}

{[ { id: "Balanced", icon: }, diff --git a/src/components/match/MatchPanels.tsx b/src/components/match/MatchPanels.tsx index a123078fd..d0cc4e6ff 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} @@ -195,7 +195,7 @@ export function Lineups({ snapshot }: { snapshot: MatchSnapshot }) { if (players.length === 0) return null; return (
-

+

{pos}s

{players.map((p) => { @@ -214,7 +214,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 : ""} )} @@ -236,7 +236,7 @@ export function Lineups({ snapshot }: { snapshot: MatchSnapshot }) { style={{ width: `${p.condition}%` }} />
- + {Math.round(p.condition)}
@@ -250,7 +250,7 @@ export function Lineups({ snapshot }: { snapshot: MatchSnapshot }) { {/* Bench */} {bench.length > 0 && (
-

+

{t("match.bench")}

{bench.map((p) => { @@ -261,7 +261,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} @@ -269,7 +269,7 @@ export function Lineups({ snapshot }: { snapshot: MatchSnapshot }) { {translatePositionAbbreviation(t, p.role ?? "")} - + {Math.round(p.condition)}
@@ -281,7 +281,7 @@ export function Lineups({ snapshot }: { snapshot: MatchSnapshot }) { {/* Sub History */} {snapshot.substitutions.filter((s) => s.side === side).length > 0 && (
-

+

{t("match.substitutions")}

{snapshot.substitutions @@ -289,7 +289,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 20ea85af1..a3cdef989 100644 --- a/src/components/match/PostMatchScreen.tsx +++ b/src/components/match/PostMatchScreen.tsx @@ -372,7 +372,7 @@ export default function PostMatchScreen({ {/* Main Content */}
-
+
{/* Left: Match Events */}
@@ -483,19 +483,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}

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

+

{t("home.leagueTable")}

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

+

{t("home.topScorers")}

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

+

{opt.description}

diff --git a/src/components/match/PreMatchLineup.tsx b/src/components/match/PreMatchLineup.tsx index 26aeaa6fa..b745b6abd 100644 --- a/src/components/match/PreMatchLineup.tsx +++ b/src/components/match/PreMatchLineup.tsx @@ -355,8 +355,8 @@ export default function PreMatchLineup({ {/* Formation fit bar */}
- - {t("match.roleCoverage")} + + {t("match.formationFit")} {LOL_ROLE_ORDER.map((role) => { const homeCount = homeTeam.players.filter((p) => getPlayerLolRole(p) === role).length; @@ -365,7 +365,7 @@ export default function PreMatchLineup({ const ok = actual === 1; return (
- + {role === "JUNGLE" ? "JG" : role} } > -
+
e.stopPropagation()} > {/* Header */} @@ -214,7 +214,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()} @@ -237,98 +237,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" - }`} - > - + + + + ); + })} + +
{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)} +
+ + {translatePositionAbbreviation(t, p.role ?? "")} - -
+
+ {ovr} + +
+
+
+
+ + {Math.round(p.condition)} + +
+
+
-
{/* Right: Bench Players + Comparison */}
@@ -346,15 +347,15 @@ export function SubPanel({
- + {selectedPlayer.name}
- + {t("common.vs")}
- + {comparedPlayer.name} @@ -430,89 +431,92 @@ 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} - -
-
-
+
+ + + + + + + + + + + {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} +
+
- {Math.round(p.condition)} + {translatePositionAbbreviation(t, p.role ?? "")} + {!posMatch && selectedOff && " !"} - -
+
+ {ovr} + +
+
+
+
+ + {Math.round(p.condition)} + +
+
+
)}
+
{/* Sub History */} {snapshot.substitutions.filter((s) => s.side === side).length > 0 && (
-

+

{t("match.history")}

{snapshot.substitutions @@ -520,7 +524,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 1f40ee687..7cbef5046 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 1f75b26ac..d739d3df1 100644 --- a/src/components/playerProfile/PlayerProfile.tsx +++ b/src/components/playerProfile/PlayerProfile.tsx @@ -793,7 +793,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 efb148ed0..050a21ad1 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 751c67f53..512fc5f7e 100644 --- a/src/components/schedule/ScheduleTab.tsx +++ b/src/components/schedule/ScheduleTab.tsx @@ -149,7 +149,7 @@ export default function ScheduleTab({ const standings = [...playerLeague.standings].sort(compareStandingsByLolScore); return ( -
+
{isPreseason && ( diff --git a/src/components/scouting/ScoutingPlayerSearchCard.tsx b/src/components/scouting/ScoutingPlayerSearchCard.tsx index f80f19f5b..e0de285a5 100644 --- a/src/components/scouting/ScoutingPlayerSearchCard.tsx +++ b/src/components/scouting/ScoutingPlayerSearchCard.tsx @@ -209,10 +209,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 c15d179cc..2e69afe26 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 (

-