Skip to content

Commit

Permalink
feat(docs): add generated table of contents.
Browse files Browse the repository at this point in the history
  • Loading branch information
Hyperkid123 committed Jul 1, 2021
1 parent abf966f commit 7107e71
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 11 deletions.
53 changes: 53 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 28 additions & 11 deletions packages/docs/components/layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
Page,
PageHeader,
PageSidebar,
Split,
SplitItem,
Stack,
StackItem
} from '@patternfly/react-core';
Expand All @@ -14,6 +16,7 @@ import HeaderTools from './header-tools';
import useNavigation from './use-navigation';
import navigationMapper from '../navigation/navigation-mapper';
import Breadcrumbs from './breadcrumbs';
import TableOfContents from '../table-of-contents';

const useStyles = createUseStyles({
page: {
Expand All @@ -27,13 +30,20 @@ const useStyles = createUseStyles({
},
content: {
marginLeft: 'initial',
marginRight: 'initial'
marginRight: 'initial',
width: 'calc(100% - 16px * 2)'
},
tableOfContents: {
display: 'none'
},
'@media (min-width: 1200px)': {
content: {
width: 900,
marginLeft: 'auto',
marginRight: 'auto'
},
tableOfContents: {
display: 'block'
}
}
});
Expand All @@ -59,16 +69,23 @@ const Layout = ({ children }) => {
const Sidebar = <PageSidebar nav={NavComponent && <NavComponent />} isNavOpen={isOpen} />;
return (
<Page className={classes.page} header={Header} sidebar={NavComponent && Sidebar}>
<div className={classnames('pf-u-p-md', classes.content)}>
<Stack hasGutter>
<StackItem>
<Breadcrumbs />
</StackItem>
<StackItem>
{children}
</StackItem>
</Stack>
</div>
<Split hasGutter>
<SplitItem isFilled>
<div className={classnames('pf-u-p-md', classes.content)}>
<Stack hasGutter>
<StackItem>
<Breadcrumbs />
</StackItem>
<StackItem id="docs-content">
{children}
</StackItem>
</Stack>
</div>
</SplitItem>
<SplitItem className={classes.tableOfContents}>
<TableOfContents />
</SplitItem>
</Split>
</Page>
);
};
Expand Down
119 changes: 119 additions & 0 deletions packages/docs/components/table-of-contents/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { createUseStyles } from 'react-jss';
import classnames from 'classnames';
import PropTypes from 'prop-types';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
import { Menu, MenuContent, MenuList, MenuItem } from '@patternfly/react-core';
import StickyBox from 'react-sticky-box';

const useStyles = createUseStyles({
tableOfContent: {

},
list: {
minWidth: 250,
boxShadow: 'none !important',
background: 'none !important'
},
listItem: {
color: 'var(--pf-global--palette--black-700)',
'&:hover': {
color: 'var(--pf-global--palette--black-900)'
}
},
activeLink: {
color: 'var(--pf-global--palette--black-900) !important',
background: 'var(--pf-global--palette--white) !important',
position: 'relative',
'&::before': {
content: '""',
position: 'absolute',
left: -8,
top: 0,
bottom: 0,
borderLeft: '10px solid var(--pf-global--palette--blue-400)'
}
}
});

const ContentLink = ({ title, setActive, isActive, targetId }) => {
const classes = useStyles();
return (
<MenuItem onClick={() => {
setActive(targetId);
}} className={classnames(classes.listItem, {
[classes.activeLink]: isActive
})} to={`#${targetId}`}>
{title}
</MenuItem>
);
};

ContentLink.propTypes = {
title: PropTypes.node.isRequired,
targetId: PropTypes.string.isRequired,
isActive: PropTypes.bool,
setActive: PropTypes.func.isRequired
};

const TableOfContents = () => {
const classes = useStyles();
const { pathname } = useRouter();
const [ links, setLinks ] = useState([]);
const [ activeItem, setActive ] = useState();
let isMounted = true;

const scrollListener = (setActive) => {
const contentElement = document.getElementById('docs-content');
const anchors = Array.from(contentElement.getElementsByClassName('docs-content-link'));
const min = -20;
const max = 20;
const elem = anchors.find((elem) => {
const { top } = elem.getBoundingClientRect();
return top > min && top < max;
});
if (isMounted && elem) {
setActive(elem.firstElementChild.id);
}
};

useEffect(() => {
isMounted = true;
document.querySelector('.pf-c-page__main').addEventListener('scroll', () => scrollListener(setActive));
scrollListener(setActive);
return () => {
isMounted = false;
document.removeEventListener('scroll', scrollListener);
};
}, []);

useEffect(() => {
const contentElement = document.getElementById('docs-content');
const anchors = Array.from(contentElement.getElementsByClassName('docs-content-link'));
const links = anchors.map(elem => ({
component: elem.tagName,
title: elem.textContent,
targetId: elem.firstElementChild.id,
level: Number(elem.tagName.replace('H', '')) - 1
}));
setLinks(links);
}, [ pathname ]);

return links.length > 0 ? (
<StickyBox offsetTop={0} offsetBottom={0}>
<div className={classes.tableOfContent}>
<Menu className={classes.list}>
<MenuContent>
<MenuList>
{/* eslint-disable react/prop-types */}
{links.map(props => <ContentLink setActive={setActive} key={props.targetId} isActive={props.targetId === activeItem} {...props} />)}
{/* eslint-enable react/prop-types */}
</MenuList>
</MenuContent>
</Menu>
</div>
</StickyBox>
) : null;
};

export default TableOfContents;
1 change: 1 addition & 0 deletions packages/docs/docker.package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"react-json-view": "^1.19.1",
"react-redux": "^7.2.2",
"react-router-dom": "^5.2.0",
"react-sticky-box": "^0.9.3",
"redux": "^4.0.5"
},
"devDependencies": {
Expand Down
1 change: 1 addition & 0 deletions packages/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"react-json-view": "^1.19.1",
"react-redux": "^7.2.2",
"react-router-dom": "^5.2.0",
"react-sticky-box": "^0.9.3",
"redux": "^4.0.5"
},
"devDependencies": {
Expand Down

0 comments on commit 7107e71

Please sign in to comment.