package seasonsview import "git.haelnorr.com/h/oslstats/internal/db" import "git.haelnorr.com/h/oslstats/internal/view/component/links" import "fmt" import "sort" // fixtureMatchPreviewTab renders the full Match Preview tab content. // Shows team standings comparison, recent form, and full rosters side-by-side. templ fixtureMatchPreviewTab( fixture *db.Fixture, rosters map[string][]*db.PlayerWithPlayStatus, preview *db.MatchPreviewData, ) {
@matchPreviewHeader(fixture, preview) @matchPreviewFormGuide(fixture, preview) @matchPreviewRosters(fixture, rosters)
} // matchPreviewHeader renders the broadcast-style team comparison with standings. templ matchPreviewHeader(fixture *db.Fixture, preview *db.MatchPreviewData) {

Team Comparison

if fixture.HomeTeam.Color != "" {
}

@links.TeamNameLinkInSeason(fixture.HomeTeam, fixture.Season, fixture.League)

{ fixture.HomeTeam.ShortName }
VS
if fixture.AwayTeam.Color != "" {
}

@links.TeamNameLinkInSeason(fixture.AwayTeam, fixture.Season, fixture.League)

{ fixture.AwayTeam.ShortName }
{{ homePos := ordinal(preview.HomePosition) awayPos := ordinal(preview.AwayPosition) if preview.HomePosition == 0 { homePos = "N/A" } if preview.AwayPosition == 0 { awayPos = "N/A" } }}
@previewStatRow( homePos, "Position", awayPos, preview.HomePosition > 0 && preview.HomePosition < preview.AwayPosition, preview.AwayPosition > 0 && preview.AwayPosition < preview.HomePosition, ) @previewStatRow( fmt.Sprint(preview.HomeRecord.Points), "Points", fmt.Sprint(preview.AwayRecord.Points), preview.HomeRecord.Points > preview.AwayRecord.Points, preview.AwayRecord.Points > preview.HomeRecord.Points, ) @previewStatRow( fmt.Sprint(preview.HomeRecord.Played), "Played", fmt.Sprint(preview.AwayRecord.Played), false, false, ) @previewStatRow( fmt.Sprint(preview.HomeRecord.Wins), "Wins", fmt.Sprint(preview.AwayRecord.Wins), preview.HomeRecord.Wins > preview.AwayRecord.Wins, preview.AwayRecord.Wins > preview.HomeRecord.Wins, ) @previewStatRow( fmt.Sprint(preview.HomeRecord.OvertimeWins), "OT Wins", fmt.Sprint(preview.AwayRecord.OvertimeWins), preview.HomeRecord.OvertimeWins > preview.AwayRecord.OvertimeWins, preview.AwayRecord.OvertimeWins > preview.HomeRecord.OvertimeWins, ) @previewStatRow( fmt.Sprint(preview.HomeRecord.OvertimeLosses), "OT Losses", fmt.Sprint(preview.AwayRecord.OvertimeLosses), preview.HomeRecord.OvertimeLosses < preview.AwayRecord.OvertimeLosses, preview.AwayRecord.OvertimeLosses < preview.HomeRecord.OvertimeLosses, ) @previewStatRow( fmt.Sprint(preview.HomeRecord.Losses), "Losses", fmt.Sprint(preview.AwayRecord.Losses), preview.HomeRecord.Losses < preview.AwayRecord.Losses, preview.AwayRecord.Losses < preview.HomeRecord.Losses, ) @previewStatRow( fmt.Sprint(preview.HomeRecord.GoalsFor), "Goals For", fmt.Sprint(preview.AwayRecord.GoalsFor), preview.HomeRecord.GoalsFor > preview.AwayRecord.GoalsFor, preview.AwayRecord.GoalsFor > preview.HomeRecord.GoalsFor, ) @previewStatRow( fmt.Sprint(preview.HomeRecord.GoalsAgainst), "Goals Against", fmt.Sprint(preview.AwayRecord.GoalsAgainst), preview.HomeRecord.GoalsAgainst < preview.AwayRecord.GoalsAgainst, preview.AwayRecord.GoalsAgainst < preview.HomeRecord.GoalsAgainst, ) {{ homeDiff := preview.HomeRecord.GoalsFor - preview.HomeRecord.GoalsAgainst awayDiff := preview.AwayRecord.GoalsFor - preview.AwayRecord.GoalsAgainst homeDiffStr := fmt.Sprintf("%+d", homeDiff) awayDiffStr := fmt.Sprintf("%+d", awayDiff) }} @previewStatRow( homeDiffStr, "Goal Diff", awayDiffStr, homeDiff > awayDiff, awayDiff > homeDiff, )
} // previewStatRow renders a single comparison stat row in the broadcast-style layout. // The stat label is centered, with home value on the left and away value on the right. // homeHighlight/awayHighlight indicate which side has the better value. templ previewStatRow(homeValue, label, awayValue string, homeHighlight, awayHighlight bool) {
{ homeValue }
{ label }
{ awayValue }
} // matchPreviewFormGuide renders the recent form section with last 5 game outcome icons. templ matchPreviewFormGuide(fixture *db.Fixture, preview *db.MatchPreviewData) {

