Added autolinking headings in mdx docs

This commit is contained in:
Piotr Janosz
2019-08-28 17:44:46 +02:00
parent 219e09d157
commit ab283ddd9b
6 changed files with 93 additions and 13 deletions

View File

@@ -126,6 +126,7 @@
"cache-loader": "^4.1.0",
"compare-versions": "^3.5.1",
"css-loader": "0.23.x",
"extend": "^3.0.2",
"glob": "^7.1.4",
"json-stringify-pretty-compact": "^2.0.0",
"less-loader": "^4.1.0",
@@ -149,6 +150,7 @@
"unist-util-find-after": "^2.0.4",
"unist-util-modify-children": "^1.1.4",
"unist-util-select": "^2.0.2",
"unist-util-visit": "^2.0.0",
"unist-util-visit-parents": "^3.0.0",
"webpack": "^4.39.2",
"webpack-cli": "3.3.7",

View File

@@ -1,7 +1,35 @@
import styled from 'styled-components';
import { Heading } from 'ts/components/text';
const H1 = styled(Heading).attrs({
const MDXHeading = styled(Heading)`
position: relative;
&:hover {
.heading-link-icon {
opacity: 1;
}
}
.heading-link-icon {
display: inline-block;
width: 16px;
height: 16px;
position: absolute;
transform: translateY(-50%);
top: 50%;
left: -26px;
padding-right: 26px;
opacity: 0;
transition: opacity 200ms ease-in-out;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' %3E%3Cpath d='M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3M8 12h8'/%3E%3C/svg%3E");
background-repeat: no-repeat;
}
`;
const H1 = styled(MDXHeading).attrs({
size: 34,
asElement: 'h1',
marginBottom: '1rem',
@@ -12,32 +40,32 @@ const H1 = styled(Heading).attrs({
}
`;
const H2 = styled(Heading).attrs({
const H2 = styled(MDXHeading).attrs({
size: 'default',
asElement: 'h2',
marginBottom: '1rem',
})``;
const H3 = styled(Heading).attrs({
const H3 = styled(MDXHeading).attrs({
size: 'small',
asElement: 'h3',
fontWeight: '300',
marginBottom: '1rem',
})``;
const H4 = styled(Heading).attrs({
const H4 = styled(MDXHeading).attrs({
asElement: 'h4',
fontWeight: '300',
marginBottom: '1rem',
})``;
const H5 = styled(Heading).attrs({
const H5 = styled(MDXHeading).attrs({
asElement: 'h5',
fontWeight: '300',
marginBottom: '1rem',
})``;
const H6 = styled(Heading).attrs({
const H6 = styled(MDXHeading).attrs({
asElement: 'h6',
fontWeight: '300',
marginBottom: '1rem',

View File

@@ -5,6 +5,7 @@ const TerserPlugin = require('terser-webpack-plugin');
const RollbarSourceMapPlugin = require('rollbar-sourcemap-webpack-plugin');
const childProcess = require('child_process');
const remarkSlug = require('remark-slug');
const remarkAutolinkHeadings = require('./webpack/remark_autolink_headings');
const remarkSectionizeHeadings = require('./webpack/remark_sectionize_headings');
const mdxTableOfContents = require('./webpack/mdx_table_of_contents');
@@ -65,7 +66,7 @@ const config = {
{
loader: '@mdx-js/loader',
options: {
remarkPlugins: [remarkSlug, remarkSectionizeHeadings],
remarkPlugins: [remarkSlug, remarkAutolinkHeadings, remarkSectionizeHeadings],
compilers: [mdxTableOfContents],
},
},

View File

@@ -61,11 +61,14 @@ function isSlugifiedSection(node) {
}
function toFragment(nodes) {
if (nodes.length === 1 && nodes[0].type === 'text') {
return JSON.stringify(nodes[0].value);
} else {
return '<React.Fragment>' + nodes.map(toJSX).join('') + '</React.Fragment>';
// Because of autolinking headings earlier (at remark stage), the headings (nodes)
// contain an anchor tag next to the title, we only want to render the text.
// Unless there is no text, then we render whatever nodes we get in a Fragment
const textNode = nodes.find(node => node.type === 'text');
if (textNode) {
return JSON.stringify(textNode.value);
}
return '<React.Fragment>' + nodes.map(toJSX).join('') + '</React.Fragment>';
}
function tableOfContentsListSerializer(nodes, indent = 0) {

View File

@@ -0,0 +1,45 @@
const visit = require('unist-util-visit');
const extend = require('extend');
const content = {
type: 'element',
tagName: 'i',
properties: { className: ['heading-link-icon'] },
};
const linkProperties = { ariaHidden: 'true' };
const hChildren = Array.isArray(content) ? content : [content];
module.exports = plugin;
function plugin() {
return transform;
}
function transform(tree) {
visit(tree, 'heading', visitor);
}
function visitor(node) {
const { data } = node;
const id = data && data.hProperties && data.hProperties.id;
const url = '#' + id;
if (id) {
inject(node, url);
}
}
function inject(node, url) {
node.children.unshift({
type: 'link',
url,
title: null,
children: [],
data: {
hProperties: extend(true, {}, linkProperties),
hChildren: extend(true, [], hChildren),
},
});
}

View File

@@ -8903,9 +8903,10 @@ extend@^3.0.0, extend@~3.0.0, extend@~3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
extend@~3.0.2:
extend@^3.0.2, extend@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
external-editor@^2.0.4:
version "2.2.0"
@@ -20723,7 +20724,7 @@ unist-util-visit-parents@^3.0.0:
"@types/unist" "^2.0.3"
unist-util-is "^4.0.0"
unist-util-visit@2.0.0:
unist-util-visit@2.0.0, unist-util-visit@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-2.0.0.tgz#1fdae5ea88251651bfe49b7e84390d664fc227c5"
integrity sha512-kiTpWKsF54u/78L/UU/i7lxrnqGiEWBgqCpaIZBYP0gwUC+Akq0Ajm4U8JiNIoQNfAioBdsyarnOcTEAb9mLeQ==