Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reference Template #18

Merged
merged 13 commits into from
Apr 27, 2020
6 changes: 4 additions & 2 deletions src/components/Container.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';

import './Container.scss';

const Container = ({ children }) => (
<div className="u-container">{children}</div>
const Container = ({ children, className }) => (
<div className={cx('u-container', className)}>{children}</div>
);

Container.propTypes = {
children: PropTypes.node.isRequired,
className: PropTypes.string,
};

export default Container;
10 changes: 5 additions & 5 deletions src/components/HamburgerMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import cx from 'classnames';

import './HamburgerMenu.scss';

const HamburgerMenu = ({ toggle, open }) => (
const HamburgerMenu = ({ toggle, isOpen }) => (
<button
aria-expanded={open}
aria-expanded={isOpen}
aria-label="Mobile Menu"
type="button"
className={cx('HamburgerMenu', { 'is-open': open })}
className={cx('HamburgerMenu', { 'is-open': isOpen })}
onClick={() => toggle()}
>
<div />
Expand All @@ -20,11 +20,11 @@ const HamburgerMenu = ({ toggle, open }) => (

HamburgerMenu.propTypes = {
toggle: PropTypes.func.isRequired,
open: PropTypes.bool,
isOpen: PropTypes.bool,
};

HamburgerMenu.defaultProps = {
open: false,
isOpen: false,
};

export default HamburgerMenu;
36 changes: 15 additions & 21 deletions src/components/Header.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import './Header.scss';

import { Link, graphql, useStaticQuery } from 'gatsby';
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { Link, graphql, useStaticQuery } from 'gatsby';
import cx from 'classnames';

import { link } from '../types';
import Container from './Container';
import ExternalLink from './ExternalLink';
import HamburgerMenu from './HamburgerMenu';
import PropTypes from 'prop-types';
import cx from 'classnames';
import './Header.scss';

const Header = ({ pages }) => {
const [menuOpen, setMenuOpen] = useState(false);
const [isOpen, setIsOpen] = useState(false);

// NOTE: we may want to abstract this
const data = useStaticQuery(graphql`
Expand All @@ -33,7 +33,7 @@ const Header = ({ pages }) => {
`);

return (
<header className={cx('Header--main', { 'is-open': menuOpen })}>
<header className={cx('Header--main', { 'is-open': isOpen })}>
<Container>
<nav
role="navigation"
Expand Down Expand Up @@ -70,14 +70,14 @@ const Header = ({ pages }) => {
<Link to="/">{'</>'} New Relic Developers</Link>
</h1>

<HamburgerMenu toggle={() => setMenuOpen(!menuOpen)} open={menuOpen} />
<HamburgerMenu toggle={() => setIsOpen(!isOpen)} isOpen={isOpen} />

<nav role="navigation" aria-label="Main" className="Header-nav--main">
<h3 className="u-hideOnDesktop">Developers</h3>
<ul>
{pages.map((page, i) => (
<li key={i}>
<Link to={page.path}>{page.displayName}</Link>
<Link to={page.url}>{page.displayName}</Link>
</li>
))}
</ul>
Expand All @@ -103,22 +103,16 @@ const Header = ({ pages }) => {
};

Header.propTypes = {
pages: PropTypes.arrayOf(
PropTypes.shape({
displayName: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
active: PropTypes.bool,
})
),
pages: PropTypes.arrayOf(link),
};

Header.defaultProps = {
pages: [
{ displayName: 'Collect Data', path: '' },
{ displayName: 'Explore Data', path: 'explore-data' },
{ displayName: 'Build Apps', path: '' },
{ displayName: 'Automate New Relic', path: '' },
{ displayName: 'Reference Docs', path: '' },
{ displayName: 'Collect Data', url: '' },
{ displayName: 'Explore Data', url: 'explore-data' },
{ displayName: 'Build Apps', url: '' },
{ displayName: 'Automate New Relic', url: '' },
{ displayName: 'Reference Docs', url: '' },
],
};

Expand Down
5 changes: 0 additions & 5 deletions src/components/Layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ const Layout = ({ children }) => (
<>
<Header />
<main>{children}</main>
<footer>
© {new Date().getFullYear()}, Built with
{` `}
<a href="https://www.gatsbyjs.org">Gatsby</a>
</footer>
</>
);

Expand Down
49 changes: 49 additions & 0 deletions src/components/Sidebar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'gatsby';
import cx from 'classnames';

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

// recursively create navigation
const renderNav = (page, index) => (
<li key={index}>
<Link to={page.url} className={cx({ 'is-active': page.active })}>
{page.displayName}
</Link>
{page.children && <ul>{page.children.map(renderNav)}</ul>}
</li>
);

const Sidebar = ({ pages, isOpen, toggle }) => (
<aside className={cx('Sidebar', { 'is-open': isOpen })}>
<div className="Sidebar-top">
<h3>Pages</h3>
<button
aria-expanded={isOpen}
className="Sidebar-toggle"
aria-label="Main Menu Toggle"
type="button"
onClick={() => toggle()}
>
{isOpen ? 'close' : 'open'}
</button>
</div>
<nav role="navigation" aria-label="Sidebar">
<ul>{pages.map(renderNav)}</ul>
</nav>
</aside>
);

Sidebar.propTypes = {
toggle: PropTypes.func.isRequired,
pages: PropTypes.arrayOf(link).isRequired,
isOpen: PropTypes.bool,
};

Sidebar.defaultProps = {
isOpen: false,
};

export default Sidebar;
61 changes: 61 additions & 0 deletions src/components/Sidebar.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
.Sidebar {
padding: 1rem;

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

a {
text-decoration: none;
color: var(--color-black);
display: inline-block;
padding: 0.2rem 0;

&:hover {
text-decoration: underline;
}

&.is-active {
font-weight: bold;
}
}

h3 {
margin: 0;
}

button {
background: none;
border: 0;
cursor: pointer;
width: 3rem;
display: none;

@media (max-width: 760px) {
display: block;
}
}

.Sidebar-top {
display: flex;
justify-content: space-between;
}

nav {
margin-top: 1rem;

@media (max-width: 760px) {
display: none;
}
}

&.is-open {
nav {
@media (max-width: 760px) {
display: block;
}
}
}
}
78 changes: 78 additions & 0 deletions src/pages/reference.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import React, { useState } from 'react';

import Container from '../components/Container';
import Layout from '../components/Layout';
import Sidebar from '../components/Sidebar';

// TODO: move this js file to same directory and update import
import '../templates/Reference.scss';

// TODO: pull this in from Gatsby
const pages = [
{ displayName: 'Overview', url: '' },
{
displayName: 'CLI',
url: '',
children: [
{ displayName: 'newrelic', url: '' },
{ displayName: 'nr1', url: '' },
],
},
{ displayName: 'GraphQL', url: '' },
{
displayName: 'Applications',
url: '',
children: [
{ displayName: 'Component Library', url: '', active: true },
{ displayName: 'File structure', url: '' },
],
},
{
displayName: 'Data Collectors',
url: '',
children: [
{ displayName: 'Custom Attributes', url: '' },
{ displayName: 'Custom Events', url: '' },
{ displayName: 'Open Telemetry', url: '' },
{ displayName: 'Telemetry SDK', url: '' },
],
},
{
displayName: 'Automation',
url: '',
children: [
{ displayName: 'Cloud Formation Provider', url: '' },
{ displayName: 'Terraform Provider', url: '' },
{
displayName: 'Agent Deploy',
url: '',
children: [
{ displayName: 'Ansible', url: '' },
{ displayName: 'Chef', url: '' },
{ displayName: 'Puppet', url: '' },
],
},
],
},
];

const Reference = () => {
const [isOpen, setIsOpen] = useState(false);

return (
<Layout>
<Container className="ReferenceTemplate">
<Sidebar
pages={pages}
isOpen={isOpen}
toggle={() => setIsOpen(!isOpen)}
/>
<main className="ReferenceTemplate-content">
The main page content goes here
</main>
</Container>
</Layout>
);
};

export default Reference;
18 changes: 18 additions & 0 deletions src/templates/Reference.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.ReferenceTemplate {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-areas: 'sidebar main';

@media (max-width: 760px) {
grid-template-columns: none;
grid-template-areas: 'sidebar' 'main';
}

.Sidebar {
grid-area: sidebar;
}

.ReferenceTemplate-content {
grid-area: main;
}
}
10 changes: 10 additions & 0 deletions src/types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import PropTypes from 'prop-types';

// NOTE: while creating a recursive data structure is feasible,
// it is not very performant.
export const link = PropTypes.shape({
displayName: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
active: PropTypes.bool,
children: PropTypes.array,
});