feat(aio): add GH-style anchor links to headings (#16161)
Closes #16126 PR Close #16161
This commit is contained in:
		
							parent
							
								
									1bfa7c6f14
								
							
						
					
					
						commit
						1e848d696b
					
				| @ -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", | ||||
|  | ||||
							
								
								
									
										42
									
								
								aio/src/styles/2-modules/_heading-anchors.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								aio/src/styles/2-modules/_heading-anchors.scss
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
|   } | ||||
| } | ||||
| @ -23,4 +23,5 @@ | ||||
|    @import 'scrollbar'; | ||||
|    @import 'callout'; | ||||
|    @import 'resources'; | ||||
|    @import 'edit-page-cta'; | ||||
|    @import 'edit-page-cta'; | ||||
|    @import 'heading-anchors'; | ||||
| @ -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) => { | ||||
|  | ||||
| @ -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', () => { | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -16,7 +16,7 @@ describe('remark: renderMarkdown service', () => { | ||||
|     const output = renderMarkdown(content); | ||||
| 
 | ||||
|     expect(output).toEqual( | ||||
|         '<h1>heading 1</h1>\n' + | ||||
|         '<h1 id="heading-1"><a href="#heading-1" aria-hidden="true"><span class="icon icon-link"></span></a>heading 1</h1>\n' + | ||||
|         '<p>A paragraph with <strong>bold</strong> and <em>italic</em>.</p>\n' + | ||||
|         '<ul>\n' + | ||||
|         '<li>List item 1</li>\n' + | ||||
| @ -25,9 +25,9 @@ describe('remark: renderMarkdown service', () => { | ||||
|   }); | ||||
| 
 | ||||
|   it('should not process markdown inside inline tags', () => { | ||||
|     const content = '# heading {@link some_url_path}'; | ||||
|     const content = '* list item {@link some_url_path}'; | ||||
|     const output = renderMarkdown(content); | ||||
|     expect(output).toEqual('<h1>heading {@link some_url_path}</h1>\n'); | ||||
|     expect(output).toEqual('<ul>\n<li>list item {@link some_url_path}</li>\n</ul>\n'); | ||||
|   }); | ||||
| 
 | ||||
|   it('should not put block level inline tags inside paragraphs', () => { | ||||
| @ -67,4 +67,14 @@ describe('remark: renderMarkdown service', () => { | ||||
|     const output = renderMarkdown(content); | ||||
|     expect(output).toEqual('<p>some text</p>\n<p>    indented text</p>\n<p>other text</p>\n'); | ||||
|   }); | ||||
| 
 | ||||
|   it('should add id slugs and links to headings', () => { | ||||
|     const content = '# heading 1\n\nSome text\n\n## heading 2\n\nMore text'; | ||||
|     const output = renderMarkdown(content); | ||||
|     expect(output).toEqual( | ||||
|       '<h1 id="heading-1"><a href="#heading-1" aria-hidden="true"><span class="icon icon-link"></span></a>heading 1</h1>\n' + | ||||
|       '<p>Some text</p>\n' + | ||||
|       '<h2 id="heading-2"><a href="#heading-2" aria-hidden="true"><span class="icon icon-link"></span></a>heading 2</h2>\n' + | ||||
|       '<p>More text</p>\n'); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| @ -2024,6 +2024,10 @@ ember-cli-string-utils@^1.0.0: | ||||
|   version "1.1.0" | ||||
|   resolved "https://registry.yarnpkg.com/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" | ||||
| 
 | ||||
| emoji-regex@^6.0.0: | ||||
|   version "6.4.2" | ||||
|   resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.4.2.tgz#a30b6fee353d406d96cfb9fa765bdc82897eff6e" | ||||
| 
 | ||||
| emojis-list@^2.0.0: | ||||
|   version "2.1.0" | ||||
|   resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" | ||||
| @ -2766,6 +2770,12 @@ getpass@^0.1.1: | ||||
|   dependencies: | ||||
|     assert-plus "^1.0.0" | ||||
| 
 | ||||
| github-slugger@^1.0.0: | ||||
|   version "1.1.1" | ||||
|   resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.1.1.tgz#5444671f65e5a5a424cfa8ba3255cc1f7baf07ea" | ||||
|   dependencies: | ||||
|     emoji-regex "^6.0.0" | ||||
| 
 | ||||
| gl-matrix@2.3.2: | ||||
|   version "2.3.2" | ||||
|   resolved "https://registry.yarnpkg.com/gl-matrix/-/gl-matrix-2.3.2.tgz#aac808c74af7d5db05fe04cb60ca1a0fcb174d74" | ||||
| @ -4285,6 +4295,10 @@ mdast-util-to-hast@^2.1.1: | ||||
|     unist-util-visit "^1.1.0" | ||||
|     xtend "^4.0.1" | ||||
| 
 | ||||
| mdast-util-to-string@^1.0.0: | ||||
|   version "1.0.2" | ||||
|   resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-1.0.2.tgz#dc996a24d2b521178d3fac3993680c03a683e1dd" | ||||
| 
 | ||||
| media-typer@0.3.0: | ||||
|   version "0.3.0" | ||||
|   resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" | ||||
| @ -5605,6 +5619,12 @@ relateurl@0.2.x: | ||||
|   version "0.2.7" | ||||
|   resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" | ||||
| 
 | ||||
| remark-autolink-headings@^4.0.0: | ||||
|   version "4.0.0" | ||||
|   resolved "https://registry.yarnpkg.com/remark-autolink-headings/-/remark-autolink-headings-4.0.0.tgz#1edabab6636e8cb26a36bf4c06caaec28355d3fc" | ||||
|   dependencies: | ||||
|     unist-util-visit "^1.0.1" | ||||
| 
 | ||||
| remark-html@^6.0.0: | ||||
|   version "6.0.0" | ||||
|   resolved "https://registry.yarnpkg.com/remark-html/-/remark-html-6.0.0.tgz#ade7d94b60e452158f28615218450682601dbfc1" | ||||
| @ -5635,6 +5655,14 @@ remark-parse@^3.0.0: | ||||
|     vfile-location "^2.0.0" | ||||
|     xtend "^4.0.1" | ||||
| 
 | ||||
| remark-slug@^4.2.2: | ||||
|   version "4.2.2" | ||||
|   resolved "https://registry.yarnpkg.com/remark-slug/-/remark-slug-4.2.2.tgz#3cfaa02e2e24d98405b296072f2ebbdfad279eb6" | ||||
|   dependencies: | ||||
|     github-slugger "^1.0.0" | ||||
|     mdast-util-to-string "^1.0.0" | ||||
|     unist-util-visit "^1.0.0" | ||||
| 
 | ||||
| remark-stringify@^3.0.0: | ||||
|   version "3.0.0" | ||||
|   resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-3.0.0.tgz#f1720893a3e7c845824d95bb573d628d1346ba2a" | ||||
| @ -6915,7 +6943,7 @@ unist-util-stringify-position@^1.0.0: | ||||
|   dependencies: | ||||
|     has "^1.0.1" | ||||
| 
 | ||||
| unist-util-visit@^1.0.0, unist-util-visit@^1.1.0: | ||||
| unist-util-visit@^1.0.0, unist-util-visit@^1.0.1, unist-util-visit@^1.1.0: | ||||
|   version "1.1.1" | ||||
|   resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.1.1.tgz#e917a3b137658b335cb4420c7da2e74d928e4e94" | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user