فهرست منبع

Create error page

Lee Morgan 4 روز پیش
والد
کامیت
0753f11849
1فایلهای تغییر یافته به همراه139 افزوده شده و 0 حذف شده
  1. 139 0
      src/routes/+error.svelte

+ 139 - 0
src/routes/+error.svelte

@@ -0,0 +1,139 @@
+<script>
+	import { page } from '$app/state';
+	import logoMark from '$lib/images/logo_white.svg';
+
+	const status = $derived(page.status);
+	const isNotFound = $derived(status === 404);
+	const title = $derived(isNotFound ? 'Page not found' : 'Something broke');
+	const message = $derived(
+		isNotFound
+			? 'That route is not on the board. Head back and keep training.'
+			: (page.error?.message ?? 'Unexpected error. Try again.')
+	);
+</script>
+
+<svelte:head>
+	<title>{status} — Torus</title>
+</svelte:head>
+
+<div class="page">
+	<header class="top">
+		<a class="brand" href="/">
+			<img class="brand-mark" src={logoMark} alt="" width="28" height="28" />
+			<span class="brand-name">Torus</span>
+		</a>
+		<a class="btn btn-ghost" href="/register">Create account</a>
+	</header>
+
+	<main>
+		<section class="panel" aria-labelledby="error-title">
+			<p class="code">{status}</p>
+			<h1 id="error-title">{title}</h1>
+			<p class="lede">{message}</p>
+			<div class="actions">
+				<a class="btn btn-primary" href="/">Back home</a>
+				{#if isNotFound}
+					<a class="btn btn-ghost" href="/register">Create account</a>
+				{/if}
+			</div>
+		</section>
+	</main>
+</div>
+
+<style>
+	.page {
+		min-height: 100vh;
+		display: flex;
+		flex-direction: column;
+	}
+
+	.top {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		gap: 16px;
+		padding: 16px 20px;
+		border-bottom: 1px solid var(--border);
+	}
+
+	.brand {
+		display: inline-flex;
+		align-items: center;
+		gap: 10px;
+		font-weight: 700;
+		letter-spacing: -0.02em;
+	}
+
+	.brand-mark {
+		display: block;
+		width: 28px;
+		height: 28px;
+		flex-shrink: 0;
+	}
+
+	.brand-name {
+		font-size: 15px;
+	}
+
+	main {
+		flex: 1;
+		display: flex;
+		align-items: flex-start;
+		justify-content: center;
+		padding: 48px 20px 64px;
+	}
+
+	.panel {
+		width: min(440px, 100%);
+		background: var(--surface);
+		border: 1px solid var(--border);
+		border-radius: var(--radius-lg);
+		padding: 28px 24px;
+	}
+
+	.code {
+		margin: 0 0 12px;
+		font-size: 0.8rem;
+		font-weight: 750;
+		letter-spacing: 0.08em;
+		text-transform: uppercase;
+		color: var(--heat);
+		font-variant-numeric: tabular-nums;
+	}
+
+	h1 {
+		margin: 0;
+		font-size: clamp(1.6rem, 4vw, 2rem);
+		letter-spacing: -0.03em;
+		font-weight: 750;
+	}
+
+	.lede {
+		margin: 10px 0 0;
+		color: var(--text-muted);
+		font-size: 0.98rem;
+		line-height: 1.5;
+	}
+
+	.actions {
+		display: flex;
+		flex-wrap: wrap;
+		gap: 10px;
+		margin-top: 24px;
+	}
+
+	@media (min-width: 720px) {
+		.top {
+			padding: 16px 28px;
+		}
+
+		main {
+			align-items: center;
+			padding: 64px 28px 80px;
+		}
+
+		.panel {
+			padding: 32px 28px;
+		}
+	}
+</style>