Add short game join codes
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 game’s 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;
|
||||
|
||||
Reference in New Issue
Block a user