feat: replace connection indicator with live clock
A ticking clock serves as an implicit connection indicator - if it stops updating, users know the connection is stale. Simpler and more useful than a status dot.
This commit is contained in:
@@ -25,6 +25,7 @@ templ GamePage(g *connect4.Game, myColor int, messages []chat.Message, chatCfg c
|
|||||||
|
|
||||||
templ GameContent(g *connect4.Game, myColor int, messages []chat.Message, chatCfg chatcomponents.Config) {
|
templ GameContent(g *connect4.Game, myColor int, messages []chat.Message, chatCfg chatcomponents.Config) {
|
||||||
<div id="game-content">
|
<div id="game-content">
|
||||||
|
@sharedcomponents.LiveClock()
|
||||||
@sharedcomponents.BackToLobby()
|
@sharedcomponents.BackToLobby()
|
||||||
@sharedcomponents.StealthTitle("text-3xl font-bold")
|
@sharedcomponents.StealthTitle("text-3xl font-bold")
|
||||||
@components.PlayerInfo(g, myColor)
|
@components.PlayerInfo(g, myColor)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package components
|
package components
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"time"
|
||||||
|
|
||||||
"github.com/starfederation/datastar-go/datastar"
|
"github.com/starfederation/datastar-go/datastar"
|
||||||
)
|
)
|
||||||
@@ -48,60 +48,12 @@ templ NicknamePrompt(returnPath string) {
|
|||||||
</main>
|
</main>
|
||||||
}
|
}
|
||||||
|
|
||||||
func isStale(lastPing int64) bool {
|
// LiveClock shows the current server time, updated with each SSE patch.
|
||||||
return lastPing == 0
|
// If the clock stops updating, users know the connection is stale.
|
||||||
}
|
templ LiveClock() {
|
||||||
|
<div class="fixed top-2 right-2 text-xs opacity-50 font-mono">
|
||||||
var connectionWatcherHandle = templ.NewOnceHandle()
|
{ time.Now().Format("15:04:05") }
|
||||||
|
|
||||||
// ConnectionIndicator shows a small dot indicating SSE connection status.
|
|
||||||
// Server patches this with a timestamp; client JS detects staleness.
|
|
||||||
templ ConnectionIndicator(lastPing int64) {
|
|
||||||
<div
|
|
||||||
id="connection-indicator"
|
|
||||||
class="fixed top-2 right-2"
|
|
||||||
data-last-ping={ fmt.Sprintf("%d", lastPing) }
|
|
||||||
>
|
|
||||||
<div class="inline-grid *:[grid-area:1/1]">
|
|
||||||
<div
|
|
||||||
id="connection-ping"
|
|
||||||
class={
|
|
||||||
"status status-sm",
|
|
||||||
templ.KV("status-success animate-ping", !isStale(lastPing)),
|
|
||||||
templ.KV("status-error", isStale(lastPing)),
|
|
||||||
}
|
|
||||||
></div>
|
|
||||||
<div
|
|
||||||
id="connection-dot"
|
|
||||||
class={
|
|
||||||
"status status-sm",
|
|
||||||
templ.KV("status-success", !isStale(lastPing)),
|
|
||||||
templ.KV("status-error", isStale(lastPing)),
|
|
||||||
}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
@connectionWatcherHandle.Once() {
|
|
||||||
@connectionWatcher()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
script connectionWatcher() {
|
|
||||||
setInterval(function() {
|
|
||||||
var el = document.getElementById('connection-indicator');
|
|
||||||
var dot = document.getElementById('connection-dot');
|
|
||||||
var ping = document.getElementById('connection-ping');
|
|
||||||
if (!el || !dot || !ping) return;
|
|
||||||
|
|
||||||
var lastPing = parseInt(el.dataset.lastPing, 10) || 0;
|
|
||||||
var stale = Date.now() - lastPing > 20000;
|
|
||||||
|
|
||||||
dot.classList.toggle('status-success', !stale);
|
|
||||||
dot.classList.toggle('status-error', stale);
|
|
||||||
ping.classList.toggle('status-success', !stale);
|
|
||||||
ping.classList.toggle('status-error', stale);
|
|
||||||
ping.classList.toggle('animate-ping', !stale);
|
|
||||||
}, 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
templ GameJoinPrompt(loginURL string, registerURL string, gamePath string) {
|
templ GameJoinPrompt(loginURL string, registerURL string, gamePath string) {
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ templ GamePage(sg *snake.SnakeGame, mySlot int, messages []chat.Message, chatCfg
|
|||||||
|
|
||||||
templ GameContent(sg *snake.SnakeGame, mySlot int, messages []chat.Message, chatCfg chatcomponents.Config, gameID string) {
|
templ GameContent(sg *snake.SnakeGame, mySlot int, messages []chat.Message, chatCfg chatcomponents.Config, gameID string) {
|
||||||
<div id="game-content">
|
<div id="game-content">
|
||||||
|
@components.LiveClock()
|
||||||
@components.BackToLobby()
|
@components.BackToLobby()
|
||||||
<h1 class="text-3xl font-bold">~~~~</h1>
|
<h1 class="text-3xl font-bold">~~~~</h1>
|
||||||
@snakecomponents.PlayerList(sg, mySlot)
|
@snakecomponents.PlayerList(sg, mySlot)
|
||||||
|
|||||||
Reference in New Issue
Block a user