Merge pull request #267 from the-programmers-hangout/fix-replace-gatsby-remark-auto-headers

fix: replace gatsby remark auto headers
This commit is contained in:
Jean-Philippe Sirois
2020-05-22 01:07:18 -04:00
committed by GitHub
9 changed files with 273 additions and 32 deletions
+1 -1
View File
@@ -31,7 +31,7 @@ module.exports = {
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [`gatsby-remark-auto-headers`],
plugins: [`gatsby-remark-auto-headers-improved`],
},
},
{
-28
View File
@@ -10015,34 +10015,6 @@
}
}
},
"gatsby-remark-auto-headers": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/gatsby-remark-auto-headers/-/gatsby-remark-auto-headers-1.0.3.tgz",
"integrity": "sha512-bLcZD53sXU3jklGlbtT4MEN+a8w+WocSxe+sqRFkoHWOJeB1ClyqM0IH7wHUV0M/BFyQ54i+ycwjrUa17op1bg==",
"requires": {
"@babel/runtime": "^7.0.0",
"github-slugger": "^1.2.0",
"unist-util-visit": "^1.4.0"
},
"dependencies": {
"unist-util-visit": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz",
"integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==",
"requires": {
"unist-util-visit-parents": "^2.0.0"
}
},
"unist-util-visit-parents": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz",
"integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==",
"requires": {
"unist-util-is": "^3.0.0"
}
}
}
},
"gatsby-source-filesystem": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/gatsby-source-filesystem/-/gatsby-source-filesystem-2.3.5.tgz",
+1 -1
View File
@@ -40,10 +40,10 @@
"gatsby-plugin-react-svg": "^3.0.0",
"gatsby-plugin-sharp": "^2.6.6",
"gatsby-plugin-styled-components": "^3.3.1",
"gatsby-remark-auto-headers": "^1.0.3",
"gatsby-source-filesystem": "^2.3.5",
"gatsby-transformer-remark": "^2.8.10",
"gatsby-transformer-sharp": "^2.5.2",
"github-slugger": "^1.3.0",
"lodash": "^4.17.15",
"polished": "^3.6.3",
"prismjs": "^1.20.0",
@@ -0,0 +1,43 @@
var attr = "id"
const getTargetOffset = (hash) => {
const id = window.decodeURI(hash.replace(`#`, ``))
if (id !== ``) {
const element = document.querySelector("[" + attr + "=" + id + "]")
if (element) {
return getElementTop(element)
}
}
return null
}
function getElementTop(el) {
let actualTop = el.offsetTop
let current = el.offsetParent
while (current !== null) {
actualTop += current.offsetTop
current = current.offsetParent
}
return actualTop
}
exports.onInitialClientRender = (_, pluginOptions) => {
if (pluginOptions.offsetY) {
attr = pluginOptions.attr
}
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
}
@@ -0,0 +1,85 @@
const React = require("react")
const pluginDefaults = {
className: `anchor`,
icon: true,
offsetY: 0,
attr: "id",
}
exports.onRenderBody = ({ setHeadComponents }, pluginOptions) => {
const { className, icon, attr } = 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 = `
function getElementTop(el) {
var actualTop = el.offsetTop
var current = el.offsetParent
while (current !== null) {
actualTop += current.offsetTop
current = current.offsetParent
}
return actualTop
}
document.addEventListener("DOMContentLoaded", function(event) {
var hash = window.decodeURI(location.hash.replace('#', ''))
if (hash !== '') {
var element = document.querySelector('[${attr}=' + hash + ']')
if (element) {
var offset = getElementTop(element)
// Wait for the browser to finish rendering before scrolling.
setTimeout((function() {
window.scrollTo(0, offset)
}), 0)
}
}
})
`
const style = icon ? (
<style key={`gatsby-remark-autolink-headers-style`} type="text/css">
{styles}
</style>
) : undefined
return setHeadComponents([
style,
<script
key={`gatsby-remark-autolink-headers-script`}
dangerouslySetInnerHTML={{ __html: script }}
/>,
])
}
@@ -0,0 +1,69 @@
const visit = require(`unist-util-visit`)
const slugs = require(`github-slugger`)()
function toString(node) {
return (
valueOf(node) ||
(node.children && node.children.map(toString).join("")) ||
""
)
}
function valueOf(node) {
return (
(node && node.value ? node.value : node.alt ? node.alt : node.title) || ""
)
}
function patch(context, key, value) {
if (!context[key]) {
context[key] = value
}
return context[key]
}
function stripLeadingNumber(value) {
return value.replace(/^(\d*\-)(.*)/, "$2")
}
const svgIcon = `<svg aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>`
module.exports = (
{ markdownAST },
{ icon = svgIcon, attr = "id", className = "anchor", maintainCase = false }
) => {
slugs.reset()
visit(markdownAST, `heading`, (node) => {
const id = slugs.slug(toString(node), maintainCase)
const strippedId = stripLeadingNumber(id)
const data = patch(node, `data`, {})
patch(data, attr, strippedId)
patch(data, `htmlAttributes`, {})
patch(data, `hProperties`, {})
patch(data.htmlAttributes, attr, strippedId)
patch(data.hProperties, attr, strippedId)
if (icon !== false) {
node.children.unshift({
type: `link`,
url: `#${strippedId}`,
title: null,
data: {
hProperties: {
"aria-hidden": true,
class: className,
},
hChildren: [
{
type: `raw`,
// The Octicon link icon is the default. But users can set their own icon via the "icon" option.
value: icon,
},
],
},
})
}
})
return markdownAST
}
@@ -0,0 +1,50 @@
{
"name": "gatsby-remark-auto-headers-improved",
"version": "0.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/unist": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz",
"integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ=="
},
"emoji-regex": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.1.1.tgz",
"integrity": "sha1-xs0OwbBkLio8Z6ETfvxeeW2k+I4="
},
"github-slugger": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.3.0.tgz",
"integrity": "sha512-gwJScWVNhFYSRDvURk/8yhcFBee6aFjye2a7Lhb2bUyRulpIoek9p0I9Kt7PT67d/nUlZbFu8L9RLiA0woQN8Q==",
"requires": {
"emoji-regex": ">=6.0.0 <=6.1.1"
}
},
"unist-util-is": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.0.2.tgz",
"integrity": "sha512-Ofx8uf6haexJwI1gxWMGg6I/dLnF2yE+KibhD3/diOqY2TinLcqHXCV6OI5gFVn3xQqDH+u0M625pfKwIwgBKQ=="
},
"unist-util-visit": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.2.tgz",
"integrity": "sha512-HoHNhGnKj6y+Sq+7ASo2zpVdfdRifhTgX2KTU3B/sO/TTlZchp7E3S4vjRzDJ7L60KmrCPsQkVK3lEF3cz36XQ==",
"requires": {
"@types/unist": "^2.0.0",
"unist-util-is": "^4.0.0",
"unist-util-visit-parents": "^3.0.0"
}
},
"unist-util-visit-parents": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.0.2.tgz",
"integrity": "sha512-yJEfuZtzFpQmg1OSCyS9M5NJRrln/9FbYosH3iW0MG402QbdbaB8ZESwUv9RO6nRfLAKvWcMxCwdLWOov36x/g==",
"requires": {
"@types/unist": "^2.0.0",
"unist-util-is": "^4.0.0"
}
}
}
}
@@ -0,0 +1,14 @@
{
"name": "gatsby-remark-auto-headers-improved",
"version": "0.1.0",
"description": "Gatsby remark plugin to add headers to markdown, improved from gatsby-remark-auto-headers",
"main": "index.js",
"scripts": {},
"keywords": [],
"author": "Jean-Philippe Sirois <[email protected]>",
"license": "MIT",
"dependencies": {
"github-slugger": "^1.3.0",
"unist-util-visit": "^2.0.2"
}
}
+10 -2
View File
@@ -1,4 +1,4 @@
import kebabCase from "lodash/kebabCase"
import GithubSlugger from "github-slugger"
import chain from "ramda/es/chain"
import partition from "ramda/es/partition"
import pipe from "ramda/es/pipe"
@@ -7,6 +7,8 @@ import sort from "ramda/es/sort"
import { IFile, IFileOrFolder, IFolder, ITocItem } from "../types"
import { MarkdownRemark } from "../../generated/graphql"
const slugger = new GithubSlugger()
function specificWordsToUpper(str: string): string {
const wordsToUpper = ["pdo", "c"]
const toUpper = (word: string) =>
@@ -144,12 +146,18 @@ export function buildToc(headings: MarkdownRemark["headings"]): ITocItem[] {
return []
}
const strip = (value: string) => value.replace(/^(\d*\-)(.*)/, "$2")
slugger.reset()
return headings
.filter((h) => h?.depth === 2)
.map((h) => {
const slug = slugger.slug(h!.value!)
return {
depth: h!.depth!,
link: `#${kebabCase(h!.value!)}`,
link: `#${strip(slug)}`,
title: h!.value!,
}
})