feat(web): remove legacy [state] routes — redirect now in hooks.server.ts

This commit is contained in:
2026-05-10 19:27:27 +02:00
parent 6a8fc07a3d
commit 4b191a3cfd
4 changed files with 0 additions and 323 deletions
@@ -1,48 +0,0 @@
import type { PageServerLoad } from './$types.js';
import { apiFetch } from '$lib/api/client.js';
import type { MarketSummary } from '$lib/api/types.js';
import { slugToState, stateToSlug, toSlug } from '$lib/utils/slug.js';
import { error } from '@sveltejs/kit';
export interface CityInfo {
slug: string;
name: string;
count: number;
}
export const load: PageServerLoad = async ({ params, fetch }) => {
const stateName = slugToState(params.state);
if (!stateName) {
error(404, { message: 'Bundesland nicht gefunden.' });
}
let allMarkets: MarketSummary[] = [];
try {
const res = await apiFetch<MarketSummary[]>('/markets?per_page=1000', { fetch });
allMarkets = res.data;
} catch {
// Backend unreachable
}
const markets = allMarkets.filter((m) => stateToSlug(m.state) === params.state);
if (markets.length === 0) {
error(404, { message: `Keine Märkte in ${stateName} gefunden.` });
}
const countByCity = new Map<string, number>();
for (const m of markets) {
countByCity.set(m.city, (countByCity.get(m.city) ?? 0) + 1);
}
const cities: CityInfo[] = Array.from(countByCity.entries())
.map(([name, count]) => ({ slug: toSlug(name), name, count }))
.sort((a, b) => a.name.localeCompare(b.name, 'de'));
return {
stateName,
stateSlug: params.state,
markets,
cities
};
};
-122
View File
@@ -1,122 +0,0 @@
<script lang="ts">
import MarketCard from '$lib/components/market/MarketCard.svelte';
import type { CityInfo } from './+page.server.js';
import type { MarketSummary } from '$lib/api/types.js';
import { page } from '$app/stores';
let { data } = $props();
const stateName: string = $derived(data.stateName);
const stateSlug: string = $derived(data.stateSlug);
const markets: MarketSummary[] = $derived(data.markets);
const cities: CityInfo[] = $derived(data.cities);
const origin = $derived($page.url.origin);
const jsonLdBreadcrumbHtml = $derived(
'<script type="application/ld+json">' +
JSON.stringify({
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: [
{
'@type': 'ListItem',
position: 1,
name: 'Startseite',
item: `${origin}/`
},
{
'@type': 'ListItem',
position: 2,
name: 'Märkte nach Bundesland',
item: `${origin}/maerkte/`
},
{
'@type': 'ListItem',
position: 3,
name: stateName,
item: `${origin}/maerkte/${stateSlug}/`
}
]
}) +
'</' +
'script>'
);
const jsonLdItemListHtml = $derived(
'<script type="application/ld+json">' +
JSON.stringify({
'@context': 'https://schema.org',
'@type': 'ItemList',
name: `Mittelaltermärkte in ${stateName}`,
numberOfItems: markets.length,
itemListElement: markets.slice(0, 30).map((m, i) => ({
'@type': 'ListItem',
position: i + 1,
url: `${origin}/markt/${m.slug}`
}))
}) +
'</' +
'script>'
);
</script>
<svelte:head>
<title>Mittelaltermärkte in {stateName} - Marktvogt</title>
<meta
name="description"
content="Finde {markets.length} Mittelaltermärkte in {stateName}. Ritterturniere, historische Feste und mittelalterliche Spektakel nach Stadt durchsuchen."
/>
<meta property="og:title" content="Mittelaltermärkte in {stateName} - Marktvogt" />
<meta
property="og:description"
content="{markets.length} Mittelaltermärkte in {stateName} entdecken."
/>
<meta property="og:type" content="website" />
{@html jsonLdBreadcrumbHtml}
{@html jsonLdItemListHtml}
</svelte:head>
<div class="mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
<nav class="mb-6 text-sm text-stone-500 dark:text-stone-400" aria-label="Breadcrumb">
<ol class="flex items-center gap-1.5">
<li><a href="/" class="hover:text-stone-700 dark:hover:text-stone-200">Startseite</a></li>
<li aria-hidden="true">/</li>
<li>
<a href="/maerkte/" class="hover:text-stone-700 dark:hover:text-stone-200">Bundesländer</a>
</li>
<li aria-hidden="true">/</li>
<li class="text-stone-900 dark:text-stone-100">{stateName}</li>
</ol>
</nav>
<h1 class="text-3xl font-bold text-stone-900 sm:text-4xl dark:text-stone-100">
Mittelaltermärkte in {stateName}
</h1>
<p class="mt-2 text-lg text-stone-600 dark:text-stone-300">
{markets.length}
{markets.length === 1 ? 'Markt' : 'Märkte'} in {stateName}
</p>
{#if cities.length > 1}
<div class="mt-6">
<h2 class="text-sm font-medium tracking-wider text-stone-500 uppercase dark:text-stone-400">
Städte
</h2>
<div class="mt-2 flex flex-wrap gap-2">
{#each cities as city (city.slug)}
<a
href="/maerkte/{stateSlug}/{city.slug}/"
class="bg-vellum hover:border-primary-300 hover:text-primary-700 dark:hover:border-primary-500 dark:hover:text-primary-400 rounded-full border border-stone-200 px-3 py-1 text-sm text-stone-700 transition-colors dark:border-stone-600 dark:text-stone-300"
>
{city.name} ({city.count})
</a>
{/each}
</div>
</div>
{/if}
<div class="mt-8 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
{#each markets as market (market.id)}
<MarketCard {market} />
{/each}
</div>
</div>
@@ -1,38 +0,0 @@
import type { PageServerLoad } from './$types.js';
import { apiFetch } from '$lib/api/client.js';
import type { MarketSummary } from '$lib/api/types.js';
import { slugToState, stateToSlug, toSlug } from '$lib/utils/slug.js';
import { error } from '@sveltejs/kit';
export const load: PageServerLoad = async ({ params, fetch }) => {
const stateName = slugToState(params.state);
if (!stateName) {
error(404, { message: 'Bundesland nicht gefunden.' });
}
let allMarkets: MarketSummary[] = [];
try {
const res = await apiFetch<MarketSummary[]>('/markets?per_page=1000', { fetch });
allMarkets = res.data;
} catch {
// Backend unreachable
}
const markets = allMarkets.filter(
(m) => stateToSlug(m.state) === params.state && toSlug(m.city) === params.city
);
if (markets.length === 0) {
error(404, { message: 'Keine Märkte in dieser Stadt gefunden.' });
}
const cityName = markets[0].city;
return {
stateName,
stateSlug: params.state,
cityName,
citySlug: params.city,
markets
};
};
@@ -1,115 +0,0 @@
<script lang="ts">
import MarketCard from '$lib/components/market/MarketCard.svelte';
import type { MarketSummary } from '$lib/api/types.js';
import { page } from '$app/stores';
let { data } = $props();
const stateName: string = $derived(data.stateName);
const stateSlug: string = $derived(data.stateSlug);
const cityName: string = $derived(data.cityName);
const markets: MarketSummary[] = $derived(data.markets);
const origin = $derived($page.url.origin);
const jsonLdBreadcrumbHtml = $derived(
'<script type="application/ld+json">' +
JSON.stringify({
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: [
{
'@type': 'ListItem',
position: 1,
name: 'Startseite',
item: `${origin}/`
},
{
'@type': 'ListItem',
position: 2,
name: 'Märkte nach Bundesland',
item: `${origin}/maerkte/`
},
{
'@type': 'ListItem',
position: 3,
name: stateName,
item: `${origin}/maerkte/${stateSlug}/`
},
{
'@type': 'ListItem',
position: 4,
name: cityName,
item: `${origin}/maerkte/${stateSlug}/${data.citySlug}/`
}
]
}) +
'</' +
'script>'
);
const jsonLdItemListHtml = $derived(
'<script type="application/ld+json">' +
JSON.stringify({
'@context': 'https://schema.org',
'@type': 'ItemList',
name: `Mittelaltermärkte in ${cityName}`,
numberOfItems: markets.length,
itemListElement: markets.map((m, i) => ({
'@type': 'ListItem',
position: i + 1,
url: `${origin}/markt/${m.slug}`
}))
}) +
'</' +
'script>'
);
</script>
<svelte:head>
<title>Mittelaltermärkte in {cityName}, {stateName} - Marktvogt</title>
<meta
name="description"
content="Finde {markets.length} Mittelaltermärkte in {cityName}, {stateName}. Ritterturniere, historische Feste und mittelalterliche Spektakel."
/>
<meta property="og:title" content="Mittelaltermärkte in {cityName}, {stateName} - Marktvogt" />
<meta
property="og:description"
content="{markets.length} Mittelaltermärkte in {cityName} entdecken."
/>
<meta property="og:type" content="website" />
{@html jsonLdBreadcrumbHtml}
{@html jsonLdItemListHtml}
</svelte:head>
<div class="mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
<nav class="mb-6 text-sm text-stone-500 dark:text-stone-400" aria-label="Breadcrumb">
<ol class="flex items-center gap-1.5">
<li><a href="/" class="hover:text-stone-700 dark:hover:text-stone-200">Startseite</a></li>
<li aria-hidden="true">/</li>
<li>
<a href="/maerkte/" class="hover:text-stone-700 dark:hover:text-stone-200">Bundesländer</a>
</li>
<li aria-hidden="true">/</li>
<li>
<a href="/maerkte/{stateSlug}/" class="hover:text-stone-700 dark:hover:text-stone-200"
>{stateName}</a
>
</li>
<li aria-hidden="true">/</li>
<li class="text-stone-900 dark:text-stone-100">{cityName}</li>
</ol>
</nav>
<h1 class="text-3xl font-bold text-stone-900 sm:text-4xl dark:text-stone-100">
Mittelaltermärkte in {cityName}
</h1>
<p class="mt-2 text-lg text-stone-600 dark:text-stone-300">
{markets.length}
{markets.length === 1 ? 'Markt' : 'Märkte'} in {cityName}, {stateName}
</p>
<div class="mt-8 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
{#each markets as market (market.id)}
<MarketCard {market} />
{/each}
</div>
</div>