Commit 624d8405 authored by Sandro Lutz's avatar Sandro Lutz Committed by Sandro Lutz
Browse files

Add item highlighting on «How to Ersti» page

parent fdc3d3b0
...@@ -5369,14 +5369,6 @@ ...@@ -5369,14 +5369,6 @@
} }
} }
}, },
"animated-scroll-to": {
"version": "2.0.12",
"resolved": "https://registry.npmjs.org/animated-scroll-to/-/animated-scroll-to-2.0.12.tgz",
"integrity": "sha512-08TlNWa0Os38ShzScfrlV7c4w3QCZWUG+jhrx2ojMmI8apR8o3C1RwLxEaSKyu8RmcJvU89z3HcKObbAdHMHGQ==",
"requires": {
"@types/node": "^14.11.10"
}
},
"ansi-align": { "ansi-align": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz",
...@@ -18205,6 +18197,11 @@ ...@@ -18205,6 +18197,11 @@
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
"integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4="
}, },
"lodash.throttle": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
"integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
},
"lodash.toarray": { "lodash.toarray": {
"version": "4.4.0", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
...@@ -21971,6 +21968,15 @@ ...@@ -21971,6 +21968,15 @@
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
"integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==" "integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg=="
}, },
"react-scroll": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/react-scroll/-/react-scroll-1.8.1.tgz",
"integrity": "sha512-UAKmawFHn+c7x/DoXuHqOsQ5xwNk2Dxv7vP8Ft41K2hglPWkshcSos0tMTr8704UkFqImoUGzMTdN4vuZXoqbw==",
"requires": {
"lodash.throttle": "^4.1.1",
"prop-types": "^15.7.2"
}
},
"react-transition-group": { "react-transition-group": {
"version": "4.4.1", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
"@reach/router": "^1.3.4", "@reach/router": "^1.3.4",
"ajv": "^6.12.6", "ajv": "^6.12.6",
"amiv-react-components": "git+https://gitlab.ethz.ch/amiv/react-components.git#fc02eef7d6af30831310c21fc258e56218b023db", "amiv-react-components": "git+https://gitlab.ethz.ch/amiv/react-components.git#fc02eef7d6af30831310c21fc258e56218b023db",
"animated-scroll-to": "^2.0.12",
"axios": "^0.21.0", "axios": "^0.21.0",
"debounce": "^1.2.0", "debounce": "^1.2.0",
"filesize": "^6.1.0", "filesize": "^6.1.0",
...@@ -45,6 +44,7 @@ ...@@ -45,6 +44,7 @@
"react-helmet": "^6.1.0", "react-helmet": "^6.1.0",
"react-intl": "^5.10.6", "react-intl": "^5.10.6",
"react-redux": "^7.2.2", "react-redux": "^7.2.2",
"react-scroll": "^1.8.1",
"redux": "^4.0.5", "redux": "^4.0.5",
"redux-thunk": "^2.3.0", "redux-thunk": "^2.3.0",
"typeface-roboto": "1.1.13" "typeface-roboto": "1.1.13"
......
import { useState, useEffect, useRef } from 'react' import { useState, useEffect, useRef } from 'react'
import { useDispatch } from 'react-redux' import { useDispatch } from 'react-redux'
import animateScrollTo from 'animated-scroll-to' import { animateScroll } from 'react-scroll'
import { useIntl } from 'gatsby-plugin-intl' import { useIntl } from 'gatsby-plugin-intl'
import { useTheme } from '@material-ui/core' import { useTheme } from '@material-ui/core'
...@@ -68,10 +68,15 @@ const useFilteredList = ( ...@@ -68,10 +68,15 @@ const useFilteredList = (
useEffect(() => { useEffect(() => {
if (itemsReady && ref.current && shouldScroll) { if (itemsReady && ref.current && shouldScroll) {
setShouldScroll(false) setShouldScroll(false)
animateScrollTo(ref.current, { console.log(ref.current.offsetTop)
verticalOffset: -theme.shape.headerHeight, console.log(ref.current.getBoundingClientRect().top)
speed: 125, animateScroll.scrollTo(
}) ref.current.getBoundingClientRect().top - theme.shape.headerHeight,
{
duration: 250,
smooth: 'easeInOutQuint',
}
)
} }
}, [itemsReady, ref.current, shouldScroll]) }, [itemsReady, ref.current, shouldScroll])
......
import React from 'react' import React, { useState } from 'react'
import { useStaticQuery, graphql } from 'gatsby' import { useStaticQuery, graphql } from 'gatsby'
import { makeStyles } from '@material-ui/styles' import { makeStyles, useTheme } from '@material-ui/styles'
import { FormattedMessage } from 'gatsby-plugin-intl' import { FormattedMessage } from 'gatsby-plugin-intl'
import { Link } from 'react-scroll'
import Layout from '../../components/layout' import Layout from '../../components/layout'
import FilteredListLayout from '../../components/filteredListPage/layout' import FilteredListLayout from '../../components/filteredListPage/layout'
import TranslatedContent from '../../components/general/translatedContent' import TranslatedContent from '../../components/general/translatedContent'
import { rateLimit } from '../../utils'
const useStyles = makeStyles( const useStyles = makeStyles(
theme => ({ theme => ({
...@@ -48,10 +50,15 @@ const useStyles = makeStyles( ...@@ -48,10 +50,15 @@ const useStyles = makeStyles(
tableOfContentLinkItem: { tableOfContentLinkItem: {
color: theme.palette.text.primary, color: theme.palette.text.primary,
textDecoration: 'none', textDecoration: 'none',
cursor: 'pointer',
'&:hover': { '&:hover': {
color: theme.palette.secondary.main, color: theme.palette.secondary.main,
}, },
}, },
tableOfContentActiveLinkItem: {
color: theme.palette.secondary.main,
fontWeigth: 600,
},
tableOfContentMainLinkItem: { tableOfContentMainLinkItem: {
fontWeight: 600, fontWeight: 600,
}, },
...@@ -60,7 +67,9 @@ const useStyles = makeStyles( ...@@ -60,7 +67,9 @@ const useStyles = makeStyles(
) )
const HowToErstiPage = () => { const HowToErstiPage = () => {
const [activeMenuItem, setActiveMenuItem] = useState(undefined)
const classes = useStyles() const classes = useStyles()
const theme = useTheme()
const { const {
howToErstiJson: { nodes: howToErstiJsonNodes }, howToErstiJson: { nodes: howToErstiJsonNodes },
} = useStaticQuery( } = useStaticQuery(
...@@ -118,6 +127,54 @@ const HowToErstiPage = () => { ...@@ -118,6 +127,54 @@ const HowToErstiPage = () => {
const menuItems = [] const menuItems = []
const contentItems = [] const contentItems = []
const handleScroll = () => {
const windowScrollTop =
document.body.scrollTop || document.documentElement.scrollTop
const checkActiveState = slug => {
const element = document.getElementById(slug)
return (
element &&
windowScrollTop < element.offsetTop - element.offsetHeight / 2
)
}
const findActiveItem = (items, firstIteration) => {
let newActiveItem
items.forEach(item => {
if (newActiveItem) return
const slug = firstIteration ? item.data.slug : item.slug
const subitems = firstIteration ? item.data.subitems : item.subitems
if (checkActiveState(slug)) {
newActiveItem = slug
return
}
if (subitems) {
newActiveItem = findActiveItem(subitems, false)
}
})
return newActiveItem
}
const newActiveItem = findActiveItem(howToErstiJsonNodes, true)
setActiveMenuItem(newActiveItem)
}
const handleScrollRateLimited = rateLimit(handleScroll, 250)
React.useEffect(() => {
window.addEventListener('scroll', handleScrollRateLimited)
// cleanup this component
return () => {
window.removeEventListener('scroll', handleScroll)
}
}, [])
const createMenuItem = (hierarchyLevel, { title, slug, subitems }) => { const createMenuItem = (hierarchyLevel, { title, slug, subitems }) => {
if (!title) return undefined if (!title) return undefined
...@@ -125,17 +182,23 @@ const HowToErstiPage = () => { ...@@ -125,17 +182,23 @@ const HowToErstiPage = () => {
if (hierarchyLevel <= 2) { if (hierarchyLevel <= 2) {
classNames.push(classes.tableOfContentMainLinkItem) classNames.push(classes.tableOfContentMainLinkItem)
} }
if (activeMenuItem === slug) {
classNames.push(classes.tableOfContentActiveLinkItem)
}
return ( return (
<li> <li>
<TranslatedContent <TranslatedContent
content={title} content={title}
parseMarkdown={false} parseMarkdown={false}
component="a" component={Link}
noEscape noEscape
noHint noHint
className={classNames.join(' ')} className={classNames.join(' ')}
href={`#${slug}`} to={slug}
offset={-theme.shape.headerHeight - 120}
smooth={true}
duration={500}
/> />
{subitems && subitems.length > 0 && ( {subitems && subitems.length > 0 && (
<ul> <ul>
......
...@@ -37,11 +37,33 @@ const sleep = milliseconds => { ...@@ -37,11 +37,33 @@ const sleep = milliseconds => {
return new Promise(resolve => setTimeout(resolve, milliseconds)) return new Promise(resolve => setTimeout(resolve, milliseconds))
} }
const rateLimit = (func, wait) => {
let timeout
let lastCalled = 0
return function outer(...args) {
const context = this
const callFunc = () => {
timeout = null
lastCalled = Date.now()
func.apply(context, args)
}
const callNow = Date.now() - wait > lastCalled
clearTimeout(timeout)
if (callNow) {
callFunc()
} else {
timeout = setTimeout(callFunc, wait)
}
}
}
export { export {
isBrowser, isBrowser,
isDevEnvironment, isDevEnvironment,
isObject, isObject,
sleep, sleep,
rateLimit,
randomString, randomString,
translateMessage, translateMessage,
} }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment