Browse Source

SONAR-12375 Fix floating TOC in documentation

tags/8.2.0.32929
Wouter Admiraal 4 years ago
parent
commit
4691d62918

+ 30
- 35
server/sonar-docs/src/components/HeadingsLink.tsx View File

@@ -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<Props, State> {
@@ -43,18 +41,17 @@ export default class HeadingsLink extends React.PureComponent<Props, State> {
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<Props, State> {
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<Props, State> {
}
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<Props, State> {
}
};

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<Props, State> {
}

return (
<div className="headings-container" style={{ marginTop: this.state.marginTop + 'px' }}>
<span>On this page</span>
<ul>
{headers.map((header, index) => {
return (
<HeadingAnchor
active={this.state.activeIndex === index}
clickHandler={this.clickHandler}
index={index + 1}
key={index}>
{header.value}
</HeadingAnchor>
);
})}
</ul>
<div className="headings-container">
<div className="headings-container-fixed">
<span>On this page</span>
<ul>
{headers.map((header, index) => {
return (
<HeadingAnchor
active={this.state.activeIndex === index}
clickHandler={this.clickHandler}
index={index + 1}
key={index}>
{header.value}
</HeadingAnchor>
);
})}
</ul>
</div>
</div>
);
}

+ 39
- 0
server/sonar-docs/src/components/__tests__/HeadingsLink-test.tsx View File

@@ -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<HeadingsLink['props']> = {}) {
return shallow(
<HeadingsLink
headers={[
{ value: 'Table of Contents', depth: 2 },
{ value: 'Foo', depth: 2 },
{ value: 'Br', depth: 2 }
]}
{...props}
/>
);
}

+ 33
- 0
server/sonar-docs/src/components/__tests__/__snapshots__/HeadingsLink-test.tsx.snap View File

@@ -0,0 +1,33 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly 1`] = `
<div
className="headings-container"
>
<div
className="headings-container-fixed"
>
<span>
On this page
</span>
<ul>
<HeadingAnchor
active={false}
clickHandler={[Function]}
index={1}
key="0"
>
Foo
</HeadingAnchor>
<HeadingAnchor
active={false}
clickHandler={[Function]}
index={2}
key="1"
>
Br
</HeadingAnchor>
</ul>
</div>
</div>
`;

+ 10
- 2
server/sonar-docs/src/layouts/layout.css View File

@@ -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 {

Loading…
Cancel
Save