From 1e848d696b682d785eec887b0924e9993b03cd7a Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 19 Apr 2017 16:03:15 +0100 Subject: [PATCH] feat(aio): add GH-style anchor links to headings (#16161) Closes #16126 PR Close #16161 --- aio/package.json | 2 + .../styles/2-modules/_heading-anchors.scss | 42 +++++++++++++++++++ aio/src/styles/2-modules/_modules-dir.scss | 3 +- .../processors/fixInternalDocumentLinks.js | 2 +- .../fixInternalDocumentLinks.spec.js | 2 +- .../remark-package/services/renderMarkdown.js | 4 ++ .../services/renderMarkdown.spec.js | 16 +++++-- aio/yarn.lock | 30 ++++++++++++- 8 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 aio/src/styles/2-modules/_heading-anchors.scss diff --git a/aio/package.json b/aio/package.json index a72ee642ae..f560a34c89 100644 --- a/aio/package.json +++ b/aio/package.json @@ -81,7 +81,9 @@ "lodash": "^4.17.4", "protractor": "~5.1.0", "remark": "^7.0.0", + "remark-autolink-headings": "^4.0.0", "remark-html": "^6.0.0", + "remark-slug": "^4.2.2", "rho": "https://github.com/petebacondarwin/rho#master", "rimraf": "^2.6.1", "shelljs": "^0.7.7", diff --git a/aio/src/styles/2-modules/_heading-anchors.scss b/aio/src/styles/2-modules/_heading-anchors.scss new file mode 100644 index 0000000000..e186bcc21a --- /dev/null +++ b/aio/src/styles/2-modules/_heading-anchors.scss @@ -0,0 +1,42 @@ +h1, h2, h3, h4, h5, h6 { + .icon-link { + color: $darkgray; + vertical-align: middle; + visibility: hidden; + margin: 8px; + + font: normal normal 24px 'Material Icons'; + display: inline-block; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + + /* Support for all WebKit browsers. */ + -webkit-font-smoothing: antialiased; + /* Support for Safari and Chrome. */ + text-rendering: optimizeLegibility; + + /* Support for Firefox. */ + -moz-osx-font-smoothing: grayscale; + + /* Support for IE. */ + font-feature-settings: 'liga'; + + &:before { content: 'link'; } + } + + a { + text-decoration: none; + padding-left: 8px; + margin-left: -30px; + display: inline-block; + vertical-align: middle; + } + + &:hover .icon-link { + visibility: visible + } +} \ No newline at end of file diff --git a/aio/src/styles/2-modules/_modules-dir.scss b/aio/src/styles/2-modules/_modules-dir.scss index 09dfe3f2d1..04779aab5e 100644 --- a/aio/src/styles/2-modules/_modules-dir.scss +++ b/aio/src/styles/2-modules/_modules-dir.scss @@ -23,4 +23,5 @@ @import 'scrollbar'; @import 'callout'; @import 'resources'; - @import 'edit-page-cta'; \ No newline at end of file + @import 'edit-page-cta'; + @import 'heading-anchors'; \ No newline at end of file diff --git a/aio/tools/transforms/angular.io-package/processors/fixInternalDocumentLinks.js b/aio/tools/transforms/angular.io-package/processors/fixInternalDocumentLinks.js index ed12787a52..0ed3b3bade 100644 --- a/aio/tools/transforms/angular.io-package/processors/fixInternalDocumentLinks.js +++ b/aio/tools/transforms/angular.io-package/processors/fixInternalDocumentLinks.js @@ -12,7 +12,7 @@ module.exports = function fixInternalDocumentLinks() { return { $runAfter: ['inlineTagProcessor'], - $runBefore: ['writeFilesProcessor'], + $runBefore: ['convertToJsonProcessor'], $process: function(docs) { docs.forEach(doc => { doc.renderedContent = doc.renderedContent.replace(INTERNAL_LINK, (_, pre, hash) => { diff --git a/aio/tools/transforms/angular.io-package/processors/fixInternalDocumentLinks.spec.js b/aio/tools/transforms/angular.io-package/processors/fixInternalDocumentLinks.spec.js index b2d6802466..138198ce41 100644 --- a/aio/tools/transforms/angular.io-package/processors/fixInternalDocumentLinks.spec.js +++ b/aio/tools/transforms/angular.io-package/processors/fixInternalDocumentLinks.spec.js @@ -13,7 +13,7 @@ describe('fixInternalDocumentLinks processor', () => { it('should run before the correct processor', () => { const processor = processorFactory(); - expect(processor.$runBefore).toEqual(['writeFilesProcessor']); + expect(processor.$runBefore).toEqual(['convertToJsonProcessor']); }); it('should run after the correct processor', () => { diff --git a/aio/tools/transforms/remark-package/services/renderMarkdown.js b/aio/tools/transforms/remark-package/services/renderMarkdown.js index 3e9b0bc2eb..acfa9ab4f8 100644 --- a/aio/tools/transforms/remark-package/services/renderMarkdown.js +++ b/aio/tools/transforms/remark-package/services/renderMarkdown.js @@ -1,4 +1,6 @@ const remark = require('remark'); +const slug = require('remark-slug'); +const autolinkHeadings = require('remark-autolink-headings'); const html = require('remark-html'); /** @@ -15,6 +17,8 @@ module.exports = function renderMarkdown() { // .use(() => tree => { // console.log(require('util').inspect(tree, { colors: true, depth: 4 })); // }) + .use(slug) + .use(autolinkHeadings) .use(html); return function renderMarkdownImpl(content) { diff --git a/aio/tools/transforms/remark-package/services/renderMarkdown.spec.js b/aio/tools/transforms/remark-package/services/renderMarkdown.spec.js index 3bb1b9352c..c74e9573a6 100644 --- a/aio/tools/transforms/remark-package/services/renderMarkdown.spec.js +++ b/aio/tools/transforms/remark-package/services/renderMarkdown.spec.js @@ -16,7 +16,7 @@ describe('remark: renderMarkdown service', () => { const output = renderMarkdown(content); expect(output).toEqual( - '

heading 1

\n' + + '

heading 1

\n' + '

A paragraph with bold and italic.

\n' + '