unify nav/section copy, replace toggle links with pill switch
This commit is contained in:
parent
abf93a0848
commit
a426bad841
@ -26,9 +26,8 @@
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
<nav class="nav" aria-label="Main navigation">
|
<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="#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>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@ -56,7 +55,7 @@
|
|||||||
Start Playing
|
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>
|
<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>
|
||||||
<a href="#about" class="btn btn--ghost">How it works</a>
|
<a href="#about" class="btn btn--ghost">How to play</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -85,33 +84,57 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="about" id="about">
|
<section class="about" id="about">
|
||||||
<div class="container about__inner">
|
<div class="container about__inner">
|
||||||
|
|
||||||
<div class="about__left">
|
<div class="about__left">
|
||||||
<p class="section-label reveal">About the game</p>
|
<p class="section-label reveal">How to play</p>
|
||||||
<h2 class="section-title reveal reveal-delay-1">What it is &<br>How to play</h2>
|
<h2 class="section-title reveal reveal-delay-1">About<br>the Game</h2>
|
||||||
<p class="about__desc reveal reveal-delay-2">
|
<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.
|
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>
|
</p>
|
||||||
|
|
||||||
<div class="mini-globe-wrap reveal reveal-delay-3">
|
<div class="mini-globe-wrap reveal reveal-delay-3">
|
||||||
<div class="map-outline">
|
<svg class="game-preview-svg" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||||
<svg viewBox="0 0 100 130" xmlns="http://www.w3.org/2000/svg">
|
<!-- Grid lines -->
|
||||||
<path d="M50 4 L78 14 L90 34 L82 56 L88 82 L62 110 L36 100 L16 76 L18 46 Z"
|
<line x1="0" y1="66" x2="200" y2="66" stroke="rgba(11,31,42,.06)" stroke-width="1"/>
|
||||||
fill="rgba(26,127,196,.12)"
|
<line x1="0" y1="133" x2="200" y2="133" stroke="rgba(11,31,42,.06)" stroke-width="1"/>
|
||||||
stroke="var(--sea)"
|
<line x1="66" y1="0" x2="66" y2="200" stroke="rgba(11,31,42,.06)" stroke-width="1"/>
|
||||||
stroke-width="2.5"
|
<line x1="133" y1="0" x2="133" y2="200" stroke="rgba(11,31,42,.06)" stroke-width="1"/>
|
||||||
stroke-linejoin="round"/>
|
|
||||||
<path d="M50 4 L78 14 L90 34 L82 56 L88 82 L62 110 L36 100 L16 76 L18 46 Z"
|
<!-- Reference outline (filled) -->
|
||||||
fill="none"
|
<path d="M100 22 L148 40 L162 76 L150 112 L124 148 L80 142 L52 108 L54 66 Z"
|
||||||
stroke="var(--leaf)"
|
fill="rgba(26,127,196,.10)"
|
||||||
stroke-width="1.5"
|
stroke="rgba(26,127,196,.5)"
|
||||||
stroke-dasharray="5 4"
|
stroke-width="2"
|
||||||
stroke-linejoin="round"
|
stroke-linejoin="round"/>
|
||||||
transform="translate(4,-2) scale(0.96) translate(-2,2)"/>
|
|
||||||
</svg>
|
<!-- Player's drawn path (slightly off, freehand feel) -->
|
||||||
</div>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -149,31 +172,53 @@
|
|||||||
<div class="container register__inner">
|
<div class="container register__inner">
|
||||||
|
|
||||||
<div class="register__intro reveal">
|
<div class="register__intro reveal">
|
||||||
<p class="section-label">Join the game</p>
|
<p class="section-label">Play</p>
|
||||||
<h2 class="section-title">Create your<br>lobby</h2>
|
<h2 class="section-title">Create or join<br>a lobby</h2>
|
||||||
<p class="register__desc">
|
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="register__card reveal reveal-delay-1">
|
<div class="register__card reveal reveal-delay-1">
|
||||||
<p class="card-title">Create a game</p>
|
|
||||||
|
|
||||||
<form class="form">
|
<!-- Toggle switch -->
|
||||||
<div class="field">
|
<div class="lobby-toggle" role="group" aria-label="Lobby action">
|
||||||
<label for="username">Lobby name</label>
|
<button type="button" class="lobby-toggle__btn lobby-toggle__btn--active" id="toggle-create-btn">Create</button>
|
||||||
<input id="username" type="text" placeholder="myLobby" />
|
<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>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button type="button" class="btn btn--primary btn--full" id="reg-btn">
|
<!-- Join form (hidden by default) -->
|
||||||
Create game
|
<div id="form-join" hidden>
|
||||||
<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>
|
<p class="card-title">Join a game</p>
|
||||||
</button>
|
<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>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -185,7 +230,6 @@
|
|||||||
<div class="container footer__inner">
|
<div class="container footer__inner">
|
||||||
|
|
||||||
<div class="footer__left">
|
<div class="footer__left">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer__center">
|
<div class="footer__center">
|
||||||
|
|||||||
@ -3,44 +3,83 @@
|
|||||||
import { createLobby } from "./api.js";
|
import { createLobby } from "./api.js";
|
||||||
import { saveLobbyName } from "./storage.js";
|
import { saveLobbyName } from "./storage.js";
|
||||||
|
|
||||||
/**
|
// ── DOM refs
|
||||||
* Handle the "Create game" button click.
|
const formCreate = document.getElementById("form-create");
|
||||||
* Validates the lobby name, persists it, and navigates to the lobby page.
|
const formJoin = document.getElementById("form-join");
|
||||||
*/
|
const createInput = /** @type {HTMLInputElement|null} */ (document.getElementById("lobby-create"));
|
||||||
document.getElementById("reg-btn")?.addEventListener("click", async () => {
|
const joinInput = /** @type {HTMLInputElement|null} */ (document.getElementById("lobby-join"));
|
||||||
const lobbyInput = /** @type {HTMLInputElement|null} */ (
|
const createBtn = /** @type {HTMLButtonElement|null} */ (document.getElementById("reg-btn"));
|
||||||
document.getElementById("username")
|
const joinBtn = /** @type {HTMLButtonElement|null} */ (document.getElementById("join-btn"));
|
||||||
);
|
const createError = document.getElementById("lobby-error");
|
||||||
const button = /** @type {HTMLButtonElement|null} */ (
|
const joinError = document.getElementById("join-error");
|
||||||
document.getElementById("reg-btn")
|
const toggleCreateBtn = /** @type {HTMLButtonElement|null} */ (document.getElementById("toggle-create-btn"));
|
||||||
);
|
const toggleJoinBtn = /** @type {HTMLButtonElement|null} */ (document.getElementById("toggle-join-btn"));
|
||||||
const lobbyName = lobbyInput ? lobbyInput.value.trim() : "";
|
|
||||||
|
// ── 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) {
|
if (!lobbyName) {
|
||||||
lobbyInput?.focus();
|
createInput.focus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const errorEl = /** @type {HTMLElement|null} */ (
|
|
||||||
document.getElementById("lobby-error")
|
|
||||||
);
|
|
||||||
if (errorEl) errorEl.textContent = "";
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (button) button.disabled = true;
|
createBtn.disabled = true;
|
||||||
await createLobby(lobbyName);
|
await createLobby(lobbyName);
|
||||||
saveLobbyName(lobbyName);
|
saveLobbyName(lobbyName);
|
||||||
window.location.href = "lobby.html";
|
window.location.href = "lobby.html";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (errorEl)
|
createError.textContent =
|
||||||
errorEl.textContent =
|
error instanceof Error ? error.message : "Could not create lobby.";
|
||||||
error instanceof Error ? error.message : "Could not create lobby.";
|
createBtn.disabled = false;
|
||||||
if (button) button.disabled = false;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Scroll reveal - animate elements into view as they enter the viewport
|
// ── Join lobby — actual joinLobby() API call happens in lobby.js
|
||||||
const reveals = document.querySelectorAll(".reveal");
|
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(
|
const observer = new IntersectionObserver(
|
||||||
(entries) => {
|
(entries) => {
|
||||||
entries.forEach((entry) => {
|
entries.forEach((entry) => {
|
||||||
@ -53,6 +92,4 @@ const observer = new IntersectionObserver(
|
|||||||
{ threshold: 0.12 },
|
{ threshold: 0.12 },
|
||||||
);
|
);
|
||||||
|
|
||||||
reveals.forEach((el) => {
|
document.querySelectorAll(".reveal").forEach((el) => observer.observe(el));
|
||||||
observer.observe(el);
|
|
||||||
});
|
|
||||||
|
|||||||
@ -297,6 +297,13 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.game-preview-svg {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* ─── STEPS ─── */
|
/* ─── STEPS ─── */
|
||||||
.steps {
|
.steps {
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -394,6 +401,36 @@
|
|||||||
text-align: center;
|
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 ─── */
|
/* ─── RESPONSIVE ─── */
|
||||||
@media (max-width: 960px) {
|
@media (max-width: 960px) {
|
||||||
.hero__inner,
|
.hero__inner,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user