Files
games/features/snakegame/pages/game.templ
Ryan Hamamura 2bea5bb489
Some checks failed
CI / Deploy / test (pull_request) Failing after 13s
CI / Deploy / lint (pull_request) Failing after 24s
CI / Deploy / deploy (pull_request) Has been skipped
chore: gitignore generated _templ.go files, track .templ sources
Generated _templ.go files are deterministic output from .templ sources,
same as output.css from input.css. Remove them from version control to
reduce diff noise and merge conflicts. Add build:templ and live:templ
tasks to the Taskfile so generation happens as part of the build.
2026-03-02 15:27:38 -10:00

76 lines
2.5 KiB
Plaintext

package pages
import (
"fmt"
"github.com/ryanhamamura/c4/features/common/components"
"github.com/ryanhamamura/c4/features/common/layouts"
snakecomponents "github.com/ryanhamamura/c4/features/snakegame/components"
"github.com/ryanhamamura/c4/snake"
"github.com/starfederation/datastar-go/datastar"
)
// keydownScript builds the inline JS for a single data-on:keydown handler
// that dispatches WASD/arrow keys to direction POST endpoints.
func keydownScript(gameID string) string {
return fmt.Sprintf(
"const k=evt.key;"+
"if(k==='w'||k==='ArrowUp'){evt.preventDefault();%s}"+
"else if(k==='s'||k==='ArrowDown'){evt.preventDefault();%s}"+
"else if(k==='a'||k==='ArrowLeft'){evt.preventDefault();%s}"+
"else if(k==='d'||k==='ArrowRight'){evt.preventDefault();%s}",
datastar.PostSSE("/snake/%s/dir?d=0", gameID),
datastar.PostSSE("/snake/%s/dir?d=1", gameID),
datastar.PostSSE("/snake/%s/dir?d=2", gameID),
datastar.PostSSE("/snake/%s/dir?d=3", gameID),
)
}
templ GamePage(sg *snake.SnakeGame, mySlot int, messages []snakecomponents.ChatMessage, gameID string) {
@layouts.Base("Snake") {
<main
class="snake-wrapper flex flex-col items-center gap-4 p-4"
data-signals={ `{"chatMsg":""}` }
data-init={ datastar.GetSSE("/snake/%s/events", gameID) }
data-on:keydown.throttle_100ms={ keydownScript(gameID) }
tabindex="0"
>
@components.BackToLobby()
<h1 class="text-3xl font-bold">~~~~</h1>
@snakecomponents.PlayerList(sg, mySlot)
@snakecomponents.StatusBanner(sg, mySlot, gameID)
if sg.Status == snake.StatusInProgress || sg.Status == snake.StatusFinished {
if sg.Mode == snake.ModeMultiplayer {
<div class="snake-game-area">
@snakecomponents.Board(sg)
@snakecomponents.Chat(messages, gameID)
</div>
} else {
@snakecomponents.Board(sg)
}
} else if sg.Mode == snake.ModeMultiplayer {
@snakecomponents.Chat(messages, gameID)
}
if sg.Mode == snake.ModeMultiplayer && (sg.Status == snake.StatusWaitingForPlayers || sg.Status == snake.StatusCountdown) {
@snakecomponents.InviteLink(gameID)
}
</main>
}
}
templ JoinPage(gameID string) {
@layouts.Base("Snake - Join") {
@components.GameJoinPrompt(
fmt.Sprintf("/login?return_url=/snake/%s", gameID),
fmt.Sprintf("/register?return_url=/snake/%s", gameID),
fmt.Sprintf("/snake/%s", gameID),
)
}
}
templ NicknamePage(gameID string) {
@layouts.Base("Snake - Join") {
@components.NicknamePrompt(fmt.Sprintf("/snake/%s/join", gameID))
}
}