Server patches the ConnectionIndicator element with a timestamp on each heartbeat. Client-side JS checks every second if the timestamp is stale (>20s) and toggles red/green accordingly. This properly detects connection loss since the indicator will turn red if no patches are received.
91 lines
2.7 KiB
Plaintext
91 lines
2.7 KiB
Plaintext
package components
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/starfederation/datastar-go/datastar"
|
|
)
|
|
|
|
templ BackToLobby() {
|
|
<a class="link text-sm opacity-70" href="/">← Back</a>
|
|
}
|
|
|
|
templ StealthTitle(class string) {
|
|
<span class={ class }>
|
|
<span style="color:#4a2a3a">●</span>
|
|
<span style="color:#2a4545">●</span>
|
|
<span style="color:#4a2a3a">●</span>
|
|
<span style="color:#2a4545">●</span>
|
|
</span>
|
|
}
|
|
|
|
templ NicknamePrompt(returnPath string) {
|
|
<main class="max-w-sm mx-auto mt-8 text-center" data-signals="{nickname: ''}">
|
|
<h1 class="text-3xl font-bold">Join Game</h1>
|
|
<p class="mb-4">Enter your nickname to join the game.</p>
|
|
<form>
|
|
<fieldset class="fieldset">
|
|
<label class="label" for="nickname">Your Nickname</label>
|
|
<input
|
|
class="input input-bordered w-full"
|
|
id="nickname"
|
|
type="text"
|
|
placeholder="Enter your nickname"
|
|
data-bind="nickname"
|
|
data-on:keydown={ "evt.key === 'Enter' && " + datastar.PostSSE("%s", returnPath) }
|
|
required
|
|
autofocus
|
|
/>
|
|
</fieldset>
|
|
<button
|
|
class="btn btn-primary w-full"
|
|
type="button"
|
|
data-on:click={ datastar.PostSSE("%s", returnPath) }
|
|
>
|
|
Join
|
|
</button>
|
|
</form>
|
|
</main>
|
|
}
|
|
|
|
// 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 flex items-center gap-1 text-xs text-gray-500"
|
|
title="Connection status"
|
|
data-last-ping={ fmt.Sprintf("%d", lastPing) }
|
|
>
|
|
<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) {
|
|
<main class="max-w-sm mx-auto mt-8 text-center">
|
|
<h1 class="text-3xl font-bold">Join Game</h1>
|
|
<p class="mb-4">Log in to track your game history, or continue as a guest.</p>
|
|
<div class="flex flex-col gap-2 my-4">
|
|
<a class="btn btn-primary w-full" href={ templ.SafeURL(loginURL) }>Login</a>
|
|
<a class="btn btn-secondary w-full" href={ templ.SafeURL(gamePath + "?guest=1") }>Continue as Guest</a>
|
|
</div>
|
|
<p class="text-sm opacity-60">
|
|
Don't have an account?
|
|
<a class="link" href={ templ.SafeURL(registerURL) }>Register</a>
|
|
</p>
|
|
</main>
|
|
}
|