A note under each table option while it is chosen, and the rules page offers the way back to the game it was opened from

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
This commit is contained in:
Eric Wagoner
2026-09-23 18:48:57 -04:00
co-authored by Claude Fable 5.1
parent 7aa05536c2
commit de430c3794
4 changed files with 23 additions and 9 deletions
+15 -6
View File
@@ -168,12 +168,16 @@
{#if game.options?.length} {#if game.options?.length}
<div class="options"> <div class="options">
{#each game.options as o (o.key)} {#each game.options as o (o.key)}
<label class="option"> {@const chosen = o.choices.find((c) => c.value === options[o.key])}
<span>{o.label}</span> <div class="option-block">
<select bind:value={options[o.key]}> <label class="option">
{#each o.choices as c (c.value)}<option value={c.value}>{c.label}</option>{/each} <span>{o.label}</span>
</select> <select bind:value={options[o.key]}>
</label> {#each o.choices as c (c.value)}<option value={c.value}>{c.label}</option>{/each}
</select>
</label>
{#if chosen?.note}<p class="option-note muted small">{chosen.note}</p>{/if}
</div>
{/each} {/each}
</div> </div>
{/if} {/if}
@@ -601,6 +605,11 @@
gap: 0.5rem; gap: 0.5rem;
font-size: 0.9rem; font-size: 0.9rem;
} }
.option-note {
margin: 0.2rem 0 0;
max-width: 22em;
}
.tally { .tally {
display: grid; display: grid;
grid-template-columns: max-content 1fr; grid-template-columns: max-content 1fr;
+2 -1
View File
@@ -25,7 +25,8 @@ export interface Outcome {
export interface TableOption { export interface TableOption {
key: string; key: string;
label: string; label: string;
choices: { value: string; label: string }[]; /** A choice's note is shown under the selector while it is chosen: the one line a player needs to pick. */
choices: { value: string; label: string; note?: string }[];
/** The value a table gets when the host chooses nothing. */ /** The value a table gets when the host chooses nothing. */
default: string; default: string;
} }
+1 -1
View File
@@ -121,7 +121,7 @@
{/if} {/if}
{/if} {/if}
<a class="quiet" href="/guide">How to play</a> <a class="quiet" href="/guide">How to play</a>
<a class="quiet" href="/rules">Rules</a> <a class="quiet" href={room ? `/rules?room=${roomId}` : '/rules'}>Rules</a>
{#if room} {#if room}
<button type="button" class="quiet" title="Something behaved unexpectedly? Tell the keeper." onclick={() => (reporting = true)}>Report</button> <button type="button" class="quiet" title="Something behaved unexpectedly? Tell the keeper." onclick={() => (reporting = true)}>Report</button>
{/if} {/if}
+5 -1
View File
@@ -2,6 +2,10 @@
// The rules page: the game's own text, structured for reading mid-game. // The rules page: the game's own text, structured for reading mid-game.
// Keep the original rules text verbatim in docs/ and render from it // Keep the original rules text verbatim in docs/ and render from it
// where you can, so the page and the engine follow one source. // where you can, so the page and the engine follow one source.
import { page } from '$app/state';
/** Opened from a table, the page offers the way back to it. */
const room = $derived((page.url.searchParams.get('room') ?? '').toUpperCase());
</script> </script>
<svelte:head> <svelte:head>
@@ -10,7 +14,7 @@
<main class="rules"> <main class="rules">
<header> <header>
<a class="back" href="/">Back to the hall</a> · <a class="back" href="/guide">How to play</a> {#if room}<a class="back" href={`/join/${room}`}>Back to your game</a> · {/if}<a class="back" href="/">Back to the hall</a> · <a class="back" href="/guide">How to play</a>
<h1>The rules</h1> <h1>The rules</h1>
<p class="lede">One paragraph on where these rules come from and which edition or text this page follows.</p> <p class="lede">One paragraph on where these rules come from and which edition or text this page follows.</p>
</header> </header>