unify nav/section copy, replace toggle links with pill switch

This commit is contained in:
pengniklas 2026-06-01 15:54:42 +02:00
parent abf93a0848
commit a426bad841
3 changed files with 184 additions and 66 deletions

View File

@ -26,9 +26,8 @@
</a>
<nav class="nav" aria-label="Main navigation">
<a href="#hero" class="nav__link">Play</a>
<a href="#about" class="nav__link">How to play</a>
<a href="#register" class="nav__cta">Create lobby</a>
<a href="#register" class="nav__cta">Play</a>
</nav>
</div>
</header>
@ -56,7 +55,7 @@
Start Playing
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3 8h10M9 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
</a>
<a href="#about" class="btn btn--ghost">How it works</a>
<a href="#about" class="btn btn--ghost">How to play</a>
</div>
</div>
@ -85,33 +84,57 @@
</div>
</section>
<section class="about" id="about">
<div class="container about__inner">
<div class="about__left">
<p class="section-label reveal">About the game</p>
<h2 class="section-title reveal reveal-delay-1">What it is &<br>How to play</h2>
<p class="section-label reveal">How to play</p>
<h2 class="section-title reveal reveal-delay-1">About<br>the Game</h2>
<p class="about__desc reveal reveal-delay-2">
GeoDraw is a competitive browser game built on memory and precision. You get a country name, sketch its outline, and the system calculates how close you were to the real border.
</p>
<div class="mini-globe-wrap reveal reveal-delay-3">
<div class="map-outline">
<svg viewBox="0 0 100 130" xmlns="http://www.w3.org/2000/svg">
<path d="M50 4 L78 14 L90 34 L82 56 L88 82 L62 110 L36 100 L16 76 L18 46 Z"
fill="rgba(26,127,196,.12)"
stroke="var(--sea)"
stroke-width="2.5"
stroke-linejoin="round"/>
<path d="M50 4 L78 14 L90 34 L82 56 L88 82 L62 110 L36 100 L16 76 L18 46 Z"
fill="none"
stroke="var(--leaf)"
stroke-width="1.5"
stroke-dasharray="5 4"
stroke-linejoin="round"
transform="translate(4,-2) scale(0.96) translate(-2,2)"/>
</svg>
</div>
<svg class="game-preview-svg" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<!-- Grid lines -->
<line x1="0" y1="66" x2="200" y2="66" stroke="rgba(11,31,42,.06)" stroke-width="1"/>
<line x1="0" y1="133" x2="200" y2="133" stroke="rgba(11,31,42,.06)" stroke-width="1"/>
<line x1="66" y1="0" x2="66" y2="200" stroke="rgba(11,31,42,.06)" stroke-width="1"/>
<line x1="133" y1="0" x2="133" y2="200" stroke="rgba(11,31,42,.06)" stroke-width="1"/>
<!-- Reference outline (filled) -->
<path d="M100 22 L148 40 L162 76 L150 112 L124 148 L80 142 L52 108 L54 66 Z"
fill="rgba(26,127,196,.10)"
stroke="rgba(26,127,196,.5)"
stroke-width="2"
stroke-linejoin="round"/>
<!-- Player's drawn path (slightly off, freehand feel) -->
<path d="M96 26 L152 44 L164 82 L146 118 L120 152 L76 144 L48 106 L52 62 Z"
fill="none"
stroke="#1a7fc4"
stroke-width="2.5"
stroke-linejoin="round"
stroke-linecap="round"/>
<!-- City dot: Bern -->
<circle cx="96" cy="100" r="4" fill="rgba(240,180,40,.9)"/>
<circle cx="96" cy="100" r="4" fill="none" stroke="white" stroke-width="1.5"/>
<!-- City dot: Zurich -->
<circle cx="118" cy="72" r="4" fill="rgba(240,180,40,.9)"/>
<circle cx="118" cy="72" r="4" fill="none" stroke="white" stroke-width="1.5"/>
<!-- Score badge -->
<rect x="118" y="22" width="62" height="26" rx="8" fill="white" filter="url(#shadow)"/>
<defs>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="0" dy="2" stdDeviation="3" flood-color="rgba(11,31,42,.12)"/>
</filter>
</defs>
<circle cx="131" cy="35" r="4" fill="#41b869"/>
<text x="139" y="39" font-family="Syne, sans-serif" font-weight="700" font-size="11" fill="#0b1f2a">82%</text>
</svg>
</div>
</div>
@ -149,31 +172,53 @@
<div class="container register__inner">
<div class="register__intro reveal">
<p class="section-label">Join the game</p>
<h2 class="section-title">Create your<br>lobby</h2>
<p class="section-label">Play</p>
<h2 class="section-title">Create or join<br>a lobby</h2>
<p class="register__desc">
Create a private lobby to challenge friends or play solo.
Create your own lobby and share the name with friends, or enter an existing lobby name to join their game.
</p>
</div>
<div class="register__card reveal reveal-delay-1">
<p class="card-title">Create a game</p>
<form class="form">
<div class="field">
<label for="username">Lobby name</label>
<input id="username" type="text" placeholder="myLobby" />
<!-- Toggle switch -->
<div class="lobby-toggle" role="group" aria-label="Lobby action">
<button type="button" class="lobby-toggle__btn lobby-toggle__btn--active" id="toggle-create-btn">Create</button>
<button type="button" class="lobby-toggle__btn" id="toggle-join-btn">Join</button>
</div>
<!-- Create form (shown by default) -->
<div id="form-create">
<p class="card-title">Create a game</p>
<div class="form">
<div class="field">
<label for="lobby-create">Lobby name</label>
<input id="lobby-create" type="text" placeholder="myLobby" />
</div>
<button type="button" class="btn btn--primary btn--full" id="reg-btn">
Create game
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3 8h10M9 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
</button>
<span class="field-error" id="lobby-error" role="alert"></span>
</div>
</div>
<button type="button" class="btn btn--primary btn--full" id="reg-btn">
Create game
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3 8h10M9 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
</button>
<!-- Join form (hidden by default) -->
<div id="form-join" hidden>
<p class="card-title">Join a game</p>
<div class="form">
<div class="field">
<label for="lobby-join">Lobby name</label>
<input id="lobby-join" type="text" placeholder="myLobby" />
</div>
<button type="button" class="btn btn--primary btn--full" id="join-btn">
Join game
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3 8h10M9 4l4 4-4 4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
</button>
<span class="field-error" id="join-error" role="alert"></span>
</div>
</div>
<span class="field-error" id="lobby-error" role="alert"></span>
<p class="form-footer"><a href="#" style="color:var(--sea);font-weight:600;">Join a game instead</a></p>
</form>
</div>
</div>
@ -185,7 +230,6 @@
<div class="container footer__inner">
<div class="footer__left">
</div>
<div class="footer__center">

