feat: highlighted sidebar as you scroll on doc reference pages

This commit is contained in:
Fabio Berger
2018-10-15 17:35:40 +01:00
parent 96d145f54f
commit ce151f630d
5 changed files with 58 additions and 20 deletions

View File

@@ -20,6 +20,7 @@ export interface MarkdownSectionProps {
headerSize?: HeaderSizes;
githubLink?: string;
shouldReformatTitle?: boolean;
alternativeSectionTitle?: string;
}
interface DefaultMarkdownSectionProps {
@@ -47,22 +48,25 @@ export class MarkdownSection extends React.Component<MarkdownSectionProps, Markd
const { sectionName, markdownContent, headerSize, githubLink } = this.props as PropsWithDefaults;
const id = utils.getIdFromName(sectionName);
const finalSectionName = this.props.shouldReformatTitle
const formattedSectionName = this.props.shouldReformatTitle
? utils.convertCamelCaseToSpaces(sectionName)
: sectionName;
const title = !_.isUndefined(this.props.alternativeSectionTitle)
? this.props.alternativeSectionTitle
: formattedSectionName;
return (
<div
className="md-px1 sm-px2 overflow-hidden"
onMouseOver={this._setAnchorVisibility.bind(this, true)}
onMouseOut={this._setAnchorVisibility.bind(this, false)}
>
<ScrollElement name={id}>
<Container className="clearfix" marginBottom="20px">
<ScrollElement name={id} style={{ paddingBottom: 20 }}>
<Container className="clearfix" paddingTop="30px" paddingBottom="20px">
<div className="col lg-col-8 md-col-8 sm-col-12">
<span style={{ color: colors.grey700 }}>
<AnchorTitle
headerSize={headerSize}
title={_.capitalize(finalSectionName)}
title={_.capitalize(title)}
id={id}
shouldShowAnchor={this.state.shouldShowAnchor}
/>
@@ -87,13 +91,7 @@ export class MarkdownSection extends React.Component<MarkdownSectionProps, Markd
paragraph: MarkdownParagraphBlock,
}}
/>
<Container
width={'100%'}
height={'1px'}
backgroundColor={colors.grey300}
marginTop={'32px'}
marginBottom={'32px'}
/>
<Container width={'100%'} height={'1px'} backgroundColor={colors.grey300} marginTop={'32px'} />
</ScrollElement>
</div>
);

View File

@@ -14,9 +14,12 @@ export interface NestedSidebarMenuProps {
sidebarHeader?: React.ReactNode;
shouldDisplaySectionHeaders?: boolean;
shouldReformatMenuItemNames?: boolean;
parentName?: string;
}
export interface NestedSidebarMenuState {}
export interface NestedSidebarMenuState {
scrolledToId: string;
}
const styles: Styles = {
menuItemWithHeaders: {
@@ -40,7 +43,28 @@ export class NestedSidebarMenu extends React.Component<NestedSidebarMenuProps, N
public static defaultProps: Partial<NestedSidebarMenuProps> = {
shouldDisplaySectionHeaders: true,
shouldReformatMenuItemNames: true,
parentName: 'default',
};
private _urlIntervalCheckId: number;
constructor(props: NestedSidebarMenuProps) {
super(props);
this.state = {
scrolledToId: '',
};
}
public componentDidMount(): void {
this._urlIntervalCheckId = window.setInterval(() => {
const scrollId = location.hash.slice(1);
if (scrollId !== this.state.scrolledToId) {
this.setState({
scrolledToId: scrollId,
});
}
}, 200);
}
public componentWillUnmount(): void {
window.clearInterval(this._urlIntervalCheckId);
}
public render(): React.ReactNode {
const navigation = _.map(this.props.sectionNameToLinks, (links: ALink[], sectionName: string) => {
const finalSectionName = utils.convertCamelCaseToSpaces(sectionName);
@@ -48,7 +72,7 @@ export class NestedSidebarMenu extends React.Component<NestedSidebarMenuProps, N
// tslint:disable-next-line:no-unused-variable
return (
<div key={`section-${sectionName}`} className="py1" style={{ color: colors.greyTheme }}>
<div style={{ fontSize: 14, letterSpacing: 0.5 }} className="py1">
<div style={{ fontSize: 14, letterSpacing: 0.5 }} className="py1 pl1">
{finalSectionName.toUpperCase()}
</div>
{this._renderMenuItems(links)}
@@ -61,23 +85,37 @@ export class NestedSidebarMenu extends React.Component<NestedSidebarMenuProps, N
return (
<div>
{this.props.sidebarHeader}
<div className="pl1">{navigation}</div>
<div>{navigation}</div>
</div>
);
}
private _renderMenuItems(links: ALink[]): React.ReactNode[] {
const scrolledToId = this.state.scrolledToId;
const menuItemStyles = this.props.shouldDisplaySectionHeaders
? styles.menuItemWithHeaders
: styles.menuItemWithoutHeaders;
const menuItemInnerDivStyles = this.props.shouldDisplaySectionHeaders ? styles.menuItemInnerDivWithHeaders : {};
const menuItems = _.map(links, link => {
const isScrolledTo = link.to === scrolledToId;
const finalMenuItemName = this.props.shouldReformatMenuItemNames
? utils.convertDashesToSpaces(link.title)
: link.title;
return (
<div key={`menuItem-${finalMenuItemName}`}>
<Link to={link.to} shouldOpenInNewTab={link.shouldOpenInNewTab}>
<MenuItem style={menuItemStyles} innerDivStyle={menuItemInnerDivStyles}>
<MenuItem
style={{
...menuItemStyles,
paddingLeft: 8,
borderRadius: 6,
backgroundColor: isScrolledTo ? colors.lightLinkBlue : 'inherit',
}}
innerDivStyle={{
...menuItemInnerDivStyles,
color: isScrolledTo ? colors.white : 'inherit',
fontWeight: isScrolledTo ? 'bold' : 'inherit',
}}
>
<span
style={{
textTransform: this.props.shouldReformatMenuItemNames ? 'capitalize' : 'none',