trains: pokedex pages (builders, operators, countries, detail, random) and registrations
All checks were successful
Deploy production / deploy (push) Successful in 1m9s
All checks were successful
Deploy production / deploy (push) Successful in 1m9s
This commit is contained in:
117
src/routes/trackers/trains/countries/+page.svelte
Normal file
117
src/routes/trackers/trains/countries/+page.svelte
Normal file
@@ -0,0 +1,117 @@
|
||||
<script lang="ts">
|
||||
import { flag, fmtNumber, monogram, brandHue, thumbAt } from '#lib/trains/shared.js';
|
||||
import ArrowLeft from 'lucide-svelte/icons/arrow-left';
|
||||
import type { PageProps } from './$types';
|
||||
|
||||
let { data }: PageProps = $props();
|
||||
</script>
|
||||
|
||||
<div class="mx-auto max-w-6xl px-4 py-12 sm:px-6 sm:py-16">
|
||||
<a href="/trackers/trains" class="back"><ArrowLeft size={15} /> all trains</a>
|
||||
<header class="mt-6 mb-8">
|
||||
<h1 class="text-4xl font-semibold tracking-tight sm:text-5xl">countries</h1>
|
||||
<p class="mt-3 max-w-2xl text-[var(--site-muted)]">
|
||||
Train types from {fmtNumber(data.countries.length)} countries, counted where they were built and
|
||||
where they ran. Tap one for its trains, oldest first.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<ul class="grid">
|
||||
{#each data.countries as c, i (c.slug)}
|
||||
<li>
|
||||
<a href="/trackers/trains/countries/{c.slug}" class="tile">
|
||||
<span class="media" style:--hue={brandHue(c.name)}>
|
||||
{#if c.photo}
|
||||
<img
|
||||
src={thumbAt(c.photo, 330)}
|
||||
alt=""
|
||||
loading={i < 8 ? 'eager' : 'lazy'}
|
||||
decoding="async"
|
||||
width="330"
|
||||
height="186"
|
||||
/>
|
||||
{:else}
|
||||
<span class="placeholder" aria-hidden="true">{monogram(c.name)}</span>
|
||||
{/if}
|
||||
</span>
|
||||
<span class="name">{flag(c.name)} {c.name}</span>
|
||||
<span class="meta">{fmtNumber(c.types)} {c.types === 1 ? 'type' : 'types'}</span>
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.back {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
font-size: 0.85rem;
|
||||
color: var(--site-muted);
|
||||
}
|
||||
.back:hover {
|
||||
color: var(--site-text);
|
||||
}
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
|
||||
gap: 0.75rem;
|
||||
}
|
||||
.tile {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3rem;
|
||||
height: 100%;
|
||||
padding: 0 0 0.65rem;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--site-border);
|
||||
border-radius: 0.9rem;
|
||||
background: var(--site-surface);
|
||||
transition:
|
||||
transform 0.15s,
|
||||
border-color 0.15s,
|
||||
background 0.15s;
|
||||
}
|
||||
.tile:hover,
|
||||
.tile:focus-visible {
|
||||
transform: translateY(-2px);
|
||||
border-color: var(--site-muted);
|
||||
background: var(--site-hover);
|
||||
}
|
||||
.media {
|
||||
position: relative;
|
||||
display: block;
|
||||
aspect-ratio: 16 / 9;
|
||||
margin-bottom: 0.3rem;
|
||||
background: radial-gradient(circle at 30% 20%, hsl(var(--hue) 35% 22%), hsl(var(--hue) 30% 9%));
|
||||
}
|
||||
.media img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
.placeholder {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-size: 2rem;
|
||||
font-weight: 800;
|
||||
color: hsl(var(--hue) 50% 60% / 0.25);
|
||||
}
|
||||
.name,
|
||||
.meta {
|
||||
padding: 0 0.75rem;
|
||||
}
|
||||
.name {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.meta {
|
||||
font-size: 0.72rem;
|
||||
color: var(--site-muted);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user