fix(site): add explicit not-found page
All checks were successful
ci / build (push) Successful in 41s

This commit is contained in:
Yun Chan 2026-08-30 18:24:48 +09:00
parent 82e8c8f8ae
commit 7ef9106723
3 changed files with 274 additions and 3 deletions

View file

@ -11,9 +11,10 @@ interface Props {
title: string;
description: string;
translationPath?: string | null;
noindex?: boolean;
}
const { lang, title, description } = Astro.props;
const { lang, title, description, noindex = false } = Astro.props;
const copy = lang === "ko" ? landingKo : landingEn;
const socialPreview = lang === "ko" ? socialPreviewKo : socialPreviewEn;
const socialPreviewAlt = lang === "ko"
@ -67,6 +68,7 @@ const schema = isHome
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{title}</title>
<meta name="description" content={description} />
{noindex && <meta name="robots" content="noindex, follow" />}
<meta name="theme-color" content="#f2f1eb" />
<meta name="color-scheme" content="light" />
<link rel="icon" href={favicon} />

View file

@ -0,0 +1,213 @@
---
import Base from "../layouts/Base.astro";
const title = "페이지를 찾을 수 없습니다 | Page not found | designpaca";
const description = "요청한 주소를 찾을 수 없습니다. 한국어 또는 영어 홈에서 다시 시작할 수 있습니다. Page not found. Return to the Korean or English home page.";
---
<Base lang="ko" title={title} description={description} translationPath={null} noindex>
<section class="not-found grain" aria-labelledby="not-found-title">
<div class="not-found-grid shell">
<div class="not-found-copy">
<p class="status-code mono">HTTP 404</p>
<h1 id="not-found-title">페이지를 찾을 수 없습니다</h1>
<p class="not-found-lead">
주소가 바뀌었거나 페이지가 이동했습니다. 아래 홈 화면에서 다시 시작해 주세요.
</p>
<p class="not-found-en" lang="en">
Page not found. The address may have changed or the page may have moved.
</p>
</div>
<nav class="recovery-map frame" aria-label="홈 화면으로 이동">
<div class="recovery-source">
<span class="recovery-label">현재 위치 <span lang="en">Current route</span></span>
<span class="recovery-value nums" aria-hidden="true">404</span>
</div>
<div class="recovery-links">
<a class="recovery-link" href="/">
<span class="recovery-code mono" aria-hidden="true">KO</span>
<span>한국어 홈</span>
</a>
<a class="recovery-link" href="/en/" lang="en">
<span class="recovery-code mono" aria-hidden="true">EN</span>
<span>English home</span>
</a>
</div>
</nav>
</div>
</section>
</Base>
<style>
.not-found {
min-height: calc(100dvh - var(--header-h));
display: grid;
align-items: center;
padding-block: var(--space-8);
}
.not-found-grid {
display: grid;
grid-template-columns: minmax(0, 7fr) minmax(18rem, 5fr);
gap: var(--space-7);
align-items: stretch;
}
.not-found-copy {
align-self: center;
max-width: 40rem;
padding-block: var(--space-6);
}
.status-code {
margin-bottom: var(--space-5);
color: var(--accent);
font-size: var(--step--1);
font-weight: var(--weight-medium);
letter-spacing: 0.08em;
}
h1 {
max-width: 11ch;
}
.not-found-lead,
.not-found-en {
max-width: var(--measure-narrow);
color: var(--ink-muted);
}
.not-found-lead {
margin-top: var(--space-5);
}
.not-found-en {
margin-top: var(--space-3);
font-size: var(--step--1);
}
.recovery-map {
position: relative;
min-height: 25rem;
display: grid;
grid-template-rows: minmax(0, 1fr) auto;
overflow: hidden;
}
.recovery-map::before {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
background-image:
linear-gradient(to right, transparent calc(50% - 0.5px), var(--line) 50%, transparent calc(50% + 0.5px)),
linear-gradient(to bottom, transparent calc(50% - 0.5px), var(--line) 50%, transparent calc(50% + 0.5px));
opacity: 0.38;
}
.recovery-source,
.recovery-links {
position: relative;
z-index: 1;
}
.recovery-source {
display: flex;
flex-direction: column;
justify-content: space-between;
gap: var(--space-6);
padding: var(--space-6);
}
.recovery-label {
color: var(--ink-muted);
font-size: var(--step--1);
}
.recovery-label span {
display: block;
margin-top: var(--space-1);
}
.recovery-value {
align-self: flex-end;
color: var(--ink);
font-size: clamp(5rem, 12vw, 10rem);
font-weight: var(--weight-body);
line-height: 0.82;
letter-spacing: -0.055em;
}
.recovery-links {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
border-top: var(--line-width) solid var(--line-strong);
background: var(--surface-raised);
}
.recovery-link {
min-height: 4.75rem;
display: grid;
grid-template-columns: auto minmax(0, 1fr);
align-items: center;
gap: var(--space-3);
padding: var(--space-4) var(--space-5);
color: var(--ink);
font-weight: var(--weight-medium);
line-height: 1.25;
text-decoration: none;
}
.recovery-link + .recovery-link {
border-left: var(--line-width) solid var(--line-strong);
}
.recovery-link:hover,
.recovery-link:focus-visible {
background: var(--surface-soft);
}
.recovery-link:active {
background: var(--surface);
}
.recovery-code {
color: var(--accent);
}
@media (max-width: 48rem) {
.not-found {
align-items: start;
padding-block: var(--space-7);
}
.not-found-grid {
grid-template-columns: minmax(0, 1fr);
gap: var(--space-6);
}
.not-found-copy {
padding-block: 0;
}
.recovery-map {
min-height: 20rem;
}
.recovery-value {
font-size: clamp(5rem, 30vw, 8rem);
}
}
@media (max-width: 23rem) {
.recovery-links {
grid-template-columns: minmax(0, 1fr);
}
.recovery-link + .recovery-link {
border-top: var(--line-width) solid var(--line-strong);
border-left: 0;
}
}
</style>