Files
oslstats/internal/view/seasonsview/playoff_bracket.templ
2026-03-15 17:43:39 +11:00

166 lines
4.9 KiB
Plaintext

package seasonsview
import "git.haelnorr.com/h/oslstats/internal/db"
import "git.haelnorr.com/h/oslstats/internal/view/component/links"
import "fmt"
// PlayoffBracketView renders the full bracket visualization
templ PlayoffBracketView(season *db.Season, league *db.League, bracket *db.PlayoffBracket) {
<div class="space-y-6">
<!-- Bracket Header -->
<div class="flex items-center justify-between">
<div>
<h2 class="text-xl font-bold text-text flex items-center gap-2">
<span class="text-yellow">&#9733;</span>
Finals Bracket
</h2>
<p class="text-sm text-subtext0 mt-1">
{ formatLabel(bracket.Format) }
</p>
</div>
<div>
@playoffStatusBadge(bracket.Status)
</div>
</div>
<!-- Bracket Series List -->
<div class="space-y-4">
@bracketRounds(season, league, bracket)
</div>
</div>
}
// bracketRounds groups series by round and renders them
templ bracketRounds(season *db.Season, league *db.League, bracket *db.PlayoffBracket) {
{{
// Group series by round
rounds := groupSeriesByRound(bracket.Series)
roundOrder := getRoundOrder(bracket.Format)
}}
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>
</div>
}
}
}
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) }>
<!-- Series Header -->
<div class="bg-mantle px-4 py-2 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)
</div>
@seriesStatusBadge(series.Status)
</div>
<!-- Teams -->
<div class="divide-y divide-surface1">
@seriesTeamRow(season, league, series.Team1, series.Team1Seed, series.Team1Wins,
series.WinnerTeamID, series.MatchesToWin)
@seriesTeamRow(season, league, series.Team2, series.Team2Seed, series.Team2Wins,
series.WinnerTeamID, series.MatchesToWin)
</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">
{ fmt.Sprint(series.Team1Wins) } - { fmt.Sprint(series.Team2Wins) }
</div>
}
</div>
}
templ seriesTeamRow(season *db.Season, league *db.League, team *db.Team, seed *int, wins int, winnerID *int, matchesToWin int) {
{{
isWinner := false
if team != nil && winnerID != nil {
isWinner = team.ID == *winnerID
}
isTBD := team == nil
}}
<div class={ "flex items-center justify-between px-4 py-2.5",
templ.KV("bg-green/5", isWinner) }>
<div class="flex items-center gap-2">
if seed != nil {
<span class="text-xs font-mono text-subtext0 w-5 text-right">
{ fmt.Sprint(*seed) }
</span>
} else {
<span class="text-xs font-mono text-subtext0 w-5 text-right">-</span>
}
if isTBD {
<span class="text-sm text-subtext1 italic">TBD</span>
} else {
@links.TeamLinkInSeason(team, season, league)
if isWinner {
<span class="text-green text-xs">✓</span>
}
}
</div>
if matchesToWin > 1 {
<span class={ "text-sm font-mono",
templ.KV("text-text", !isWinner),
templ.KV("text-green font-bold", isWinner) }>
{ fmt.Sprint(wins) }
</span>
}
</div>
}
templ playoffStatusBadge(status db.PlayoffStatus) {
switch status {
case db.PlayoffStatusUpcoming:
<span class="px-2 py-0.5 bg-blue/20 text-blue rounded text-xs font-medium">
Upcoming
</span>
case db.PlayoffStatusInProgress:
<span class="px-2 py-0.5 bg-yellow/20 text-yellow rounded text-xs font-medium">
In Progress
</span>
case db.PlayoffStatusCompleted:
<span class="px-2 py-0.5 bg-green/20 text-green rounded text-xs font-medium">
Completed
</span>
}
}
templ seriesFormatBadge(matchesToWin int) {
{{
label := fmt.Sprintf("BO%d", matchesToWin*2-1)
}}
<span class="px-1.5 py-0.5 bg-surface1 text-subtext1 rounded text-xs font-mono">
{ label }
</span>
}
templ seriesStatusBadge(status db.SeriesStatus) {
switch status {
case db.SeriesStatusPending:
<span class="px-1.5 py-0.5 bg-surface1 text-subtext0 rounded text-xs">
Pending
</span>
case db.SeriesStatusInProgress:
<span class="px-1.5 py-0.5 bg-blue/20 text-blue rounded text-xs">
Live
</span>
case db.SeriesStatusCompleted:
<span class="px-1.5 py-0.5 bg-green/20 text-green rounded text-xs">
Complete
</span>
case db.SeriesStatusBye:
<span class="px-1.5 py-0.5 bg-surface1 text-subtext0 rounded text-xs">
Bye
</span>
}
}