New account selector UI in top bar (#7179)

* Add a dropdown popup for account selector

* Install sui latest version for hideOnScroll bug fix

* Update ui

* Update package-lock after rebase

* Require parity/ui v3.0.3

* Pass accountStore as props

* Require parity/ui v3.0.4
This commit is contained in:
Amaury Martiny 2017-12-04 12:09:08 +01:00 committed by Jaco Greeff
parent dde6baedec
commit 83ff213f6c
10 changed files with 336 additions and 19 deletions

64
js/package-lock.json generated
View File

@ -516,6 +516,18 @@
"integrity": "sha1-jgOPbdsUvXZa4fS1IW4SCUUR4NA=",
"dev": true
},
"semantic-ui-react": {
"version": "0.76.0",
"resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-0.76.0.tgz",
"integrity": "sha512-CdiIT8n7ZwUlytZkYsQMnaVGmoIZI/mVs4lijvLcR568kcnlRkYYaFKhMLq5tFDQU6+QhdTD+8WebF7ov0Ql6Q==",
"dev": true,
"requires": {
"babel-runtime": "6.26.0",
"classnames": "2.2.5",
"lodash": "4.17.4",
"prop-types": "15.6.0"
}
},
"webrtc-adapter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-2.1.0.tgz",
@ -996,6 +1008,26 @@
"integrity": "sha1-jgOPbdsUvXZa4fS1IW4SCUUR4NA=",
"dev": true
},
"semantic-ui-react": {
"version": "0.76.0",
"resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-0.76.0.tgz",
"integrity": "sha512-CdiIT8n7ZwUlytZkYsQMnaVGmoIZI/mVs4lijvLcR568kcnlRkYYaFKhMLq5tFDQU6+QhdTD+8WebF7ov0Ql6Q==",
"dev": true,
"requires": {
"babel-runtime": "6.26.0",
"classnames": "2.2.5",
"lodash": "4.17.4",
"prop-types": "15.6.0"
},
"dependencies": {
"lodash": {
"version": "4.17.4",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
"dev": true
}
}
},
"webrtc-adapter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-2.1.0.tgz",
@ -1152,9 +1184,9 @@
}
},
"@parity/ui": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@parity/ui/-/ui-3.0.2.tgz",
"integrity": "sha512-96hH+2+usH7Itl0j+nErFYXXGW9G+GvowEYxx9nqW3yAp5PCwzS3+qUI9ETz/cX9DroItXixHWICHareW9eIFw==",
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@parity/ui/-/ui-3.0.4.tgz",
"integrity": "sha512-/IS+6Qxr5HGAvdaB0xud9lU2c48Crg2dY7yzkb7V+99qvqYV/OAI31IffaBOt3UbLz/QWF+Da+ZOWT96eIVlAg==",
"requires": {
"@parity/api": "2.1.5",
"@parity/etherscan": "2.1.3",
@ -1243,6 +1275,17 @@
"prop-types": "15.6.0",
"warning": "3.0.0"
}
},
"semantic-ui-react": {
"version": "0.76.0",
"resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-0.76.0.tgz",
"integrity": "sha512-CdiIT8n7ZwUlytZkYsQMnaVGmoIZI/mVs4lijvLcR568kcnlRkYYaFKhMLq5tFDQU6+QhdTD+8WebF7ov0Ql6Q==",
"requires": {
"babel-runtime": "6.26.0",
"classnames": "2.2.5",
"lodash": "4.17.4",
"prop-types": "15.6.0"
}
}
}
},
@ -15482,9 +15525,9 @@
}
},
"rtcpeerconnection-shim": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.1.tgz",
"integrity": "sha512-1IsK2xj8yrxYfce1YpaI53KwMlwHfnAMx34DjPja9nUbmOlJe43L5ZlAuE5wh+SynyuuSZxoxhFoIlXPgXPEKA==",
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.2.tgz",
"integrity": "sha512-8gk72X25Z31XEkk5DZd6y4aziHgj0mZMB7xMv4mUrS6moTmZOrcKE8+rvEVRModMkaaUyspEVwBn8JGuG8Z1ww==",
"requires": {
"sdp": "2.5.0"
}
@ -15630,12 +15673,13 @@
}
},
"semantic-ui-react": {
"version": "0.76.0",
"resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-0.76.0.tgz",
"integrity": "sha512-CdiIT8n7ZwUlytZkYsQMnaVGmoIZI/mVs4lijvLcR568kcnlRkYYaFKhMLq5tFDQU6+QhdTD+8WebF7ov0Ql6Q==",
"version": "0.77.0",
"resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-0.77.0.tgz",
"integrity": "sha512-lUnlpbIbMtse335kjZAw8ClulCQAUWDm77pw2yY754mL02PlTNYtZQanoGjhBFts41YHpg6ExK156J/9Ynb8IQ==",
"requires": {
"babel-runtime": "6.26.0",
"classnames": "2.2.5",
"fbjs": "0.8.16",
"lodash": "4.17.4",
"prop-types": "15.5.10"
}
@ -18099,7 +18143,7 @@
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-5.0.6.tgz",
"integrity": "sha512-dh2hPQFOPP0tLEYlFxtGI5vuQmRqkOdYni5wMKUHIx5I2dw0TJ1HdG7P+UechRWt6TvwPWhtbjVNQcQf1KXJmQ==",
"requires": {
"rtcpeerconnection-shim": "1.2.1",
"rtcpeerconnection-shim": "1.2.2",
"sdp": "2.5.0"
}
},

