diff --git a/gatsby-config.js b/gatsby-config.js index 873736a..288df0b 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -73,12 +73,6 @@ module.exports = { }, }, `gatsby-transformer-sharp`, - { - resolve: "gatsby-plugin-anchor-links", - options: { - offset: -100, - }, - }, `gatsby-plugin-react-svg`, `gatsby-plugin-remove-trailing-slashes`, `gatsby-plugin-sharp`, diff --git a/package-lock.json b/package-lock.json index 2408a9e..431336c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3753,6 +3753,15 @@ "@types/react": "*" } }, + "@types/react-scrollspy": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@types/react-scrollspy/-/react-scrollspy-3.3.2.tgz", + "integrity": "sha512-nbCB4wg2AhsFWKZ0LnMqGZWWC+6fNOC4USCzvBC++YST7tLMGvQKLVdWCQHec5/HzSlrSD4UfnYYVcuSYIhvmg==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/rimraf": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-2.0.4.tgz", @@ -10151,14 +10160,6 @@ } } }, - "gatsby-plugin-anchor-links": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/gatsby-plugin-anchor-links/-/gatsby-plugin-anchor-links-1.1.1.tgz", - "integrity": "sha512-mgSHUAEa7RRWD/lcmJVUWD9mIT14EIJvMPcxJ1W2Ev+rNuqBBpk1j4vDWy1uxas+qusi0vrtZ4HdU7mse12qDw==", - "requires": { - "scroll-to-element": "^2.0.3" - } - }, "gatsby-plugin-google-fonts": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gatsby-plugin-google-fonts/-/gatsby-plugin-google-fonts-1.0.1.tgz", @@ -17348,14 +17349,6 @@ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==" }, - "raf": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", - "requires": { - "performance-now": "^2.1.0" - } - }, "ramda": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.0.tgz", @@ -17734,6 +17727,16 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.7.2.tgz", "integrity": "sha512-u5l7fhAJXecWUJzVxzMRU2Zvw8m4QmDNHlTrT5uo3KBlYBhmChd7syAakBoay1yIiVhx/8Fi7a6v6kQZfsw81Q==" }, + "react-scrollspy": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/react-scrollspy/-/react-scrollspy-3.4.2.tgz", + "integrity": "sha512-mFev6IBPPGdn0WsAiS0eCoHGUUet0ZRZUHHUw3qLcsvsQZPlubik0N9cf8CcgIbdVzNd04K9L9A0inHhPt7drw==", + "requires": { + "babel-runtime": "^6.26.0", + "classnames": "^2.2.5", + "prop-types": "^15.5.10" + } + }, "react-side-effect": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.0.tgz", @@ -18716,14 +18719,6 @@ "invariant": "^2.2.4" } }, - "scroll-to-element": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/scroll-to-element/-/scroll-to-element-2.0.3.tgz", - "integrity": "sha512-5herPcm9jMfQgRwu94lH5mei+2YhipR4RQ2nAvnBxJb2tG+P7O0ctOKAaAZBXbBejnn+MImh3wrAUA5EcLnjEQ==", - "requires": { - "raf": "^3.4.0" - } - }, "scuid": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/scuid/-/scuid-1.1.0.tgz", diff --git a/package.json b/package.json index 64b1539..dd1a756 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,6 @@ "@reach/router": "^1.3.3", "classnames": "^2.2.6", "gatsby": "^2.22.11", - "gatsby-plugin-anchor-links": "^1.1.1", "gatsby-plugin-google-fonts": "^1.0.1", "gatsby-plugin-layout": "^1.3.2", "gatsby-plugin-manifest": "^2.4.9", @@ -57,6 +56,7 @@ "react-highlight": "^0.12.0", "react-particles-js": "^3.2.1", "react-perfect-scrollbar": "^1.5.8", + "react-scrollspy": "^3.4.2", "styled-components": "^5.1.1", "typescript": "^3.9.3" }, @@ -72,6 +72,7 @@ "@types/react": "^16.9.35", "@types/react-dom": "^16.9.8", "@types/react-helmet": "^6.0.0", + "@types/react-scrollspy": "^3.3.2", "@types/styled-components": "^5.1.0", "babel-plugin-polished": "^1.1.0", "babel-plugin-styled-components": "^1.10.7", diff --git a/src/components/PageSidebarLink/index.tsx b/src/components/PageSidebarLink/index.tsx index ad49c3e..619abe2 100644 --- a/src/components/PageSidebarLink/index.tsx +++ b/src/components/PageSidebarLink/index.tsx @@ -16,7 +16,7 @@ export const PageSidebarLink: FC = ({ type = "internal", }) => { if (type === "anchor") { - return {text} + return {text} } if (type === "external") { diff --git a/src/components/PageSidebarLink/styles.tsx b/src/components/PageSidebarLink/styles.tsx index 7d2ead0..13b816e 100644 --- a/src/components/PageSidebarLink/styles.tsx +++ b/src/components/PageSidebarLink/styles.tsx @@ -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}; ` diff --git a/src/components/Toc/index.tsx b/src/components/Toc/index.tsx index f1dff38..0b5fb47 100644 --- a/src/components/Toc/index.tsx +++ b/src/components/Toc/index.tsx @@ -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 = ({ header, items }) => { - const windowGlobal = typeof window !== "undefined" && window + const [scrollSpyCache, setScrollSpyCache] = React.useState() - // window is not available on build - if (!windowGlobal) { - return null - } - - const { pathname } = windowGlobal.location return ( {header} - {items.map((item) => { - const { prefix, title } = extractTitle(item.title) + 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 ( - - {prefix} - - - ) - })} + return ( + + {prefix} + + + ) + })} + ) } diff --git a/src/components/Toc/styles.tsx b/src/components/Toc/styles.tsx index 69ea637..562ceaf 100644 --- a/src/components/Toc/styles.tsx +++ b/src/components/Toc/styles.tsx @@ -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; } `