feat: toc for blog post

This commit is contained in:
Timothy Lin 2021-08-06 22:13:30 +08:00
parent 304318376c
commit afbc2d9c66
7 changed files with 52 additions and 1 deletions

View File

@ -3,10 +3,12 @@ import { useMemo } from 'react'
import { getMDXComponent } from 'mdx-bundler/client'
import Image from './Image'
import CustomLink from './Link'
import TOCInline from './TOCInline'
import Pre from './Pre'
export const MDXComponents = {
Image,
TOCInline,
a: CustomLink,
pre: Pre,
wrapper: ({ components, layout, ...rest }) => {

18
components/TOCInline.js Normal file
View File

@ -0,0 +1,18 @@
const TOCInline = ({ toc, indentDepth = 3 }) => {
return (
<details open>
<summary className="pt-2 pb-2 ml-6 text-xl font-bold">Table of Contents</summary>
<div className="ml-6">
<ul>
{toc.map((heading) => (
<li key={heading.value} className={`${heading.depth >= indentDepth && 'ml-6'}`}>
<a href={heading.url}>{heading.value}</a>
</li>
))}
</ul>
</div>
</details>
)
}
export default TOCInline

View File

@ -7,6 +7,8 @@ summary: 'An overview of the new features released in v1 - code block copy, mult
layout: PostSimple
---
<TOCInline toc={props.toc} />
## Overview
A post on the new features introduced in v1.0. New features:

View File

@ -5,6 +5,7 @@ import path from 'path'
import readingTime from 'reading-time'
import visit from 'unist-util-visit'
import codeTitles from './remark-code-title'
import remarkTocHeadings from './remark-toc-headings'
import imgToJsx from './img-to-jsx'
import getAllFilesRecursively from './utils/files'
@ -66,6 +67,8 @@ export async function getFileBySlug(type, slug) {
)
}
let toc = []
const { frontmatter, code } = await bundleMDX(source, {
// mdx imports can be automatically source from the components directory
cwd: path.join(process.cwd(), 'components'),
@ -77,6 +80,7 @@ export async function getFileBySlug(type, slug) {
...(options.remarkPlugins ?? []),
require('remark-slug'),
require('remark-autolink-headings'),
[remarkTocHeadings, { exportRef: toc }],
require('remark-gfm'),
codeTitles,
[require('remark-footnotes'), { inlineNotes: true }],
@ -111,6 +115,7 @@ export async function getFileBySlug(type, slug) {
return {
mdxSource: code,
toc,
frontMatter: {
readingTime: readingTime(code),
slug: slug || null,

View File

@ -0,0 +1,12 @@
import visit from 'unist-util-visit'
module.exports = function (options) {
return (tree) =>
visit(tree, 'heading', (node, index, parent) => {
options.exportRef.push({
value: node.children[1].value,
url: node.children[0].url,
depth: node.depth,
})
})
}

View File

@ -39,13 +39,14 @@ export async function getStaticProps({ params }) {
}
export default function Blog({ post, authorDetails, prev, next }) {
const { mdxSource, frontMatter } = post
const { mdxSource, toc, frontMatter } = post
return (
<>
{frontMatter.draft !== true ? (
<MDXLayoutRenderer
layout={frontMatter.layout || DEFAULT_LAYOUT}
toc={toc}
mdxSource={mdxSource}
frontMatter={frontMatter}
authorDetails={authorDetails}

View File

@ -74,6 +74,14 @@ module.exports = {
'code:after': {
content: 'none',
},
details: {
backgroundColor: theme('colors.gray.100'),
paddingLeft: '4px',
paddingRight: '4px',
paddingTop: '2px',
paddingBottom: '2px',
borderRadius: '0.25rem',
},
hr: { borderColor: theme('colors.gray.200') },
'ol li:before': {
fontWeight: '600',
@ -119,6 +127,9 @@ module.exports = {
code: {
backgroundColor: theme('colors.gray.800'),
},
details: {
backgroundColor: theme('colors.gray.800'),
},
hr: { borderColor: theme('colors.gray.700') },
'ol li:before': {
fontWeight: '600',