components/layout.tsx (153 lines of code) (raw):
import { useEffect, createContext, useCallback, useState } from "react";
import tinykeys from "tinykeys";
import { useRouter } from "next/router";
import Head from "next/head";
import { useStyletron, ThemeProvider, styled } from "baseui";
import { darkTheme } from "../lib/theme";
import { Modal, ModalHeader, ModalBody } from "baseui/modal";
import SideNavigation from "./side-navigation";
import Header from "./header";
import { Page, SiteMap } from "../lib/types";
import BottomNavigation from "./bottom-navigation";
import { useSiblingPages } from "../lib/hooks";
const HotKey = styled("span", {
display: "inline-flex",
alignItems: "center",
justifyContent: "center",
fontFamily: "Menlo, Consolas, sans serif",
fontSize: "14px",
color: "black",
border: "solid 1px #ddd",
borderRadius: "3px",
width: "24px",
height: "24px",
background: "#f6f6f6",
});
interface Context {
siteMap: SiteMap;
figmaLink: string;
activePage?: Page;
openHelpModal: () => void;
}
export const PageContext = createContext({
siteMap: [],
figmaLink: "",
activePage: {},
} as Context);
interface Props extends Context {
children?: React.ReactNode;
}
function Layout({ children, ...pageProps }: Props) {
const [css, theme] = useStyletron();
const router = useRouter();
const [helpModalIsOpen, setHelpModalState] = useState(false);
pageProps.openHelpModal = useCallback(() => {
setHelpModalState(true);
}, []);
const activePageKey = pageProps?.activePage?.key;
const [previousPage, nextPage] = useSiblingPages(
pageProps.siteMap,
activePageKey
);
useEffect(() => {
const unsubscribe = tinykeys(window, {
f: (event) => {
if ((event.target as HTMLInputElement).id !== "search") {
window.open(pageProps.figmaLink, "_blank");
}
},
"Shift+?": (event) => {
if ((event.target as HTMLInputElement).id !== "search") {
setHelpModalState(true);
}
},
ArrowLeft: () => router.push("/[pageKey]", `/${previousPage.key}`),
ArrowRight: () => router.push("/[pageKey]", `/${nextPage.key}`),
});
return () => {
unsubscribe();
};
}, [pageProps.figmaLink]);
return (
<div>
<Head>
<title>Base Documentation</title>
<meta
name="description"
content="A reference for both high-level patterns as well as
component specific guidelines when using the Base design system."
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/base.svg" />
</Head>
<div>
<PageContext.Provider value={pageProps}>
<Modal
isOpen={helpModalIsOpen}
onClose={() => setHelpModalState(false)}
closeable
animate
autoFocus
unstable_ModalBackdropScroll
>
<ModalHeader>Help & Suggestions</ModalHeader>
<ModalBody>
<p>
This site allows you to quickly access documentation that the
Design Platform team maintains in Figma. Each page is a snapshot
of one of the frames you can find in the Figma documentation
project.
</p>
<p>
Here is a list of hotkeys you can use to make navigating the
documentation even faster:
</p>
<ul className={css({ listStyle: "circle" })}>
{[
["/", "Focus the search input."],
["f", "Open current page's frame in Figma."],
["←", "Navigate to the previous page in documentation."],
["→", "Navigate to the next page in documentation."],
["?", "Open the help & suggestions modal."],
].map(([key, description]) => (
<li key={key} className={css({ marginBottom: "4px" })}>
<HotKey $style={{ marginRight: "8px" }}>{key}</HotKey>{" "}
{description}
</li>
))}
</ul>
<p>
Using these hotkeys, you can quickly search for the right page
by pressing <HotKey>/</HotKey> or navigate to related pages with{" "}
<HotKey>←</HotKey> and <HotKey>→</HotKey>. If you want to leave
a comment or inspect further you can always open the
corresponding frame in Figma with <HotKey>f</HotKey>.
</p>
</ModalBody>
</Modal>
<ThemeProvider theme={darkTheme}>
<Header />
</ThemeProvider>
<SideNavigation />
<main
className={css({
marginTop: "24px",
[theme.mediaQuery.medium]: {
marginTop: "84px",
},
[theme.mediaQuery.large]: {
marginLeft: "300px",
},
padding: theme.sizing.scale800,
paddingTop: 0,
})}
>
{children}
</main>
<BottomNavigation />
</PageContext.Provider>
</div>
</div>
);
}
export default Layout;