diff --git a/app/static/app.css b/app/static/app.css index 3301c48..df34f94 100644 --- a/app/static/app.css +++ b/app/static/app.css @@ -79,6 +79,26 @@ body { border-radius: 4px; } +.quick-join-form { + display: flex; + align-items: center; + gap: 8px; +} + +.quick-join-form input { + width: 116px; + border: 1px solid var(--border); + border-radius: 4px; + padding: 9px 10px; + font: inherit; + text-transform: uppercase; + background: var(--surface); +} + +.home-join { + margin-top: 10px; +} + .page-wrap { max-width: 1000px; margin: 0 auto; @@ -329,6 +349,17 @@ h3 { text-align: center; } + .quick-join-form { + flex: 1; + min-width: 0; + } + + .quick-join-form input { + flex: 1; + min-width: 0; + width: auto; + } + .page-wrap { padding: 16px 14px 24px; } diff --git a/app/static/js/play/app.js b/app/static/js/play/app.js index 61062fe..d58ff42 100644 --- a/app/static/js/play/app.js +++ b/app/static/js/play/app.js @@ -87,6 +87,7 @@ export class PlayApp { this.displayBoardSize = 640; this.squareSize = 80; this.dpr = Math.max(1, window.devicePixelRatio || 1); + this.urlJoinConsumed = false; this.loadPieceImages(); this.installControls(); @@ -127,6 +128,7 @@ export class PlayApp { installSocket() { this.socket = createWSClient({ + onServerReady: () => this.consumeJoinCodeFromUrl(), onGameStarted: handleGameStarted, onP2Connected: handleP2Connected, onGameCreated: handleCodeGameCreated, @@ -170,16 +172,7 @@ export class PlayApp { }); this.joinBtn.addEventListener("click", () => { - const code = this.joinInput.value.trim().toUpperCase(); - if (!code) { - this.showModal("Join game", "Enter a game code first.", [ - { label: "OK" }, - ]); - return; - } - this.gameCode = code; - this.socket.emit("join_code_game", { code }); - this.setLobbyStatus("Joining game..."); + this.joinCode(this.joinInput.value); }); this.copyCodeBtn.addEventListener("click", async () => { @@ -358,6 +351,40 @@ export class PlayApp { }); } + joinCode(rawCode) { + const code = String(rawCode || "").trim().toUpperCase(); + if (!code) { + this.showModal("Join game", "Enter a game code first.", [ + { label: "OK" }, + ]); + return false; + } + + this.gameCode = code; + this.joinInput.value = code; + this.socket.emit("join_code_game", { code }); + this.setLobbyStatus("Joining game..."); + return true; + } + + consumeJoinCodeFromUrl() { + if (this.urlJoinConsumed) { + return; + } + + const url = new URL(window.location.href); + const code = url.searchParams.get("code"); + if (!code) { + return; + } + + this.urlJoinConsumed = true; + url.searchParams.delete("code"); + const nextUrl = `${url.pathname}${url.search}${url.hash}`; + window.history.replaceState({}, "", nextUrl); + this.joinCode(code); + } + onCodeCreated(data) { this.gameCode = data.code; this.codeEl.textContent = data.code; diff --git a/app/templates/home.html b/app/templates/home.html index 06ad151..d58a7dd 100644 --- a/app/templates/home.html +++ b/app/templates/home.html @@ -10,4 +10,20 @@ >Past games +
+
+ + +
+
{% endblock %}