Files
gw-svelte/src/routes/+error.svelte
T
2026-05-07 21:47:42 +12:00

214 lines
4.6 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang="ts">
import { page } from '$app/stores';
$: status = $page.status;
$: errorMessage = $page.error?.message ?? '';
$: isNotFound = status === 404;
$: heading = isNotFound ? 'This page wandered off' : 'Something went wrong';
$: subtitle = isNotFound
? 'The page you were looking for cant be found. It may have moved, or the link might be a little chewed up.'
: 'We hit a snag loading this page. Try heading home and well get you back on the trail.';
</script>
<svelte:head>
<title>{status} · GoodWalk</title>
<meta name="robots" content="noindex" />
</svelte:head>
<main class="error-page">
<div class="error-bg" aria-hidden="true">
<span class="paw paw-1">🐾</span>
<span class="paw paw-2">🐾</span>
<span class="paw paw-3">🐾</span>
<span class="paw paw-4">🐾</span>
<span class="paw paw-5">🐾</span>
</div>
<div class="error-content">
<div class="error-status">{status}</div>
<h1 class="error-heading">{heading}</h1>
<p class="error-subtitle">{subtitle}</p>
{#if errorMessage && errorMessage !== heading}
<p class="error-detail">{errorMessage}</p>
{/if}
<div class="error-actions">
<a href="/" class="btn btn-yellow">Take me home</a>
<a href="/contact-us" class="btn btn-outline">Book a Meet &amp; Greet</a>
</div>
</div>
</main>
<style>
.error-page {
position: relative;
min-height: 100dvh;
display: grid;
place-items: center;
background:
radial-gradient(circle at 20% 15%, #2a3e2a 0%, transparent 55%),
radial-gradient(circle at 80% 85%, #1a261a 0%, transparent 55%),
var(--gw-green);
color: #fff;
overflow: hidden;
padding: 48px 24px;
}
.error-bg {
position: absolute;
inset: 0;
pointer-events: none;
overflow: hidden;
}
.paw {
position: absolute;
user-select: none;
color: var(--yellow);
opacity: 0.07;
line-height: 1;
}
.paw-1 {
top: 6%;
left: 5%;
font-size: 110px;
transform: rotate(-18deg);
}
.paw-2 {
top: 14%;
right: 8%;
font-size: 140px;
transform: rotate(22deg);
}
.paw-3 {
bottom: 10%;
left: 9%;
font-size: 160px;
transform: rotate(35deg);
}
.paw-4 {
bottom: 6%;
right: 6%;
font-size: 120px;
transform: rotate(-12deg);
}
.paw-5 {
top: 48%;
left: 50%;
font-size: 80px;
transform: translate(-50%, -50%) rotate(8deg);
opacity: 0.04;
}
.error-content {
position: relative;
text-align: center;
max-width: 640px;
z-index: 1;
animation: rise 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.error-status {
font-family: var(--font-head);
font-size: clamp(120px, 22vw, 220px);
font-weight: 700;
color: var(--yellow);
line-height: 0.9;
letter-spacing: -0.04em;
margin-bottom: 16px;
text-shadow: 0 6px 32px rgba(0, 0, 0, 0.25);
}
.error-heading {
font-family: var(--font-head);
font-size: clamp(28px, 4vw, 40px);
font-weight: 600;
line-height: 1.2;
margin: 0 0 16px;
color: #fff;
}
.error-subtitle {
font-size: clamp(15px, 1.6vw, 17px);
line-height: 1.65;
color: rgba(255, 255, 255, 0.78);
margin: 0 auto 16px;
max-width: 520px;
}
.error-detail {
display: inline-block;
font-size: 12px;
letter-spacing: 0.04em;
color: rgba(255, 255, 255, 0.55);
margin: 0 0 32px;
padding: 6px 14px;
background: rgba(255, 255, 255, 0.06);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 100px;
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.error-content :not(.error-detail) + .error-actions {
margin-top: 36px;
}
.error-actions {
display: flex;
gap: 14px;
justify-content: center;
flex-wrap: wrap;
margin-top: 8px;
}
@keyframes rise {
from {
opacity: 0;
transform: translateY(12px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (prefers-reduced-motion: reduce) {
.error-content {
animation: none;
}
}
@media (max-width: 560px) {
.error-page {
padding: 32px 20px;
}
.paw-1 {
font-size: 70px;
}
.paw-2 {
font-size: 86px;
}
.paw-3 {
font-size: 96px;
}
.paw-4 {
font-size: 76px;
}
.paw-5 {
display: none;
}
.error-actions {
flex-direction: column;
align-items: stretch;
width: 100%;
max-width: 320px;
margin-left: auto;
margin-right: auto;
}
.error-actions :global(.btn) {
width: 100%;
}
}
</style>