diff --git a/gatsby-config.js b/gatsby-config.js index ed0799f34..456396f92 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -55,7 +55,7 @@ module.exports = { maxWidth: 840, }, }, - 'gatsby-remark-autolink-headers', + 'gatsby-remark-header-custom-ids', { resolve: 'gatsby-remark-code-repls', options: { diff --git a/package.json b/package.json index a9930ccc8..d050abaf5 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ "gatsby-plugin-react-helmet": "^3.0.0", "gatsby-plugin-sharp": "^2.0.0", "gatsby-plugin-twitter": "^2.0.0", - "gatsby-remark-autolink-headers": "^2.0.12", "gatsby-remark-code-repls": "^2.0.0", "gatsby-remark-copy-linked-files": "^2.0.0", "gatsby-remark-embed-snippet": "^3.0.0", @@ -40,8 +39,10 @@ "gatsby-source-filesystem": "^2.0.0", "gatsby-transformer-remark": "^2.0.0", "gatsby-transformer-sharp": "^2.0.0", + "github-slugger": "^1.2.1", "glamor": "^2.20.40", "hex2rgba": "^0.0.1", + "mdast-util-to-string": "^1.0.5", "normalize.css": "^8.0.0", "prettier": "^1.7.4", "prismjs": "^1.15.0", diff --git a/plugins/gatsby-remark-header-custom-ids/gatsby-client.js b/plugins/gatsby-remark-header-custom-ids/gatsby-client.js new file mode 100644 index 000000000..6b24d0b13 --- /dev/null +++ b/plugins/gatsby-remark-header-custom-ids/gatsby-client.js @@ -0,0 +1,30 @@ +let offsetY = 0; + +const getTargetOffset = hash => { + const id = window.decodeURI(hash.replace(`#`, ``)); + if (id !== ``) { + const element = document.getElementById(id); + if (element) { + return element.offsetTop - offsetY; + } + } + return null; +}; + +exports.onInitialClientRender = (_, pluginOptions) => { + if (pluginOptions.offsetY) { + offsetY = pluginOptions.offsetY; + } + + requestAnimationFrame(() => { + const offset = getTargetOffset(window.location.hash); + if (offset !== null) { + window.scrollTo(0, offset); + } + }); +}; + +exports.shouldUpdateScroll = ({routerProps: {location}}) => { + const offset = getTargetOffset(location.hash); + return offset !== null ? [0, offset] : true; +}; diff --git a/plugins/gatsby-remark-header-custom-ids/gatsby-ssr.js b/plugins/gatsby-remark-header-custom-ids/gatsby-ssr.js new file mode 100644 index 000000000..8d9ca0d41 --- /dev/null +++ b/plugins/gatsby-remark-header-custom-ids/gatsby-ssr.js @@ -0,0 +1,76 @@ +const React = require(`react`); + +const pluginDefaults = { + className: `anchor`, + icon: true, + offsetY: 0, +}; + +exports.onRenderBody = ({setHeadComponents}, pluginOptions) => { + const {className, icon, offsetY} = Object.assign( + pluginDefaults, + pluginOptions, + ); + + const styles = ` + .${className} { + float: left; + padding-right: 4px; + margin-left: -20px; + } + h1 .${className} svg, + h2 .${className} svg, + h3 .${className} svg, + h4 .${className} svg, + h5 .${className} svg, + h6 .${className} svg { + visibility: hidden; + } + h1:hover .${className} svg, + h2:hover .${className} svg, + h3:hover .${className} svg, + h4:hover .${className} svg, + h5:hover .${className} svg, + h6:hover .${className} svg, + h1 .${className}:focus svg, + h2 .${className}:focus svg, + h3 .${className}:focus svg, + h4 .${className}:focus svg, + h5 .${className}:focus svg, + h6 .${className}:focus svg { + visibility: visible; + } + `; + + const script = ` + document.addEventListener("DOMContentLoaded", function(event) { + var hash = window.decodeURI(location.hash.replace('#', '')) + if (hash !== '') { + var element = document.getElementById(hash) + if (element) { + var offset = element.offsetTop + // Wait for the browser to finish rendering before scrolling. + setTimeout((function() { + window.scrollTo(0, offset - ${offsetY}) + }), 0) + } + } + }) + `; + + const style = icon ? ( + + ) : ( + undefined + ); + + return setHeadComponents([ + style, +