View File

@ -151,7 +151,7 @@
"@parity/plugin-signer-hardware": "paritytech/plugin-signer-hardware",
"@parity/plugin-signer-qr": "paritytech/plugin-signer-qr",
"@parity/shared": "2.2.x",
"@parity/ui": "3.0.x",
"@parity/ui": "~3.0.4",
"keythereum": "1.0.2",
"lodash.flatten": "4.4.0",
"lodash.omitby": "4.6.0",
@ -172,6 +172,7 @@
"react-tap-event-plugin": "3.0.2",
"react-transition-group": "2.2.1",
"redux": "3.7.2",
"semantic-ui-react": "0.77.0",
"solc": "ngotchac/solc-js",
"store": "1.3.20",
"web3": "0.17.0-beta"

View File

@ -0,0 +1,36 @@
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.defaultContent {
color: rgba(0, 0, 0, 0.8);
vertical-align: middle !important;
}
.avatarWrapper {
width: 4.2em !important;
display: flex;
justify-content: center;
}
.bigAvatar {
width: 4em !important;
height: 4em !important;
}
.description {
margin-top: 0.5em;
}

View File

@ -0,0 +1,64 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Image from 'semantic-ui-react/dist/commonjs/elements/Image';
import List from 'semantic-ui-react/dist/commonjs/elements/List';
import IdentityIcon from '@parity/ui/lib/IdentityIcon';
import styles from './accountItem.css';
class AccountItem extends PureComponent {
static propTypes = {
account: PropTypes.object.isRequired,
isDefault: PropTypes.bool,
onClick: PropTypes.func
}
handleClick = () => {
this.props.onClick(this.props.account.address);
}
render () {
const { account, isDefault } = this.props;
return (
<List.Item
onClick={ this.handleClick }
disabled={ isDefault }
>
<Image avatar>
<div className={ styles.avatarWrapper }>
<IdentityIcon address={ account.address }
alt={ account.address }
className={ isDefault ? styles.bigAvatar : '' }
/>
</div>
</Image>
<List.Content className={ isDefault ? styles.defaultContent : '' }>
<List.Header>
{account.name}
</List.Header>
{account.address}
{isDefault && <p className={ styles.description }>{account.meta.description}</p>}
</List.Content>
</List.Item>
);
}
}
export default AccountItem;

View File

@ -0,0 +1,17 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './accountItem';

View File