View File

@ -3,44 +3,83 @@
import { createLobby } from "./api.js";
import { saveLobbyName } from "./storage.js";
/**
* Handle the "Create game" button click.
* Validates the lobby name, persists it, and navigates to the lobby page.
*/
document.getElementById("reg-btn")?.addEventListener("click", async () => {
const lobbyInput = /** @type {HTMLInputElement|null} */ (
document.getElementById("username")
);
const button = /** @type {HTMLButtonElement|null} */ (
document.getElementById("reg-btn")
);
const lobbyName = lobbyInput ? lobbyInput.value.trim() : "";
// ── DOM refs
const formCreate = document.getElementById("form-create");
const formJoin = document.getElementById("form-join");
const createInput = /** @type {HTMLInputElement|null} */ (document.getElementById("lobby-create"));
const joinInput = /** @type {HTMLInputElement|null} */ (document.getElementById("lobby-join"));
const createBtn = /** @type {HTMLButtonElement|null} */ (document.getElementById("reg-btn"));
const joinBtn = /** @type {HTMLButtonElement|null} */ (document.getElementById("join-btn"));
const createError = document.getElementById("lobby-error");
const joinError = document.getElementById("join-error");
const toggleCreateBtn = /** @type {HTMLButtonElement|null} */ (document.getElementById("toggle-create-btn"));
const toggleJoinBtn = /** @type {HTMLButtonElement|null} */ (document.getElementById("toggle-join-btn"));
// ── Toggle switch
function showCreate() {
formCreate?.removeAttribute("hidden");
formJoin?.setAttribute("hidden", "");
toggleCreateBtn?.classList.add("lobby-toggle__btn--active");
toggleJoinBtn?.classList.remove("lobby-toggle__btn--active");
createInput?.focus();
}
function showJoin() {
formJoin?.removeAttribute("hidden");
formCreate?.setAttribute("hidden", "");
toggleJoinBtn?.classList.add("lobby-toggle__btn--active");
toggleCreateBtn?.classList.remove("lobby-toggle__btn--active");
joinInput?.focus();
}
toggleCreateBtn?.addEventListener("click", showCreate);
toggleJoinBtn?.addEventListener("click", showJoin);
// ── Create lobby
createBtn?.addEventListener("click", async () => {
if (!createInput || !createError) return;
const lobbyName = createInput.value.trim();
createError.textContent = "";
if (!lobbyName) {
lobbyInput?.focus();
createInput.focus();
return;
}
const errorEl = /** @type {HTMLElement|null} */ (
document.getElementById("lobby-error")
);
if (errorEl) errorEl.textContent = "";
try {
if (button) button.disabled = true;
createBtn.disabled = true;
await createLobby(lobbyName);
saveLobbyName(lobbyName);
window.location.href = "lobby.html";
} catch (error) {
if (errorEl)
errorEl.textContent =
error instanceof Error ? error.message : "Could not create lobby.";
if (button) button.disabled = false;
createError.textContent =
error instanceof Error ? error.message : "Could not create lobby.";
createBtn.disabled = false;
}
});
// Scroll reveal - animate elements into view as they enter the viewport
const reveals = document.querySelectorAll(".reveal");
// ── Join lobby — actual joinLobby() API call happens in lobby.js
joinBtn?.addEventListener("click", () => {
if (!joinInput || !joinError) return;
const lobbyName = joinInput.value.trim();
joinError.textContent = "";
if (!lobbyName) {
joinInput.focus();
return;
}
saveLobbyName(lobbyName);
window.location.href = "lobby.html";
});
// Allow Enter key on both inputs
createInput?.addEventListener("keydown", (e) => { if (e.key === "Enter") createBtn?.click(); });
joinInput?.addEventListener("keydown", (e) => { if (e.key === "Enter") joinBtn?.click(); });
// ── Scroll reveal
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
@ -53,6 +92,4 @@ const observer = new IntersectionObserver(
{ threshold: 0.12 },
);
reveals.forEach((el) => {
observer.observe(el);
});
document.querySelectorAll(".reveal").forEach((el) => observer.observe(el));

View File

@ -297,6 +297,13 @@
);
}
.game-preview-svg {
width: 100%;
height: auto;
position: relative;
z-index: 1;
}
/* ─── STEPS ─── */
.steps {
display: grid;
@ -394,6 +401,36 @@
text-align: center;
}
/* ─── LOBBY TOGGLE SWITCH ─── */
.lobby-toggle {
display: flex;
background: var(--cream);
border: 1.5px solid var(--line);
border-radius: 999px;
padding: 4px;
gap: 4px;
margin-bottom: 24px;
}
.lobby-toggle__btn {
flex: 1;
padding: 9px 16px;
border-radius: 999px;
border: none;
background: transparent;
font-family: "Syne", sans-serif;
font-weight: 700;
font-size: 0.88rem;
color: var(--ink-muted);
cursor: pointer;
transition: background 0.18s, color 0.18s;
}
.lobby-toggle__btn--active {
background: var(--ink);
color: var(--white);
}
/* ─── RESPONSIVE ─── */
@media (max-width: 960px) {
.hero__inner,