Compare commits
1 Commits
main
...
19c48d593a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19c48d593a |
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/ryanhamamura/games/connect4"
|
||||
"github.com/ryanhamamura/games/db/repository"
|
||||
"github.com/ryanhamamura/games/features/c4game/pages"
|
||||
sharedcomponents "github.com/ryanhamamura/games/features/common/components"
|
||||
"github.com/ryanhamamura/games/sessions"
|
||||
)
|
||||
|
||||
@@ -119,7 +120,7 @@ func HandleGameEvents(store *connect4.Store, nc *nats.Conn, sm *scs.SessionManag
|
||||
}
|
||||
|
||||
sendPing := func() error {
|
||||
return sse.PatchSignals([]byte(fmt.Sprintf(`{"lastPing":%d}`, time.Now().UnixMilli())))
|
||||
return sse.PatchElementTempl(sharedcomponents.ConnectionIndicator(time.Now().UnixMilli()))
|
||||
}
|
||||
|
||||
// Send initial render and ping
|
||||
|
||||
@@ -15,10 +15,10 @@ templ GamePage(g *connect4.Game, myColor int, messages []chat.Message, chatCfg c
|
||||
@layouts.Base("Connect 4") {
|
||||
<main
|
||||
class="flex flex-col items-center gap-4 p-4"
|
||||
data-signals="{chatMsg: '', lastPing: 0}"
|
||||
data-signals="{chatMsg: ''}"
|
||||
data-init={ fmt.Sprintf("@get('/games/%s/events',{requestCancellation:'disabled'})", g.ID) }
|
||||
>
|
||||
@sharedcomponents.ConnectionIndicator()
|
||||
@sharedcomponents.ConnectionIndicator(0)
|
||||
@GameContent(g, myColor, messages, chatCfg)
|
||||
</main>
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package components
|
||||
|
||||
import "github.com/starfederation/datastar-go/datastar"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/starfederation/datastar-go/datastar"
|
||||
)
|
||||
|
||||
templ BackToLobby() {
|
||||
<a class="link text-sm opacity-70" href="/">← Back</a>
|
||||
@@ -45,18 +49,29 @@ templ NicknamePrompt(returnPath string) {
|
||||
}
|
||||
|
||||
// ConnectionIndicator shows a small dot indicating SSE connection status.
|
||||
// It requires a `lastPing` signal (unix ms timestamp) to be set by the server.
|
||||
templ ConnectionIndicator() {
|
||||
// Server patches this with a timestamp; client JS detects staleness.
|
||||
templ ConnectionIndicator(lastPing int64) {
|
||||
<div
|
||||
id="connection-indicator"
|
||||
class="fixed top-2 right-2 flex items-center gap-1 text-xs text-gray-500"
|
||||
title="Connection status"
|
||||
data-last-ping={ fmt.Sprintf("%d", lastPing) }
|
||||
>
|
||||
<span
|
||||
class="w-2 h-2 rounded-full transition-colors duration-300"
|
||||
data-class="{'bg-green-500': Date.now() - $lastPing < 20000, 'bg-red-500': Date.now() - $lastPing >= 20000}"
|
||||
></span>
|
||||
<span id="connection-dot" class="w-2 h-2 rounded-full bg-green-500"></span>
|
||||
</div>
|
||||
@connectionWatcher()
|
||||
}
|
||||
|
||||
script connectionWatcher() {
|
||||
setInterval(function() {
|
||||
var el = document.getElementById('connection-indicator');
|
||||
var dot = document.getElementById('connection-dot');
|
||||
if (!el || !dot) return;
|
||||
var lastPing = parseInt(el.dataset.lastPing, 10) || 0;
|
||||
var stale = Date.now() - lastPing > 20000;
|
||||
dot.classList.toggle('bg-green-500', !stale);
|
||||
dot.classList.toggle('bg-red-500', stale);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
templ GameJoinPrompt(loginURL string, registerURL string, gamePath string) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/ryanhamamura/games/chat"
|
||||
chatcomponents "github.com/ryanhamamura/games/chat/components"
|
||||
sharedcomponents "github.com/ryanhamamura/games/features/common/components"
|
||||
"github.com/ryanhamamura/games/features/snakegame/pages"
|
||||
"github.com/ryanhamamura/games/sessions"
|
||||
"github.com/ryanhamamura/games/snake"
|
||||
@@ -125,7 +126,7 @@ func HandleSnakeEvents(snakeStore *snake.SnakeStore, nc *nats.Conn, sm *scs.Sess
|
||||
}
|
||||
|
||||
sendPing := func() error {
|
||||
return sse.PatchSignals([]byte(fmt.Sprintf(`{"lastPing":%d}`, time.Now().UnixMilli())))
|
||||
return sse.PatchElementTempl(sharedcomponents.ConnectionIndicator(time.Now().UnixMilli()))
|
||||
}
|
||||
|
||||
// Send initial render and ping
|
||||
|
||||
@@ -32,12 +32,12 @@ templ GamePage(sg *snake.SnakeGame, mySlot int, messages []chat.Message, chatCfg
|
||||
@layouts.Base("Snake") {
|
||||
<main
|
||||
class="snake-wrapper flex flex-col items-center gap-4 p-4"
|
||||
data-signals={ `{"chatMsg":"","lastPing":0}` }
|
||||
data-signals={ `{"chatMsg":""}` }
|
||||
data-init={ fmt.Sprintf("@get('/snake/%s/events',{requestCancellation:'disabled'})", gameID) }
|
||||
data-on:keydown__throttle.100ms={ keydownScript(gameID) }
|
||||
tabindex="0"
|
||||
>
|
||||
@components.ConnectionIndicator()
|
||||
@components.ConnectionIndicator(0)
|
||||
@GameContent(sg, mySlot, messages, chatCfg, gameID)
|
||||
</main>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user