Files
hoelee-blog/src/pages/404.astro
T
hoelee 8619e48271
Deploy / build (push) Successful in 2m59s
fix(404): noindex the error page instead of emitting a canonical to /404/
A canonical pointing at a URL that does not exist is worse than none. Normal pages
are untouched (canonical still emitted, no robots meta).
2026-10-16 20:57:20 +08:00

63 lines
2.3 KiB
Plaintext

---
import BaseLayout from '../layouts/BaseLayout.astro';
import { getCollection } from 'astro:content';
import { isEn } from '../lib/lang';
import { sortForListing } from '../lib/sort';
// Static 404. nginx serves it with `error_page 404 /404.html`, so the status code
// stays 404 (crawlers do not index it) while the visitor gets a way forward.
// Before this existed, a broken link showed nginx's bare default page.
const latest = sortForListing(await getCollection('posts', isEn)).slice(0, 3);
const fmt = (d: Date) =>
d.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
---
<BaseLayout
title="404 — Page Not Found — Mr Hoelee"
description="That URL does not exist on this site. Search the posts or browse the archive."
noindex
>
<h1>404 — container exited (code 1)</h1>
<p>
There is no page at this address. It may have been renamed, or the link that sent
you here may be wrong. Nothing is broken on your side.
</p>
<p class="notfound-actions">
<button id="search-cta" class="notfound-btn" type="button">⌕ Search the posts</button>
<a href="/posts/">Browse all posts</a>
<span class="sep">·</span>
<a href="/categories/">Categories</a>
<span class="sep">·</span>
<a href="/zh/">中文</a>
</p>
<h2>Recent posts</h2>
<ul class="post-list">
{latest.map((p) => (
<li class="post-row notfound-row">
<div class="body">
<a href={`/posts/${p.slug}/`}><h2>{p.data.title}</h2></a>
<div class="meta">
<time datetime={p.data.pubDate.toISOString()}>{fmt(p.data.pubDate)}</time>
<span class="sep">·</span>
<a class="tag" href={`/categories/${p.data.category}/`}>{p.data.category}</a>
</div>
<p>{p.data.description}</p>
</div>
</li>
))}
</ul>
<script>
// The search overlay is mounted on every page by BaseLayout; its trigger is the
// ⌕ button in the header (also bound to Ctrl/Cmd+K there). Route this page's
// button to the same overlay instead of growing a second search implementation.
const cta = document.getElementById('search-cta');
cta?.addEventListener('click', () => {
const toggle = document.getElementById('search-toggle');
if (toggle) toggle.click();
});
</script>
</BaseLayout>