125 wiersze
2.9 KiB
TypeScript
125 wiersze
2.9 KiB
TypeScript
import React, { MouseEvent, useContext } from "react";
|
|
import { Helmet } from "react-helmet";
|
|
import type { PageName } from "./pages";
|
|
import { getFriendlyPageName } from "./pages/friendly-page-names";
|
|
|
|
import "./page.css";
|
|
|
|
export type PageContext = {
|
|
currPage: PageName;
|
|
allPages: PageName[];
|
|
pushState: (href: string) => void;
|
|
search: URLSearchParams;
|
|
};
|
|
|
|
export const PageContext = React.createContext<PageContext>({
|
|
currPage: "vocabulary",
|
|
allPages: [],
|
|
search: new URLSearchParams(),
|
|
pushState: () => {
|
|
throw new Error("No page context is defined!");
|
|
},
|
|
});
|
|
|
|
export const PAGE_QUERY_ARG = "p";
|
|
|
|
function isNormalLinkClick(e: MouseEvent): boolean {
|
|
return !e.shiftKey && !e.altKey && !e.metaKey && !e.ctrlKey && e.button === 0;
|
|
}
|
|
|
|
const PageLink: React.FC<{ page: PageName }> = ({ page }) => {
|
|
const href = `?${PAGE_QUERY_ARG}=${encodeURIComponent(page)}`;
|
|
const { pushState } = useContext(PageContext);
|
|
const handleClick = (e: MouseEvent) => {
|
|
if (isNormalLinkClick(e)) {
|
|
pushState(href);
|
|
e.preventDefault();
|
|
}
|
|
};
|
|
|
|
return (
|
|
<a href={href} onClick={handleClick}>
|
|
{getFriendlyPageName(page)}
|
|
</a>
|
|
);
|
|
};
|
|
|
|
const Navbar: React.FC<{}> = (props) => {
|
|
const pc = useContext(PageContext);
|
|
|
|
return (
|
|
<nav>
|
|
<ul className="navbar">
|
|
{pc.allPages.map((pageName) => (
|
|
<li key={pageName}>
|
|
{pc.currPage === pageName ? (
|
|
getFriendlyPageName(pageName)
|
|
) : (
|
|
<PageLink page={pageName} />
|
|
)}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</nav>
|
|
);
|
|
};
|
|
|
|
export type PageProps = {
|
|
title: string;
|
|
children?: any;
|
|
};
|
|
|
|
export const Page: React.FC<PageProps> = ({ title, children }) => {
|
|
const fullTitle = ` Mystic Symbolic ${title}`;
|
|
|
|
return (
|
|
<div className="page">
|
|
<Helmet>
|
|
<title>{fullTitle}</title>
|
|
</Helmet>
|
|
<header>
|
|
<h1>
|
|
<img
|
|
src="img/mysticsymbolic-logo-sun.svg"
|
|
alt="Mystic Symbolic"
|
|
title="Mystic Symbolic"
|
|
className="MSlogo"
|
|
/>{" "}
|
|
{title}
|
|
</h1>
|
|
<Navbar />
|
|
</header>
|
|
{children}
|
|
<footer>
|
|
<p>
|
|
For more details about this project, see its{" "}
|
|
<a
|
|
href="https://github.com/toolness/mystic-symbolic"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
GitHub repository
|
|
</a>{" "}
|
|
and{" "}
|
|
<a
|
|
href="https://blog.ninapaley.com/category/mysticsymbolic/"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
Nina Paley's blog
|
|
</a>
|
|
. You can also{" "}
|
|
<a
|
|
href="https://www.gofundme.com/f/mysticsymbolic-development"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
donate to the project
|
|
</a>
|
|
.
|
|
</p>
|
|
</footer>
|
|
</div>
|
|
);
|
|
};
|