Browse Source

[Beta] Move MDX Preprocessing (#4976)

main
dan 3 years ago
committed by GitHub
parent
commit
42561f013a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 100
      beta/src/components/Layout/MarkdownPage.tsx
  2. 103
      beta/src/pages/_app.tsx

100
beta/src/components/Layout/MarkdownPage.tsx

@ -11,110 +11,28 @@ import {Seo} from 'components/Seo';
import PageHeading from 'components/PageHeading';
import {useRouteMeta} from './useRouteMeta';
import {Toc} from './Toc';
export interface MarkdownProps<Frontmatter> {
meta: Frontmatter & {description?: string};
children?: React.ReactNode;
}
function MaxWidth({children}: {children: any}) {
return <div className="max-w-4xl ml-0 2xl:mx-auto">{children}</div>;
toc: Array<{
url: string;
text: React.ReactNode;
depth: number;
}>;
}
export function MarkdownPage<
T extends {title: string; status?: string} = {title: string; status?: string}
>({children, meta}: MarkdownProps<T>) {
>({children, meta, toc}: MarkdownProps<T>) {
const {route, nextRoute, prevRoute} = useRouteMeta();
const title = meta.title || route?.title || '';
const description = meta.description || route?.description || '';
let anchors: Array<{
url: string;
text: React.ReactNode;
depth: number;
}> = React.Children.toArray(children)
.filter((child: any) => {
if (child.props?.mdxType) {
return ['h1', 'h2', 'h3', 'Challenges', 'Recap'].includes(
child.props.mdxType
);
}
return false;
})
.map((child: any) => {
if (child.props.mdxType === 'Challenges') {
return {
url: '#challenges',
depth: 0,
text: 'Challenges',
};
}
if (child.props.mdxType === 'Recap') {
return {
url: '#recap',
depth: 0,
text: 'Recap',
};
}
return {
url: '#' + child.props.id,
depth:
(child.props?.mdxType &&
parseInt(child.props.mdxType.replace('h', ''), 0)) ??
0,
text: child.props.children,
};
});
if (anchors.length > 0) {
anchors.unshift({
depth: 1,
text: 'Overview',
url: '#',
});
}
if (!route) {
console.error('This page was not added to one of the sidebar JSON files.');
}
const isHomePage = route?.path === '/';
// Auto-wrap everything except a few types into
// <MaxWidth> wrappers. Keep reusing the same
// wrapper as long as we can until we meet
// a full-width section which interrupts it.
let fullWidthTypes = [
'Sandpack',
'FullWidth',
'Illustration',
'IllustrationBlock',
'Challenges',
'Recipes',
];
let wrapQueue: React.ReactNode[] = [];
let finalChildren: React.ReactNode[] = [];
function flushWrapper(key: string | number) {
if (wrapQueue.length > 0) {
finalChildren.push(<MaxWidth key={key}>{wrapQueue}</MaxWidth>);
wrapQueue = [];
}
}
function handleChild(child: any, key: string | number) {
if (child == null) {
return;
}
if (typeof child !== 'object') {
wrapQueue.push(child);
return;
}
if (fullWidthTypes.includes(child.props.mdxType)) {
flushWrapper(key);
finalChildren.push(child);
} else {
wrapQueue.push(child);
}
}
React.Children.forEach(children, handleChild);
flushWrapper('last');
return (
<>
<div className="lg:pt-0 pt-20 pl-0 lg:pl-80 2xl:px-80 ">
@ -129,7 +47,7 @@ export function MarkdownPage<
<div className="px-5 sm:px-12">
<div className="max-w-7xl mx-auto">
<MDXContext.Provider value={MDXComponents}>
{finalChildren}
{children}
</MDXContext.Provider>
</div>
<DocsPageFooter
@ -140,7 +58,7 @@ export function MarkdownPage<
</div>
</div>
<div className="w-full lg:max-w-xs hidden 2xl:block">
{!isHomePage && anchors.length > 0 && <Toc headings={anchors} />}
{!isHomePage && toc.length > 0 && <Toc headings={toc} />}
</div>
</>
);

103
beta/src/pages/_app.tsx

@ -55,10 +55,111 @@ export default function MyApp({Component, pageProps}: AppProps) {
routeTree = sidebarLearn as RouteItem;
break;
}
const rawChildren = mdxContent.props.children;
const toc = getTableOfContents(rawChildren);
const children = wrapChildrenInMaxWidthContainers(rawChildren);
content = (
<MarkdownPage meta={meta}>{mdxContent.props.children}</MarkdownPage>
<MarkdownPage toc={toc} meta={meta}>
{children}
</MarkdownPage>
);
}
return <Page routeTree={routeTree}>{content}</Page>;
}
function MaxWidth({children}: {children: any}) {
return <div className="max-w-4xl ml-0 2xl:mx-auto">{children}</div>;
}
function wrapChildrenInMaxWidthContainers(
children: React.ReactNode
): React.ReactNode {
// Auto-wrap everything except a few types into
// <MaxWidth> wrappers. Keep reusing the same
// wrapper as long as we can until we meet
// a full-width section which interrupts it.
let fullWidthTypes = [
'Sandpack',
'FullWidth',
'Illustration',
'IllustrationBlock',
'Challenges',
'Recipes',
];
let wrapQueue: React.ReactNode[] = [];
let finalChildren: React.ReactNode[] = [];
function flushWrapper(key: string | number) {
if (wrapQueue.length > 0) {
finalChildren.push(<MaxWidth key={key}>{wrapQueue}</MaxWidth>);
wrapQueue = [];
}
}
function handleChild(child: any, key: string | number) {
if (child == null) {
return;
}
if (typeof child !== 'object') {
wrapQueue.push(child);
return;
}
if (fullWidthTypes.includes(child.props.mdxType)) {
flushWrapper(key);
finalChildren.push(child);
} else {
wrapQueue.push(child);
}
}
React.Children.forEach(children, handleChild);
flushWrapper('last');
return finalChildren;
}
function getTableOfContents(children: React.ReactNode): Array<{
url: string;
text: React.ReactNode;
depth: number;
}> {
const anchors = React.Children.toArray(children)
.filter((child: any) => {
if (child.props?.mdxType) {
return ['h1', 'h2', 'h3', 'Challenges', 'Recap'].includes(
child.props.mdxType
);
}
return false;
})
.map((child: any) => {
if (child.props.mdxType === 'Challenges') {
return {
url: '#challenges',
depth: 0,
text: 'Challenges',
};
}
if (child.props.mdxType === 'Recap') {
return {
url: '#recap',
depth: 0,
text: 'Recap',
};
}
return {
url: '#' + child.props.id,
depth:
(child.props?.mdxType &&
parseInt(child.props.mdxType.replace('h', ''), 0)) ??
0,
text: child.props.children,
};
});
if (anchors.length > 0) {
anchors.unshift({
depth: 1,
text: 'Overview',
url: '#',
});
}
return anchors;
}

Loading…
Cancel
Save