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.
172 lines
4.8 KiB
Plaintext
172 lines
4.8 KiB
Plaintext
package pages
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/ryanhamamura/c4/features/common/components"
|
|
"github.com/ryanhamamura/c4/features/common/layouts"
|
|
lobbycomponents "github.com/ryanhamamura/c4/features/lobby/components"
|
|
"github.com/ryanhamamura/c4/snake"
|
|
"github.com/starfederation/datastar-go/datastar"
|
|
)
|
|
|
|
templ LobbyPage(data LobbyData) {
|
|
@layouts.Base("Game Lobby") {
|
|
<main
|
|
class="max-w-md mx-auto mt-8 text-center"
|
|
data-signals="{activeTab: 'connect4', nickname: '', selectedSpeed: 1}"
|
|
>
|
|
// Auth header
|
|
if data.IsLoggedIn {
|
|
<div class="flex justify-center items-center gap-4 mb-4 p-2 bg-base-200 rounded-lg">
|
|
<span>Logged in as <strong>{ data.Username }</strong></span>
|
|
<button
|
|
type="button"
|
|
class="btn btn-ghost btn-sm"
|
|
data-on:click={ datastar.PostSSE("/logout") }
|
|
>
|
|
Logout
|
|
</button>
|
|
</div>
|
|
} else {
|
|
<div class="alert text-sm mb-4">
|
|
Playing as guest.
|
|
<a class="link" href="/login">Login</a>
|
|
or
|
|
<a class="link" href="/register">Register</a>
|
|
to save your games.
|
|
</div>
|
|
}
|
|
// Title
|
|
<h1 class="text-3xl font-bold mb-4">
|
|
@components.StealthTitle("")
|
|
</h1>
|
|
// Tab buttons
|
|
<div class="tabs tabs-box mb-6 justify-center">
|
|
<button
|
|
class="tab"
|
|
type="button"
|
|
data-class="{'tab-active': $activeTab==='connect4'}"
|
|
data-on:click="$activeTab='connect4'"
|
|
>
|
|
@components.StealthTitle("")
|
|
</button>
|
|
<button
|
|
class="tab"
|
|
type="button"
|
|
data-class="{'tab-active': $activeTab==='snake'}"
|
|
data-on:click="$activeTab='snake'"
|
|
>
|
|
~~~~
|
|
</button>
|
|
</div>
|
|
// Connect4 tab
|
|
<div data-show="$activeTab==='connect4'">
|
|
<p class="mb-4">Start a new session</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"
|
|
required
|
|
data-on:keydown.enter={ datastar.PostSSE("/games") }
|
|
/>
|
|
</fieldset>
|
|
<button
|
|
class="btn btn-primary w-full"
|
|
type="button"
|
|
data-on:click={ datastar.PostSSE("/games") }
|
|
>
|
|
Create Game
|
|
</button>
|
|
</form>
|
|
@lobbycomponents.GameList(data.UserGames)
|
|
</div>
|
|
// Snake tab
|
|
<div data-show="$activeTab==='snake'">
|
|
// Nickname
|
|
<div class="mb-4">
|
|
<fieldset class="fieldset">
|
|
<label class="label" for="snake-nickname">Your Nickname</label>
|
|
<input
|
|
class="input input-bordered w-full"
|
|
id="snake-nickname"
|
|
type="text"
|
|
placeholder="Enter your nickname"
|
|
data-bind="nickname"
|
|
required
|
|
/>
|
|
</fieldset>
|
|
</div>
|
|
// Speed selector
|
|
<div class="mb-4">
|
|
<label class="label">Speed</label>
|
|
<div class="btn-group">
|
|
for i, preset := range snake.SpeedPresets {
|
|
<button
|
|
class="btn btn-sm"
|
|
type="button"
|
|
data-class={ fmt.Sprintf("{'btn-active': $selectedSpeed===%d}", i) }
|
|
data-on:click={ fmt.Sprintf("$selectedSpeed=%d", i) }
|
|
>
|
|
{ preset.Name }
|
|
</button>
|
|
}
|
|
</div>
|
|
</div>
|
|
// Solo play
|
|
<div class="mb-6">
|
|
<h3 class="text-lg font-bold mb-2">Play Solo</h3>
|
|
<div class="flex gap-2 justify-center flex-wrap">
|
|
for i, preset := range snake.GridPresets {
|
|
<button
|
|
class="btn btn-secondary"
|
|
type="button"
|
|
data-on:click={ datastar.PostSSE("/snake?mode=solo&preset=%d", i) }
|
|
>
|
|
{ fmt.Sprintf("%s (%d\u00d7%d)", preset.Name, preset.Width, preset.Height) }
|
|
</button>
|
|
}
|
|
</div>
|
|
</div>
|
|
// Multiplayer
|
|
<div class="mb-6">
|
|
<h3 class="text-lg font-bold mb-2">Create Multiplayer Game</h3>
|
|
<div class="flex gap-2 justify-center flex-wrap">
|
|
for i, preset := range snake.GridPresets {
|
|
<button
|
|
class="btn btn-primary"
|
|
type="button"
|
|
data-on:click={ datastar.PostSSE("/snake?mode=multi&preset=%d", i) }
|
|
>
|
|
{ fmt.Sprintf("%s (%d\u00d7%d)", preset.Name, preset.Width, preset.Height) }
|
|
</button>
|
|
}
|
|
</div>
|
|
</div>
|
|
// Active snake games
|
|
if len(data.ActiveSnakeGames) > 0 {
|
|
<div class="mt-6">
|
|
<h3 class="text-lg font-bold mb-2 text-center">Join a Game</h3>
|
|
<div class="flex flex-col gap-2">
|
|
for _, g := range data.ActiveSnakeGames {
|
|
<a
|
|
href={ templ.SafeURL("/snake/" + g.ID) }
|
|
class="flex justify-between items-center p-3 bg-base-200 rounded-lg hover:bg-base-300 no-underline text-base-content"
|
|
>
|
|
<span>{ fmt.Sprintf("%d\u00d7%d \u2014 %d/8 players", g.Width, g.Height, g.PlayerCount) }</span>
|
|
<span class="text-sm opacity-60">{ g.StatusLabel }</span>
|
|
</a>
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
</main>
|
|
}
|
|
}
|