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

Dang 123/Main vertical navigation #19

Merged
merged 44 commits into from Jun 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
71b7b08
wip
mercedesb May 25, 2021
fdef02a
Merge branch 'main' into DANG-123/main-nav
mercedesb May 25, 2021
a57ece9
Merge branch 'main' into DANG-123/main-nav
mercedesb May 25, 2021
ec5e9a2
initial styles for main nav item
mercedesb May 25, 2021
dd333c7
create plugin for accessing Lob constants
mercedesb May 25, 2021
9023176
create component to render top level main nav item
mercedesb May 25, 2021
4e3cf6c
move example icon to assets
mercedesb May 26, 2021
27a622b
testing MainNavigationItem
mercedesb May 26, 2021
ad01677
finish styling main nav item child container
mercedesb May 27, 2021
8a8ae17
dynamically render button or link if to prop is present
mercedesb May 27, 2021
de667e0
integrate main nav with vue router
mercedesb May 27, 2021
437438d
test for link or button
mercedesb May 27, 2021
0cd30a7
clean up item styles and specs
mercedesb May 27, 2021
f69dc2e
initial child item component
mercedesb May 27, 2021
74b6d7b
initial Main Nav component
mercedesb May 27, 2021
21fe1f0
test nav child item
mercedesb May 27, 2021
bf45fd8
test main nav component
mercedesb May 27, 2021
f037db1
clean up nav desktop styles more
mercedesb May 27, 2021
56cebc9
update stories
mercedesb May 27, 2021
6bfe87d
Merge branch 'main' into DANG-123/main-nav
mercedesb May 27, 2021
0708b7f
update docs
mercedesb May 27, 2021
0dd5fae
create custom decorator for routing state in storybook
mercedesb May 28, 2021
3b49fe7
clean up some stories and styles
mercedesb May 28, 2021
5b65a5f
update text styles
mercedesb May 28, 2021
03cf7e9
consolidate main nav stories
mercedesb May 28, 2021
2e5ad61
stop propagation on router link click events
mercedesb May 28, 2021
3d8b5c3
add more to nav story
mercedesb May 28, 2021
a99727c
fix caret direction in nav item
mercedesb May 28, 2021
460ac40
animate drawer opening and closing
mercedesb May 28, 2021
79e6e0d
animate drawer with pure CSS, better performance and easier mobile st…
mercedesb May 30, 2021
3cd92bf
add collapsible prop to MainNav and MainNavItem
mercedesb Jun 1, 2021
542fe7d
add more docs to stories for main nav
mercedesb Jun 1, 2021
979c51a
add tests for expandable and collapsible logic
mercedesb Jun 1, 2021
3cd0654
get docs addon and routeDecorator to play nice
mercedesb Jun 1, 2021
23cb72b
remove deprecated docs
mercedesb Jun 1, 2021
5a0ebf5
lint css
mercedesb Jun 1, 2021
7401499
remove gsap package from js animation iteration
mercedesb Jun 1, 2021
d0b858d
Merge branch 'main' into DANG-123/main-nav
mercedesb Jun 2, 2021
61e0c04
add subcomponents to main nav story
mercedesb Jun 2, 2021
1450e07
Merge branch 'main' into DANG-123/main-nav
mercedesb Jun 2, 2021
57fbfbc
fix colors
mercedesb Jun 2, 2021
136bd9a
fix failing spec
mercedesb Jun 2, 2021
afa8d38
small reorg of main nav doc
mercedesb Jun 2, 2021
37a342f
turn off stylelint at-rule-no-unknown
mercedesb Jun 2, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 2 additions & 4 deletions .storybook/preview.js
Expand Up @@ -4,11 +4,9 @@ import * as configs from '../src/config';

import '../src/assets/styles/main.scss';

for (const configName in configs) {
const config = configs[configName];
config.configure();
}
configs.icons.configure();

Vue.use(configs.constants);
Vue.component('font-awesome-icon', FontAwesomeIcon);

