spotters: fix random 404 on client navigation (random is a page load, not an endpoint shadowed by [slug]); square logo tiles everywhere
Some checks failed
Deploy production / deploy (push) Has been cancelled
Some checks failed
Deploy production / deploy (push) Has been cancelled
This commit is contained in:
@@ -22,11 +22,14 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
/* Every logo sits in a fixed square tile (object-fit: contain, centred, padded, neutral
|
||||||
|
background), so wide wordmarks and tall crests line up in grids and lists. */
|
||||||
.badge,
|
.badge,
|
||||||
.tile {
|
.tile {
|
||||||
display: inline-grid;
|
display: inline-grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
aspect-ratio: 1;
|
||||||
}
|
}
|
||||||
.badge {
|
.badge {
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
@@ -43,26 +46,31 @@
|
|||||||
0 2px 8px hsl(var(--hue) 60% 20% / 0.4);
|
0 2px 8px hsl(var(--hue) 60% 20% / 0.4);
|
||||||
}
|
}
|
||||||
.tile {
|
.tile {
|
||||||
|
overflow: hidden;
|
||||||
border-radius: 0.55rem;
|
border-radius: 0.55rem;
|
||||||
background: #fff;
|
background: #f6f6f4;
|
||||||
padding: 0.2rem;
|
padding: 12%;
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 0 0 1px rgb(0 0 0 / 0.08),
|
0 0 0 1px rgb(0 0 0 / 0.08),
|
||||||
0 2px 8px rgb(0 0 0 / 0.35);
|
0 2px 8px rgb(0 0 0 / 0.35);
|
||||||
}
|
}
|
||||||
.tile img {
|
.tile img {
|
||||||
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
|
object-position: center;
|
||||||
}
|
}
|
||||||
.sm {
|
.sm {
|
||||||
width: 1.9rem;
|
width: 2.1rem;
|
||||||
height: 1.9rem;
|
height: 2.1rem;
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
}
|
}
|
||||||
.tile.sm {
|
.tile.sm {
|
||||||
width: 2.6rem;
|
padding: 0.2rem;
|
||||||
padding: 0.18rem 0.25rem;
|
border-radius: 0.45rem;
|
||||||
}
|
}
|
||||||
.md {
|
.md {
|
||||||
width: 2.6rem;
|
width: 2.6rem;
|
||||||
@@ -76,19 +84,18 @@
|
|||||||
}
|
}
|
||||||
.tile.lg {
|
.tile.lg {
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
padding: 0.5rem;
|
|
||||||
}
|
}
|
||||||
|
/* xl fills the parent's height and stays square inside it. */
|
||||||
.xl {
|
.xl {
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
max-width: 100%;
|
||||||
font-size: 1.6rem;
|
font-size: 1.6rem;
|
||||||
}
|
}
|
||||||
.badge.xl {
|
.badge.xl {
|
||||||
width: 3.6rem;
|
|
||||||
height: 3.6rem;
|
height: 3.6rem;
|
||||||
|
width: 3.6rem;
|
||||||
}
|
}
|
||||||
.tile.xl {
|
.tile.xl {
|
||||||
border-radius: 0.6rem;
|
border-radius: 0.7rem;
|
||||||
padding: 0.6rem 0.8rem;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -44,10 +44,10 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
aspect-ratio: 16 / 9;
|
aspect-ratio: 4 / 3;
|
||||||
}
|
}
|
||||||
.compact .mark {
|
.compact .mark {
|
||||||
aspect-ratio: 2 / 1;
|
aspect-ratio: 3 / 2;
|
||||||
}
|
}
|
||||||
.name {
|
.name {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|||||||
@@ -44,10 +44,10 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
aspect-ratio: 16 / 9;
|
aspect-ratio: 4 / 3;
|
||||||
}
|
}
|
||||||
.compact .mark {
|
.compact .mark {
|
||||||
aspect-ratio: 2 / 1;
|
aspect-ratio: 3 / 2;
|
||||||
}
|
}
|
||||||
.name {
|
.name {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|||||||
@@ -48,10 +48,10 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
aspect-ratio: 16 / 9;
|
aspect-ratio: 4 / 3;
|
||||||
}
|
}
|
||||||
.compact .mark {
|
.compact .mark {
|
||||||
aspect-ratio: 2 / 1;
|
aspect-ratio: 3 / 2;
|
||||||
}
|
}
|
||||||
.name {
|
.name {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|||||||
@@ -45,20 +45,7 @@
|
|||||||
</figure>
|
</figure>
|
||||||
{/if}
|
{/if}
|
||||||
<header class="mt-6 mb-8 flex items-center gap-5">
|
<header class="mt-6 mb-8 flex items-center gap-5">
|
||||||
{#if b.logo}
|
<BrandBadge name={b.name} logo={b.logo} size="lg" />
|
||||||
<img
|
|
||||||
class="logo"
|
|
||||||
src={b.logo}
|
|
||||||
alt="{b.name} logo"
|
|
||||||
title="Logo: {b.logoAuthor ?? 'Wikimedia Commons'}{b.logoLicense
|
|
||||||
? ` (${b.logoLicense})`
|
|
||||||
: ''}"
|
|
||||||
width="72"
|
|
||||||
height="72"
|
|
||||||
/>
|
|
||||||
{:else}
|
|
||||||
<BrandBadge name={b.name} size="lg" />
|
|
||||||
{/if}
|
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-4xl font-semibold tracking-tight sm:text-5xl">{b.name}</h1>
|
<h1 class="text-4xl font-semibold tracking-tight sm:text-5xl">{b.name}</h1>
|
||||||
<p class="mt-2 text-[var(--site-muted)]">
|
<p class="mt-2 text-[var(--site-muted)]">
|
||||||
@@ -130,15 +117,6 @@
|
|||||||
.hero figcaption a {
|
.hero figcaption a {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
.logo {
|
|
||||||
width: 4.5rem;
|
|
||||||
height: 4.5rem;
|
|
||||||
object-fit: contain;
|
|
||||||
padding: 0.5rem;
|
|
||||||
border-radius: 1rem;
|
|
||||||
background: #fff;
|
|
||||||
border: 1px solid var(--site-border);
|
|
||||||
}
|
|
||||||
.grid {
|
.grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
|
|||||||
11
src/routes/trackers/cars/random/+page.server.ts
Normal file
11
src/routes/trackers/cars/random/+page.server.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { redirect } from '@sveltejs/kit';
|
||||||
|
import { randomCar } from '#lib/server/cars.js';
|
||||||
|
import type { PageServerLoad } from './$types';
|
||||||
|
|
||||||
|
// A page load (not a +server.ts endpoint): the client router only knows page routes, so an
|
||||||
|
// endpoint here made client-side navigation fall through to the [brand] page and 404.
|
||||||
|
export const load: PageServerLoad = async ({ setHeaders }) => {
|
||||||
|
const car = await randomCar();
|
||||||
|
setHeaders({ 'cache-control': 'no-store' });
|
||||||
|
redirect(303, car ? `/trackers/cars/${car.brandSlug}/${car.slug}` : '/trackers/cars');
|
||||||
|
};
|
||||||
1
src/routes/trackers/cars/random/+page.svelte
Normal file
1
src/routes/trackers/cars/random/+page.svelte
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<!-- Never rendered: the load always redirects to a random entry. -->
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { redirect } from '@sveltejs/kit';
|
|
||||||
import { randomCar } from '#lib/server/cars.js';
|
|
||||||
import type { RequestHandler } from './$types';
|
|
||||||
|
|
||||||
export const GET: RequestHandler = async ({ setHeaders }) => {
|
|
||||||
const car = await randomCar();
|
|
||||||
setHeaders({ 'cache-control': 'no-store' });
|
|
||||||
redirect(303, car ? `/trackers/cars/${car.brandSlug}/${car.slug}` : '/trackers/cars');
|
|
||||||
};
|
|
||||||
@@ -45,20 +45,7 @@
|
|||||||
</figure>
|
</figure>
|
||||||
{/if}
|
{/if}
|
||||||
<header class="mt-6 mb-8 flex items-center gap-5">
|
<header class="mt-6 mb-8 flex items-center gap-5">
|
||||||
{#if b.logo}
|
<BrandBadge name={b.name} logo={b.logo} size="lg" />
|
||||||
<img
|
|
||||||
class="logo"
|
|
||||||
src={b.logo}
|
|
||||||
alt="{b.name} logo"
|
|
||||||
title="Logo: {b.logoAuthor ?? 'Wikimedia Commons'}{b.logoLicense
|
|
||||||
? ` (${b.logoLicense})`
|
|
||||||
: ''}"
|
|
||||||
width="72"
|
|
||||||
height="72"
|
|
||||||
/>
|
|
||||||
{:else}
|
|
||||||
<BrandBadge name={b.name} size="lg" />
|
|
||||||
{/if}
|
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-4xl font-semibold tracking-tight sm:text-5xl">{b.name}</h1>
|
<h1 class="text-4xl font-semibold tracking-tight sm:text-5xl">{b.name}</h1>
|
||||||
{#if b.fullName && b.fullName !== b.name}<p class="mt-1 text-sm text-[var(--site-muted)]">
|
{#if b.fullName && b.fullName !== b.name}<p class="mt-1 text-sm text-[var(--site-muted)]">
|
||||||
@@ -134,15 +121,6 @@
|
|||||||
.hero figcaption a {
|
.hero figcaption a {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
.logo {
|
|
||||||
width: 4.5rem;
|
|
||||||
height: 4.5rem;
|
|
||||||
object-fit: contain;
|
|
||||||
padding: 0.5rem;
|
|
||||||
border-radius: 1rem;
|
|
||||||
background: #fff;
|
|
||||||
border: 1px solid var(--site-border);
|
|
||||||
}
|
|
||||||
.grid {
|
.grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
|
|||||||
11
src/routes/trackers/planes/random/+page.server.ts
Normal file
11
src/routes/trackers/planes/random/+page.server.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { redirect } from '@sveltejs/kit';
|
||||||
|
import { randomPlane } from '#lib/server/planes.js';
|
||||||
|
import type { PageServerLoad } from './$types';
|
||||||
|
|
||||||
|
// A page load (not a +server.ts endpoint): the client router only knows page routes, so an
|
||||||
|
// endpoint here made client-side navigation fall through to the [maker] page and 404.
|
||||||
|
export const load: PageServerLoad = async ({ setHeaders }) => {
|
||||||
|
const plane = await randomPlane();
|
||||||
|
setHeaders({ 'cache-control': 'no-store' });
|
||||||
|
redirect(303, plane ? `/trackers/planes/${plane.makerSlug}/${plane.slug}` : '/trackers/planes');
|
||||||
|
};
|
||||||
1
src/routes/trackers/planes/random/+page.svelte
Normal file
1
src/routes/trackers/planes/random/+page.svelte
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<!-- Never rendered: the load always redirects to a random entry. -->
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { redirect } from '@sveltejs/kit';
|
|
||||||
import { randomPlane } from '#lib/server/planes.js';
|
|
||||||
import type { RequestHandler } from './$types';
|
|
||||||
|
|
||||||
export const GET: RequestHandler = async ({ setHeaders }) => {
|
|
||||||
const plane = await randomPlane();
|
|
||||||
setHeaders({ 'cache-control': 'no-store' });
|
|
||||||
redirect(303, plane ? `/trackers/planes/${plane.makerSlug}/${plane.slug}` : '/trackers/planes');
|
|
||||||
};
|
|
||||||
@@ -45,20 +45,7 @@
|
|||||||
</figure>
|
</figure>
|
||||||
{/if}
|
{/if}
|
||||||
<header class="mt-6 mb-8 flex items-center gap-5">
|
<header class="mt-6 mb-8 flex items-center gap-5">
|
||||||
{#if b.logo}
|
<BrandBadge name={b.name} logo={b.logo} size="lg" />
|
||||||
<img
|
|
||||||
class="logo"
|
|
||||||
src={b.logo}
|
|
||||||
alt="{b.name} logo"
|
|
||||||
title="Logo: {b.logoAuthor ?? 'Wikimedia Commons'}{b.logoLicense
|
|
||||||
? ` (${b.logoLicense})`
|
|
||||||
: ''}"
|
|
||||||
width="72"
|
|
||||||
height="72"
|
|
||||||
/>
|
|
||||||
{:else}
|
|
||||||
<BrandBadge name={b.name} size="lg" />
|
|
||||||
{/if}
|
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-4xl font-semibold tracking-tight sm:text-5xl">{b.name}</h1>
|
<h1 class="text-4xl font-semibold tracking-tight sm:text-5xl">{b.name}</h1>
|
||||||
{#if b.fullName && b.fullName !== b.name}<p class="mt-1 text-sm text-[var(--site-muted)]">
|
{#if b.fullName && b.fullName !== b.name}<p class="mt-1 text-sm text-[var(--site-muted)]">
|
||||||
@@ -134,15 +121,6 @@
|
|||||||
.hero figcaption a {
|
.hero figcaption a {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
.logo {
|
|
||||||
width: 4.5rem;
|
|
||||||
height: 4.5rem;
|
|
||||||
object-fit: contain;
|
|
||||||
padding: 0.5rem;
|
|
||||||
border-radius: 1rem;
|
|
||||||
background: #fff;
|
|
||||||
border: 1px solid var(--site-border);
|
|
||||||
}
|
|
||||||
.grid {
|
.grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
|
|||||||
@@ -44,20 +44,7 @@
|
|||||||
</figure>
|
</figure>
|
||||||
{/if}
|
{/if}
|
||||||
<header class="mt-6 mb-8 flex items-center gap-5">
|
<header class="mt-6 mb-8 flex items-center gap-5">
|
||||||
{#if b.logo}
|
<BrandBadge name={b.name} logo={b.logo} size="lg" />
|
||||||
<img
|
|
||||||
class="logo"
|
|
||||||
src={b.logo}
|
|
||||||
alt="{b.name} logo"
|
|
||||||
title="Logo: {b.logoAuthor ?? 'Wikimedia Commons'}{b.logoLicense
|
|
||||||
? ` (${b.logoLicense})`
|
|
||||||
: ''}"
|
|
||||||
width="72"
|
|
||||||
height="72"
|
|
||||||
/>
|
|
||||||
{:else}
|
|
||||||
<BrandBadge name={b.name} size="lg" />
|
|
||||||
{/if}
|
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-4xl font-semibold tracking-tight sm:text-5xl">{b.name}</h1>
|
<h1 class="text-4xl font-semibold tracking-tight sm:text-5xl">{b.name}</h1>
|
||||||
{#if b.fullName && b.fullName !== b.name}<p class="mt-1 text-sm text-[var(--site-muted)]">
|
{#if b.fullName && b.fullName !== b.name}<p class="mt-1 text-sm text-[var(--site-muted)]">
|
||||||
@@ -131,15 +118,6 @@
|
|||||||
.hero figcaption a {
|
.hero figcaption a {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
.logo {
|
|
||||||
width: 4.5rem;
|
|
||||||
height: 4.5rem;
|
|
||||||
object-fit: contain;
|
|
||||||
padding: 0.5rem;
|
|
||||||
border-radius: 1rem;
|
|
||||||
background: #fff;
|
|
||||||
border: 1px solid var(--site-border);
|
|
||||||
}
|
|
||||||
.grid {
|
.grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
|
|||||||
11
src/routes/trackers/trains/random/+page.server.ts
Normal file
11
src/routes/trackers/trains/random/+page.server.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { redirect } from '@sveltejs/kit';
|
||||||
|
import { randomTrain } from '#lib/server/trains.js';
|
||||||
|
import type { PageServerLoad } from './$types';
|
||||||
|
|
||||||
|
// A page load (not a +server.ts endpoint): the client router only knows page routes, so an
|
||||||
|
// endpoint here made client-side navigation fall through to the [maker] page and 404.
|
||||||
|
export const load: PageServerLoad = async ({ setHeaders }) => {
|
||||||
|
const train = await randomTrain();
|
||||||
|
setHeaders({ 'cache-control': 'no-store' });
|
||||||
|
redirect(303, train ? `/trackers/trains/${train.makerSlug}/${train.slug}` : '/trackers/trains');
|
||||||
|
};
|
||||||
1
src/routes/trackers/trains/random/+page.svelte
Normal file
1
src/routes/trackers/trains/random/+page.svelte
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<!-- Never rendered: the load always redirects to a random entry. -->
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { redirect } from '@sveltejs/kit';
|
|
||||||
import { randomTrain } from '#lib/server/trains.js';
|
|
||||||
import type { RequestHandler } from './$types';
|
|
||||||
|
|
||||||
export const GET: RequestHandler = async ({ setHeaders }) => {
|
|
||||||
const train = await randomTrain();
|
|
||||||
setHeaders({ 'cache-control': 'no-store' });
|
|
||||||
redirect(303, train ? `/trackers/trains/${train.makerSlug}/${train.slug}` : '/trackers/trains');
|
|
||||||
};
|
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
import { redirect } from '@sveltejs/kit';
|
import { redirect } from '@sveltejs/kit';
|
||||||
import { randomSpecies } from '#lib/server/wildlife.js';
|
import { randomSpecies } from '#lib/server/wildlife.js';
|
||||||
import type { RequestHandler } from './$types';
|
import type { PageServerLoad } from './$types';
|
||||||
|
|
||||||
export const GET: RequestHandler = async ({ setHeaders, url }) => {
|
// A page load (not a +server.ts endpoint): the client router only knows page routes, so an
|
||||||
|
// endpoint here made client-side navigation fall through to the [group] page and 404.
|
||||||
|
export const load: PageServerLoad = async ({ setHeaders, url }) => {
|
||||||
const group = (url.searchParams.get('group') ?? '').replace(/[^a-z0-9-]/g, '') || undefined;
|
const group = (url.searchParams.get('group') ?? '').replace(/[^a-z0-9-]/g, '') || undefined;
|
||||||
const s = await randomSpecies(group);
|
const s = await randomSpecies(group);
|
||||||
setHeaders({ 'cache-control': 'no-store' });
|
setHeaders({ 'cache-control': 'no-store' });
|
||||||
1
src/routes/trackers/wildlife/random/+page.svelte
Normal file
1
src/routes/trackers/wildlife/random/+page.svelte
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<!-- Never rendered: the load always redirects to a random entry. -->
|
||||||
Reference in New Issue
Block a user