64 lines
1.8 KiB
TypeScript
64 lines
1.8 KiB
TypeScript
import React, {type PropsWithChildren, ReactElement} from "react";
|
|
import {useRouter} from "./RouterContext";
|
|
import {Path} from "./router";
|
|
|
|
export type Route = [Path, string];
|
|
type Routes = [Route, Route, Route, Route];
|
|
export const ROUTES: Routes = [
|
|
["/", "Home"],
|
|
["/about", "About"],
|
|
["/articles", "Articles"],
|
|
["/links", "Links"]
|
|
];
|
|
|
|
type RouteProps = PropsWithChildren & {route: Route};
|
|
function Route(props: RouteProps) {
|
|
const {route: [path], children} = props;
|
|
const router = useRouter();
|
|
// remove search params
|
|
const [cleanPath] = /\/?\w*[^?]/.exec(router.current) ?? [path];
|
|
|
|
return <>{cleanPath === path && children}</>
|
|
}
|
|
|
|
|
|
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 <>
|
|
<RouteSwitch>
|
|
<Route route={index}>
|
|
<Canvas/>
|
|
</Route>
|
|
<Route route={about}>
|
|
<About/>
|
|
</Route>
|
|
<Route route={articles}>
|
|
<ArticlesList/>
|
|
</Route>
|
|
<Route route={links}>
|
|
<LinkTree/>
|
|
</Route>
|
|
</RouteSwitch>
|
|
</>
|
|
}
|