From 4691d62918615ce3eb313dad0c405c332a3775b4 Mon Sep 17 00:00:00 2001 From: Wouter Admiraal Date: Thu, 2 Jan 2020 10:27:22 +0100 Subject: [PATCH] SONAR-12375 Fix floating TOC in documentation --- .../src/components/HeadingsLink.tsx | 65 +++++++++---------- .../__tests__/HeadingsLink-test.tsx | 39 +++++++++++ .../__snapshots__/HeadingsLink-test.tsx.snap | 33 ++++++++++ server/sonar-docs/src/layouts/layout.css | 12 +++- 4 files changed, 112 insertions(+), 37 deletions(-) create mode 100644 server/sonar-docs/src/components/__tests__/HeadingsLink-test.tsx create mode 100644 server/sonar-docs/src/components/__tests__/__snapshots__/HeadingsLink-test.tsx.snap diff --git a/server/sonar-docs/src/components/HeadingsLink.tsx b/server/sonar-docs/src/components/HeadingsLink.tsx index fb595c12176..e9d620097de 100644 --- a/server/sonar-docs/src/components/HeadingsLink.tsx +++ b/server/sonar-docs/src/components/HeadingsLink.tsx @@ -21,7 +21,6 @@ import * as React from 'react'; import { MarkdownHeading } from '../@types/graphql-types'; import HeadingAnchor from './HeadingAnchor'; -const MINIMUM_TOP_MARGIN = 80; const HEADER_SCROLL_MARGIN = 100; interface Props { @@ -31,7 +30,6 @@ interface Props { interface State { activeIndex: number; headers: MarkdownHeading[]; - marginTop: number; } export default class HeadingsLink extends React.PureComponent { @@ -43,18 +41,17 @@ export default class HeadingsLink extends React.PureComponent { activeIndex: -1, headers: props.headers.filter( h => h.depth === 2 && h.value && h.value.toLowerCase() !== 'table of contents' - ), - marginTop: MINIMUM_TOP_MARGIN + ) }; } componentDidMount() { document.addEventListener('scroll', this.scrollHandler, true); - this.scrollHandler(); } componentWillReceiveProps(nextProps: Props) { this.setState({ + activeIndex: -1, headers: nextProps.headers.filter( h => h.depth === 2 && h.value && h.value.toLowerCase() !== 'table of contents' ) @@ -65,6 +62,16 @@ export default class HeadingsLink extends React.PureComponent { document.removeEventListener('scroll', this.scrollHandler, true); } + scrollHandler = () => { + if (this.skipScrollingHandler) { + this.skipScrollingHandler = false; + return; + } + + const scrollTop = window.pageYOffset || document.body.scrollTop; + this.highlightHeading(scrollTop); + }; + highlightHeading = (scrollTop: number) => { let headingIndex = 0; for (let i = 0; i < this.state.headers.length; i++) { @@ -74,11 +81,7 @@ export default class HeadingsLink extends React.PureComponent { } headingIndex = i; } - const scrollLimit = document.body.scrollHeight - document.body.clientHeight; - this.setState({ - activeIndex: headingIndex, - marginTop: Math.max(MINIMUM_TOP_MARGIN, Math.min(scrollTop, scrollLimit)) - }); + this.setState({ activeIndex: headingIndex }); this.markH2(headingIndex + 1, false); }; @@ -99,16 +102,6 @@ export default class HeadingsLink extends React.PureComponent { } }; - scrollHandler = () => { - if (this.skipScrollingHandler) { - this.skipScrollingHandler = false; - return; - } - - const scrollTop = window.pageYOffset || document.body.scrollTop; - this.highlightHeading(scrollTop); - }; - clickHandler = (index: number) => { this.markH2(index, true); }; @@ -120,21 +113,23 @@ export default class HeadingsLink extends React.PureComponent { } return ( -
- On this page -
    - {headers.map((header, index) => { - return ( - - {header.value} - - ); - })} -
+
+
+ On this page +
    + {headers.map((header, index) => { + return ( + + {header.value} + + ); + })} +
+
); } diff --git a/server/sonar-docs/src/components/__tests__/HeadingsLink-test.tsx b/server/sonar-docs/src/components/__tests__/HeadingsLink-test.tsx new file mode 100644 index 00000000000..5340a531d6d --- /dev/null +++ b/server/sonar-docs/src/components/__tests__/HeadingsLink-test.tsx @@ -0,0 +1,39 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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 { shallow } from 'enzyme'; +import * as React from 'react'; +import HeadingsLink from '../HeadingsLink'; + +it('should render correctly', () => { + expect(shallowRender()).toMatchSnapshot(); +}); + +function shallowRender(props: Partial = {}) { + return shallow( + + ); +} diff --git a/server/sonar-docs/src/components/__tests__/__snapshots__/HeadingsLink-test.tsx.snap b/server/sonar-docs/src/components/__tests__/__snapshots__/HeadingsLink-test.tsx.snap new file mode 100644 index 00000000000..3449ded4537 --- /dev/null +++ b/server/sonar-docs/src/components/__tests__/__snapshots__/HeadingsLink-test.tsx.snap @@ -0,0 +1,33 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` +
+
+ + On this page + +
    + + Foo + + + Br + +
+
+
+`; diff --git a/server/sonar-docs/src/layouts/layout.css b/server/sonar-docs/src/layouts/layout.css index adf69979c52..7e5f94ea145 100644 --- a/server/sonar-docs/src/layouts/layout.css +++ b/server/sonar-docs/src/layouts/layout.css @@ -328,10 +328,18 @@ a.search-result .note { } .page-container .headings-container { - float: right; width: 200px; - border-left: 1px solid #cfd3d7; + float: right; + margin-top: 80px; +} + +.page-container .headings-container-fixed { + position: fixed; + width: inherit; padding-left: 26px; + border-left: 1px solid #cfd3d7; + z-index: 100; + background: white; } .page-container .headings-container span { -- 2.39.5