Recent Form

if fixture.HomeTeam.Color != "" { }

{ fixture.HomeTeam.Name }

if len(preview.HomeRecentGames) == 0 {

No recent matches played

} else {
for _, g := range preview.HomeRecentGames { @gameOutcomeIcon(g) }
for i := len(preview.HomeRecentGames) - 1; i >= 0; i-- { @recentGameRow(preview.HomeRecentGames[i]) }
}
if fixture.AwayTeam.Color != "" { }

{ fixture.AwayTeam.Name }

if len(preview.AwayRecentGames) == 0 {

No recent matches played

} else {
for _, g := range preview.AwayRecentGames { @gameOutcomeIcon(g) }
for i := len(preview.AwayRecentGames) - 1; i >= 0; i-- { @recentGameRow(preview.AwayRecentGames[i]) }
}
} // outcomeStyle holds the styling info for a game outcome type. type outcomeStyle struct { iconBg string // Background class for the icon badge rowBg string // Background class for the row text string // Text color class label string // Short label (W, L, OW, OL, D, F) fullLabel string // Full label for row display (W, OTW, OTL, L, D, FF) desc string // Human-readable description (Win, Loss, etc.) } func getOutcomeStyle(outcomeType string) outcomeStyle { switch outcomeType { case "W": return outcomeStyle{"bg-green/20", "bg-green/10", "text-green", "W", "W", "Win"} case "OTW": return outcomeStyle{"bg-yellow/20", "bg-yellow/10", "text-yellow", "OW", "OTW", "OT Win"} case "OTL": return outcomeStyle{"bg-peach/20", "bg-peach/10", "text-peach", "OL", "OTL", "OT Loss"} case "L": return outcomeStyle{"bg-red/20", "bg-red/10", "text-red", "L", "L", "Loss"} case "D": return outcomeStyle{"bg-overlay0/20", "bg-overlay0/10", "text-overlay0", "D", "D", "Draw"} case "F": return outcomeStyle{"bg-red/30", "bg-red/15", "text-red", "F", "FF", "Forfeit"} default: return outcomeStyle{"bg-surface1", "bg-surface0", "text-subtext0", "?", "?", "Unknown"} } } // gameOutcomeIcon renders a single game outcome as a colored badge. templ gameOutcomeIcon(outcome *db.GameOutcome) { {{ style := getOutcomeStyle(outcome.Type) tooltip := "" if outcome.Opponent != nil { tooltip = fmt.Sprintf("%s vs %s", style.desc, outcome.Opponent.Name) if outcome.IsForfeit { tooltip += " (Forfeit)" } else if outcome.Score != "" { tooltip += fmt.Sprintf(" (%s)", outcome.Score) } } }} { style.label } } // recentGameRow renders a single recent game result as a compact row. templ recentGameRow(outcome *db.GameOutcome) { {{ style := getOutcomeStyle(outcome.Type) opponentName := "Unknown" if outcome.Opponent != nil { opponentName = outcome.Opponent.Name } }}
{ style.fullLabel } vs { opponentName } if outcome.IsForfeit { Forfeit } else if outcome.Score != "" { { outcome.Score } }
} // matchPreviewRosters renders team rosters side-by-side for the match preview. templ matchPreviewRosters( fixture *db.Fixture, rosters map[string][]*db.PlayerWithPlayStatus, ) { {{ homePlayers := rosters["home"] awayPlayers := rosters["away"] }}

Team Rosters

@previewRosterColumn(fixture.HomeTeam, homePlayers, fixture.Season, fixture.League) @previewRosterColumn(fixture.AwayTeam, awayPlayers, fixture.Season, fixture.League)
} // previewRosterColumn renders a single team's roster for the match preview. templ previewRosterColumn( team *db.Team, players []*db.PlayerWithPlayStatus, season *db.Season, league *db.League, ) { {{ // Separate managers and regular players var managers []*db.PlayerWithPlayStatus var roster []*db.PlayerWithPlayStatus for _, p := range players { if p.IsManager { managers = append(managers, p) } else { roster = append(roster, p) } } // Sort roster alphabetically by display name sort.Slice(roster, func(i, j int) bool { return roster[i].Player.DisplayName() < roster[j].Player.DisplayName() }) }}
if team.Color != "" { }

@links.TeamNameLinkInSeason(team, season, league)

{ fmt.Sprint(len(players)) } players
if len(players) == 0 {

No players on roster.

} else {
for _, p := range managers {
@links.PlayerLink(p.Player) if p.IsFreeAgent { FA }
} for _, p := range roster {
@links.PlayerLink(p.Player) if p.IsFreeAgent { FA }
}
}
}