fix(client): scroll top and focus an article on guide navigation
This commit is contained in:
@ -29,7 +29,16 @@ const propTypes = {
|
|||||||
location: PropTypes.object
|
location: PropTypes.object
|
||||||
};
|
};
|
||||||
|
|
||||||
const Layout = ({ children }) => (
|
class Layout extends React.Component {
|
||||||
|
getContentRef = ref => (this.contentRef = ref);
|
||||||
|
|
||||||
|
handleNavigation = () => {
|
||||||
|
this.contentRef.scrollTop = 0;
|
||||||
|
this.contentRef.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
<StaticQuery
|
<StaticQuery
|
||||||
query={graphql`
|
query={graphql`
|
||||||
query LayoutQuery {
|
query LayoutQuery {
|
||||||
@ -69,19 +78,24 @@ const Layout = ({ children }) => (
|
|||||||
>
|
>
|
||||||
<SideNav
|
<SideNav
|
||||||
expandedState={expandedState}
|
expandedState={expandedState}
|
||||||
|
onNavigate={this.handleNavigation}
|
||||||
pages={pages}
|
pages={pages}
|
||||||
toggleDisplaySideNav={toggleDisplaySideNav}
|
toggleDisplaySideNav={toggleDisplaySideNav}
|
||||||
toggleExpandedState={toggleExpandedState}
|
toggleExpandedState={toggleExpandedState}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col
|
<Col
|
||||||
className='content'
|
|
||||||
md={8}
|
md={8}
|
||||||
smHidden={displaySideNav}
|
smHidden={displaySideNav}
|
||||||
xsHidden={displaySideNav}
|
xsHidden={displaySideNav}
|
||||||
>
|
>
|
||||||
<main className='main' id='main' tabIndex='-1'>
|
<main
|
||||||
{children}
|
className='content'
|
||||||
|
id='main'
|
||||||
|
ref={this.getContentRef}
|
||||||
|
tabIndex='-1'
|
||||||
|
>
|
||||||
|
{this.props.children}
|
||||||
</main>
|
</main>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
@ -92,7 +106,9 @@ const Layout = ({ children }) => (
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Layout.displayName = 'Layout';
|
Layout.displayName = 'Layout';
|
||||||
Layout.propTypes = propTypes;
|
Layout.propTypes = propTypes;
|
||||||
|
@ -4,23 +4,30 @@ import Link from 'gatsby-link';
|
|||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
isStubbed: PropTypes.bool,
|
isStubbed: PropTypes.bool,
|
||||||
|
onNavigate: PropTypes.func.isRequired,
|
||||||
path: PropTypes.string,
|
path: PropTypes.string,
|
||||||
router: PropTypes.object,
|
router: PropTypes.object,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
toggleDisplaySideNav: PropTypes.func.isRequired
|
toggleDisplaySideNav: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
function NavItem(props) {
|
class NavItem extends React.Component {
|
||||||
const { isStubbed, path, title } = props;
|
handleClick = () => {
|
||||||
|
this.props.toggleDisplaySideNav();
|
||||||
|
this.props.onNavigate();
|
||||||
|
};
|
||||||
|
render() {
|
||||||
|
const { isStubbed, path, title } = this.props;
|
||||||
return (
|
return (
|
||||||
<li>
|
<li>
|
||||||
<Link data-navitem='true' onClick={props.toggleDisplaySideNav} to={path}>
|
<Link data-navitem='true' onClick={this.handleClick} to={path}>
|
||||||
<span className={'navItemTitle' + (isStubbed ? ' stubbed' : '')}>
|
<span className={'navItemTitle' + (isStubbed ? ' stubbed' : '')}>
|
||||||
{title}
|
{title}
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NavItem.displayName = 'NavItem';
|
NavItem.displayName = 'NavItem';
|
||||||
|
@ -9,6 +9,7 @@ const propTypes = {
|
|||||||
handleClick: PropTypes.func.isRequired,
|
handleClick: PropTypes.func.isRequired,
|
||||||
hasChildren: PropTypes.bool,
|
hasChildren: PropTypes.bool,
|
||||||
isExpanded: PropTypes.bool,
|
isExpanded: PropTypes.bool,
|
||||||
|
onNavigate: PropTypes.func.isRequired,
|
||||||
path: PropTypes.string,
|
path: PropTypes.string,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
toggleDisplaySideNav: PropTypes.func.isRequired
|
toggleDisplaySideNav: PropTypes.func.isRequired
|
||||||
@ -52,9 +53,10 @@ class NavPanel extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleTitleClick() {
|
handleTitleClick() {
|
||||||
const { path, toggleDisplaySideNav } = this.props;
|
const { path, toggleDisplaySideNav, onNavigate } = this.props;
|
||||||
toggleDisplaySideNav();
|
toggleDisplaySideNav();
|
||||||
navigate(path);
|
navigate(path);
|
||||||
|
onNavigate();
|
||||||
}
|
}
|
||||||
|
|
||||||
renderHeader() {
|
renderHeader() {
|
||||||
@ -94,8 +96,6 @@ class NavPanel extends Component {
|
|||||||
return (
|
return (
|
||||||
<Panel
|
<Panel
|
||||||
bsClass='panelStyle panel'
|
bsClass='panelStyle panel'
|
||||||
collapsible={true}
|
|
||||||
expanded={isExpanded}
|
|
||||||
id={`${dashedName}-panel`}
|
id={`${dashedName}-panel`}
|
||||||
role='listitem'
|
role='listitem'
|
||||||
>
|
>
|
||||||
|
@ -7,6 +7,7 @@ import NavItem from './NavItem';
|
|||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
expandedState: PropTypes.object,
|
expandedState: PropTypes.object,
|
||||||
|
onNavigate: PropTypes.func.isRequired,
|
||||||
pages: PropTypes.arrayOf(PropTypes.object),
|
pages: PropTypes.arrayOf(PropTypes.object),
|
||||||
parents: PropTypes.arrayOf(PropTypes.object),
|
parents: PropTypes.arrayOf(PropTypes.object),
|
||||||
toggleDisplaySideNav: PropTypes.func.isRequired,
|
toggleDisplaySideNav: PropTypes.func.isRequired,
|
||||||
@ -42,7 +43,9 @@ class SideNav extends Component {
|
|||||||
const [category] = pages.filter(page => page.path === path);
|
const [category] = pages.filter(page => page.path === path);
|
||||||
const { title, hasChildren, dashedName } = category;
|
const { title, hasChildren, dashedName } = category;
|
||||||
|
|
||||||
const children = this.renderChildren(childrenForParent, pages);
|
const children = isExpanded
|
||||||
|
? this.renderChildren(childrenForParent, pages)
|
||||||
|
: null;
|
||||||
return (
|
return (
|
||||||
<NavPanel
|
<NavPanel
|
||||||
dashedName={dashedName}
|
dashedName={dashedName}
|
||||||
@ -50,11 +53,12 @@ class SideNav extends Component {
|
|||||||
hasChildren={hasChildren}
|
hasChildren={hasChildren}
|
||||||
isExpanded={isExpanded}
|
isExpanded={isExpanded}
|
||||||
key={parent.path}
|
key={parent.path}
|
||||||
|
onNavigate={this.props.onNavigate}
|
||||||
path={parent.path}
|
path={parent.path}
|
||||||
title={title}
|
title={title}
|
||||||
toggleDisplaySideNav={this.props.toggleDisplaySideNav}
|
toggleDisplaySideNav={this.props.toggleDisplaySideNav}
|
||||||
>
|
>
|
||||||
{isExpanded ? children : null}
|
{children}
|
||||||
</NavPanel>
|
</NavPanel>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -68,6 +72,7 @@ class SideNav extends Component {
|
|||||||
<NavItem
|
<NavItem
|
||||||
isStubbed={child.isStubbed}
|
isStubbed={child.isStubbed}
|
||||||
key={child.path}
|
key={child.path}
|
||||||
|
onNavigate={this.props.onNavigate}
|
||||||
path={child.path}
|
path={child.path}
|
||||||
title={child.title}
|
title={child.title}
|
||||||
toggleDisplaySideNav={this.props.toggleDisplaySideNav}
|
toggleDisplaySideNav={this.props.toggleDisplaySideNav}
|
||||||
|
@ -84,36 +84,6 @@
|
|||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 404 */
|
|
||||||
|
|
||||||
.flexWrapper {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 50vh;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.verticalAlign {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
color: #006400;
|
|
||||||
background: #fff;
|
|
||||||
border-color: #006400;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button:hover {
|
|
||||||
color: #fff;
|
|
||||||
background: #006400;
|
|
||||||
border-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SideNav */
|
/* SideNav */
|
||||||
|
|
||||||
.caretStyle {
|
.caretStyle {
|
||||||
@ -197,6 +167,6 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
.article {
|
.content {
|
||||||
outline: 0;
|
outline: 0;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { Component, Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { graphql } from 'gatsby';
|
import { graphql } from 'gatsby';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
@ -13,20 +13,7 @@ const propTypes = {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
class GuideArticle extends Component {
|
const GuideArticle = props => {
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.article = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
if (this.article && document.activeElement.hasAttribute('data-navitem')) {
|
|
||||||
this.article.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
const {
|
||||||
location: { pathname },
|
location: { pathname },
|
||||||
data: {
|
data: {
|
||||||
@ -37,7 +24,7 @@ class GuideArticle extends Component {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
pageContext: { meta }
|
pageContext: { meta }
|
||||||
} = this.props;
|
} = props;
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Helmet>
|
<Helmet>
|
||||||
@ -63,15 +50,11 @@ class GuideArticle extends Component {
|
|||||||
className='article'
|
className='article'
|
||||||
dangerouslySetInnerHTML={{ __html: html }}
|
dangerouslySetInnerHTML={{ __html: html }}
|
||||||
id='article'
|
id='article'
|
||||||
ref={article => {
|
|
||||||
this.article = article;
|
|
||||||
}}
|
|
||||||
tabIndex='-1'
|
tabIndex='-1'
|
||||||
/>
|
/>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
GuideArticle.displayName = 'GuideArticle';
|
GuideArticle.displayName = 'GuideArticle';
|
||||||
GuideArticle.propTypes = propTypes;
|
GuideArticle.propTypes = propTypes;
|
||||||
|
Reference in New Issue
Block a user