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 {};
}
+22 -4
View File
@@ -1,13 +1,31 @@
<script lang="ts"> <script lang="ts">
import './layout.css'; import './layout.css';
import favicon from '$lib/assets/favicon.png'; import favicon from '$lib/assets/favicon.png';
import * as all from '$lib/all';
import { resolve } from '$app/paths'; import { resolve } from '$app/paths';
import type { LayoutProps } from './$types';
import { page } from '$app/state';
let { children } = $props(); let { children }: LayoutProps = $props();
const cur = $derived(all.page(page.route.id));
const title = $derived(cur.name);
const desc = $derived(
cur.description ??
"She's read all about Umamusume, and she's always happy to share her knowledge and give recommendations! Tools and editorials for Umamusume optimization.",
);
</script> </script>
<svelte:head> <svelte:head>
<title>Zenno Rob Roy</title> {#if title != null}
<title>Zenno Rob Roy &ndash; {title}</title>
{:else}
<title>Zenno Rob Roy</title>
{/if}
<meta name="description" content={desc} />
<meta name="color-scheme" content="light dark" />
<meta name="referrer" content="strict-origin-when-cross-origin" />
<meta name="robots" content="noimageindex" />
<link rel="icon" href={favicon} /> <link rel="icon" href={favicon} />
</svelte:head> </svelte:head>
@@ -23,9 +41,9 @@
<a href={resolve('/doc')} class="mx-8 my-1 inline-block">Documents</a> <a href={resolve('/doc')} class="mx-8 my-1 inline-block">Documents</a>
</span> </span>
</nav> </nav>
<div class="mx-4 grow lg:m-auto lg:max-w-7xl lg:min-w-7xl"> <main class="mx-4 grow lg:m-auto lg:max-w-7xl lg:min-w-7xl">
{@render children()} {@render children()}
</div> </main>
<footer <footer
class="inset-x-0 bottom-0 mt-12 border-t bg-mist-300 p-4 text-center text-sm md:mt-20 dark:border-none dark:bg-mist-900" class="inset-x-0 bottom-0 mt-12 border-t bg-mist-300 p-4 text-center text-sm md:mt-20 dark:border-none dark:bg-mist-900"
> >
+6 -49
View File
@@ -1,59 +1,16 @@
<script lang="ts"> <script lang="ts">
import { resolve } from '$app/paths'; import * as all from '$lib/all';
import IndexSection from '$lib/IndexSection.svelte';
</script> </script>
<h1 class="m-8 text-center text-7xl">Zenno Rob Roy</h1> <h1 class="m-8 text-center text-7xl">Zenno Rob Roy</h1>
<p>She's read all about Umamusume, and she's always happy to share her knowledge and give recommendations!</p> <p>She's read all about Umamusume, and she's always happy to share her knowledge and give recommendations!</p>
<h2 class="mt-8 mb-4 text-4xl">Race Mechanics Tools</h2> <IndexSection title="Race Mechanics Tools" pages={all.PAGES.race} />
<ul class="mb-4 list-disc pl-4"> <IndexSection title="Character Tools" pages={all.PAGES.chara} />
<li> <IndexSection title="Documents" pages={all.PAGES.doc} />
<a href={resolve('/race/spurt')}>Spurt Speed</a> &mdash; Calculate a horse's target speed in the last spurt and compare to other
distance aptitudes and running styles.
</li>
<li>
<a href={resolve('/race/mspeed')}>Front Runner Mechanical Speed Comparator</a> &mdash; Compare spot struggle and lane combo to the
effects of individual skills.
</li>
<li>
<a href={resolve('/race/gate')}>Gate Calculator</a> &mdash; Calculate the importance of acceleration effects at the starting gate.
</li>
</ul>
<h2 class="mt-8 mb-4 text-4xl">Character Tools</h2>
<ul class="mb-4 list-disc pl-4">
<li>
<a href={resolve('/chara/affinity')}>Affinity Details</a> &mdash; Details of why characters have the base compatibility numbers
they have.
</li>
<li>
<a href={resolve('/chara/convo')}>Lobby Conversations</a> &mdash; Check participants in lobby conversations and get recommendations
on unlocking them quickly.
</li>
</ul>
<h2 class="my-4 text-4xl">Documents</h2>
<ul class="mb-4 list-disc pl-4">
<li>
<a href={resolve('/doc/frbm')}>Front Runner Black Magic</a> &mdash; Detailed analysis of how front runners interact with race mechanics.
</li>
<li>
<a href={resolve('/doc/lanecalc')}>Gaikokujin's Guide to Lanecalc</a> &mdash; English language manual for
<a href="https://lanecalc.hf-uma.net/" target="_blank" rel="noopener noreferrer">危険回避シミュ</a>, or Lanecalc, for precise
lane combo simulation.
</li>
<li>
<a href={resolve('/doc/race')}>Race Mechanics Charts</a> &mdash; Interactive adaptation of
<a
href="https://docs.google.com/document/d/15VzW9W2tXBBTibBRbZ8IVpW6HaMX8H0RP03kq6Az7Xg/edit"
target="_blank"
rel="noopener noreferrer">KuromiAK's race mechanics documentation</a
> for easier visualization of how mechanics scale.
</li>
<li>
<a href={resolve('/doc/spark')}>Spark Explorer</a> &mdash; View all possible inheritance effects of any spark.
</li>
</ul>
<!-- Not a real index section in, terms of types. -->
<h2 class="my-4 text-4xl">&amp;c.</h2> <h2 class="my-4 text-4xl">&amp;c.</h2>
<ul class="mb-4 list-disc pl-4"> <ul class="mb-4 list-disc pl-4">
<li> <li>
+8 -14
View File
@@ -1,17 +1,11 @@
<script lang="ts"> <script lang="ts">
import { resolve } from '$app/paths'; import { page } from '$app/state';
import * as all from '$lib/all';
import IndexSection from '$lib/IndexSection.svelte';
const cur = $derived(all.page(page.route.id));
</script> </script>
<h1 class="m-8 text-center text-7xl">Zenno Rob Roy &mdash; Character Tools</h1> <h1 class="m-8 text-center text-7xl">Zenno Rob Roy &mdash; {cur.name}</h1>
<p>Tools related to understanding Umamusume characters.</p> <p>{cur.description}</p>
<IndexSection pages={all.PAGES.chara} />
<ul class="mb-4 list-disc pl-4">
<li>
<a href={resolve('/chara/affinity')}>Affinity Details</a> &mdash; Details of why characters have the base compatibility numbers
they have.
</li>
<li>
<a href={resolve('/chara/convo')}>Lobby Conversations</a> &mdash; Check participants in lobby conversations and get recommendations
on unlocking them quickly.
</li>
</ul>
+8 -25
View File
@@ -1,28 +1,11 @@
<script lang="ts"> <script lang="ts">
import { resolve } from '$app/paths'; import { page } from '$app/state';
import * as all from '$lib/all';
import IndexSection from '$lib/IndexSection.svelte';
const cur = $derived(all.page(page.route.id));
</script> </script>
<h1 class="m-8 text-center text-7xl">Zenno Rob Roy &mdash; Documents</h1> <h1 class="m-8 text-center text-7xl">Zenno Rob Roy &mdash; {cur.name}</h1>
<p>Articles about Umamusume, including editorials and research.</p> <p>{cur.description}</p>
<IndexSection pages={all.PAGES.doc} />
<ul class="mb-4 list-disc pl-4">
<li>
<a href={resolve('/doc/frbm')}>Front Runner Black Magic</a> &mdash; Detailed analysis of how front runners interact with race mechanics.
</li>
<li>
<a href={resolve('/doc/lanecalc')}>Gaikokujin's Guide to Lanecalc</a> &mdash; English language manual for
<a href="https://lanecalc.hf-uma.net/" target="_blank" rel="noopener noreferrer">危険回避シミュ</a>, or Lanecalc, for precise
lane combo simulation.
</li>
<li>
<a href={resolve('/doc/race')}>Race Mechanics Charts</a> &mdash; Interactive adaptation of
<a
href="https://docs.google.com/document/d/15VzW9W2tXBBTibBRbZ8IVpW6HaMX8H0RP03kq6Az7Xg/edit"
target="_blank"
rel="noopener noreferrer">KuromiAK's race mechanics documentation</a
> for easier visualization of how mechanics scale.
</li>
<li>
<a href={resolve('/doc/spark')}>Spark Explorer</a> &mdash; View all possible inheritance effects of any spark.
</li>
</ul>
+8 -17
View File
@@ -1,20 +1,11 @@
<script lang="ts"> <script lang="ts">
import { resolve } from '$app/paths'; import { page } from '$app/state';
import * as all from '$lib/all';
import IndexSection from '$lib/IndexSection.svelte';
const cur = $derived(all.page(page.route.id));
</script> </script>
<h1 class="m-8 text-center text-7xl">Zenno Rob Roy &mdash; Character Tools</h1> <h1 class="m-8 text-center text-7xl">Zenno Rob Roy &mdash; {cur.name}</h1>
<p>Tools related to understanding Umamusume characters.</p> <p>{cur.description}</p>
<IndexSection pages={all.PAGES.race} />
<ul class="mb-4 list-disc pl-4">
<li>
<a href={resolve('/race/spurt')}>Spurt Speed</a> &mdash; Calculate a horse's target speed in the last spurt and compare to other
distance aptitudes and running styles.
</li>
<li>
<a href={resolve('/race/mspeed')}>Front Runner Mechanical Speed Comparator</a> &mdash; Compare spot struggle and lane combo to the
effects of individual skills.
</li>
<li>
<a href={resolve('/race/gate')}>Gate Calculator</a> &mdash; Calculate the importance of acceleration effects at the starting gate.
</li>
</ul>