feat: implement table of contents

This commit is contained in:
Jean-Philippe Sirois
2020-05-12 00:05:17 -04:00
parent 465d026392
commit b17527cd6c
12 changed files with 194 additions and 14 deletions
+12 -1
View File
@@ -1,11 +1,14 @@
import React, { FC, Fragment } from "react"
import { ITocItem } from "../../types"
import { humanize } from "../../utils"
import * as SC from "./styles"
import { Container } from "../Container"
import { Toc } from "../Toc"
import * as SC from "./styles"
interface IPageContentProps {
content: JSX.Element
toc?: ITocItem[]
recommendedReading?: string[]
externalResources?: string[]
}
@@ -42,6 +45,7 @@ function ExtraLink({
export const PageContent: FC<IPageContentProps> = ({
content,
toc = [],
recommendedReading,
externalResources,
}) => {
@@ -52,6 +56,13 @@ export const PageContent: FC<IPageContentProps> = ({
</SC.Content>
<SC.Sidebar>
{toc.length > 0 && (
<Toc
header={<SC.SidebarHeader>Table of Contents</SC.SidebarHeader>}
items={toc}
/>
)}
{recommendedReading && (
<SC.RecommendedReading>
<SC.SidebarHeader>Recommended reading</SC.SidebarHeader>
+7 -1
View File
@@ -21,6 +21,8 @@ export const Sidebar = styled.div`
color: ${props => (props.theme.name === "dark" ? "#f9f9f9" : "#172129")};
margin: 64px 0;
padding: 0 32px;
position: sticky;
top: 32px;
&:empty {
display: none;
@@ -50,7 +52,11 @@ export const SidebarHeader = styled.div`
`
const ExtraLinks = styled.div`
margin-top: 16px;
margin-top: 32px;
&:first-child {
margin-top: 0;
}
`
export const RecommendedReading = styled(ExtraLinks)``
+42
View File
@@ -0,0 +1,42 @@
import React, { FC } from "react"
import { ITocItem } from "../../types"
import * as SC from "./styles"
interface ITocProps {
header: React.ReactNode
items: ITocItem[]
}
interface ITitle {
prefix?: string
title: string
}
function extractTitle(title: string): ITitle {
const maybePrefix = title.match(/^(\w+\.)/)
const rest = maybePrefix ? title.replace(maybePrefix[0], "") : title
return {
prefix: maybePrefix ? maybePrefix[0] : undefined,
title: rest,
}
}
export const Toc: FC<ITocProps> = ({ header, items }) => {
const { pathname } = window.location
return (
<SC.TocWrapper>
{header}
{items.map(item => {
const { prefix, title } = extractTitle(item.title)
return (
<SC.TocItem key={item.link} className={`depth-${item.depth}`}>
{prefix}
<SC.TocLink to={`${pathname}${item.link}`}>{title}</SC.TocLink>
</SC.TocItem>
)
})}
</SC.TocWrapper>
)
}
+30
View File
@@ -0,0 +1,30 @@
import { AnchorLink } from "gatsby-plugin-anchor-links"
import styled from "styled-components"
export const TocWrapper = styled.div`
display: flex;
flex-direction: column;
`
export const TocItem = styled.div`
display: inline-block;
&.depth-3 {
margin-left: 8px;
}
&.depth-2 + &.depth-2,
&.depth-3 + &.depth-2 {
margin-top: 8px;
}
`
export const TocLink = styled(AnchorLink)`
color: ${props => props.theme.main.foreground};
text-decoration: none;
&:hover,
&:focus {
text-decoration: underline;
}
`