The family list knows the hall: about panels link to gamehall.kestrelsnest.social, and a new game gets a card there

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 21:04:29 -04:00
co-authored by Claude Fable 5.1
parent e95a090ac0
commit c04e82e085
3 changed files with 21 additions and 9 deletions
+7 -3
View File
@@ -3,7 +3,7 @@
// bot, open a table, join by code, the ledger of your tables, and the // bot, open a table, join by code, the ledger of your tables, and the
// about panel with the rules, the guide and a way to reach the keeper. // about panel with the rules, the guide and a way to reach the keeper.
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { otherGames, type FamilyGame } from '$lib/family'; import { loadFamily, type FamilyGame } from '$lib/family';
import Preferences from './Preferences.svelte'; import Preferences from './Preferences.svelte';
import { prefs, setPref } from '$lib/prefs.svelte'; import { prefs, setPref } from '$lib/prefs.svelte';
import { allSeats, doubtSeat, forgetSeat, rememberSeat, ServerError, trustSeat } from '$lib/net/client'; import { allSeats, doubtSeat, forgetSeat, rememberSeat, ServerError, trustSeat } from '$lib/net/client';
@@ -35,8 +35,12 @@
const hours = (minutes: number) => (minutes < 90 ? `${minutes} minutes` : `${Math.round(minutes / 60)} hours`); const hours = (minutes: number) => (minutes < 90 ? `${minutes} minutes` : `${Math.round(minutes / 60)} hours`);
/** The other games of Kestrel's Hall, for the about panel. */ /** The other games of Kestrel's Hall, for the about panel. */
let family = $state<FamilyGame[]>([]); let family = $state<FamilyGame[]>([]);
let hall = $state('');
$effect(() => { $effect(() => {
void otherGames('hnefatafl').then((g) => (family = g)); void loadFamily('hnefatafl').then((f) => {
family = f.games;
hall = f.hall;
});
}); });
/** Reports this browser's seats have filed, with the keeper's replies. */ /** Reports this browser's seats have filed, with the keeper's replies. */
let reports = $state<Report[]>([]); let reports = $state<Report[]>([]);
@@ -283,7 +287,7 @@
</p> </p>
{/if} {/if}
{#if family.length} {#if family.length}
<h3>More games in Kestrel's Hall</h3> <h3>More games in {#if hall}<a href={hall}>Kestrel's Hall</a>{:else}Kestrel's Hall{/if}</h3>
<ul class="family"> <ul class="family">
{#each family as g (g.slug)} {#each family as g (g.slug)}
<li><a href={g.url}>{g.name}</a>: {g.pitch} <span class="muted">{g.players} players; {g.origin}.</span></li> <li><a href={g.url}>{g.name}</a>: {g.pitch} <span class="muted">{g.players} players; {g.origin}.</span></li>
+13 -6
View File
@@ -1,6 +1,7 @@
// The other games of Kestrel's Hall, from the family list the kit keeps // The other games of Kestrel's Hall, from the family list the kit keeps
// (family.json, one copy shipped with every game), so a player who liked one // (family.json, one copy shipped with every game), so a player who liked one
// table can find the next. This game is left out of its own list. // table can find the next, and the hall's front door. This game is left out
// of its own list.
export interface FamilyGame { export interface FamilyGame {
slug: string; slug: string;
@@ -11,13 +12,19 @@ export interface FamilyGame {
origin: string; origin: string;
} }
export async function otherGames(self: string): Promise<FamilyGame[]> { /** The family list: the hall's front door and every game but this one. */
export interface Family {
hall: string;
games: FamilyGame[];
}
export async function loadFamily(self: string): Promise<Family> {
try { try {
const res = await fetch('/family.json', { cache: 'no-cache' }); const res = await fetch('/family.json', { cache: 'no-cache' });
if (!res.ok) return []; if (!res.ok) return { hall: '', games: [] };
const data = (await res.json()) as { games?: FamilyGame[] }; const data = (await res.json()) as { hall?: string; games?: FamilyGame[] };
return (data.games ?? []).filter((g) => g.slug !== self); return { hall: data.hall ?? '', games: (data.games ?? []).filter((g) => g.slug !== self) };
} catch { } catch {
return []; return { hall: '', games: [] };
} }
} }
+1
View File
@@ -1,5 +1,6 @@
{ {
"family": "Kestrel's Hall", "family": "Kestrel's Hall",
"hall": "https://gamehall.kestrelsnest.social",
"games": [ "games": [
{ {
"slug": "wizwar", "slug": "wizwar",