Add NotFound page for virtual 404s inside the SPA
All checks were successful
/ image_build (push) Successful in 1m19s

This commit is contained in:
2026-09-25 14:07:22 -04:00
parent 75d05beb7a
commit 503f075b98
7 changed files with 128 additions and 23 deletions

View File

@@ -1,8 +1,8 @@
import React, {PropsWithChildren} from "react";
import React, {type PropsWithChildren, ReactElement} from "react";
import {useRouter} from "./RouterContext";
import {Path} from "./router";
type Route = [Path, string];
export type Route = [Path, string];
type Routes = [Route, Route, Route, Route];
export const ROUTES: Routes = [
["/", "Home"],
@@ -11,7 +11,8 @@ export const ROUTES: Routes = [
["/links", "Links"]
];
function Route(props: PropsWithChildren & {route: Route}) {
type RouteProps = PropsWithChildren & {route: Route};
function Route(props: RouteProps) {
const {route: [path], children} = props;
const router = useRouter();
// remove search params
@@ -25,22 +26,38 @@ const Canvas = React.lazy(() => import("../index/Canvas"));
const About = React.lazy(() => import("../about/AboutPage"));
const ArticlesList = React.lazy(() => import("../articles/ArticlesList"));
const LinkTree = React.lazy(() => import("../links/LinkTree"));
const NotFound = React.lazy(() => import("../404/NotFound"));
// ensures only one route is rendered at a time, with a virtual 404 page as fallback
function RouteSwitch({children}: {children: ReactElement<RouteProps, typeof Route>[]}) {
const router = useRouter();
const child = children.find(child => {
const [expected] = child.props.route;
const [current] = /\/?\w*[^?]/.exec(router.current) ?? [location.pathname];
return current === expected
});
return <>{child || <NotFound/>}</>
}
export function Routes() {
const [index, about, articles, links] = ROUTES;
return <>
<Route route={index}>
<Canvas/>
</Route>
<Route route={about}>
<About/>
</Route>
<Route route={articles}>
<ArticlesList/>
</Route>
<Route route={links}>
<LinkTree/>
</Route>
</>
}
<RouteSwitch>
<Route route={index}>
<Canvas/>
</Route>
<Route route={about}>
<About/>
</Route>
<Route route={articles}>
<ArticlesList/>
</Route>
<Route route={links}>
<LinkTree/>
</Route>
</RouteSwitch>
</>
}