You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
getcryst.al/pages/docs/[[...slug]].tsx

154 lines
4.1 KiB
TypeScript

import { serialize } from "next-mdx-remote/serialize";
import { MDXRemote, MDXRemoteSerializeResult } from "next-mdx-remote";
import { ReactElement, useEffect } from "react";
import { resolve } from "path";
import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
import { removeExt, walkFiles } from "../../lib/files";
import remarkGfm from "remark-gfm";
import TreeNode from "../../components/TreeItem";
import DocWrapper from "../../components/DocWrapper";
import { findCurrentDir, ITreeItem } from "../../lib/tree";
import rehypeAutolinkHeadings from "rehype-autolink-headings";
import rehypeSlug from "rehype-slug";
import rehypeHighlight from "rehype-highlight";
import { NextPageWithLayout } from "../_app";
import { useRouter } from "next/router";
import Link from "next/link";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import TranslationInfo from "../../components/TranslationInfo";
import trees from "../../lib/trees";
export const getStaticPaths: GetStaticPaths = async ({ locales }) => {
const paths: GetStaticPathsResult["paths"] = [];
for (const locale of locales!) {
for await (const file of walkFiles(`_docs/${locale}`)) {
const path = file.slice(
resolve(process.cwd(), `_docs/${locale}/`).length
);
paths.push({
params: {
slug: removeExt(path).split("/").slice(1),
locale,
},
});
}
}
return {
paths,
fallback: "blocking",
};
};
export const getStaticProps: GetStaticProps = async ({ params, locale }) => {
const slug = params!.slug === undefined ? [] : (params!.slug as string[]);
const translations = await serverSideTranslations(locale!, [
"common",
"footer",
"navbar",
"meta",
]);
const rootySlug = ["root", ...slug];
const tree = trees[locale!].copy();
tree.walkCurrents(rootySlug);
const me = tree.find(rootySlug);
if (slug.length === 0 || me === undefined) {
const plain = tree.plain();
return {
props: {
source: null,
tree: plain,
dir: findCurrentDir(plain),
...translations,
},
};
}
return {
props: {
source: await serialize(me.contents!, {
parseFrontmatter: true,
mdxOptions: {
remarkPlugins: [remarkGfm],
rehypePlugins: [
rehypeSlug,
[
rehypeAutolinkHeadings,
{
behavior: "wrap",
},
],
rehypeHighlight,
],
},
}),
tree: tree.plain(),
...translations,
},
};
};
const DocPage: NextPageWithLayout<{
source: MDXRemoteSerializeResult | null;
tree: ITreeItem;
dir: ITreeItem | null;
}> = ({ source, tree, dir }) => {
const {
query: { slug },
push,
} = useRouter();
useEffect(() => {
if (slug === undefined) {
push("/docs/crystal-linux/getting-started");
}
}, [push, slug]);
return (
<div className="mx-auto min-h-screen max-w-8xl space-y-12 space-x-4 px-4 pb-16 pt-24 md:px-8 md:pb-28 lg:pt-28">
<aside className="right-auto mb-8 flex w-80 flex-col break-normal align-top lg:fixed lg:mb-0">
<TreeNode node={tree} path="/docs" />
</aside>
<DocWrapper>
{dir ? (
<>
{dir.pretty !== null && <h1>{dir.pretty}</h1>}
<TranslationInfo />
<ul>
{slug &&
dir.children.map((child) => (
<li key={child.value}>
<Link
href={`${(slug as string[]).join("/")}/${child.value}`}
>
<a>{child.pretty ? child.pretty : child.value}</a>
</Link>
</li>
))}
</ul>
</>
) : (
<>
{source!.frontmatter?.title && <h1>{source!.frontmatter.title}</h1>}
<TranslationInfo />
<MDXRemote {...source!} />
</>
)}
</DocWrapper>
</div>
);
};
DocPage.getLayout = function getLayout(page: ReactElement) {
return <main>{page}</main>;
};
export default DocPage;