Skip to content
This repository has been archived by the owner on May 10, 2019. It is now read-only.

Commit

Permalink
Merge pull request #119 from Caleb-Ellis/104-sidebar-nav
Browse files Browse the repository at this point in the history
104: Add SideNav, SideNavBanner, SideNavGroup and SideNavLink components
  • Loading branch information
barrymcgee authored Feb 9, 2018
2 parents 09303c0 + 8b376e2 commit 48c5aa6
Show file tree
Hide file tree
Showing 10 changed files with 1,117 additions and 26 deletions.
43 changes: 20 additions & 23 deletions src/lib/components/Link/Link.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,37 @@
import React from 'react';
import PropTypes from 'prop-types';
import getClassName from '../../utils/getClassName';

const Link = (props) => {
let classArray = [];

if (props.soft) {
classArray = [...classArray, 'p-link--soft'];
}

if (props.strong) {
classArray = [...classArray, 'p-link--strong'];
}

if (props.inverted) {
classArray = [...classArray, 'p-link--inverted'];
}

if (props.external) {
classArray = [...classArray, 'p-link--external'];
}

const classString = classArray.join(' ');

if (props.top) {
const {
soft, strong, inverted, external, top,
} = props;
const customClasses = props.className;

const className = getClassName({
'p-link--soft': soft,
'p-link--strong': strong,
'p-link--inverted': inverted,
'p-link--external': external,
'p-top__link': top,
[`${customClasses}`]: customClasses,
});

if (top) {
return (
<div className="p-top">
<a href={props.href} className={`${classString} p-top__link`}>{props.children}</a>
<a href={props.href} className={className}>{props.children}</a>
</div>
);
}

return (
<a href={props.href} className={classString}>{props.children}</a>
<a href={props.href} className={className}>{props.children}</a>
);
};

Link.defaultProps = {
className: '',
soft: false,
strong: false,
inverted: false,
Expand All @@ -45,6 +41,7 @@ Link.defaultProps = {

Link.propTypes = {
children: PropTypes.node.isRequired,
className: PropTypes.string,
href: PropTypes.string.isRequired,
soft: PropTypes.bool,
strong: PropTypes.bool,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/Link/__snapshots__/Link.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ exports[`Link component should accept modifiers correctly 1`] = `
className="p-top"
>
<a
className=" p-top__link"
className="p-top__link"
href="https://vanilla-framework.github.io/vanilla-framework-react/"
>
Back to top
Expand Down
75 changes: 75 additions & 0 deletions src/lib/components/SideNav/SideNav.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from 'react';

import SideNavBanner from './SideNavBanner';

class SideNav extends React.Component {
constructor() {
super();
this.handleMenuClick = this.handleMenuClick.bind(this);

this.state = { menuOpen: false };
}

handleMenuClick() {
const { menuOpen } = this.state;
this.setState({ menuOpen: !menuOpen });
}

render() {
const { children } = this.props;
const { menuOpen } = this.state;
const content = [];
let banner;

React.Children.forEach(children, (child) => {
if (child.type === SideNavBanner) {
banner = React.cloneElement(child, {
...this.props,
onClick: this.handleMenuClick,
open: this.state.menuOpen,
});
} else {
content.push(child);
}
});

return (
<div className="p-navigation--sidebar">
{ banner }
<div className={`sidebar__content u-no-margin--top ${menuOpen ? '' : 'u-hide'}`}>
<ul className="p-list">
{ content }
</ul>
</div>
</div>
);
}
}

SideNav.defaultProps = {
children: null,
};

SideNav.propTypes = {
children: (props, propName, componentName) => {
const prop = props[propName];
let error = null;
let count = 0;

React.Children.forEach(prop, (child) => {
if (child.type === SideNavBanner) {
count += 1;
}
});

if (count !== 1) {
error = new Error(`${componentName} should have exactly one child of type "SideNavBanner".`);
}

return error;
},
};

SideNav.displayName = 'SideNav';

export default SideNav;
184 changes: 184 additions & 0 deletions src/lib/components/SideNav/SideNav.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import { number, text } from '@storybook/addon-knobs';
import { withInfo } from '@storybook/addon-info';

import Link from '../Link/Link';
import List from '../List/List';
import ListItem from '../List/ListItem';
import SideNav from './SideNav';
import SideNavBanner from './SideNavBanner';
import SideNavGroup from './SideNavGroup';
import SideNavLink from './SideNavLink';

const options = {
range: true,
min: 3,
max: 12,
step: 1,
};

storiesOf('SideNav', module)
.add('Text Banner',
withInfo('The SideNav component allows for navigation from a collapsing menu on the side of the page. It requires a SideNavBanner which contains a title/logo, optional tagline, and a space for the small screen burger menu. SideNavLinks can be placed directly inside SideNav, or inside a SideNavGroup to keep them under section titles. This example will expand to fill the space available to it so it needs to be used in conjunction with the grid to set the layout.')(() => (
<div className={`col-${number('Column size', 12, options)}`}>
<SideNav>
<SideNavBanner
href="#"
tagline={text('Tagline', 'Lorem ipsum')}
title={text('Title', 'Vanilla')}
/>
<SideNavGroup label="Section title 1">
<SideNavLink href="#" label="Second level 1" />
<SideNavLink href="#" label="Second level 2" />
<SideNavGroup label="Second level 3">
<SideNavLink href="#" label="Third level 1" />
<SideNavLink href="#" label="Third level 2" />
<SideNavLink href="#" label="Third level 3" />
<SideNavLink href="#" label="Third level 4" />
<SideNavLink href="#" label="Third level 5" />
</SideNavGroup>
<SideNavLink href="#" label="Second level 4" />
<SideNavLink href="#" label="Second level 5" />
</SideNavGroup>
<SideNavGroup label="Section title 2">
<SideNavLink href="#" label="Second level 1" />
<SideNavLink href="#" label="Second level 2" />
<SideNavGroup label="Second level 3">
<SideNavLink href="#" label="Third level 1" />
<SideNavLink href="#" label="Third level 2" />
<SideNavLink href="#" label="Third level 3" />
<SideNavLink href="#" label="Third level 4" />
<SideNavLink href="#" label="Third level 5" />
</SideNavGroup>
<SideNavLink href="#" label="Second level 4" />
<SideNavLink href="#" label="Second level 5" />
</SideNavGroup>
<SideNavGroup label="Section title 3">
<SideNavLink href="#" label="Second level 1" />
<SideNavLink href="#" label="Second level 2" />
<SideNavGroup label="Second level 3">
<SideNavLink href="#" label="Third level 1" />
<SideNavLink href="#" label="Third level 2" />
<SideNavLink href="#" label="Third level 3" />
<SideNavLink href="#" label="Third level 4" />
<SideNavLink href="#" label="Third level 5" />
</SideNavGroup>
<SideNavLink href="#" label="Second level 4" />
<SideNavLink href="#" label="Second level 5" />
</SideNavGroup>
<SideNavLink href="#" label="First level 1" />
<hr />
<List>
<ListItem>
<Link external className="sidebar__link" href="#a">Supplementary link 1</Link>
</ListItem>
<ListItem>
<Link external className="sidebar__link" href="#a">Supplementary link 2</Link>
</ListItem>
</List>
</SideNav>
</div>),
),
)

.add('Logo Banner',
withInfo('A logo object prop can also be passed to SideNavBanner, which will replace a simple text banner.')(() => (
<div className={`col-${number('Column size', 12, options)}`}>
<SideNav>
<SideNavBanner
href="#"
logo={{
src: text('Logo src', 'https://assets.ubuntu.com/v1/d96d86b5-vanilla_black-orange_hex.svg'),
alt: '',
}}
tagline={text('Tagline', 'Documentation')}
/>
<SideNavGroup label="Basics">
<SideNavLink href="#" label="Color" />
<SideNavLink href="#" label="Font" />
<SideNavLink href="#" label="Reset" />
<SideNavLink href="#" label="Spacing" />
</SideNavGroup>
<SideNavGroup label="Global layout">
<SideNavLink href="#" label="Breakpoints" />
<SideNavLink href="#" label="Grid" />
<SideNavLink href="#" label="Strip" />
<SideNavLink href="#" label="Structure" />
</SideNavGroup>
<SideNavGroup label="One-off layout">
<SideNavLink href="#" label="Alignment" />
<SideNavLink href="#" label="Clearfix" />
<SideNavLink href="#" label="Equal height" />
<SideNavLink href="#" label="Floats" />
<SideNavLink href="#" label="Hide" />
<SideNavLink href="#" label="Image position" />
<SideNavLink href="#" label="Margin collapse" />
<SideNavLink href="#" label="Off-screen elements" />
<SideNavLink href="#" label="Padding collapse" />
<SideNavLink href="#" label="Show" />
<SideNavLink href="#" label="Vertically center" />
</SideNavGroup>
<SideNavGroup label="Navigation">
<SideNavLink href="#" label="Accordion" />
<SideNavLink href="#" label="Aside" />
<SideNavLink href="#" label="Breadcrumbs" />
<SideNavLink href="#" label="Contextual menu" />
<SideNavLink href="#" label="Footer" />
<SideNavLink href="#" label="Global navigation" />
<SideNavLink href="#" label="Pagination" />
<SideNavLink href="#" label="Tabs" />
</SideNavGroup>
<SideNavGroup label="Page structure">
<SideNavLink href="#" label="Cards" />
<SideNavLink href="#" label="Divider list" />
<SideNavLink href="#" label="Heading icon" />
<SideNavLink href="#" label="Images" />
<SideNavLink href="#" label="Inline images" />
<SideNavLink href="#" label="Lists" />
<SideNavLink href="#" label="Matrix" />
<SideNavLink href="#" label="Media object" />
<SideNavLink href="#" label="Muted heading" />
</SideNavGroup>
<SideNavGroup label="Text">
<SideNavLink href="#" label="Code" />
<SideNavLink href="#" label="Code numbered" />
<SideNavLink href="#" label="Code snippet" />
<SideNavLink href="#" label="Typography" />
<SideNavLink href="#" label="Quotes" />
</SideNavGroup>
<SideNavGroup label="Interactive elements">
<SideNavLink href="#" label="Buttons" />
<SideNavLink href="#" label="Forms" />
<SideNavLink href="#" label="Form layout" />
<SideNavLink href="#" label="Form validation" />
<SideNavLink href="#" label="Links" />
<SideNavLink href="#" label="List tree" />
<SideNavLink href="#" label="Modal" />
<SideNavLink href="#" label="Notifications" />
<SideNavLink href="#" label="Search box" />
<SideNavLink href="#" label="Slider" />
<SideNavLink href="#" label="Switch" />
<SideNavLink href="#" label="Table" />
<SideNavLink href="#" label="Table sortable" />
<SideNavLink href="#" label="Table expanding" />
<SideNavLink href="#" label="Table mobile card" />
<SideNavLink href="#" label="Tooltips" />
</SideNavGroup>
<SideNavGroup label="Media">
<SideNavLink href="#" label="Animations" />
<SideNavLink href="#" label="Assets" />
<SideNavLink href="#" label="Embedded media" />
<SideNavLink href="#" label="Icons" />
<SideNavLink href="#" label="Spin" />
</SideNavGroup>
<hr />
<List>
<ListItem>
<Link external className="sidebar__link" href="https://vanillaframework.io">vanillaframework.io</Link>
</ListItem>
</List>
</SideNav>
</div>),
),
);
Loading

0 comments on commit 48c5aa6

Please sign in to comment.