beta/src/components/Layout/LayoutPost.tsx (100 lines of code) (raw):
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
// @ts-ignore
import {MDXContext} from '@mdx-js/react';
import recentPostsRouteTree from 'blogIndexRecent.json';
import {DocsPageFooter} from 'components/DocsFooter';
import {ExternalLink} from 'components/ExternalLink';
import {MDXComponents} from 'components/MDX/MDXComponents';
import {Seo} from 'components/Seo';
import {Toc} from 'components/Layout/Toc';
import format from 'date-fns/format';
import {useRouter} from 'next/router';
import * as React from 'react';
import {getAuthor} from 'utils/getAuthor';
import toCommaSeparatedList from 'utils/toCommaSeparatedList';
import {Page} from './Page';
import {RouteItem, useRouteMeta} from './useRouteMeta';
import {useTwitter} from './useTwitter';
interface PageFrontmatter {
id?: string;
title: string;
author: string[];
date?: string;
}
interface LayoutPostProps {
/** Sidebar/Nav */
routes: RouteItem[];
/** Markdown frontmatter */
meta: PageFrontmatter;
/** The mdx */
children: React.ReactNode;
}
/** Return the date of the current post given the path */
function getDateFromPath(path: string) {
// All paths are /blog/year/month/day/title
const [year, month, day] = path
.substr(1) // first `/`
.split('/') // make an array
.slice(1) // ignore blog
.map((i) => parseInt(i, 10)); // convert to numbers
return {
date: format(new Date(year, month, day), 'MMMM dd, yyyy'),
dateTime: [year, month, day].join('-'),
};
}
function LayoutPost({meta, children}: LayoutPostProps) {
const {pathname} = useRouter();
const {date, dateTime} = getDateFromPath(pathname);
const {route, nextRoute, prevRoute} = useRouteMeta();
const anchors = React.Children.toArray(children)
.filter(
(child: any) =>
child.props?.mdxType && ['h2', 'h3'].includes(child.props.mdxType)
)
.map((child: any) => ({
url: '#' + child.props.id,
depth: parseInt(child.props.mdxType.replace('h', ''), 0),
text: child.props.children,
}));
useTwitter();
return (
<>
<div className="w-full px-12">
<div className="h-full mx-auto max-w-4xl relative pt-16 w-full overflow-x-hidden">
<Seo title={meta.title} />
<h1 className="mb-6 pt-8 text-4xl md:text-5xl font-bold leading-snug tracking-tight text-primary dark:text-primary-dark">
{meta.title}
</h1>
<p className="mb-6 text-lgtext-secondary dark:text-secondary-dark">
By{' '}
{toCommaSeparatedList(meta.author, (author) => (
<ExternalLink
href={getAuthor(author).url}
className="text-link dark:text-link-dark underline font-bold">
{getAuthor(author).name}
</ExternalLink>
))}
<span className="mx-2">·</span>
<span className="lead inline-flex text-gray-50">
<time dateTime={dateTime}>{date}</time>
</span>
</p>
<MDXContext.Provider value={MDXComponents}>
{children}
</MDXContext.Provider>
<DocsPageFooter
route={route}
nextRoute={nextRoute}
prevRoute={prevRoute}
/>
</div>
</div>
<div className="w-full lg:max-w-xs h-full hidden 2xl:block">
<Toc headings={anchors} />
</div>
</>
);
}
function AppShell(props: {children: React.ReactNode}) {
return <Page routeTree={recentPostsRouteTree as RouteItem} {...props} />;
}
export default function withLayoutPost(meta: any) {
function LayoutPostWrapper(props: LayoutPostProps) {
return <LayoutPost {...props} meta={meta} />;
}
LayoutPostWrapper.appShell = AppShell;
return LayoutPostWrapper;
}