Add short game join codes

This commit is contained in:
2026-07-10 12:30:43 -07:00
parent 8470da4aa9
commit b253a06b45
11 changed files with 189 additions and 3 deletions

View File

@@ -6,10 +6,17 @@
// - Add a CHANGELOG entry only when a commit changes something players can
// see. Skip refactors, tests, and tooling. Keep wording player-facing.
export const VERSION = 18;
export const VERSION = 19;
// Newest first. Each entry: { version, date: 'YYYY-MM-DD', changes: [string, ...] }.
export const CHANGELOG = [
{
version: 19,
date: '2026-07-10',
changes: [
'Games now have short join codes that can be entered on the home page and shared from the Admin Panel.',
],
},
{
version: 18,
date: '2026-07-10',

View File

@@ -119,6 +119,7 @@
<div class="card">
<h2 class="mb-4">Game: {data.game.crew_name}</h2>
<p><strong>Phase:</strong> {data.game.phase}</p>
<p><strong>Join Code:</strong> <span class="admin-key-chip">{data.game.join_code}</span></p>
<p><strong>Admin Key:</strong> <span class="admin-key-chip">{data.game.admin_key}</span></p>
{#if error}

View File

@@ -15,6 +15,9 @@
let crewName = '';
let error = '';
let creating = false;
let joinCode = '';
let joinCodeError = '';
let joiningByCode = false;
function sessionRat(s) {
if (s.ratName && s.playerName && s.ratName !== s.playerName) return `${s.ratName} (${s.playerName})`;
@@ -53,6 +56,26 @@
creating = false;
}
}
function updateJoinCode(event) {
joinCode = event.currentTarget.value
.toUpperCase()
.replace(/[^ABCDEFGHJKLMNPQRSTUVWXYZ23456789]/g, '')
.slice(0, 5);
}
async function joinByCode() {
if (joinCode.length !== 5) return;
joiningByCode = true;
joinCodeError = '';
try {
const data = await apiRequest(`/game/code/${joinCode}`);
push(`/game/${data.id}/join`);
} catch (err) {
joinCodeError = err.message;
joiningByCode = false;
}
}
</script>
<div class="welcome-container">
@@ -91,6 +114,36 @@
</div>
{/if}
<div class="glass-panel creation-card join-code-card">
<h2>Join a Crew</h2>
<p class="info-text">Enter the five-character code shared by your games Admin.</p>
<form class="join-code-form" on:submit|preventDefault={joinByCode}>
<label for="joinCode">Join Code</label>
<div class="join-code-action">
<input
type="text"
id="joinCode"
value={joinCode}
on:input={updateJoinCode}
required
minlength="5"
maxlength="5"
placeholder="ABCDE"
class="input-field input-large join-code-input"
autocomplete="off"
autocapitalize="characters"
spellcheck="false"
/>
<button type="submit" class="btn btn-primary btn-large" disabled={joiningByCode || joinCode.length !== 5}>
{joiningByCode ? 'Joining...' : 'Join'}
</button>
</div>
</form>
{#if joinCodeError}
<div class="alert alert-danger mt-4">{joinCodeError}</div>
{/if}
</div>
<div class="glass-panel creation-card">
<h2>Muster a New Crew</h2>
<form on:submit|preventDefault={createGame}>
@@ -128,6 +181,25 @@
.saved-sessions {
margin-bottom: 1.75rem;
}
.join-code-card {
margin-bottom: 1.75rem;
}
.join-code-form {
margin-top: 1rem;
}
.join-code-action {
display: flex;
gap: 0.75rem;
align-items: stretch;
}
.join-code-input {
flex: 1;
min-width: 0;
font-family: ui-monospace, monospace;
font-weight: 700;
letter-spacing: 0.25em;
text-transform: uppercase;
}
.session-list {
list-style: none;
margin: 0;