export const parameters = {
Expand Down
21 changes: 21 additions & 0 deletions .storybook/routeDecorator.js
@@ -0,0 +1,21 @@
import Vue from 'vue';
import VueRouter from 'vue-router';

// abbreviated example of https://github.com/gvaldambrini/storybook-router/blob/master/packages/vue/vue.js

export default (path = '/') => {
return (storyFn) => {
Vue.use(VueRouter);
const router = new VueRouter({ mode: 'history' });

router.replace(path);

const WrappedComponent = storyFn();

return Vue.extend({
router,
components: { WrappedComponent },
template: '<wrapped-component/>'
});
}
}
5 changes: 4 additions & 1 deletion .stylelintrc
@@ -1,3 +1,6 @@
{
"extends": "stylelint-config-standard"
"extends": "stylelint-config-standard",
"rules": {
"at-rule-no-unknown": null
}
}
13 changes: 12 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -26,7 +26,8 @@
"@fortawesome/pro-light-svg-icons": "^5.15.3",
"@fortawesome/vue-fontawesome": "^2.0.2",
"core-js": "^3.6.5",
"vue": "^2.6.11"
"vue": "^2.6.11",
"vue-router": "^3.5.1"
},
"devDependencies": {
"@babel/core": "^7.13.16",
Expand Down
20 changes: 20 additions & 0 deletions src/assets/images/iconOverview.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
92 changes: 92 additions & 0 deletions src/components/MainNavigation/MainNavigation.mdx
@@ -0,0 +1,92 @@
import {
Preview,
Story,
ArgsTable,
PRIMARY_STORY,
} from "@storybook/addon-docs/blocks";
import MainNavigation from "./MainNavigation.vue";
import MainNavigationItem from "./MainNavigationItem.vue";
import MainNavigationChildItem from "./MainNavigationChildItem.vue";

# MainNavigation

The main navigation component is used for displaying the main, vertical navigation.

<Preview>
<Story id="components-main-navigation--primary" />
</Preview>

## How to Use

The main navigation renders a semantic `nav` element with a `ul`. It is made to work with `main-navigation-item` components. However, you can also write custom components for its slot as long as the root element is an `li` (for accessibility).

The main navigation has a single prop, `collapsible` to control whether it has a click event on desktop that animates the navigation on click to slide in to a smaller width. This can give the user more screen real estate. `collapsible` defaults to true. If you do not want this animation, set this to false.

When `collapsible` is true, the main navigation component passes information about it's expanded/collapsed state through slot props. This requires you passes the expanded prop to the child components in the template (see example below).

Example of using this component in a template
```html
<main-navigation v-bind="$props">
<template v-slot="{ expanded }">
<main-navigation-item title="Overview" iconSrc="overviewIconSrcFile" iconAltText="Overview icon" to="/overview" :expanded="expanded" />
<main-navigation-item title="Address Verification" iconSrc="addressVerificationIconSrcFile" iconAltText="Address verification icon" :subNavCollapsed="false" :expanded="expanded">
<main-navigation-child-item title="US Verifications" to="/us-verifications" />
<main-navigation-child-item title="Int'l Verifications" to="/intl-verifications" />
</main-navigation-item>
</template>
</main-navigation>
```

# Main Navigation Item

The main navigation item component is used for displaying a top level navigation item in the main, vertical navigation.

<Preview>
<Story id="components-main-navigation--item" />
</Preview>

## How to Use

The main navigation item component can render as a traditional link (hooked up to your app's routing) or as a button that will show its child nav items on click.

If you pass a `to` property, it will render as a link. Otherwise, it will render as a button.

The `expanded` prop should come from the parent main navigation component and will control whether the item renders at full width on desktop or only renders wide enough to show its icon.

Example of using this component in a template as a link.
```html
<main-navigation-item title="Overview" iconSrc="overviewIconSrcFile" iconAltText="Overview icon" to="/overview" :expanded="expanded" />
```

If you provide children elements in the default slot, it will bind a click event to the button to hide/show the child nav items. If you do not want to allow the user to collapse this subnavigation (i.e. you want the child items always visible), set the `collapsible` prop on the main navigation item component to false.

If you want the component to render with the child items collapsed by default, you can use the `subNavCollapsed` prop set to true.

Example of using this component in a template as a button with child nav items.
```html
<main-navigation-item title="Address Verification" iconSrc="addressVerificationIconSrcFile" iconAltText="Address verification icon" :expanded="expanded">
<main-navigation-child-item title="US Verifications" to="/us-verifications" />
<main-navigation-child-item title="Int'l Verifications" to="/intl-verifications" />
</main-navigation-item>
```

# MainNavigationChildItem

The main navigation child item component is used for displaying a sub level navigation item in the main, vertical navigation.

<Preview>
<Story id="components-main-navigation--child-item" />
</Preview>

## How to Use

The main navigation child item component renders as link (hooked up to your app's routing).

Example of using this component in a template
```html
<main-navigation-child-item title="US Verifications" to="/us-verifications" />
```

## Props

<ArgsTable story={PRIMARY_STORY} />
109 changes: 109 additions & 0 deletions src/components/MainNavigation/MainNavigation.stories.js
@@ -0,0 +1,109 @@
import routeDecorator from '../../../.storybook/routeDecorator';

import MainNavigation from './MainNavigation.vue';
import MainNavigationItem from './MainNavigationItem.vue';
import MainNavigationChildItem from './MainNavigationChildItem.vue';
import mdx from './MainNavigation.mdx';
import iconOverview from '../../assets/images/iconOverview.svg';

export default {
title: 'Components/Main Navigation',
component: MainNavigation,
subcomponents: { MainNavigationItem, MainNavigationChildItem },
decorators: [
() => ({ template: '<div class="block bg-offWhite"><story /></div>' }),
routeDecorator()
],
parameters: {
docs: {
page: mdx
}
},
argTypes: {
iconSrc: {
table: {
disable: true
},
control: {
disable: true
}
}
}
};

const primaryTemplateStr = (args) => `
<main-navigation v-bind="$props">
<template v-slot="{ expanded }">
<main-navigation-item title="Overview" iconSrc="${args.iconSrc}" iconAltText="Overview icon" to="/overview" :expanded="expanded" />
<main-navigation-item title="Mail Analytics" iconSrc="${args.iconSrc}" iconAltText="Overview icon" to="/mail-analytics" :expanded="expanded" />
<main-navigation-item title="Address Books" iconSrc="${args.iconSrc}" iconAltText="Overview icon" to="/address-verification" :expanded="expanded" />
<main-navigation-item title="Address Verification" iconSrc="${args.iconSrc}" iconAltText="Overview icon" :expanded="expanded">
<main-navigation-child-item title="US Verifications" to="/us-verifications" />
<main-navigation-child-item title="Int'l Verifications" to="/intl-verifications" />
</main-navigation-item>
<main-navigation-item title="Print & Mail" iconSrc="${args.iconSrc}" iconAltText="Overview icon" :expanded="expanded">
<main-navigation-child-item title="Postcards" to="/postcards" />
<main-navigation-child-item title="Letters" to="/letters" />
</main-navigation-item>
</template>
</main-navigation>
`;

const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { MainNavigation, MainNavigationChildItem, MainNavigationItem },
template: primaryTemplateStr(args)
});

export const Primary = Template.bind({});
Primary.args = {
iconSrc: iconOverview
};
Primary.parameters = {
docs: {
source: {
code: primaryTemplateStr({ iconSrc: 'srcFilePath' })
}
}
};

const itemTemplateStr = '<main-navigation-item v-bind="$props" />';
const ItemTemplate = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { MainNavigationItem },
template: itemTemplateStr
});
export const Item = ItemTemplate.bind({});
Item.args = {
title: 'Overview',
iconSrc: iconOverview,
iconAltText: 'Overview icon',
to: '/overview',
expanded: true
};
Item.parameters = {
docs: {
source: {
code: itemTemplateStr
}
}
};

