Skip to content

Commit

Permalink
feat: Responsive nav
Browse files Browse the repository at this point in the history
  • Loading branch information
timglaser committed Jun 17, 2020
1 parent db6443b commit f232e0a
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 140 deletions.
2 changes: 1 addition & 1 deletion src/components/GlobalHeader.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@

@media screen and (max-width: 1240px) {
.global-header-container {
padding: 0 1rem;
padding: 0 1.75rem;
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/components/Layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ import PropTypes from 'prop-types';

import Footer from './Footer';
import GlobalHeader from './GlobalHeader';
import MobileHeader from './MobileHeader';
import Sidebar from './Sidebar';
import styles from './Layout.module.scss';
import pages from '../data/sidenav.json';
import './styles.scss';

const Layout = ({ children }) => (
<>
<GlobalHeader />
<MobileHeader className={styles.hideOnDesktop} />
<div className={styles.layout}>
<Sidebar className={styles.sidebar} pages={pages} />
<Sidebar className={styles.hideOnMobile} />
<main>{children}</main>
</div>
<Footer />
Expand Down
16 changes: 12 additions & 4 deletions src/components/Layout.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@
.layout {
display: block;
}

.sidebar {
display: none;
}
}

@media screen and (max-width: 1240px) {
Expand All @@ -24,3 +20,15 @@
padding-right: 1rem;
}
}

.hideOnDesktop {
@media (min-width: 760px) {
display: none;
}
}

.hideOnMobile {
@media (max-width: 760px) {
display: none;
}
}
19 changes: 19 additions & 0 deletions src/components/MobileHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'gatsby';
import cx from 'classnames';
import Navigation from './Navigation';
import styles from './MobileHeader.module.scss';

const MobileHeader = ({ className }) => (
<aside className={cx(styles.container, className)}>
<Link to="/" className={styles.logo} />
{/* <Navigation /> */}
</aside>
);

MobileHeader.propTypes = {
className: PropTypes.string,
};

export default MobileHeader;
17 changes: 17 additions & 0 deletions src/components/MobileHeader.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.container {
display: flex;
align-items: center;
justify-content: space-between;
height: 60px;
padding: 0 1rem;
border-bottom: 1px solid var(--color-neutrals-100);
}

.logo {
width: 160px;
height: 34px;
background-size: 160px 34px;
background-repeat: no-repeat;
display: inline-block;
background-image: url('../images/developers-logo.svg');
}
66 changes: 66 additions & 0 deletions src/components/Navigation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { useState, useContext } from 'react';
import PropTypes from 'prop-types';
import { Link } from 'gatsby';
import cx from 'classnames';
import { BreadcrumbContext } from './BreadcrumbContext';
import pages from '../data/sidenav.json';
import { link } from '../types';

import styles from './Navigation.module.scss';

const Navigation = () => {
return (
<nav className={styles.container} role="navigation" aria-label="Navigation">
<ul className={styles.listNav}>{renderNav(pages)}</ul>
</nav>
);
};

Navigation.propTypes = {
className: PropTypes.string,
pages: PropTypes.arrayOf(link).isRequired,
};

export default Navigation;

// recursively create navigation
const renderNav = (pages, depthLevel = 0) => {
return pages.map((page, index) => {
const crumbs = useContext(BreadcrumbContext).flatMap((x) => x.displayName);
const [isDisplay, setIsDisplay] = useState(
crumbs.length === depthLevel || crumbs.includes(page.displayName)
);
const isCurrentPage = crumbs[crumbs.length - 1] === page.displayName;

const display = page.url ? (
<Link to={page.url}>{page.displayName}</Link>
) : (
<div
role="button"
onClick={() => setIsDisplay(!isDisplay)}
onKeyPress={() => setIsDisplay(!isDisplay)}
tabIndex={0}
>
{page.displayName}
</div>
);
let subNav;

if (page.children) {
subNav = renderNav(page.children, depthLevel + 1);
}
return (
<li
className={cx(styles[`navDepth${depthLevel}`], {
[styles.isCurrentPage]: isCurrentPage,
})}
key={index}
>
{display}
<ul className={cx(styles.nestedNav, { [styles.isDisplay]: isDisplay })}>
{subNav}
</ul>
</li>
);
});
};
75 changes: 75 additions & 0 deletions src/components/Navigation.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
.container {
font-size: 0.875rem;

ul {
margin: 0;
padding-left: 1rem;
list-style: none;
}

a {
color: var(--color-black);
}

// remove?
button {
background: none;
border: 0;
cursor: pointer;
width: 3rem;
display: none;
}

nav {
margin-top: 1rem;
}
}

.nestedNav {
display: none;
}

.isDisplay {
display: block;
}

.listNav {
ul {
padding-left: 1rem;
}
}

.navDepth0 {
color: var(--color-black);
font-weight: bold;
div {
margin: 1rem 0;
}
li {
margin: 1rem 0;
}
}

.navDepth1 {
font-weight: normal;
ul {
padding-left: 0.2rem;
}
}

.navDepth2 {
font-weight: bold;
text-transform: uppercase;
color: var(--color-neutrals-600);
font-size: 14px;
}

.navDepth3 {
font-weight: normal;
text-transform: initial;
color: var(--color-black);
}

.isCurrentPage {
font-weight: bold;
}
55 changes: 4 additions & 51 deletions src/components/Sidebar.js
Original file line number Diff line number Diff line change
@@ -1,66 +1,19 @@
import React, { useState, useContext } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'gatsby';
import cx from 'classnames';
import { BreadcrumbContext } from './BreadcrumbContext';

import { link } from '../types';
import Navigation from './Navigation';
import styles from './Sidebar.module.scss';

// recursively create navigation
const renderNav = (pages, depthLevel = 0) => {
return pages.map((page, index) => {
const crumbs = useContext(BreadcrumbContext).flatMap((x) => x.displayName);
const [isDisplay, setIsDisplay] = useState(
crumbs.length === depthLevel || crumbs.includes(page.displayName)
);
const isCurrentPage = crumbs[crumbs.length - 1] === page.displayName;

const display = page.url ? (
<Link to={page.url}>{page.displayName}</Link>
) : (
<div
role="button"
onClick={() => setIsDisplay(!isDisplay)}
onKeyPress={() => setIsDisplay(!isDisplay)}
tabIndex={0}
>
{page.displayName}
</div>
);
let subNav;

if (page.children) {
subNav = renderNav(page.children, depthLevel + 1);
}
return (
<li
className={cx(styles[`navDepth${depthLevel}`], {
[styles.isCurrentPage]: isCurrentPage,
})}
key={index}
>
{display}
<ul className={cx(styles.nestedNav, { [styles.isDisplay]: isDisplay })}>
{subNav}
</ul>
</li>
);
});
};

const Sidebar = ({ className, pages }) => (
const Sidebar = ({ className }) => (
<aside className={cx(styles.sidebar, className)}>
<Link to="/" className={styles.logo} />
<nav role="navigation" aria-label="Sidebar">
<ul className={styles.listNav}>{renderNav(pages)}</ul>
</nav>
<Navigation />
</aside>
);

Sidebar.propTypes = {
className: PropTypes.string,
pages: PropTypes.arrayOf(link).isRequired,
};

export default Sidebar;
Loading

0 comments on commit f232e0a

Please sign in to comment.