Skip to content

Commit

Permalink
[docs] Update the styling of the TOC (#14520)
Browse files Browse the repository at this point in the history
* [docs] Update the styling of the TOC

(Just scratching an itch 😄)

* Update the TOC on click of #, update the URL

* no hash for title

* Hide subitems for sections other than current

* new selection strategy

* fix duplicate id

* change offset

* move styles back

* Collapse transition

* Revert the use of -

* Refactor styles

* Revert "Collapse transition"

This reverts commit 6e8fd97.

* don't hide sub-headings

* prettier

* more subtle styling

* no smooth scrolling

* fix scroll position on page change

* Don't use state for tracking clicked links

* tweak the intendation & spacing

* prettier

* small change
  • Loading branch information
mbrookes authored and oliviertassinari committed Feb 15, 2019
1 parent 41ebd30 commit 19aa8ad
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 18 deletions.
4 changes: 2 additions & 2 deletions docs/src/modules/components/AppContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ const styles = theme => ({
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2),
[theme.breakpoints.up('sm')]: {
paddingLeft: theme.spacing(4),
paddingLeft: theme.spacing(3),
paddingRight: theme.spacing(4),
maxWidth: 'calc(100% - 167px)',
maxWidth: 'calc(100% - 175px)',
},
[theme.breakpoints.up('lg')]: {
paddingLeft: theme.spacing(5),
Expand Down
99 changes: 86 additions & 13 deletions docs/src/modules/components/AppTableOfContents.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import marked from 'marked';
import warning from 'warning';
import throttle from 'lodash/throttle';
import EventListener from 'react-event-listener';
import clsx from 'clsx';
import { withStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import { textToHash } from '@material-ui/docs/MarkdownElement/MarkdownElement';
Expand Down Expand Up @@ -48,14 +49,14 @@ const styles = theme => ({
top: 70 + 29,
// Fix IE 11 position sticky issue.
marginTop: 70 + 29,
width: 167,
width: 175,
flexShrink: 0,
order: 2,
position: 'sticky',
wordBreak: 'break-word',
height: 'calc(100vh - 70px)',
height: 'calc(100vh - 70px - 29px)',
overflowY: 'auto',
padding: `${theme.spacing(2)}px ${theme.spacing(2)}px ${theme.spacing(2)}px 5px`,
padding: theme.spacing(2, 2, 2, 0),
display: 'none',
[theme.breakpoints.up('sm')]: {
display: 'block',
Expand All @@ -71,8 +72,24 @@ const styles = theme => ({
},
item: {
fontSize: 13,
padding: theme.spacing(0.5, 0),
padding: theme.spacing(0.5, 0, 0.5, 1),
borderLeft: '4px solid transparent',
boxSizing: 'content-box',
'&:hover': {
borderLeft: `4px solid ${
theme.palette.type === 'light' ? theme.palette.grey[200] : theme.palette.grey[900]
}`,
},
'&$active': {
borderLeft: `4px solid ${
theme.palette.type === 'light' ? theme.palette.grey[300] : theme.palette.grey[800]
}`,
},
},
secondaryItem: {
paddingLeft: theme.spacing(2.5),
},
active: {},
});

function checkDuplication(uniq, item) {
Expand All @@ -88,6 +105,8 @@ class AppTableOfContents extends React.Component {
this.findActiveIndex();
}, 166); // Corresponds to 10 frames at 60 Hz.

clicked = false;

constructor(props) {
super();
this.itemsServer = getItems(props.contents);
Expand Down Expand Up @@ -118,25 +137,49 @@ class AppTableOfContents extends React.Component {
});
}
});
this.findActiveIndex();
window.addEventListener('hashchange', this.handleHashChange);
}

componentWillUnmount() {
this.handleScroll.cancel();
clearTimeout(this.unsetClicked);
window.removeEventListener('hashchange', this.handleHashChange);
}

// Update the active TOC entry if the hash changes through click on '#' icon
handleHashChange = () => {
const hash = window.location.hash.substring(1);

if (this.state.active !== hash) {
this.setState({
active: hash,
});
}
};

findActiveIndex = () => {
// Don't set the active index based on scroll if a link was just clicked
if (this.clicked) {
return;
}

let active;

for (let i = 0; i < this.itemsClient.length; i += 1) {
for (let i = this.itemsClient.length - 1; i >= 0; i -= 1) {
// No hash if we're near the top of the page
if (document.documentElement.scrollTop < 200) {
active = { hash: null };
break;
}

const item = this.itemsClient[i];

warning(item.node, `Missing node on the item ${JSON.stringify(item, null, 2)}`);

if (
item.node &&
(document.documentElement.scrollTop < item.node.offsetTop + 100 ||
i === this.itemsClient.length - 1)
item.node.offsetTop <
document.documentElement.scrollTop + document.documentElement.clientHeight / 8
) {
active = item;
break;
Expand All @@ -147,6 +190,28 @@ class AppTableOfContents extends React.Component {
this.setState({
active: active.hash,
});

window.history.replaceState(
null,
null,
active.hash === null
? `${window.location.pathname}${window.location.search}`
: `#${active.hash}`,
);
}
};

handleClick = hash => () => {
// Used to disable findActiveIndex if the page scrolls due to a click
this.clicked = true;
this.unsetClicked = setTimeout(() => {
this.clicked = false;
}, 1000);

if (this.state.active !== hash) {
this.setState({
active: hash,
});
}
};

Expand All @@ -169,7 +234,12 @@ class AppTableOfContents extends React.Component {
block
color={active === item2.hash ? 'textPrimary' : 'textSecondary'}
href={`#${item2.hash}`}
className={classes.item}
underline="none"
onClick={this.handleClick(item2.hash)}
className={clsx(
classes.item,
active === item2.hash ? classes.active : undefined,
)}
>
<span dangerouslySetInnerHTML={{ __html: item2.text }} />
</Link>
Expand All @@ -181,10 +251,13 @@ class AppTableOfContents extends React.Component {
block
color={active === item3.hash ? 'textPrimary' : 'textSecondary'}
href={`#${item3.hash}`}
className={classes.item}
style={{
paddingLeft: 8 * 2,
}}
underline="none"
onClick={this.handleClick(item3.hash)}
className={clsx(
classes.item,
classes.secondaryItem,
active === item3.hash ? classes.active : undefined,
)}
>
<span dangerouslySetInnerHTML={{ __html: item3.text }} />
</Link>
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/style/icons/FontAwesome.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class FontAwesome extends React.Component {
componentDidMount() {
loadCSS(
'https://use.fontawesome.com/releases/v5.1.0/css/all.css',
document.querySelector('#font-awesome'),
document.querySelector('#font-awesome-css'),
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ const styles = theme => ({
fontSize: 16,
color: theme.palette.text.primary,
'& .anchor-link': {
marginTop: -96, // Offset for the anchor.
marginTop: -96 - 29, // Offset for the anchor.
position: 'absolute',
},
'& pre, & pre[class*="language-"]': {
Expand Down
2 changes: 1 addition & 1 deletion pages/_document.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class MyDocument extends Document {
*/}
<link href="https://fonts.gstatic.com" rel="preconnect" crossOrigin="anonymous" />
<style id="material-icon-font" />
<style id="font-awesome" />
<style id="font-awesome-css" />
<style id="app-search" />
<style id="insertion-point-jss" />
</Head>
Expand Down

0 comments on commit 19aa8ad

Please sign in to comment.