datahub/site/pages/[...slug].tsx
João Demenech a954575397
Website v0.4 (#860)
* [#858,site][xl]: add Examples to the Navbar, rename gallery to showcases, remove examples from showcases, move github stars to the navbar, add view on github button to the hero section, reduce padding on buttons, add RHS image to the hero

* [#858,site][xl]: make sidebar consistent on all pages

* [site][xs]: fix ts error on GitHub button component

* [site][xs]: fix external links on navbar needing two clicks to open

* [site, hero][xs]: align RHS image to the top
2023-05-09 14:39:23 -03:00

182 lines
5.2 KiB
TypeScript

import fs from 'fs';
import parse from '../lib/markdown.mjs';
import MDXPage from '../components/MDXPage';
import clientPromise from '@/lib/mddb';
import Layout from 'components/Layout';
import { useEffect, useState } from 'react';
import { useRouter } from 'next/router.js';
import { NavGroup, NavItem, collectHeadings } from '@flowershow/core';
import { GetStaticProps, GetStaticPropsResult } from 'next';
import { CustomAppProps } from './_app.jsx';
import computeFields from '@/lib/computeFields';
import { getAuthorsDetails } from '@/lib/getAuthorsDetails';
export default function Page({ source, meta, sidebarTree }) {
source = JSON.parse(source);
const router = useRouter();
const [tableOfContents, setTableOfContents] = useState([]);
useEffect(() => {
const headingNodes = document.querySelectorAll(
'h2,h3'
) as NodeListOf<HTMLHeadingElement>;
const toc = collectHeadings(headingNodes);
setTableOfContents(toc ?? []);
}, [router.asPath]); // update table of contents on route change with next/link
return (
<Layout
tableOfContents={tableOfContents}
title={meta.title}
sidebarTree={sidebarTree}
urlPath={meta.urlPath}
>
<MDXPage source={source} frontMatter={meta} />
</Layout>
);
}
interface SlugPageProps extends CustomAppProps {
source: any;
}
export const getStaticProps: GetStaticProps = async ({
params,
}): Promise<GetStaticPropsResult<SlugPageProps>> => {
const urlPath = params?.slug ? (params.slug as string[]).join('/') : '/';
const mddb = await clientPromise;
const dbFile = await mddb.getFileByUrl(urlPath);
const filePath = dbFile!.file_path;
const frontMatter = dbFile!.metadata ?? {};
// Temporary, so that blogs work properly
if (dbFile.metadata.filetype === 'blog') {
frontMatter.layout = 'blog';
frontMatter.authorsDetails = await getAuthorsDetails(
dbFile.metadata.authors
);
}
// Temporary, docs pages should present the LHS sidebar
if (dbFile.url_path.startsWith('docs')) {
frontMatter.showSidebar = true;
frontMatter.sidebarTreeFile = 'content/assets/sidebar.json';
}
const source = fs.readFileSync(filePath, { encoding: 'utf-8' });
const { mdxSource } = await parse(source, 'mdx', {});
// TODO temporary replacement for contentlayer's computedFields
const frontMatterWithComputedFields = await computeFields({
frontMatter,
urlPath,
filePath,
source,
});
let sidebarTree: Array<NavGroup | NavItem> = [];
if (frontMatterWithComputedFields?.showSidebar) {
let sidebarTreeFile = frontMatterWithComputedFields?.sidebarTreeFile;
// Added this file funcionality so that we can control
// which items appear in the sidebar and the order via
// a json file
if (sidebarTreeFile) {
const tree = fs.readFileSync(sidebarTreeFile, { encoding: 'utf-8' });
sidebarTree = JSON.parse(tree);
} else {
const allPages = await mddb.getFiles({ extensions: ['md', 'mdx'] });
const pages = allPages.filter((p) => !p.metadata?.isDraft);
pages.forEach((page) => {
addPageToSitemap(page, sidebarTree);
});
}
}
return {
props: {
source: JSON.stringify(mdxSource),
meta: frontMatterWithComputedFields,
sidebarTree,
},
};
};
export async function getStaticPaths() {
const mddb = await clientPromise;
let allDocuments = await mddb.getFiles({ extensions: ['md', 'mdx'] });
const paths = allDocuments
.filter((page) => page.metadata?.isDraft !== true)
.map((page) => {
const parts = page.url_path!.split('/');
return { params: { slug: parts } };
});
return {
paths,
fallback: false,
};
}
function capitalize(str: string) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
/* function addPageToGroup(page: MddbFile, sitemap: Array<NavGroup>) { */
function addPageToSitemap(page: any, sitemap: Array<NavGroup | NavItem>) {
const urlParts = page.url_path!.split('/').filter((part) => part);
// don't add home page to the sitemap
if (urlParts.length === 0) return;
// top level, root pages
if (urlParts.length === 1) {
sitemap.push({
name: page.metadata?.title || urlParts[0],
href: page.url_path,
});
} else {
// /blog/blogtest
const nestingLevel = urlParts.length - 1; // 1
let currArray: Array<NavItem | NavGroup> = sitemap;
for (let level = 0; level <= nestingLevel; level++) {
if (level === nestingLevel) {
currArray.push({
name: urlParts[level],
href: page.url_path,
});
continue;
}
const matchingGroup = currArray
.filter(isNavGroup)
.find(
(group) =>
group.path !== undefined && page.url_path.startsWith(group.path)
);
if (!matchingGroup) {
const newGroup: NavGroup = {
name: capitalize(urlParts[level]),
path: urlParts.slice(0, level + 1).join('/'),
level,
children: [],
};
currArray.push(newGroup);
currArray = newGroup.children;
} else {
currArray = matchingGroup.children;
}
}
}
}
function isNavGroup(item: NavItem | NavGroup): item is NavGroup {
return (item as NavGroup).children !== undefined;
}