mirror of
https://github.com/Stone-Red-Code/website.git
synced 2026-09-06 23:43:45 +02:00
Merge pull request #276 from the-programmers-hangout/feat-resources-scrollspy
feat: implement scrollspy
This commit is contained in:
@@ -73,12 +73,6 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
`gatsby-transformer-sharp`,
|
`gatsby-transformer-sharp`,
|
||||||
{
|
|
||||||
resolve: "gatsby-plugin-anchor-links",
|
|
||||||
options: {
|
|
||||||
offset: -100,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
`gatsby-plugin-react-svg`,
|
`gatsby-plugin-react-svg`,
|
||||||
`gatsby-plugin-remove-trailing-slashes`,
|
`gatsby-plugin-remove-trailing-slashes`,
|
||||||
`gatsby-plugin-sharp`,
|
`gatsby-plugin-sharp`,
|
||||||
|
|||||||
Generated
+19
-24
@@ -3753,6 +3753,15 @@
|
|||||||
"@types/react": "*"
|
"@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": {
|
"@types/rimraf": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-2.0.4.tgz",
|
"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": {
|
"gatsby-plugin-google-fonts": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/gatsby-plugin-google-fonts/-/gatsby-plugin-google-fonts-1.0.1.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
|
||||||
"integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA=="
|
"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": {
|
"ramda": {
|
||||||
"version": "0.27.0",
|
"version": "0.27.0",
|
||||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.7.2.tgz",
|
||||||
"integrity": "sha512-u5l7fhAJXecWUJzVxzMRU2Zvw8m4QmDNHlTrT5uo3KBlYBhmChd7syAakBoay1yIiVhx/8Fi7a6v6kQZfsw81Q=="
|
"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": {
|
"react-side-effect": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.0.tgz",
|
||||||
@@ -18716,14 +18719,6 @@
|
|||||||
"invariant": "^2.2.4"
|
"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": {
|
"scuid": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/scuid/-/scuid-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/scuid/-/scuid-1.1.0.tgz",
|
||||||
|
|||||||
+2
-1
@@ -33,7 +33,6 @@
|
|||||||
"@reach/router": "^1.3.3",
|
"@reach/router": "^1.3.3",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"gatsby": "^2.22.11",
|
"gatsby": "^2.22.11",
|
||||||
"gatsby-plugin-anchor-links": "^1.1.1",
|
|
||||||
"gatsby-plugin-google-fonts": "^1.0.1",
|
"gatsby-plugin-google-fonts": "^1.0.1",
|
||||||
"gatsby-plugin-layout": "^1.3.2",
|
"gatsby-plugin-layout": "^1.3.2",
|
||||||
"gatsby-plugin-manifest": "^2.4.9",
|
"gatsby-plugin-manifest": "^2.4.9",
|
||||||
@@ -57,6 +56,7 @@
|
|||||||
"react-highlight": "^0.12.0",
|
"react-highlight": "^0.12.0",
|
||||||
"react-particles-js": "^3.2.1",
|
"react-particles-js": "^3.2.1",
|
||||||
"react-perfect-scrollbar": "^1.5.8",
|
"react-perfect-scrollbar": "^1.5.8",
|
||||||
|
"react-scrollspy": "^3.4.2",
|
||||||
"styled-components": "^5.1.1",
|
"styled-components": "^5.1.1",
|
||||||
"typescript": "^3.9.3"
|
"typescript": "^3.9.3"
|
||||||
},
|
},
|
||||||
@@ -72,6 +72,7 @@
|
|||||||
"@types/react": "^16.9.35",
|
"@types/react": "^16.9.35",
|
||||||
"@types/react-dom": "^16.9.8",
|
"@types/react-dom": "^16.9.8",
|
||||||
"@types/react-helmet": "^6.0.0",
|
"@types/react-helmet": "^6.0.0",
|
||||||
|
"@types/react-scrollspy": "^3.3.2",
|
||||||
"@types/styled-components": "^5.1.0",
|
"@types/styled-components": "^5.1.0",
|
||||||
"babel-plugin-polished": "^1.1.0",
|
"babel-plugin-polished": "^1.1.0",
|
||||||
"babel-plugin-styled-components": "^1.10.7",
|
"babel-plugin-styled-components": "^1.10.7",
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const PageSidebarLink: FC<IPageSidebarLinkProps> = ({
|
|||||||
type = "internal",
|
type = "internal",
|
||||||
}) => {
|
}) => {
|
||||||
if (type === "anchor") {
|
if (type === "anchor") {
|
||||||
return <SC.Anchor to={href}>{text}</SC.Anchor>
|
return <SC.Anchor href={href}>{text}</SC.Anchor>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === "external") {
|
if (type === "external") {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { AnchorLink } from "gatsby-plugin-anchor-links"
|
|
||||||
import styled, { css } from "styled-components"
|
import styled, { css } from "styled-components"
|
||||||
import { Link } from "gatsby"
|
import { Link } from "gatsby"
|
||||||
|
|
||||||
@@ -13,7 +12,7 @@ const extraLink = css`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export const Anchor = styled(AnchorLink)`
|
export const Anchor = styled.a`
|
||||||
${extraLink};
|
${extraLink};
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
import cx from "classnames"
|
||||||
import React, { FC } from "react"
|
import React, { FC } from "react"
|
||||||
|
import Scrollspy from "react-scrollspy"
|
||||||
import { PageSidebarLink } from "../PageSidebarLink"
|
import { PageSidebarLink } from "../PageSidebarLink"
|
||||||
import { ITocItem } from "../../types"
|
import { ITocItem } from "../../types"
|
||||||
import * as SC from "./styles"
|
import * as SC from "./styles"
|
||||||
@@ -24,31 +26,40 @@ function extractTitle(title: string): ITitle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Toc: FC<ITocProps> = ({ header, items }) => {
|
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 (
|
return (
|
||||||
<SC.TocWrapper>
|
<SC.TocWrapper>
|
||||||
{header}
|
{header}
|
||||||
{items.map((item) => {
|
<Scrollspy
|
||||||
const { prefix, title } = extractTitle(item.title)
|
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 (
|
return (
|
||||||
<SC.TocItem key={item.link} className={`depth-${item.depth}`}>
|
<SC.TocItem
|
||||||
{prefix}
|
key={item.link}
|
||||||
<PageSidebarLink
|
className={cx(`depth-${item.depth}`, {
|
||||||
href={`${pathname}${item.link}`}
|
"scrollspy-cached": scrollSpyCache === item.link.substring(1),
|
||||||
text={title}
|
})}
|
||||||
type="anchor"
|
>
|
||||||
/>
|
{prefix}
|
||||||
</SC.TocItem>
|
<PageSidebarLink href={item.link} text={title} type="anchor" />
|
||||||
)
|
</SC.TocItem>
|
||||||
})}
|
)
|
||||||
|
})}
|
||||||
|
</Scrollspy>
|
||||||
</SC.TocWrapper>
|
</SC.TocWrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,15 +5,34 @@ export const TocWrapper = styled.div`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const ScrollspyWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`
|
||||||
|
|
||||||
export const TocItem = styled.div`
|
export const TocItem = styled.div`
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
||||||
&.depth-3 {
|
&.scrollspy-current,
|
||||||
margin-left: 8px;
|
&.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-2,
|
||||||
&.depth-3 + &.depth-2 {
|
&.depth-3 {
|
||||||
margin-top: 8px;
|
padding: 4px 0;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|||||||
Reference in New Issue
Block a user