The hall puts games in play first for someone coming back, finished ones further down, and reads a game looking up as looking, not unreachable
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
f131f292ae
commit
f78ff3ef8c
+2
-1
@@ -10,7 +10,8 @@ README.
|
|||||||
- **The hall** is the landing page (`/`). Name, *Play now against the bot*,
|
- **The hall** is the landing page (`/`). Name, *Play now against the bot*,
|
||||||
*Open a table*, *or join one* with a four-letter code, then *your games*
|
*Open a table*, *or join one* with a four-letter code, then *your games*
|
||||||
(the ledger of tables this browser holds a seat at, with whose move it
|
(the ledger of tables this browser holds a seat at, with whose move it
|
||||||
is and unread talk), *your reports to the keeper*, and *about this game —
|
is and unread talk; for someone coming back it comes first, and finished
|
||||||
|
games wait further down), *your reports to the keeper*, and *about this game —
|
||||||
a labor of love*, which opens the about panel: a dialog of tabs (The
|
a labor of love*, which opens the about panel: a dialog of tabs (The
|
||||||
game, The tally, More games, Send word; a game may add its own, as Dip's
|
game, The tally, More games, Send word; a game may add its own, as Dip's
|
||||||
Playing here), `TabbedDialog.svelte`, with each game's words in its hall.
|
Playing here), `TabbedDialog.svelte`, with each game's words in its hall.
|
||||||
|
|||||||
@@ -75,12 +75,14 @@
|
|||||||
const ready = $derived(name.trim().length > 0);
|
const ready = $derived(name.trim().length > 0);
|
||||||
|
|
||||||
// Each held seat is looked up once, so the ledger can say whose move it
|
// Each held seat is looked up once, so the ledger can say whose move it
|
||||||
// is. A seat the server refuses outright is doubted; a second refusal in
|
// is; until the answer comes, its game is absent and reads "looking". A
|
||||||
// a row forgets it. Silence (a restart, a stale answer) forgets nothing.
|
// seat the server refuses outright is doubted; a second refusal in a row
|
||||||
|
// forgets it. Silence (a restart, a stale answer) forgets nothing.
|
||||||
|
const asked = new Set<string>();
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
for (const held of seats) {
|
for (const held of seats) {
|
||||||
if (held.roomId in games) continue;
|
if (asked.has(held.roomId)) continue;
|
||||||
games[held.roomId] = null;
|
asked.add(held.roomId);
|
||||||
api.view(held.roomId, held.token)
|
api.view(held.roomId, held.token)
|
||||||
.then((v) => {
|
.then((v) => {
|
||||||
trustSeat(held.roomId);
|
trustSeat(held.roomId);
|
||||||
@@ -147,6 +149,10 @@
|
|||||||
seats = allSeats();
|
seats = allSeats();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A game counts as finished once its table says so; until then, even while loading, it is in play. */
|
||||||
|
const finished = $derived(seats.filter((h) => !!games[h.roomId]?.over));
|
||||||
|
const active = $derived(seats.filter((h) => !games[h.roomId]?.over));
|
||||||
|
|
||||||
function status(held: { roomId: string; seat: string }): string {
|
function status(held: { roomId: string; seat: string }): string {
|
||||||
const g = games[held.roomId];
|
const g = games[held.roomId];
|
||||||
if (g === undefined) return 'looking';
|
if (g === undefined) return 'looking';
|
||||||
@@ -188,7 +194,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section class="lid">
|
<section class="lid" class:returning={active.length > 0}>
|
||||||
<div class="lid-head">
|
<div class="lid-head">
|
||||||
<h1>__NAME__</h1>
|
<h1>__NAME__</h1>
|
||||||
<p class="pitch">One line that says what the game is.</p>
|
<p class="pitch">One line that says what the game is.</p>
|
||||||
@@ -241,10 +247,7 @@
|
|||||||
<p class="caption">A picture of the game goes here.</p>
|
<p class="caption">A picture of the game goes here.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if seats.length}
|
{#snippet gameRow(held: (typeof seats)[number])}
|
||||||
<div class="ledger">
|
|
||||||
<div class="ledger-head">your games</div>
|
|
||||||
{#each seats as held (held.roomId)}
|
|
||||||
<div class="ledger-row" class:your-move={yourMove(held)}>
|
<div class="ledger-row" class:your-move={yourMove(held)}>
|
||||||
<a class="ledger-resume" href={`/join/${held.roomId}`}>
|
<a class="ledger-resume" href={`/join/${held.roomId}`}>
|
||||||
<span class="ledger-code">{held.roomId}</span>
|
<span class="ledger-code">{held.roomId}</span>
|
||||||
@@ -252,7 +255,22 @@
|
|||||||
</a>
|
</a>
|
||||||
<button type="button" class="dismiss" title="forget this game" onclick={() => forget(held.roomId)}>×</button>
|
<button type="button" class="dismiss" title="forget this game" onclick={() => forget(held.roomId)}>×</button>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/snippet}
|
||||||
|
|
||||||
|
<!-- The games still in play, first thing for someone coming back; finished ones wait further down. -->
|
||||||
|
{#if active.length}
|
||||||
|
<div class="ledger">
|
||||||
|
<div class="ledger-head">your games</div>
|
||||||
|
{#each active as held (held.roomId)}{@render gameRow(held)}{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if finished.length || reports.length}
|
||||||
|
<div class="ledger past">
|
||||||
|
{#if finished.length}
|
||||||
|
<div class="ledger-head">finished games</div>
|
||||||
|
{#each finished as held (held.roomId)}{@render gameRow(held)}{/each}
|
||||||
|
{/if}
|
||||||
{#if reports.length}
|
{#if reports.length}
|
||||||
<div class="ledger-head reports-head">your reports to the keeper</div>
|
<div class="ledger-head reports-head">your reports to the keeper</div>
|
||||||
{#each reports as r (r.id)}
|
{#each reports as r (r.id)}
|
||||||
@@ -347,14 +365,21 @@
|
|||||||
padding: clamp(1.4rem, 3vw, 2.2rem) clamp(1.2rem, 3vw, 2.6rem) 1.8rem;
|
padding: clamp(1.4rem, 3vw, 2.2rem) clamp(1.2rem, 3vw, 2.6rem) 1.8rem;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1fr);
|
grid-template-columns: minmax(0, 1fr);
|
||||||
grid-template-areas: 'head' 'play' 'look' 'ledger';
|
grid-template-areas: 'head' 'play' 'look' 'ledger' 'past';
|
||||||
gap: 1.2rem 2.2rem;
|
gap: 1.2rem 2.2rem;
|
||||||
}
|
}
|
||||||
|
/* Someone coming back sees their games first. */
|
||||||
|
.lid.returning {
|
||||||
|
grid-template-areas: 'head' 'ledger' 'play' 'look' 'past';
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: 901px) {
|
@media (min-width: 901px) {
|
||||||
.lid {
|
.lid {
|
||||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||||
grid-template-areas: 'head head' 'play look' 'ledger ledger';
|
grid-template-areas: 'head head' 'play look' 'ledger ledger' 'past past';
|
||||||
|
}
|
||||||
|
.lid.returning {
|
||||||
|
grid-template-areas: 'head head' 'ledger ledger' 'play look' 'past past';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,6 +499,10 @@
|
|||||||
padding-top: 0.5rem;
|
padding-top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ledger.past {
|
||||||
|
grid-area: past;
|
||||||
|
}
|
||||||
|
|
||||||
.ledger-head {
|
.ledger-head {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
color: var(--bone-dim);
|
color: var(--bone-dim);
|
||||||
|
|||||||
Reference in New Issue
Block a user