playoff visual fixes
This commit is contained in:
@@ -22,42 +22,181 @@ templ PlayoffBracketView(season *db.Season, league *db.League, bracket *db.Playo
|
||||
@playoffStatusBadge(bracket.Status)
|
||||
</div>
|
||||
</div>
|
||||
<!-- Bracket Series List -->
|
||||
<div class="space-y-4">
|
||||
@bracketRounds(season, league, bracket)
|
||||
<!-- Bracket Display -->
|
||||
switch bracket.Format {
|
||||
case db.PlayoffFormat5to6:
|
||||
@bracket5to6(season, league, bracket)
|
||||
case db.PlayoffFormat7to9:
|
||||
@bracket7to9(season, league, bracket)
|
||||
case db.PlayoffFormat10to15:
|
||||
@bracket10to15(season, league, bracket)
|
||||
}
|
||||
<!-- Legend -->
|
||||
<div class="flex items-center gap-6 text-xs text-subtext0">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-8 h-0 border-t-2 border-green"></div>
|
||||
<span>Winner</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-8 h-0 border-t-2 border-red border-dashed"></div>
|
||||
<span>Loser</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/js/bracket-lines.js"></script>
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────
|
||||
// 5-6 TEAMS FORMAT
|
||||
// ──────────────────────────────────────────────
|
||||
// Round 1: [Upper Bracket] [Lower Bracket]
|
||||
// Round 2: [Upper Final] [Lower Final]
|
||||
// Round 3: [Grand Final]
|
||||
templ bracket5to6(season *db.Season, league *db.League, bracket *db.PlayoffBracket) {
|
||||
{{
|
||||
s := seriesByNumber(bracket.Series)
|
||||
conns := connectionsJSON(bracket.Series)
|
||||
}}
|
||||
<div class="overflow-x-auto">
|
||||
<div class="relative min-w-[500px]" data-bracket-lines data-connections={ conns }>
|
||||
<svg data-bracket-svg class="absolute inset-0 w-full h-full pointer-events-none" style="z-index: 0;"></svg>
|
||||
<div class="relative" style="z-index: 1;">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
@seriesCard(season, league, s[1])
|
||||
@seriesCard(season, league, s[2])
|
||||
</div>
|
||||
<div class="h-16"></div>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
@seriesCard(season, league, s[3])
|
||||
@seriesCard(season, league, s[4])
|
||||
</div>
|
||||
<div class="h-16"></div>
|
||||
<div class="max-w-md mx-auto">
|
||||
@seriesCard(season, league, s[5])
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
// bracketRounds groups series by round and renders them
|
||||
templ bracketRounds(season *db.Season, league *db.League, bracket *db.PlayoffBracket) {
|
||||
// ──────────────────────────────────────────────
|
||||
// 7-9 TEAMS FORMAT
|
||||
// ──────────────────────────────────────────────
|
||||
// Round 1 (Quarter Finals): [QF1] [QF2]
|
||||
// Round 2 (Semi Finals): [SF1] [SF2]
|
||||
// Round 3: [3rd Place] [Grand Final]
|
||||
templ bracket7to9(season *db.Season, league *db.League, bracket *db.PlayoffBracket) {
|
||||
{{
|
||||
// Group series by round
|
||||
rounds := groupSeriesByRound(bracket.Series)
|
||||
roundOrder := getRoundOrder(bracket.Format)
|
||||
s := seriesByNumber(bracket.Series)
|
||||
conns := connectionsJSON(bracket.Series)
|
||||
}}
|
||||
for _, roundName := range roundOrder {
|
||||
if series, ok := rounds[roundName]; ok {
|
||||
<div class="space-y-3">
|
||||
<h3 class="text-sm font-semibold text-subtext0 uppercase tracking-wider">
|
||||
{ formatRoundName(roundName) }
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
for _, s := range series {
|
||||
@seriesCard(season, league, s)
|
||||
}
|
||||
<div class="overflow-x-auto">
|
||||
<div class="relative min-w-[500px]" data-bracket-lines data-connections={ conns }>
|
||||
<svg data-bracket-svg class="absolute inset-0 w-full h-full pointer-events-none" style="z-index: 0;"></svg>
|
||||
<div class="relative" style="z-index: 1;">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
@seriesCard(season, league, s[1])
|
||||
@seriesCard(season, league, s[2])
|
||||
</div>
|
||||
<div class="h-16"></div>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
@seriesCard(season, league, s[3])
|
||||
@seriesCard(season, league, s[4])
|
||||
</div>
|
||||
<div class="h-16"></div>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
@seriesCard(season, league, s[5])
|
||||
@seriesCard(season, league, s[6])
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────
|
||||
// 10-15 TEAMS FORMAT
|
||||
// ──────────────────────────────────────────────
|
||||
// 4 invisible columns, cards placed into specific cells:
|
||||
// Row 1: EF1(col2) EF2(col3)
|
||||
// Row 2: QF1(col1) QF2(col4)
|
||||
// Row 3: SF1(col2) SF2(col3)
|
||||
// Row 4: PF1(col2) PF2(col3)
|
||||
// Row 5: 3rd(col2)
|
||||
// Row 6: GF(col3)
|
||||
templ bracket10to15(season *db.Season, league *db.League, bracket *db.PlayoffBracket) {
|
||||
{{
|
||||
s := seriesByNumber(bracket.Series)
|
||||
conns := connectionsJSON(bracket.Series)
|
||||
}}
|
||||
<div class="overflow-x-auto">
|
||||
<div class="relative min-w-[700px]" data-bracket-lines data-connections={ conns }>
|
||||
<svg data-bracket-svg class="absolute inset-0 w-full h-full pointer-events-none" style="z-index: 0;"></svg>
|
||||
<div class="relative" style="z-index: 1;">
|
||||
<!-- Row 1: EF1(c2) EF2(c3) -->
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
<div></div>
|
||||
@seriesCard(season, league, s[3])
|
||||
@seriesCard(season, league, s[4])
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="h-16"></div>
|
||||
<!-- Row 2: QF1(c1) QF2(c4) -->
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
@seriesCard(season, league, s[1])
|
||||
<div></div>
|
||||
<div></div>
|
||||
@seriesCard(season, league, s[2])
|
||||
</div>
|
||||
<div class="h-16"></div>
|
||||
<!-- Row 3: SF1(c2) SF2(c3) -->
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
<div></div>
|
||||
@seriesCard(season, league, s[5])
|
||||
@seriesCard(season, league, s[6])
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="h-16"></div>
|
||||
<!-- Row 4: PF1(c2) PF2(c3) -->
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
<div></div>
|
||||
@seriesCard(season, league, s[7])
|
||||
@seriesCard(season, league, s[8])
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="h-16"></div>
|
||||
<!-- Row 5: 3rd Place(c2) -->
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
<div></div>
|
||||
@seriesCard(season, league, s[9])
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="h-16"></div>
|
||||
<!-- Row 6: Grand Final(c3) -->
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
<div></div>
|
||||
<div></div>
|
||||
@seriesCard(season, league, s[10])
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────
|
||||
// SHARED COMPONENTS
|
||||
// ──────────────────────────────────────────────
|
||||
|
||||
templ seriesCard(season *db.Season, league *db.League, series *db.PlayoffSeries) {
|
||||
<div class={ "bg-surface0 border rounded-lg overflow-hidden",
|
||||
templ.KV("border-blue/50", series.Status == db.SeriesStatusInProgress),
|
||||
templ.KV("border-surface1", series.Status != db.SeriesStatusInProgress) }>
|
||||
<div
|
||||
data-series={ fmt.Sprint(series.SeriesNumber) }
|
||||
class={ "bg-surface0 border rounded-lg overflow-hidden",
|
||||
templ.KV("border-blue/50", series.Status == db.SeriesStatusInProgress),
|
||||
templ.KV("border-surface1", series.Status != db.SeriesStatusInProgress) }
|
||||
>
|
||||
<!-- Series Header -->
|
||||
<div class="bg-mantle px-4 py-2 flex items-center justify-between border-b border-surface1">
|
||||
<div class="bg-mantle px-3 py-1.5 flex items-center justify-between border-b border-surface1">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs font-semibold text-subtext0">{ series.Label }</span>
|
||||
@seriesFormatBadge(series.MatchesToWin)
|
||||
@@ -73,7 +212,7 @@ templ seriesCard(season *db.Season, league *db.League, series *db.PlayoffSeries)
|
||||
</div>
|
||||
<!-- Series Score -->
|
||||
if series.MatchesToWin > 1 {
|
||||
<div class="bg-mantle px-4 py-1.5 text-center text-xs text-subtext0 border-t border-surface1">
|
||||
<div class="bg-mantle px-3 py-1 text-center text-xs text-subtext0 border-t border-surface1">
|
||||
{ fmt.Sprint(series.Team1Wins) } - { fmt.Sprint(series.Team2Wins) }
|
||||
</div>
|
||||
}
|
||||
@@ -88,27 +227,29 @@ templ seriesTeamRow(season *db.Season, league *db.League, team *db.Team, seed *i
|
||||
}
|
||||
isTBD := team == nil
|
||||
}}
|
||||
<div class={ "flex items-center justify-between px-4 py-2.5",
|
||||
<div class={ "flex items-center justify-between px-3 py-2",
|
||||
templ.KV("bg-green/5", isWinner) }>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
if seed != nil {
|
||||
<span class="text-xs font-mono text-subtext0 w-5 text-right">
|
||||
<span class="text-xs font-mono text-subtext0 w-4 text-right flex-shrink-0">
|
||||
{ fmt.Sprint(*seed) }
|
||||
</span>
|
||||
} else {
|
||||
<span class="text-xs font-mono text-subtext0 w-5 text-right">-</span>
|
||||
<span class="text-xs font-mono text-subtext0 w-4 text-right flex-shrink-0">-</span>
|
||||
}
|
||||
if isTBD {
|
||||
<span class="text-sm text-subtext1 italic">TBD</span>
|
||||
} else {
|
||||
@links.TeamLinkInSeason(team, season, league)
|
||||
<div class="truncate">
|
||||
@links.TeamLinkInSeason(team, season, league)
|
||||
</div>
|
||||
if isWinner {
|
||||
<span class="text-green text-xs">✓</span>
|
||||
<span class="text-green text-xs flex-shrink-0">✓</span>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
if matchesToWin > 1 {
|
||||
<span class={ "text-sm font-mono",
|
||||
<span class={ "text-sm font-mono flex-shrink-0 ml-2",
|
||||
templ.KV("text-text", !isWinner),
|
||||
templ.KV("text-green font-bold", isWinner) }>
|
||||
{ fmt.Sprint(wins) }
|
||||
|
||||
Reference in New Issue
Block a user