@ -0,0 +1,38 @@
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
/* This file is part of Parity.
/*
/* Parity is free software: you can redistribute it and/or modify
/* it under the terms of the GNU General Public License as published by
/* the Free Software Foundation, either version 3 of the License, or
/* (at your option) any later version.
/*
/* Parity is distributed in the hope that it will be useful,
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* GNU General Public License for more details.
/*
/* You should have received a copy of the GNU General Public License
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.defaultAccount {
cursor: pointer;
}
.popup {
padding: 0 !important;
}
.list {
margin: 0 !important;
padding: 1em 1em !important;
background-color: #f5f5f5;
}
.isDefault {
background-color: white;
}
.hasOtherAccounts {
border-bottom: 1px solid #D4D4D5;
}

View File

@ -0,0 +1,104 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { observer } from 'mobx-react';
import List from 'semantic-ui-react/dist/commonjs/elements/List';
import Popup from 'semantic-ui-react/dist/commonjs/modules/Popup';
import IdentityIcon from '@parity/ui/lib/IdentityIcon';
import AccountItem from './AccountItem';
import styles from './defaultAccount.css';
@observer
class DefaultAccount extends Component {
state = {
isOpen: false
}
static propTypes = {
accountStore: PropTypes.object.isRequired
}
handleOpen = () => {
this.setState({ isOpen: true });
}
handleClose = () => {
this.setState({ isOpen: false });
}
handleMakeDefault = (address) => {
this.handleClose();
if (address === this.props.accountStore.defaultAddress) { return; }
this.props.accountStore.makeDefaultAccount(address);
}
render () {
const { accounts, defaultAccount: defaultAddress } = this.props.accountStore;
const defaultAccount = accounts.find(({ address }) => address === defaultAddress);
if (!accounts || !defaultAccount) { return null; }
return (
<Popup
wide='very'
className={ styles.popup }
trigger={
<IdentityIcon
address={ defaultAddress } button
center
className={ styles.defaultAccount }
/>
}
content={
<div>
<List relaxed='very' selection className={ [styles.list, styles.isDefault, accounts.length > 1 && styles.hasOtherAccounts].join(' ') }>
<AccountItem
isDefault
account={ defaultAccount }
/>
</List>
{accounts.length > 1 &&
<List relaxed='very' selection className={ styles.list } divided>
{accounts
.filter(({ address }) => address !== defaultAddress)
.map(account => (
<AccountItem
key={ account.address }
account={ account }
onClick={ this.handleMakeDefault }
/>
))}
</List>
}
</div>
}
offset={ 13 } // Empirically looks better
on='click'
hideOnScroll
open={ this.state.isOpen }
onClose={ this.handleClose }
onOpen={ this.handleOpen }
position='bottom right'
/>
);
}
}
export default DefaultAccount;

View File

@ -0,0 +1,17 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './defaultAccount';

View File

@ -75,7 +75,6 @@ $textColor: #ccc;
opacity: 0.75;
}
.defaultAccount,
.signerPending {
cursor: pointer;
}

View File

@ -23,13 +23,13 @@ import BlockNumber from '@parity/ui/lib/BlockNumber';
import ClientVersion from '@parity/ui/lib/ClientVersion';
import GradientBg from '@parity/ui/lib/GradientBg';
import { HomeIcon } from '@parity/ui/lib/Icons';
import IdentityIcon from '@parity/ui/lib/IdentityIcon';
import NetChain from '@parity/ui/lib/NetChain';
import NetPeers from '@parity/ui/lib/NetPeers';
import SignerPending from '@parity/ui/lib/SignerPending';
import StatusIndicator from '@parity/ui/lib/StatusIndicator';
import Consensus from './Consensus';
import DefaultAccount from './DefaultAccount';
import AccountStore from '../ParityBar/accountStore';
import ParityBarStore from '../ParityBar/store';
import SyncWarning from '../SyncWarning';
@ -67,12 +67,9 @@ function Status ({ className = '', upgradeStore }, { api }) {
className={ styles.signerPending }
onClick={ parityBarStore.toggleOpenSigner }
/>
<IdentityIcon
address={ accountStore.defaultAccount }
button
center
className={ styles.defaultAccount }
onClick={ parityBarStore.toggleOpenAccounts }
<DefaultAccount
accountStore={ accountStore }
/>
<StatusIndicator
className={ styles.health }