Files
games/ui/status.go
Ryan Hamamura 2df20c2840 refactor: adopt portigo infrastructure patterns
Add config package with build-tag-switched dev/prod environments,
structured logging via zerolog, Taskfile for dev workflow, golangci-lint
config, testutil package, and improved DB setup with proper SQLite
pragmas and cleanup. Rename sqlc output package from gen to repository.

Switch to allowlist .gitignore, Alpine+UPX+scratch Dockerfile, and
CI pipeline with test/lint gates before deploy.
2026-03-02 11:48:47 -10:00

138 lines
3.1 KiB
Go

package ui
import (
"github.com/ryanhamamura/c4/config"
"github.com/ryanhamamura/c4/game"
"github.com/ryanhamamura/via/h"
)
func StatusBanner(g *game.Game, myColor int, playAgainClick h.H) h.H {
var message string
var class string
switch g.Status {
case game.StatusWaitingForPlayer:
message = "Waiting for opponent..."
class = "alert bg-base-200 text-xl font-bold"
case game.StatusInProgress:
if g.CurrentTurn == myColor {
message = "Your turn!"
class = "alert alert-success text-xl font-bold"
} else {
opponentName := getOpponentName(g, myColor)
message = opponentName + "'s turn"
class = "alert bg-base-200 text-xl font-bold"
}
case game.StatusWon:
if g.Winner != nil && g.Winner.Color == myColor {
message = "You win!"
class = "alert alert-success text-xl font-bold"
} else if g.Winner != nil {
message = g.Winner.Nickname + " wins!"
class = "alert alert-error text-xl font-bold"
}
case game.StatusDraw:
message = "It's a draw!"
class = "alert alert-warning text-xl font-bold"
}
content := []h.H{
h.Class(class),
h.Text(message),
}
// Show rematch options for finished games
if g.IsFinished() {
if g.RematchGameID != nil {
content = append(content,
h.A(
h.Class("btn btn-sm bg-white text-gray-800 border-none ml-4"),
h.Href("/game/"+*g.RematchGameID),
h.Text("Join Rematch"),
),
)
} else if playAgainClick != nil {
content = append(content,
h.Button(
h.Class("btn btn-sm bg-white text-gray-800 border-none ml-4"),
h.Type("button"),
h.Text("Play again"),
playAgainClick,
),
)
}
}
return h.Div(content...)
}
func getOpponentName(g *game.Game, myColor int) string {
for _, p := range g.Players {
if p != nil && p.Color != myColor {
return p.Nickname
}
}
return "Opponent"
}
func PlayerInfo(g *game.Game, myColor int) h.H {
var myName, opponentName string
var myColorClass, opponentColorClass string
for _, p := range g.Players {
if p == nil {
continue
}
if p.Color == myColor {
myName = p.Nickname
if p.Color == 1 {
myColorClass = "red"
} else {
myColorClass = "yellow"
}
} else {
opponentName = p.Nickname
if p.Color == 1 {
opponentColorClass = "red"
} else {
opponentColorClass = "yellow"
}
}
}
if opponentName == "" {
opponentName = "Waiting..."
}
return h.Div(h.Class("flex gap-8 mb-2"),
h.Div(h.Class("flex items-center gap-2"),
h.Span(h.Class("player-chip "+myColorClass)),
h.Span(h.Text(myName+" (You)")),
),
h.Div(h.Class("flex items-center gap-2"),
h.Span(h.Class("player-chip "+opponentColorClass)),
h.Span(h.Text(opponentName)),
),
)
}
func getBaseURL() string {
return config.Global.AppURL
}
func InviteLink(gameID string) h.H {
fullURL := getBaseURL() + "/game/" + gameID
return h.Div(h.Class("mt-4 text-center"),
h.P(h.Text("Share this link with your opponent:")),
h.Div(h.Class("bg-base-200 p-4 rounded-lg font-mono break-all my-2"),
h.Text(fullURL),
),
h.Button(
h.Class("btn btn-sm mt-2"),
h.Type("button"),
h.Text("Copy Link"),
h.Attr("onclick", "navigator.clipboard.writeText('"+fullURL+"')"),
),
)
}