N-player (2-8) real-time Snake game alongside Connect 4. Lobby has tabs to switch between games. Players join via invite link with 10-second countdown. Game loop runs at tick-based intervals with NATS pub/sub for state sync. Keyboard input not yet working (Datastar keydown binding issue still under investigation).
75 lines
2.0 KiB
Go
75 lines
2.0 KiB
Go
package ui
|
||
|
||
import (
|
||
"fmt"
|
||
|
||
"github.com/ryanhamamura/c4/snake"
|
||
"github.com/ryanhamamura/via/h"
|
||
)
|
||
|
||
func SnakeLobbyTab(nicknameBind h.H, presetClicks []h.H, activeGames []*snake.SnakeGame) h.H {
|
||
var presetButtons []h.H
|
||
for i, preset := range snake.GridPresets {
|
||
var click h.H
|
||
if i < len(presetClicks) {
|
||
click = presetClicks[i]
|
||
}
|
||
presetButtons = append(presetButtons,
|
||
h.Button(
|
||
h.Class("btn btn-primary"),
|
||
h.Type("button"),
|
||
h.Text(fmt.Sprintf("%s (%d×%d)", preset.Name, preset.Width, preset.Height)),
|
||
click,
|
||
),
|
||
)
|
||
}
|
||
|
||
createSection := h.Div(h.Class("mb-6"),
|
||
h.H3(h.Class("text-lg font-bold mb-2"), h.Text("Create Game")),
|
||
h.Div(h.Class("mb-4"),
|
||
h.FieldSet(h.Class("fieldset"),
|
||
h.Label(h.Class("label"), h.Text("Your Nickname"), h.Attr("for", "snake-nickname")),
|
||
h.Input(
|
||
h.Class("input input-bordered w-full"),
|
||
h.ID("snake-nickname"),
|
||
h.Type("text"),
|
||
h.Placeholder("Enter your nickname"),
|
||
nicknameBind,
|
||
h.Attr("required"),
|
||
),
|
||
),
|
||
),
|
||
h.Div(append([]h.H{h.Class("flex gap-2 justify-center")}, presetButtons...)...),
|
||
)
|
||
|
||
var gameListEl h.H
|
||
if len(activeGames) > 0 {
|
||
var items []h.H
|
||
for _, g := range activeGames {
|
||
playerCount := g.PlayerCount()
|
||
sizeLabel := fmt.Sprintf("%d×%d", g.State.Width, g.State.Height)
|
||
statusLabel := "Waiting"
|
||
if g.Status == snake.StatusCountdown {
|
||
statusLabel = "Starting soon"
|
||
}
|
||
items = append(items, h.A(
|
||
h.Href("/snake/"+g.ID),
|
||
h.Class("flex justify-between items-center p-3 bg-base-200 rounded-lg hover:bg-base-300 no-underline text-base-content"),
|
||
h.Span(h.Text(fmt.Sprintf("%s — %d/8 players", sizeLabel, playerCount))),
|
||
h.Span(h.Class("text-sm opacity-60"), h.Text(statusLabel)),
|
||
))
|
||
}
|
||
listAttrs := []h.H{h.Class("flex flex-col gap-2")}
|
||
listAttrs = append(listAttrs, items...)
|
||
gameListEl = h.Div(h.Class("mt-6"),
|
||
h.H3(h.Class("text-lg font-bold mb-2 text-center"), h.Text("Join a Game")),
|
||
h.Div(listAttrs...),
|
||
)
|
||
}
|
||
|
||
return h.Div(
|
||
createSection,
|
||
gameListEl,
|
||
)
|
||
}
|