const childTemplateStr = '<main-navigation-child-item v-bind="$props" />';
const ChildItemTemplate = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { MainNavigationChildItem },
template: childTemplateStr
});
export const ChildItem = ChildItemTemplate.bind({});
ChildItem.args = {
title: 'Postcards',
to: '/postcards'
};
ChildItem.parameters = {
docs: {
source: {
code: childTemplateStr
}
}
};
61 changes: 61 additions & 0 deletions src/components/MainNavigation/MainNavigation.vue
@@ -0,0 +1,61 @@
<template>
<nav>
<ul
:class="[
'bg-white-100 h-screen',
{'cursor-pointer': collapsible},
{'expanded': collapsible && expanded},
{'collapsed': collapsible && !expanded}
]"
@[clickEvent]="animateDrawer"
>
<slot
:expanded="expanded"
/>
</ul>
</nav>
</template>

<script>
export default {
name: 'MainNavigation',
props: {
collapsible: {
type: Boolean,
default: true
}
},
data: function () {
return {
expanded: true
};
},
computed: {
clickEvent () {
return this.collapsible ? 'click' : null;
}
},
methods: {
animateDrawer () {
this.expanded = !this.expanded;
}
}
};
</script>

<style scoped lang="scss">

nav {
width: 100%;

@screen md {
ul:not(.collapsed) {
width: 222px;
}

ul.collapsed {
width: 70px;
}
}
}
</style>