[#809,docs,navigation][xl]: initial commit
This commit is contained in:
@@ -4,15 +4,17 @@ import parse from '../lib/markdown.mjs';
|
||||
|
||||
import MDXPage from '../components/MDXPage';
|
||||
import clientPromise from '@/lib/mddb';
|
||||
import { getAuthorsDetails } from 'lib/getAuthorsDetails';
|
||||
import Layout from 'components/Layout';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router.js';
|
||||
import { collectHeadings } from '@flowershow/core';
|
||||
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 DRDPage({ source, frontMatter }) {
|
||||
export default function DRDPage({ source, meta, siteMap }) {
|
||||
source = JSON.parse(source);
|
||||
frontMatter = JSON.parse(frontMatter);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
@@ -27,53 +29,73 @@ export default function DRDPage({ source, frontMatter }) {
|
||||
}, [router.asPath]); // update table of contents on route change with next/link
|
||||
|
||||
return (
|
||||
<Layout tableOfContents={tableOfContents} title={frontMatter.title}>
|
||||
<MDXPage source={source} frontMatter={frontMatter} />
|
||||
<Layout
|
||||
tableOfContents={tableOfContents}
|
||||
title={meta.title}
|
||||
siteMap={siteMap}
|
||||
>
|
||||
<MDXPage source={source} frontMatter={meta} />
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
export const getStaticProps = async ({ params }) => {
|
||||
const urlPath = params.slug ? params.slug.join('/') : '';
|
||||
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 dbBacklinks = await mddb.getLinks({
|
||||
fileId: dbFile._id,
|
||||
direction: 'backward',
|
||||
});
|
||||
// TODO temporary solution, we will have a method on MddbFile to get these links
|
||||
const dbBacklinkFilesPromises = dbBacklinks.map((link) =>
|
||||
mddb.getFileById(link.from)
|
||||
);
|
||||
const dbBacklinkFiles = await Promise.all(dbBacklinkFilesPromises);
|
||||
const dbBacklinkUrls = dbBacklinkFiles.map(
|
||||
(file) => file.toObject().url_path
|
||||
);
|
||||
|
||||
// TODO we can already get frontmatter from dbFile.metadata
|
||||
// so parse could only return mdxSource
|
||||
const source = fs.readFileSync(dbFile.file_path, { encoding: 'utf-8' });
|
||||
const { mdxSource, frontMatter } = await parse(source, 'mdx', {
|
||||
backlinks: dbBacklinkUrls,
|
||||
});
|
||||
const filePath = dbFile!.file_path;
|
||||
const frontMatter = dbFile!.metadata ?? {};
|
||||
|
||||
// Temporary, so that blogs work properly
|
||||
if (
|
||||
dbFile.url_path.startsWith('blog/') ||
|
||||
(dbFile.url_path.startsWith('docs/') && dbFile.metadata.filetype === 'blog')
|
||||
) {
|
||||
if (dbFile.metadata.filetype === 'blog') {
|
||||
frontMatter.layout = 'blog';
|
||||
frontMatter.authorsDetails = await getAuthorsDetails(
|
||||
dbFile.metadata.authors
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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),
|
||||
frontMatter: JSON.stringify(frontMatter),
|
||||
meta: frontMatterWithComputedFields,
|
||||
siteMap: sidebarTree,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -82,18 +104,70 @@ export async function getStaticPaths() {
|
||||
const mddb = await clientPromise;
|
||||
let allDocuments = await mddb.getFiles({ extensions: ['md', 'mdx'] });
|
||||
|
||||
// Avoid duplicate path
|
||||
allDocuments = allDocuments.filter(
|
||||
(doc) => !doc.url_path.startsWith('data-literate/')
|
||||
);
|
||||
|
||||
const paths = allDocuments.map((page) => {
|
||||
const parts = page.url_path.split('/');
|
||||
return { params: { slug: parts } };
|
||||
});
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -5,11 +5,25 @@ import Script from "next/script";
|
||||
|
||||
import { DefaultSeo } from "next-seo";
|
||||
|
||||
import { pageview, ThemeProvider } from "@flowershow/core";
|
||||
import { NavGroup, NavItem, pageview, ThemeProvider } from "@flowershow/core";
|
||||
import { siteConfig } from "../config/siteConfig";
|
||||
import { useEffect } from "react";
|
||||
import { useRouter } from "next/dist/client/router";
|
||||
|
||||
export interface CustomAppProps {
|
||||
meta: {
|
||||
showToc: boolean;
|
||||
showEditLink: boolean;
|
||||
showSidebar: boolean;
|
||||
showComments: boolean;
|
||||
urlPath: string; // not sure what's this for
|
||||
editUrl?: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
siteMap?: Array<NavItem | NavGroup>;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
const router = useRouter();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user