The tally: a booklet tab counting the love
A new tab in the help booklet answers "how much is this getting played?" from the ledgers themselves: games chronicled (begun and fought to a finish), distinct wizards seated, every spell, step, and punch recorded, time at the table estimated by the clock between moves (gaps over ten minutes don't count — async games tell the truth), victories split by treasure-theft versus last standing, the longest game, the fullest table, and the date the first game was dealt. Computed server-side over the in-memory rooms with a 60-second cache, fetched over the socket when the tab opens. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
ced4dc5749
commit
85831828d7
@@ -6,13 +6,25 @@
|
||||
let {
|
||||
onclose,
|
||||
initialTab = "play",
|
||||
stats = null,
|
||||
onstats,
|
||||
}: {
|
||||
onclose: () => void;
|
||||
initialTab?: "play" | "rules" | "cards" | "about";
|
||||
initialTab?: "play" | "rules" | "cards" | "about" | "tally";
|
||||
stats?: Record<string, number | string | null> | null;
|
||||
onstats?: () => void;
|
||||
} = $props();
|
||||
|
||||
// svelte-ignore state_referenced_locally -- the initial tab is intentionally a one-time value
|
||||
let tab = $state<"play" | "rules" | "cards" | "about">(initialTab);
|
||||
let tab = $state<"play" | "rules" | "cards" | "about" | "tally">(initialTab);
|
||||
|
||||
function openTally() {
|
||||
tab = "tally";
|
||||
onstats?.();
|
||||
}
|
||||
function hours(mins: number): string {
|
||||
return mins < 90 ? `${mins} minutes` : `${Math.round(mins / 6) / 10} hours`;
|
||||
}
|
||||
let search = $state("");
|
||||
|
||||
// The playable pool: every card actually in the 6e game (base + Exp1).
|
||||
@@ -53,12 +65,33 @@
|
||||
<button class:current={tab === "rules"} onclick={() => (tab = "rules")}>The rules</button>
|
||||
<button class:current={tab === "cards"} onclick={() => (tab = "cards")}>Card library</button>
|
||||
<button class:current={tab === "about"} onclick={() => (tab = "about")}>About</button>
|
||||
<button class:current={tab === "tally"} onclick={openTally}>The tally</button>
|
||||
</nav>
|
||||
<button class="close" onclick={onclose} aria-label="close help">×</button>
|
||||
</header>
|
||||
|
||||
<div class="booklet-body">
|
||||
{#if tab === "about"}
|
||||
{#if tab === "tally"}
|
||||
<div class="tally">
|
||||
<h3>How much love the maze is getting</h3>
|
||||
{#if stats}
|
||||
<dl class="tally-list">
|
||||
<dt>{stats.gamesCreated}</dt><dd>games chronicled — {stats.gamesStarted} begun, {stats.gamesFinished} fought to a finish</dd>
|
||||
<dt>{stats.wizardsSeated}</dt><dd>distinct wizards have taken a seat</dd>
|
||||
<dt>{stats.commandsPlayed}</dt><dd>spells, steps, and punches recorded in the ledgers</dd>
|
||||
<dt>{hours(Number(stats.minutesAtTable))}</dt><dd>spent at the table, by the clock between moves</dd>
|
||||
<dt>{stats.winsByTreasure} / {stats.winsByLastStanding}</dt><dd>victories by treasure-theft / by last wizard standing</dd>
|
||||
<dt>{stats.longestGameCommands}</dt><dd>moves in the longest game yet played</dd>
|
||||
<dt>{stats.fullestTable}</dt><dd>wizards at the fullest table</dd>
|
||||
</dl>
|
||||
{#if stats.firstGameAt}
|
||||
<p class="colophon">The first game was dealt {new Date(String(stats.firstGameAt)).toLocaleDateString(undefined, { year: "numeric", month: "long", day: "numeric" })}. Hotseat games are played off the ledger and go uncounted.</p>
|
||||
{/if}
|
||||
{:else}
|
||||
<p>Counting the ledgers…</p>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if tab === "about"}
|
||||
<div class="about">
|
||||
<h3>What this is</h3>
|
||||
<p>
|
||||
@@ -222,6 +255,12 @@
|
||||
.booklet-body h3:first-child { margin-top: 0; }
|
||||
.booklet-body p { margin: 0.35rem 0; }
|
||||
.colophon { font-style: italic; color: #6b5a41; font-size: 0.85rem; }
|
||||
.tally-list { display: grid; grid-template-columns: auto 1fr; gap: 0.35rem 0.8rem; margin: 0.6rem 0 1rem; }
|
||||
.tally-list dt {
|
||||
font-family: "Oswald", sans-serif; font-weight: 700; font-size: 1.05rem;
|
||||
color: #b3372b; text-align: right; white-space: nowrap;
|
||||
}
|
||||
.tally-list dd { margin: 0; align-self: center; }
|
||||
|
||||
.search-row { margin-bottom: 0.8rem; }
|
||||
.search-row input {
|
||||
|
||||
Reference in New Issue
Block a user