Skip to content

Commit 70a9efc

Browse files
Merge pull request #15 from coder/cat/site-404-fix
fix(site): restore SPA path before router boots so 404 page renders
2 parents cee7caf + df19bfe commit 70a9efc

4 files changed

Lines changed: 62 additions & 21 deletions

File tree

site/index.html

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,31 @@
1010
/>
1111
<title>Coder Skill Scanner</title>
1212

13+
<script>
14+
// Restore the SPA path captured by public/404.html before main.tsx loads,
15+
// so the router sees the original path and can render its 404 route.
16+
(function () {
17+
var url = new URL(window.location.href);
18+
var p = url.searchParams.get("p");
19+
// Only restore same-origin relative paths so a crafted ?p= can't try
20+
// to replace the visible origin (replaceState would throw anyway).
21+
if (!p || p[0] !== "/" || p[1] === "/") return;
22+
url.searchParams.delete("p");
23+
// Parse `p` through URL so its own query/hash compose cleanly with
24+
// whatever extra params or hash were on the bounce URL.
25+
var restored = new URL(p, window.location.origin);
26+
url.searchParams.forEach(function (value, key) {
27+
restored.searchParams.append(key, value);
28+
});
29+
if (!restored.hash) restored.hash = url.hash;
30+
window.history.replaceState(
31+
null,
32+
"",
33+
restored.pathname + restored.search + restored.hash,
34+
);
35+
})();
36+
</script>
37+
1338
<link rel="preconnect" href="https://fonts.googleapis.com" />
1439
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
1540
<link

site/public/404.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<script>
77
// GitHub Pages SPA fallback: capture the original path in a query
88
// parameter and bounce to the SPA index, which restores it before
9-
// React Router boots. See site/src/main.tsx for the restore step.
9+
// React Router boots. See site/index.html for the restore step.
1010
//
1111
// `%BASE_URL%` is substituted at build time by the
1212
// `rewrite-public-base-url` Vite plugin (see site/vite.config.ts),

site/src/main.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,8 @@ import { StrictMode } from "react";
22
import { createRoot } from "react-dom/client";
33
import { App } from "./App";
44

5-
// Restore SPA path captured by public/404.html (GitHub Pages deep-link trick).
6-
const url = new URL(window.location.href);
7-
const original = url.searchParams.get("p");
8-
if (original) {
9-
url.searchParams.delete("p");
10-
window.history.replaceState(null, "", original + url.search + url.hash);
11-
}
5+
// Note: the `?p=...` query param emitted by public/404.html is restored
6+
// by the inline script in index.html so the router sees the original path.
127

138
const appRoot = document.getElementById("root");
149
if (appRoot === null) {

site/src/pages/NotFoundPage.tsx

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,48 @@
11
import type { FC } from "react";
2-
import { Link } from "react-router-dom";
2+
import { Link, useLocation } from "react-router-dom";
33
import { usePageTitle } from "../lib/usePageTitle";
44

55
export const NotFoundPage: FC = () => {
6+
const { pathname } = useLocation();
67
usePageTitle("not found");
78
return (
8-
<div className="mx-auto max-w-md rounded-lg border border-coder-smoke bg-coder-cinder p-8 text-center">
9-
<div className="font-mono text-5xl font-semibold text-coder-neutral-200">
9+
<div className="mx-auto flex max-w-xl flex-col items-center gap-6 rounded-lg border border-coder-smoke bg-coder-cinder p-10 text-center">
10+
<div className="font-mono text-7xl font-semibold tracking-tight text-coder-neutral-200">
1011
404
1112
</div>
12-
<p className="mt-3 text-sm text-coder-neutral-400">
13-
That path doesn&apos;t exist in this report.
14-
</p>
15-
<div className="mt-4 flex flex-col items-center gap-2 text-sm">
13+
<div className="space-y-2">
14+
<h1 className="text-xl font-semibold tracking-tight text-coder-neutral-100">
15+
That page isn&apos;t part of this scan report.
16+
</h1>
17+
<p className="text-sm text-coder-neutral-400">
18+
We couldn&apos;t find{" "}
19+
<span className="rounded bg-coder-smoke/60 px-1.5 py-0.5 font-mono text-xs text-coder-neutral-200">
20+
{pathname}
21+
</span>
22+
. It may have moved, been renamed, or never existed.
23+
</p>
24+
</div>
25+
<div className="flex flex-wrap items-center justify-center gap-x-5 gap-y-2 text-sm">
1626
<Link to="/" className="text-coder-sky hover:underline">
17-
Back to the latest scan
27+
Latest scan
1828
</Link>
19-
<Link
20-
to="/history"
21-
className="text-xs text-coder-neutral-400 hover:text-coder-neutral-100"
22-
>
23-
or browse the scan history
29+
<Link to="/history" className="text-coder-sky hover:underline">
30+
Scan history
2431
</Link>
32+
<a
33+
href={`${import.meta.env.BASE_URL}latest.json`}
34+
className="text-coder-sky hover:underline"
35+
>
36+
Raw JSON
37+
</a>
38+
<a
39+
href="https://github.com/coder/coder-skill-scanner"
40+
className="text-coder-sky hover:underline"
41+
rel="noopener noreferrer"
42+
target="_blank"
43+
>
44+
Source
45+
</a>
2546
</div>
2647
</div>
2748
);

0 commit comments

Comments
 (0)