From: Pascal Mugnier Date: Fri, 20 Jul 2018 15:24:48 +0000 (+0200) Subject: SONAR-11017 Improve ToC (#529) X-Git-Tag: 7.5~725 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=d2c355a678d71a04f59ae7b3c73adce9db3e7025;p=sonarqube.git SONAR-11017 Improve ToC (#529) --- diff --git a/server/sonar-docs/src/templates/page.css b/server/sonar-docs/src/templates/page.css index 1e6c4dd8de5..73515b1460d 100644 --- a/server/sonar-docs/src/templates/page.css +++ b/server/sonar-docs/src/templates/page.css @@ -33,6 +33,10 @@ color: #3c763d; } +ul > ul { + margin-bottom: 0 !important; +} + .collapse { border: 1px solid #e6e6e6; border-radius: 2px; @@ -72,3 +76,11 @@ .collapse .alert { margin: 0 0.5em 1.5rem; } + +img[src='/images/exclamation.svg'], +img[src='/images/check.svg'], +img[src='/images/cross.svg'], +img[src='/images/info.svg'] { + margin-bottom: 0; + top: 0 !important; +} diff --git a/server/sonar-docs/src/templates/page.js b/server/sonar-docs/src/templates/page.js index 2c04417fe55..d7f9859a945 100644 --- a/server/sonar-docs/src/templates/page.js +++ b/server/sonar-docs/src/templates/page.js @@ -54,6 +54,8 @@ export default class Page extends React.PureComponent { htmlWithInclusions = generateTableOfContents(htmlWithInclusions, page.headings); } + htmlWithInclusions = replaceDynamicLinks(htmlWithInclusions); + return (
@@ -98,10 +100,24 @@ export const query = graphql` } `; +function replaceDynamicLinks(content) { + return content.replace( + /\(.*)\<\/a\>/gim, + '$1' + ); +} + function generateTableOfContents(content, headings) { let html = '

Table Of Contents

'; let depth = headings[0].depth - 1; for (let i = 1; i < headings.length; i++) { + // Do not include title from collapsible content + if ( + content.match(new RegExp(`\
\${headings[i].value}\<\/h2\>`, 'gi')) + ) { + continue; + } + while (headings[i].depth > depth) { html += '
    '; depth++; @@ -116,7 +132,8 @@ function generateTableOfContents(content, headings) { `${headings[i].value}` ); } - return content.replace(/Table Of Contents<\/h[1-9]>/, html); + html += '
'; + return content.replace(/Table Of Contents<\/h[1-9]>/i, html); } function cutSonarCloudContent(content) { diff --git a/server/sonar-web/package.json b/server/sonar-web/package.json index 5fdb34c1017..a65e68ff7f9 100644 --- a/server/sonar-web/package.json +++ b/server/sonar-web/package.json @@ -22,6 +22,7 @@ "keymaster": "1.6.2", "lodash": "4.17.10", "lunr": "2.3.0", + "mdast-util-toc": "2.0.1", "prop-types": "15.6.1", "react": "16.2.0", "react-day-picker": "7.1.8", @@ -41,6 +42,7 @@ "remark-custom-blocks": "2.2.0", "remark-toc": "5.0.0", "unist-util-visit": "1.3.1", + "remark-slug": "5.0.0", "whatwg-fetch": "2.0.4" }, "devDependencies": { @@ -148,11 +150,18 @@ ], "jest": { "coverageDirectory": "/target/coverage", - "coveragePathIgnorePatterns": ["/node_modules", "/tests"], - "moduleFileExtensions": ["ts", "tsx", "js", "json"], + "coveragePathIgnorePatterns": [ + "/node_modules", + "/tests" + ], + "moduleFileExtensions": [ + "ts", + "tsx", + "js", + "json" + ], "moduleNameMapper": { - "^.+\\.(md|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": - "/config/jest/FileStub.js", + "^.+\\.(md|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/config/jest/FileStub.js", "^.+\\.css$": "/config/jest/CSSStub.js" }, "setupFiles": [ @@ -160,7 +169,9 @@ "/config/jest/SetupTestEnvironment.js", "/config/jest/SetupEnzyme.js" ], - "snapshotSerializers": ["enzyme-to-json/serializer"], + "snapshotSerializers": [ + "enzyme-to-json/serializer" + ], "testPathIgnorePatterns": [ "/node_modules", "/src/main/webapp", @@ -180,7 +191,10 @@ "lint-staged": { "gitDir": "../../", "linters": { - "*.{css,json}": ["prettier --write", "git add"], + "*.{css,json}": [ + "prettier --write", + "git add" + ], "*.{js,ts,tsx}": [ "eslint", "jest --bail --passWithNoTests --findRelatedTests", diff --git a/server/sonar-web/src/main/js/apps/documentation/styles.css b/server/sonar-web/src/main/js/apps/documentation/styles.css index 5eb00833df4..08c38b1b40b 100644 --- a/server/sonar-web/src/main/js/apps/documentation/styles.css +++ b/server/sonar-web/src/main/js/apps/documentation/styles.css @@ -59,6 +59,14 @@ margin: 0.8em 0 2em; } +.documentation-content.markdown ul { + margin: 0 0 2em; +} + +.documentation-content.markdown ul > ul { + margin: 0; +} + .documentation-content.markdown p + ul, .documentation-content.markdown p + ol, .documentation-content.markdown p + pre { diff --git a/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx b/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx index bb033ac2999..1480de4352c 100644 --- a/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx +++ b/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx @@ -21,11 +21,11 @@ import * as React from 'react'; import * as classNames from 'classnames'; import remark from 'remark'; import reactRenderer from 'remark-react'; -import remarkToc from 'remark-toc'; import remarkCustomBlocks from 'remark-custom-blocks'; import DocLink from './DocLink'; import DocImg from './DocImg'; import DocTooltipLink from './DocTooltipLink'; +import remarkToc from './plugins/remark-toc'; import DocCollapsibleBlock from './DocCollapsibleBlock'; import { separateFrontMatter, filterContent } from '../../helpers/markdown'; import { scrollToElement } from '../../helpers/scrolling'; @@ -43,7 +43,7 @@ export default class DocMarkdownBlock extends React.PureComponent { handleAnchorClick = (href: string, event: React.MouseEvent) => { if (this.node) { - const element = this.node.querySelector(`#user-content-${href.substr(1)}`); + const element = this.node.querySelector(`#${href.substr(1)}`); if (element) { event.preventDefault(); scrollToElement(element, { bottomOffset: window.innerHeight - 80 }); diff --git a/server/sonar-web/src/main/js/components/docs/plugins/remark-toc.js b/server/sonar-web/src/main/js/components/docs/plugins/remark-toc.js new file mode 100644 index 00000000000..84923f45f37 --- /dev/null +++ b/server/sonar-web/src/main/js/components/docs/plugins/remark-toc.js @@ -0,0 +1,52 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import slug from 'remark-slug'; +import util from 'mdast-util-toc'; + +const DEFAULT_HEADING = 'toc|table[ -]of[ -]contents?'; + +/** + * This comes from the remark-toc plugin: https://github.com/remarkjs/remark-toc + * We cannot use it directly before the following issue gets fixed: https://github.com/remarkjs/remark-toc/issues/18 + */ +export default function toc(options) { + const settings = options || {}; + const heading = settings.heading || DEFAULT_HEADING; + const depth = settings.maxDepth || 6; + const { tight } = settings; + + this.use(slug); + + return transformer; + + function transformer(node) { + const result = util(node, { heading, maxDepth: depth, tight }); + + if (result.index === null || result.index === -1 || !result.map) { + return; + } + + node.children = [].concat( + node.children.slice(0, result.index), + result.map, + node.children.slice(result.index) + ); + } +} diff --git a/server/sonar-web/yarn.lock b/server/sonar-web/yarn.lock index 5046b41e5cb..5288fdc5438 100644 --- a/server/sonar-web/yarn.lock +++ b/server/sonar-web/yarn.lock @@ -5603,7 +5603,7 @@ mdast-util-to-string@^1.0.0, mdast-util-to-string@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-1.0.4.tgz#5c455c878c9355f0c1e7f3e8b719cf583691acfb" -mdast-util-toc@^2.0.0: +mdast-util-toc@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/mdast-util-toc/-/mdast-util-toc-2.0.1.tgz#b1d2cb23bfb01f812fa7b55bffe8b0a8bedf6f21" dependencies: @@ -7396,7 +7396,7 @@ remark-react@4.0.3: hast-util-sanitize "^1.0.0" mdast-util-to-hast "^3.0.0" -remark-slug@^5.0.0: +remark-slug@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/remark-slug/-/remark-slug-5.0.0.tgz#9de71fcdc2bfae33ebb4a41eb83035288a829980" dependencies: @@ -7423,13 +7423,6 @@ remark-stringify@^5.0.0: unherit "^1.0.4" xtend "^4.0.1" -remark-toc@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/remark-toc/-/remark-toc-5.0.0.tgz#f1e13ed11062ad4d102b02e70168bd85015bf129" - dependencies: - mdast-util-toc "^2.0.0" - remark-slug "^5.0.0" - remark@9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/remark/-/remark-9.0.0.tgz#c5cfa8ec535c73a67c4b0f12bfdbd3a67d8b2f60"