zenno: add page titles and descriptions
ci/woodpecker/push/horsebot Pipeline was successful
ci/woodpecker/push/zenno Pipeline was successful

This commit is contained in:
2026-07-12 14:37:43 -04:00
parent bdafc93315
commit 009dd1d695
7 changed files with 171 additions and 109 deletions
+21
View File
@@ -0,0 +1,21 @@
<script lang="ts">
import * as all from '$lib/all';
interface Props {
title?: string;
pages: all.Page[];
}
let { title, pages }: Props = $props();
</script>
{#if title != null}
<h2 class="mt-8 mb-4 text-4xl">{title}</h2>
{/if}
<ul class="mb-4 list-disc pl-4">
{#each pages as page (page.route)}
<li>
<a href={page.route}>{page.name}</a> &mdash; {page.description}
</li>
{/each}
</ul>
+98
View File
@@ -0,0 +1,98 @@
import { resolve } from '$app/paths';
import type { ResolvedPathname } from '$app/types';
export interface Page {
route: ResolvedPathname;
name: string;
description: string;
}
/**
* All tool and doc pages in the site.
*/
export const PAGES = {
index: [
{
route: resolve('/race'),
name: 'Race Mechanics Tools',
description: 'Tools for calculating Umamusume race characteristics.',
},
{
route: resolve('/chara'),
name: 'Character Tools',
description: 'Tools for understanding Umamusume characters.',
},
{
route: resolve('/doc'),
name: 'Documents',
description: 'Articles about Umamusume, including research and editorials.',
},
] satisfies Page[],
race: [
{
route: resolve('/race/spurt'),
name: 'Spurt Speed',
description: 'Calculate target speed in the last spurt and compare to other distance aptitudes and running styles.',
},
{
route: resolve('/race/mspeed'),
name: 'Front Runner Mechanical Speed Comparator',
description: 'Compare spot struggle and lane combo to the effects of individual skills.',
},
{
route: resolve('/race/gate'),
name: 'Gate Calculator',
description: 'Calculate the importance of acceleration effects at the starting gate.',
},
] satisfies Page[],
chara: [
{
route: resolve('/chara/affinity'),
name: 'Affinity Details',
description: 'Details of why characters have the base compatibility numbers they have.',
},
{
route: resolve('/chara/convo'),
name: 'Lobby Conversations',
description: 'Check participants in lobby conversations and get recommendations on unlocking them quickly.',
},
] satisfies Page[],
doc: [
{
route: resolve('/doc/frbm'),
name: 'Front Runner Black Magic',
description: 'Detailed analysis of how front runners interact with race mechanics.',
},
{
route: resolve('/doc/lanecalc'),
name: "Gaikokujin's Guide to Lanecalc",
description: 'English language manual for 危険回避シミュ, or Lanecalc, for precise lane combo simulation.',
},
{
route: resolve('/doc/race'),
name: 'Race Mechanics Charts',
description:
"Interactive adaptation of KuromiAK's race mechanics documentation for easier visualization of how mechanics scale.",
},
{
route: resolve('/doc/spark'),
name: 'Spark Explorer',
description: 'View all possible inheritance effects of any spark.',
},
] satisfies Page[],
} as const;
/**
* Get the page object for a route.
* @param route Route ID for the page
* @returns Matching page, or an empty object if none match
*/
export function page(route: string | null): Partial<Page> {
for (const p of Object.values(PAGES)) {
const r = p.find((v) => v.route === route);
if (r != null) {
return r;
}
}
return {};
}