The script was being re-added on every SSE patch, creating multiple setInterval timers. Split into ConnectionIndicator (for patches) and ConnectionIndicatorWithScript (for initial page render).
85 lines
2.9 KiB
Plaintext
85 lines
2.9 KiB
Plaintext
package pages
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/ryanhamamura/games/chat"
|
|
chatcomponents "github.com/ryanhamamura/games/chat/components"
|
|
"github.com/ryanhamamura/games/features/common/components"
|
|
"github.com/ryanhamamura/games/features/common/layouts"
|
|
snakecomponents "github.com/ryanhamamura/games/features/snakegame/components"
|
|
"github.com/ryanhamamura/games/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 []chat.Message, chatCfg chatcomponents.Config, gameID string) {
|
|
@layouts.Base("Snake") {
|
|
<main
|
|
class="snake-wrapper flex flex-col items-center gap-4 p-4"
|
|
data-signals={ `{"chatMsg":""}` }
|
|
data-init={ fmt.Sprintf("@get('/snake/%s/events',{requestCancellation:'disabled'})", gameID) }
|
|
data-on:keydown__throttle.100ms={ keydownScript(gameID) }
|
|
tabindex="0"
|
|
>
|
|
@components.ConnectionIndicatorWithScript(0)
|
|
@GameContent(sg, mySlot, messages, chatCfg, gameID)
|
|
</main>
|
|
}
|
|
}
|
|
|
|
templ GameContent(sg *snake.SnakeGame, mySlot int, messages []chat.Message, chatCfg chatcomponents.Config, gameID string) {
|
|
<div id="game-content">
|
|
@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)
|
|
@chatcomponents.Chat(messages, chatCfg)
|
|
</div>
|
|
} else {
|
|
@snakecomponents.Board(sg)
|
|
}
|
|
} else if sg.Mode == snake.ModeMultiplayer {
|
|
@chatcomponents.Chat(messages, chatCfg)
|
|
}
|
|
if sg.Mode == snake.ModeMultiplayer && (sg.Status == snake.StatusWaitingForPlayers || sg.Status == snake.StatusCountdown) {
|
|
@snakecomponents.InviteLink(gameID)
|
|
}
|
|
</div>
|
|
}
|
|
|
|
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))
|
|
}
|
|
}
|