package ui import ( "fmt" "math" "time" "github.com/ryanhamamura/c4/snake" "github.com/ryanhamamura/via/h" ) func SnakeStatusBanner(sg *snake.SnakeGame, mySlot int, rematchClick h.H) h.H { switch sg.Status { case snake.StatusWaitingForPlayers: if sg.Mode == snake.ModeSinglePlayer { return h.Div(h.Class("alert bg-base-200 text-xl font-bold"), h.Text("Ready?"), ) } return h.Div(h.Class("alert bg-base-200 text-xl font-bold"), h.Text("Waiting for players..."), ) case snake.StatusCountdown: remaining := time.Until(sg.CountdownEnd) secs := int(math.Ceil(remaining.Seconds())) if secs < 0 { secs = 0 } return h.Div(h.Class("alert alert-info text-xl font-bold"), h.Text(fmt.Sprintf("Starting in %d...", secs)), ) case snake.StatusInProgress: if sg.State != nil && mySlot >= 0 && mySlot < len(sg.State.Snakes) { s := sg.State.Snakes[mySlot] if s != nil && !s.Alive { return h.Div(h.Class("alert alert-error text-xl font-bold"), h.Text("You're out!"), ) } } // Show score during single player gameplay if sg.Mode == snake.ModeSinglePlayer { return h.Div(h.Class("alert alert-success text-xl font-bold"), h.Text(fmt.Sprintf("Score: %d", sg.Score)), ) } return h.Div(h.Class("alert alert-success text-xl font-bold"), h.Text("Go!"), ) case snake.StatusFinished: var msg string var class string if sg.Mode == snake.ModeSinglePlayer { msg = fmt.Sprintf("Game Over! Score: %d", sg.Score) class = "alert alert-info text-xl font-bold" } else if sg.Winner != nil { if sg.Winner.Slot == mySlot { msg = "You win!" class = "alert alert-success text-xl font-bold" } else { msg = sg.Winner.Nickname + " wins!" class = "alert alert-error text-xl font-bold" } } else { msg = "It's a draw!" class = "alert alert-warning text-xl font-bold" } content := []h.H{h.Class(class), h.Text(msg)} if sg.RematchGameID != nil { content = append(content, h.A( h.Class("btn btn-sm bg-white text-gray-800 border-none ml-4"), h.Href("/snake/"+*sg.RematchGameID), h.Text("Join Rematch"), ), ) } else if rematchClick != 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"), rematchClick, ), ) } return h.Div(content...) } return nil } func SnakePlayerList(sg *snake.SnakeGame, mySlot int) h.H { var items []h.H for i, p := range sg.Players { if p == nil { continue } colorHex := "#666" if i < len(snake.SnakeColors) { colorHex = snake.SnakeColors[i] } name := p.Nickname if i == mySlot { name += " (You)" } var statusEl h.H if sg.Status == snake.StatusInProgress || sg.Status == snake.StatusFinished { if sg.State != nil && i < len(sg.State.Snakes) { s := sg.State.Snakes[i] if s != nil { if s.Alive { length := len(s.Body) statusEl = h.Span(h.Class("text-sm opacity-60"), h.Text(fmt.Sprintf(" (%d)", length))) } else { statusEl = h.Span(h.Class("text-sm opacity-40"), h.Text(" (dead)")) } } } } chipStyle := fmt.Sprintf("width:16px;height:16px;border-radius:50%%;background:%s;display:inline-block;", colorHex) items = append(items, h.Div(h.Class("flex items-center gap-2"), h.Span(h.Attr("style", chipStyle)), h.Span(h.Text(name)), statusEl, )) } listAttrs := []h.H{h.Class("flex flex-wrap gap-4 mb-2")} listAttrs = append(listAttrs, items...) return h.Div(listAttrs...) } func SnakeInviteLink(gameID string) h.H { fullURL := getBaseURL() + "/snake/" + gameID return h.Div(h.Class("mt-4 text-center"), h.P(h.Text("Share this link to invite players:")), 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+"')"), ), ) }