feat: implement scrollspy

This commit is contained in:
Jean-Philippe Sirois
2020-05-28 00:43:23 -04:00
parent 8edb4358f9
commit d1c375ecf1
7 changed files with 78 additions and 59 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ export const PageSidebarLink: FC<IPageSidebarLinkProps> = ({
type = "internal",
}) => {
if (type === "anchor") {
return <SC.Anchor to={href}>{text}</SC.Anchor>
return <SC.Anchor href={href}>{text}</SC.Anchor>
}
if (type === "external") {
+1 -2
View File
@@ -1,4 +1,3 @@
import { AnchorLink } from "gatsby-plugin-anchor-links"
import styled, { css } from "styled-components"
import { Link } from "gatsby"
@@ -13,7 +12,7 @@ const extraLink = css`
}
`
export const Anchor = styled(AnchorLink)`
export const Anchor = styled.a`
${extraLink};
`
+31 -20
View File
@@ -1,4 +1,6 @@
import cx from "classnames"
import React, { FC } from "react"
import Scrollspy from "react-scrollspy"
import { PageSidebarLink } from "../PageSidebarLink"
import { ITocItem } from "../../types"
import * as SC from "./styles"
@@ -24,31 +26,40 @@ function extractTitle(title: string): ITitle {
}
export const Toc: FC<ITocProps> = ({ header, items }) => {
const windowGlobal = typeof window !== "undefined" && window
const [scrollSpyCache, setScrollSpyCache] = React.useState<string>()
// window is not available on build
if (!windowGlobal) {
return null
}
const { pathname } = windowGlobal.location
return (
<SC.TocWrapper>
{header}
{items.map((item) => {
const { prefix, title } = extractTitle(item.title)
<Scrollspy
items={items.map((item) => item.link.substring(1))}
currentClassName="scrollspy-current"
scrolledPastClassName="scrollspy-past"
componentTag={SC.ScrollspyWrapper}
onUpdate={(updatedElement: HTMLDivElement) => {
// @ts-ignore
const id = updatedElement?.id
if (id) {
setScrollSpyCache(id)
}
}}
>
{items.map((item) => {
const { prefix, title } = extractTitle(item.title)
return (
<SC.TocItem key={item.link} className={`depth-${item.depth}`}>
{prefix}
<PageSidebarLink
href={`${pathname}${item.link}`}
text={title}
type="anchor"
/>
</SC.TocItem>
)
})}
return (
<SC.TocItem
key={item.link}
className={cx(`depth-${item.depth}`, {
"scrollspy-cached": scrollSpyCache === item.link.substring(1),
})}
>
{prefix}
<PageSidebarLink href={item.link} text={title} type="anchor" />
</SC.TocItem>
)
})}
</Scrollspy>
</SC.TocWrapper>
)
}
+24 -5
View File
@@ -5,15 +5,34 @@ export const TocWrapper = styled.div`
flex-direction: column;
`
export const ScrollspyWrapper = styled.div`
display: flex;
flex-direction: column;
`
export const TocItem = styled.div`
display: inline-block;
&.depth-3 {
margin-left: 8px;
&.scrollspy-current,
&.scrollspy-cached {
position: relative;
text-shadow: 0 0 0.65px ${(props) => props.theme.main.foreground},
0 0 0.65px ${(props) => props.theme.main.foreground};
&::after {
position: absolute;
top: 0;
left: -16px;
content: "";
display: block;
background: ${(props) => props.theme.main.foreground};
width: 2px;
height: 100%;
}
}
&.depth-2 + &.depth-2,
&.depth-3 + &.depth-2 {
margin-top: 8px;
&.depth-2,
&.depth-3 {
padding: 4px 0;
}
`