diff options
Merge pull request #5129 from MetaMask/add-sidebar-component
Add sidebar component
Diffstat (limited to 'ui/app/components')
-rw-r--r-- | ui/app/components/dropdowns/components/account-dropdowns.js | 2 | ||||
-rw-r--r-- | ui/app/components/index.scss | 4 | ||||
-rw-r--r-- | ui/app/components/menu-bar/menu-bar.container.js | 11 | ||||
-rw-r--r-- | ui/app/components/sidebars/index.js | 1 | ||||
-rw-r--r-- | ui/app/components/sidebars/index.scss | 74 | ||||
-rw-r--r-- | ui/app/components/sidebars/sidebar.component.js | 49 | ||||
-rw-r--r-- | ui/app/components/sidebars/sidebar.constants.js | 1 | ||||
-rw-r--r-- | ui/app/components/sidebars/tests/sidebars-component.test.js | 88 | ||||
-rw-r--r-- | ui/app/components/token-cell.js | 2 | ||||
-rw-r--r-- | ui/app/components/wallet-view.js | 2 |
10 files changed, 228 insertions, 6 deletions
diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index 179b6617f..b497f5c09 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -459,7 +459,7 @@ const mapDispatchToProps = (dispatch) => { function mapStateToProps (state) { return { keyrings: state.metamask.keyrings, - sidebarOpen: state.appState.sidebarOpen, + sidebarOpen: state.appState.sidebar.isOpen, } } diff --git a/ui/app/components/index.scss b/ui/app/components/index.scss index bdcb5626c..cb4065fd9 100644 --- a/ui/app/components/index.scss +++ b/ui/app/components/index.scss @@ -33,3 +33,7 @@ @import './transaction-list-item/index'; @import './transaction-status/index'; + +@import './app-header/index'; + +@import './sidebars/index'; diff --git a/ui/app/components/menu-bar/menu-bar.container.js b/ui/app/components/menu-bar/menu-bar.container.js index 2bd0ed6ed..ae32882ae 100644 --- a/ui/app/components/menu-bar/menu-bar.container.js +++ b/ui/app/components/menu-bar/menu-bar.container.js @@ -3,17 +3,22 @@ import MenuBar from './menu-bar.component' import { showSidebar, hideSidebar } from '../../actions' const mapStateToProps = state => { - const { appState: { sidebarOpen, isMascara } } = state + const { appState: { sidebar: { isOpen }, isMascara } } = state return { - sidebarOpen, + sidebarOpen: isOpen, isMascara, } } const mapDispatchToProps = dispatch => { return { - showSidebar: () => dispatch(showSidebar()), + showSidebar: () => { + dispatch(showSidebar({ + transitionName: 'sidebar-right', + type: 'wallet-view', + })) + }, hideSidebar: () => dispatch(hideSidebar()), } } diff --git a/ui/app/components/sidebars/index.js b/ui/app/components/sidebars/index.js new file mode 100644 index 000000000..732925f69 --- /dev/null +++ b/ui/app/components/sidebars/index.js @@ -0,0 +1 @@ +export { default } from './sidebar.component' diff --git a/ui/app/components/sidebars/index.scss b/ui/app/components/sidebars/index.scss new file mode 100644 index 000000000..5ab0664df --- /dev/null +++ b/ui/app/components/sidebars/index.scss @@ -0,0 +1,74 @@ +.sidebar-right-enter { + transition: transform 300ms ease-in-out; + transform: translateX(-100%); +} + +.sidebar-right-enter.sidebar-right-enter-active { + transition: transform 300ms ease-in-out; + transform: translateX(0%); +} + +.sidebar-right-leave { + transition: transform 200ms ease-out; + transform: translateX(0%); +} + +.sidebar-right-leave.sidebar-right-leave-active { + transition: transform 200ms ease-out; + transform: translateX(-100%); +} + +.sidebar-left-enter { + transition: transform 300ms ease-in-out; + transform: translateX(100%); +} + +.sidebar-left-enter.sidebar-left-enter-active { + transition: transform 300ms ease-in-out; + transform: translateX(0%); +} + +.sidebar-left-leave { + transition: transform 200ms ease-out; + transform: translateX(0%); +} + +.sidebar-left-leave.sidebar-left-leave-active { + transition: transform 200ms ease-out; + transform: translateX(100%); +} + +.sidebar-left { + flex: 1 0 230px; + background: rgb(250, 250, 250); + z-index: $sidebar-z-index; + position: fixed; + left: 15%; + right: 0; + bottom: 0; + opacity: 1; + visibility: visible; + will-change: transform; + overflow-y: auto; + box-shadow: rgba(0, 0, 0, .15) 2px 2px 4px; + width: 85%; + height: 100%; + + @media screen and (min-width: 769px) { + width: 408px; + left: calc(100% - 408px); + } +} + +.sidebar-overlay { + z-index: $sidebar-overlay-z-index; + position: fixed; + height: 100%; + width: 100%; + left: 0; + right: 0; + bottom: 0; + opacity: 1; + visibility: visible; + background-color: rgba(0, 0, 0, .3); +}
\ No newline at end of file diff --git a/ui/app/components/sidebars/sidebar.component.js b/ui/app/components/sidebars/sidebar.component.js new file mode 100644 index 000000000..57cdd7111 --- /dev/null +++ b/ui/app/components/sidebars/sidebar.component.js @@ -0,0 +1,49 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import ReactCSSTransitionGroup from 'react-addons-css-transition-group' +import WalletView from '../wallet-view' +import { WALLET_VIEW_SIDEBAR } from './sidebar.constants' + +export default class Sidebar extends Component { + + static propTypes = { + sidebarOpen: PropTypes.bool, + hideSidebar: PropTypes.func, + transitionName: PropTypes.string, + type: PropTypes.string, + }; + + renderOverlay () { + return <div className="sidebar-overlay" onClick={() => this.props.hideSidebar()} /> + } + + renderSidebarContent () { + const { type } = this.props + + switch (type) { + case WALLET_VIEW_SIDEBAR: + return <WalletView responsiveDisplayClassname={'sidebar-right' } /> + default: + return null + } + + } + + render () { + const { transitionName, sidebarOpen } = this.props + + return ( + <div> + <ReactCSSTransitionGroup + transitionName={transitionName} + transitionEnterTimeout={300} + transitionLeaveTimeout={200} + > + { sidebarOpen ? this.renderSidebarContent() : null } + </ReactCSSTransitionGroup> + { sidebarOpen ? this.renderOverlay() : null } + </div> + ) + } + +} diff --git a/ui/app/components/sidebars/sidebar.constants.js b/ui/app/components/sidebars/sidebar.constants.js new file mode 100644 index 000000000..1613a8245 --- /dev/null +++ b/ui/app/components/sidebars/sidebar.constants.js @@ -0,0 +1 @@ +export const WALLET_VIEW_SIDEBAR = 'wallet-view' diff --git a/ui/app/components/sidebars/tests/sidebars-component.test.js b/ui/app/components/sidebars/tests/sidebars-component.test.js new file mode 100644 index 000000000..e2d77518a --- /dev/null +++ b/ui/app/components/sidebars/tests/sidebars-component.test.js @@ -0,0 +1,88 @@ +import React from 'react' +import assert from 'assert' +import { shallow } from 'enzyme' +import sinon from 'sinon' +import ReactCSSTransitionGroup from 'react-addons-css-transition-group' +import Sidebar from '../sidebar.component.js' + +import WalletView from '../../wallet-view' + +const propsMethodSpies = { + hideSidebar: sinon.spy(), +} + +describe('Sidebar Component', function () { + let wrapper + + beforeEach(() => { + wrapper = shallow(<Sidebar + sidebarOpen={false} + hideSidebar={propsMethodSpies.hideSidebar} + transitionName={'someTransition'} + type={'wallet-view'} + />) + }) + + afterEach(() => { + propsMethodSpies.hideSidebar.resetHistory() + }) + + describe('renderOverlay', () => { + let renderOverlay + + beforeEach(() => { + renderOverlay = shallow(wrapper.instance().renderOverlay()) + }) + + it('should render a overlay element', () => { + assert(renderOverlay.hasClass('sidebar-overlay')) + }) + + it('should pass the correct onClick function to the element', () => { + assert.equal(propsMethodSpies.hideSidebar.callCount, 0) + renderOverlay.props().onClick() + assert.equal(propsMethodSpies.hideSidebar.callCount, 1) + }) + }) + + describe('renderSidebarContent', () => { + let renderSidebarContent + + beforeEach(() => { + wrapper.setProps({ type: 'wallet-view' }) + renderSidebarContent = wrapper.instance().renderSidebarContent() + }) + + it('should render sidebar content with the correct props', () => { + wrapper.setProps({ type: 'wallet-view' }) + renderSidebarContent = wrapper.instance().renderSidebarContent() + assert.equal(renderSidebarContent.props.responsiveDisplayClassname, 'sidebar-right') + }) + + it('should not render with an unrecognized type', () => { + wrapper.setProps({ type: 'foobar' }) + renderSidebarContent = wrapper.instance().renderSidebarContent() + assert.equal(renderSidebarContent, undefined) + }) + }) + + describe('render', () => { + it('should render a div with one child', () => { + assert(wrapper.is('div')) + assert.equal(wrapper.children().length, 1) + }) + + it('should render the ReactCSSTransitionGroup without any children', () => { + assert(wrapper.children().at(0).is(ReactCSSTransitionGroup)) + assert.equal(wrapper.children().at(0).children().length, 0) + }) + + it('should render sidebar content and the overlay if sidebarOpen is true', () => { + wrapper.setProps({ sidebarOpen: true }) + assert.equal(wrapper.children().length, 2) + assert(wrapper.children().at(1).hasClass('sidebar-overlay')) + assert.equal(wrapper.children().at(0).children().length, 1) + assert(wrapper.children().at(0).children().at(0).is(WalletView)) + }) + }) +}) diff --git a/ui/app/components/token-cell.js b/ui/app/components/token-cell.js index 58a30228d..477d97597 100644 --- a/ui/app/components/token-cell.js +++ b/ui/app/components/token-cell.js @@ -18,7 +18,7 @@ function mapStateToProps (state) { userAddress: selectors.getSelectedAddress(state), contractExchangeRates: state.metamask.contractExchangeRates, conversionRate: state.metamask.conversionRate, - sidebarOpen: state.appState.sidebarOpen, + sidebarOpen: state.appState.sidebar.isOpen, } } diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js index ffa60e3ed..6de265110 100644 --- a/ui/app/components/wallet-view.js +++ b/ui/app/components/wallet-view.js @@ -34,7 +34,7 @@ function mapStateToProps (state) { return { network: state.metamask.network, - sidebarOpen: state.appState.sidebarOpen, + sidebarOpen: state.appState.sidebar.isOpen, identities: state.metamask.identities, accounts: state.metamask.accounts, tokens: state.metamask.tokens, |