The credibility pass on Hnefatafl, ported to the template: the ops scripts count traffic through one parser, the reports digest is one program, the plaintext-token fallback and its migration are gone, and the stylesheet holds each shared rule once
From the hnefatafl repo's pass of the same day, everything that touched a kit-shared file. The visitors digest and the nightly rollup share deploy/traffic.py, installed to /usr/local/lib/<slug>; the rollup writes the finished-games count it computed behind "and False". pull-reports.sh and the reports skill both use deploy/report-digest.ts. The seat line requires its token hash and the start line its rules revision; the migration for ledgers written before hashing goes with them. The route table in server/src/index.ts lists every route; Report, ReportLine and Tally are declared once in view.ts for both sides; exports nobody imported are exports no more. In the client: .small, the × that dismisses, and the frame of the reading pages are in app.css once; the preferences panel shares the report slip's modal shape; the room store gains seatEmpty and seatUnheld, and the lobby and the join page read those instead of three spellings of their own. The room's moved and awaiting fields stay: the demo board reads them, and simultaneous rounds are the contract. The deploy README no longer describes a browser-only game; the visitors skill no longer names a /play route; the reports skill's replay call carries the room's options. The Slack channel id is passed in the environment rather than filled in as a placeholder. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GwFKMuQnPAEHJ5yA1q4orh
This commit is contained in:
1 parent
6c42e55f59
commit
33ac0ec808
41 files changed
+421
-583
No files matched your search
@@ -2,15 +2,11 @@
|
||||
import TableTalk from './TableTalk.svelte';
|
||||
import type { Room } from '$lib/net/room.svelte';
|
||||
|
||||
let { room, link }: { room: Room; link: string } = $props();
|
||||
let { room, link, copied, copyLink }: { room: Room; link: string; copied: boolean; copyLink: () => void } = $props();
|
||||
|
||||
const v = $derived(room.view);
|
||||
const hostName = $derived(v.seats.find((s) => s.id === v.host)?.name ?? 'the host');
|
||||
const seatFree = $derived(v.seats.length < v.size);
|
||||
/** A seat is free for a newcomer once the held ones are counted. */
|
||||
const seatOpen = $derived(v.seats.length + v.expected.length < v.size);
|
||||
const keeperSeated = $derived(v.seats.some((s) => s.name.toLowerCase() === v.keeper.toLowerCase()));
|
||||
let copied = $state(false);
|
||||
|
||||
/** The hour where the keeper lives, in words, so a caller knows whether to wait. */
|
||||
let minute = $state(0);
|
||||
@@ -31,22 +27,12 @@
|
||||
return '';
|
||||
}
|
||||
});
|
||||
|
||||
async function copyLink() {
|
||||
try {
|
||||
await navigator.clipboard.writeText(link);
|
||||
copied = true;
|
||||
setTimeout(() => (copied = false), 1600);
|
||||
} catch {
|
||||
// The link is on screen to copy by hand.
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<section class="lobby">
|
||||
{#if room.spectating}
|
||||
<h2>At the table</h2>
|
||||
{#if seatFree}
|
||||
{#if room.seatEmpty}
|
||||
<p>{hostName} is gathering players. Sit down above, or watch from the gallery until the game begins.</p>
|
||||
{:else}
|
||||
<p>The table is full. You watch from the Peanut Gallery; the game begins when {hostName} says.</p>
|
||||
@@ -62,7 +48,7 @@
|
||||
<li>
|
||||
<span class="seat-name">{s.name}</span>
|
||||
<span class="muted">{s.id === v.host ? 'opened the table' : s.bot ? 'the bot' : 'seated'}{s.id === v.me ? ', you' : ''}{#if s.bot && room.isHost}
|
||||
<button type="button" class="unseat" title="Send this bot away" aria-label="Send {s.name} away" onclick={() => room.unseat(s.id)}>×</button>{/if}</span>
|
||||
<button type="button" class="dismiss" title="Send this bot away" aria-label="Send {s.name} away" onclick={() => room.unseat(s.id)}>×</button>{/if}</span>
|
||||
</li>
|
||||
{/each}
|
||||
{#each v.expected as name (name)}
|
||||
@@ -78,7 +64,7 @@
|
||||
{/if}
|
||||
{#if !room.spectating}
|
||||
<div class="ways">
|
||||
{#if seatFree && room.isHost}
|
||||
{#if room.seatEmpty && room.isHost}
|
||||
<button type="button" class="quiet" onclick={() => room.addBot()}>Seat a bot</button>
|
||||
{/if}
|
||||
{#if room.isHost}
|
||||
@@ -94,13 +80,13 @@
|
||||
Let the Peanut Gallery talk at the table
|
||||
</label>
|
||||
{/if}
|
||||
{#if v.keeper && !v.challenge && !keeperSeated && seatOpen}
|
||||
{#if v.keeper && !v.challenge && !keeperSeated && room.seatUnheld}
|
||||
<div class="keeper">
|
||||
<button type="button" class="quiet" title="A seat is held for {v.keeper}, who keeps this site, and their phone rings" onclick={() => room.callKeeper()}>Challenge {v.keeper}, the keeper</button>
|
||||
<p class="muted small">{v.keeper} keeps this site and answers every call, sometimes within the minute, sometimes after a night's sleep.{#if keeperHour} It is {keeperHour} where {v.keeper} lives.{/if} The seat is held either way.</p>
|
||||
<p class="muted small note">{v.keeper} keeps this site and answers every call, sometimes within the minute, sometimes after a night's sleep.{#if keeperHour} It is {keeperHour} where {v.keeper} lives.{/if} The seat is held either way.</p>
|
||||
</div>
|
||||
{:else if v.challenge}
|
||||
<p class="muted small">{v.keeper} has been called to the table by {room.nameOf(v.challenge.by)}.{#if keeperHour} It is {keeperHour} there.{/if} A seat is held: if they can come now they will take it; if they are asleep or away they will leave a word below when they can. Meanwhile the table is yours: seat a bot, invite a friend, or open another game in a new tab and play on. This table keeps its place in your hall until you come back.</p>
|
||||
<p class="muted small note">{v.keeper} has been called to the table by {room.nameOf(v.challenge.by)}.{#if keeperHour} It is {keeperHour} there.{/if} A seat is held: if they can come now they will take it; if they are asleep or away they will leave a word below when they can. Meanwhile the table is yours: seat a bot, invite a friend, or open another game in a new tab and play on. This table keeps its place in your hall until you come back.</p>
|
||||
{/if}
|
||||
{/if}
|
||||
{#if room.error}<p class="warning">{room.error}</p>{/if}
|
||||
@@ -148,20 +134,6 @@
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.unseat {
|
||||
background: none;
|
||||
border: 0;
|
||||
color: var(--bone-faint);
|
||||
font-size: 1.1rem;
|
||||
padding: 0 0.3rem;
|
||||
margin-left: 0.3rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.unseat:hover {
|
||||
color: var(--blood);
|
||||
}
|
||||
|
||||
.ways {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -203,8 +175,7 @@
|
||||
max-width: 38em;
|
||||
}
|
||||
|
||||
.small {
|
||||
font-size: 0.85rem;
|
||||
.note {
|
||||
margin-top: 0.4rem;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user