From 93894e7bdcbedac526bd1c06275061c39e80dfce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Miernik?= Date: Wed, 24 Apr 2019 06:41:51 +0200 Subject: [PATCH] feat(v2): headings anchors (#1385) * feat(v2): headings anchors * misc: make hash link appear on hover * misc: convert to rem --- packages/docusaurus-mdx-loader/src/index.js | 3 +- .../docusaurus-mdx-loader/src/linkHeadings.js | 56 +++++++++++++++++++ .../lib/default-theme/DocBody/index.js | 1 + .../lib/default-theme/DocBody/styles.css | 34 +++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 packages/docusaurus-mdx-loader/src/linkHeadings.js create mode 100644 packages/docusaurus/lib/default-theme/DocBody/styles.css diff --git a/packages/docusaurus-mdx-loader/src/index.js b/packages/docusaurus-mdx-loader/src/index.js index 117bf41b22..63f3c0ccda 100644 --- a/packages/docusaurus-mdx-loader/src/index.js +++ b/packages/docusaurus-mdx-loader/src/index.js @@ -9,10 +9,11 @@ const mdx = require('@mdx-js/mdx'); const rehypePrism = require('@mapbox/rehype-prism'); const emoji = require('remark-emoji'); const slug = require('rehype-slug'); +const linkHeadings = require('./linkHeadings'); const rightToc = require('./rightToc'); const DEFAULT_OPTIONS = { - rehypePlugins: [[rehypePrism, {ignoreMissing: true}], slug], + rehypePlugins: [[rehypePrism, {ignoreMissing: true}], slug, linkHeadings], remarkPlugins: [emoji, rightToc], prismTheme: 'prism-themes/themes/prism-atom-dark.css', }; diff --git a/packages/docusaurus-mdx-loader/src/linkHeadings.js b/packages/docusaurus-mdx-loader/src/linkHeadings.js new file mode 100644 index 0000000000..9d2a668b95 --- /dev/null +++ b/packages/docusaurus-mdx-loader/src/linkHeadings.js @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const visit = require('unist-util-visit'); + +const createAnchor = id => ({ + type: 'element', + tagName: 'a', + properties: { + ariaHidden: true, + className: 'anchor', + id, + }, +}); + +const createLink = id => ({ + type: 'element', + tagName: 'a', + properties: { + ariaHidden: true, + className: 'hash-link', + href: `#${id}`, + }, + children: [ + { + type: 'text', + value: '#', + }, + ], +}); + +const headings = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']; + +const visitor = node => { + const {properties} = node; + if (!properties || !properties.id || !headings.includes(node.tagName)) { + return; + } + + node.children.unshift(createLink(properties.id)); + node.children.unshift(createAnchor(properties.id)); + + delete properties.id; +}; + +const transformer = node => { + visit(node, 'element', visitor); +}; + +const plugin = () => transformer; + +module.exports = plugin; diff --git a/packages/docusaurus/lib/default-theme/DocBody/index.js b/packages/docusaurus/lib/default-theme/DocBody/index.js index a06a98a158..3b0039bd1c 100644 --- a/packages/docusaurus/lib/default-theme/DocBody/index.js +++ b/packages/docusaurus/lib/default-theme/DocBody/index.js @@ -11,6 +11,7 @@ import DocsPaginator from '@theme/DocsPaginator'; // eslint-disable-line import DocusaurusContext from '@docusaurus/context'; import Head from '@docusaurus/Head'; +import './styles.css'; import styles from './styles.module.css'; const Headings = ({headings, isChild}) => { diff --git a/packages/docusaurus/lib/default-theme/DocBody/styles.css b/packages/docusaurus/lib/default-theme/DocBody/styles.css new file mode 100644 index 0000000000..cdd61ad354 --- /dev/null +++ b/packages/docusaurus/lib/default-theme/DocBody/styles.css @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +.anchor { + display: block; + position: relative; + top: -5rem; +} + +@media only screen and (max-width: 735px) { + .anchor { + top: -10rem; + } +} + +.hash-link { + position: absolute; + margin-left: -1.25rem; + padding-right: 0.25rem; +} + +@media only screen and (min-width: 736px) { + .hash-link { + display: none; + } + + *:hover > .hash-link { + display: inherit; + } +}