Make join codes easy to copy

This commit is contained in:
2026-07-10 19:12:03 -07:00
parent 929941b8ff
commit 3e912b9458
5 changed files with 72 additions and 3 deletions

View File

@@ -39,10 +39,28 @@
min-width: 10.5rem; min-width: 10.5rem;
padding: 0.85rem 1.1rem 0.95rem; padding: 0.85rem 1.1rem 0.95rem;
background: color-mix(in srgb, var(--accent) 12%, var(--well)); background: color-mix(in srgb, var(--accent) 12%, var(--well));
color: var(--text);
border: 2px solid var(--accent); border: 2px solid var(--accent);
border-radius: var(--radius-md); border-radius: var(--radius-md);
box-shadow: var(--shadow-soft); box-shadow: var(--shadow-soft);
font: inherit;
text-align: center; text-align: center;
cursor: pointer;
transition: var(--transition-smooth);
}
.admin-join-code:hover {
background: color-mix(in srgb, var(--accent) 20%, var(--well));
transform: translateY(-1px);
}
.admin-join-code:focus-visible {
outline: 3px solid color-mix(in srgb, var(--accent) 35%, transparent);
outline-offset: 2px;
}
.admin-join-code.copied {
border-color: var(--success);
} }
.admin-join-code-label { .admin-join-code-label {
@@ -65,6 +83,13 @@
letter-spacing: 0.16em; letter-spacing: 0.16em;
} }
.admin-join-code-hint {
display: block;
margin-top: 0.35rem;
color: var(--text-muted);
font-size: 0.75rem;
}
@media (max-width: 600px) { @media (max-width: 600px) {
.admin-summary { .admin-summary {
flex-direction: column; flex-direction: column;

View File

@@ -38,6 +38,11 @@
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
.lobby-join-code-item {
display: flex;
justify-content: center;
}
.copy-container { .copy-container {
display: flex; display: flex;
gap: 0.5rem; gap: 0.5rem;

View File

@@ -58,6 +58,22 @@
</div> </div>
<div class="links-box glass-panel"> <div class="links-box glass-panel">
{#if state.player.is_admin}
<div class="link-item lobby-join-code-item">
<button
type="button"
class="admin-join-code"
class:copied={copiedLink === 'code'}
aria-label="Copy join code {state.game.join_code}"
on:click={() => copyLink('code', state.game.join_code)}
>
<span class="admin-join-code-label">Join Code</span>
<strong>{state.game.join_code}</strong>
<span class="admin-join-code-hint">{copiedLink === 'code' ? '✓ Copied!' : 'Click to copy'}</span>
</button>
</div>
{/if}
<div class="link-item"> <div class="link-item">
<h4>Share Join Link:</h4> <h4>Share Join Link:</h4>
<div class="copy-container"> <div class="copy-container">

View File

@@ -6,10 +6,17 @@
// - Add a CHANGELOG entry only when a commit changes something players can // - Add a CHANGELOG entry only when a commit changes something players can
// see. Skip refactors, tests, and tooling. Keep wording player-facing. // see. Skip refactors, tests, and tooling. Keep wording player-facing.
export const VERSION = 22; export const VERSION = 23;
// Newest first. Each entry: { version, date: 'YYYY-MM-DD', changes: [string, ...] }. // Newest first. Each entry: { version, date: 'YYYY-MM-DD', changes: [string, ...] }.
export const CHANGELOG = [ export const CHANGELOG = [
{
version: 23,
date: '2026-07-10',
changes: [
'Admins can now click the join code to copy it, and the code is available directly from the lobby.',
],
},
{ {
version: 21, version: 21,
date: '2026-07-10', date: '2026-07-10',

View File

@@ -23,6 +23,8 @@
let copiedTimer = null; let copiedTimer = null;
let copiedInvite = false; let copiedInvite = false;
let copiedInviteTimer = null; let copiedInviteTimer = null;
let copiedJoinCode = false;
let copiedJoinCodeTimer = null;
$: setPageTitle('Admin', data?.game?.crew_name); $: setPageTitle('Admin', data?.game?.crew_name);
@@ -48,6 +50,13 @@
copiedInviteTimer = setTimeout(() => { copiedInvite = false; }, 2000); copiedInviteTimer = setTimeout(() => { copiedInvite = false; }, 2000);
} }
function copyJoinCode() {
navigator.clipboard.writeText(data.game.join_code);
copiedJoinCode = true;
clearTimeout(copiedJoinCodeTimer);
copiedJoinCodeTimer = setTimeout(() => { copiedJoinCode = false; }, 2000);
}
onMount(() => { onMount(() => {
// Try to load admin_key from local storage // Try to load admin_key from local storage
adminKey = localStorage.getItem(`admin_key_${gameId}`) || ''; adminKey = localStorage.getItem(`admin_key_${gameId}`) || '';
@@ -123,10 +132,17 @@
<p><strong>Phase:</strong> {data.game.phase}</p> <p><strong>Phase:</strong> {data.game.phase}</p>
<p><strong>Admin Key:</strong> <span class="admin-key-chip">{data.game.admin_key}</span></p> <p><strong>Admin Key:</strong> <span class="admin-key-chip">{data.game.admin_key}</span></p>
</div> </div>
<div class="admin-join-code" aria-label="Join code {data.game.join_code}"> <button
type="button"
class="admin-join-code"
class:copied={copiedJoinCode}
aria-label="Copy join code {data.game.join_code}"
on:click={copyJoinCode}
>
<span class="admin-join-code-label">Join Code</span> <span class="admin-join-code-label">Join Code</span>
<strong>{data.game.join_code}</strong> <strong>{data.game.join_code}</strong>
</div> <span class="admin-join-code-hint">{copiedJoinCode ? '✓ Copied!' : 'Click to copy'}</span>
</button>
</div> </div>
{#if error} {#if error}