Better display of tags (#4564)

* WIP

* Update accounts on whitelist change in Parity Bar

* Fix AccountCard width in Parity Bar (Signer)

* Added AccountCard Example

* Use horizontal tags

* Better Tags display

* Scrollable tags

* Update PR Grumbles

* Fix tests (add tags)

* PR Grumble
This commit is contained in:
Nicolas Gotchac 2017-02-16 17:42:19 +01:00 committed by Gav Wood
parent 00c843afea
commit b825c8e074
12 changed files with 262 additions and 49 deletions

View File

@ -126,6 +126,7 @@ export default class Personal {
case 'parity_setDappsAddresses': case 'parity_setDappsAddresses':
case 'parity_setNewDappsWhitelist': case 'parity_setNewDappsWhitelist':
this._defaultAccount(true); this._defaultAccount(true);
this._listAccounts();
return; return;
} }
}); });

View File

@ -74,7 +74,7 @@ $codeColor: #93a1a1;
flex: 1; flex: 1;
overflow: auto; overflow: auto;
padding: 0.5em; padding: 0.5em;
background-color: #$codeBackground; background-color: $codeBackground;
color: $codeColor; color: $codeColor;
font-size: 0.75em; font-size: 0.75em;
@ -86,5 +86,6 @@ $codeColor: #93a1a1;
.component { .component {
flex: 3; flex: 3;
padding-left: 0.5em; padding-left: 0.5em;
overflow: auto;
} }
} }

View File

@ -17,6 +17,7 @@
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import React, { Component } from 'react'; import React, { Component } from 'react';
import AccountCard from '~/ui/AccountCard/accountCard.example';
import CurrencySymbol from '~/ui/CurrencySymbol/currencySymbol.example'; import CurrencySymbol from '~/ui/CurrencySymbol/currencySymbol.example';
import QrCode from '~/ui/QrCode/qrCode.example'; import QrCode from '~/ui/QrCode/qrCode.example';
import SectionList from '~/ui/SectionList/sectionList.example'; import SectionList from '~/ui/SectionList/sectionList.example';
@ -25,6 +26,7 @@ import Portal from '~/ui/Portal/portal.example';
import PlaygroundStore from './store'; import PlaygroundStore from './store';
import styles from './playground.css'; import styles from './playground.css';
PlaygroundStore.register(<AccountCard />);
PlaygroundStore.register(<CurrencySymbol />); PlaygroundStore.register(<CurrencySymbol />);
PlaygroundStore.register(<QrCode />); PlaygroundStore.register(<QrCode />);
PlaygroundStore.register(<SectionList />); PlaygroundStore.register(<SectionList />);

View File

@ -16,18 +16,14 @@
*/ */
.account { .account {
padding: 1em; align-items: stretch;
margin: 0.5em 0;
display: flex;
flex-direction: column;
align-items: flex-start;
background-color: rgba(0, 0, 0, 0.8); background-color: rgba(0, 0, 0, 0.8);
display: flex;
flex-direction: row;
margin: 0.5em 0;
overflow: hidden;
transition: transform ease-out 0.1s; transition: transform ease-out 0.1s;
transform: scale(1); transform: scale(1);
overflow: hidden;
&.copied { &.copied {
animation-duration: 0.25s; animation-duration: 0.25s;
@ -53,6 +49,38 @@
} }
} }
.mainContainer {
flex: 1 1 auto;
overflow: hidden;
padding: 1em;
}
.tagsContainer {
flex: 0 0 auto;
position: relative;
width: 3em;
}
.tags {
background-color: rgba(0, 0, 0, 0.4);
box-sizing: content-box;
height: calc(100% - 0.5em);
overflow-x: hidden;
overflow-y: scroll;
padding: 0.25em;
padding-right: 2em;
position: absolute;
right: -2.5em;
transition: background-color 0.2s ease-out;
width: calc(100% + 0.25em);
&:hover {
background-color: rgba(0, 0, 0, 0.8);
padding-left: 0.5em;
width: auto;
}
}
.infoContainer { .infoContainer {
display: flex; display: flex;
flex-direction: row; flex-direction: row;

View File

@ -0,0 +1,110 @@
// 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 PlaygroundExample from '~/playground/playgroundExample';
import AccountCard from './accountCard';
export default class AccountCardExample extends Component {
render () {
const account = {
address: '0x639ba260535db072a41115c472830846e4e9ad0f',
description: 'This is a description for the main account',
meta: {
tags: [ 'important', 'zargo' ]
},
name: 'Main Account'
};
const balance = {
tokens: [
{
value: 100000000000000000000,
token: {
tag: 'ETH'
}
}
]
};
const accountManyTags = {
...account,
meta: { tags: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((n) => `tag #${n}`) }
};
const accountNoTags = {
...account,
meta: { tags: [] }
};
return (
<div>
<PlaygroundExample name='Standard Account Card'>
<AccountCard
account={ account }
balance={ balance }
/>
</PlaygroundExample>
<PlaygroundExample name='Small Account Card'>
<div style={ { width: 300 } }>
<AccountCard
account={ account }
balance={ balance }
/>
</div>
</PlaygroundExample>
<PlaygroundExample name='Many Tags Account Card'>
<div style={ { width: 300 } }>
<AccountCard
account={ accountManyTags }
balance={ balance }
/>
</div>
</PlaygroundExample>
<PlaygroundExample name='No Tags Account Card'>
<div style={ { width: 300 } }>
<AccountCard
account={ accountNoTags }
balance={ balance }
/>
</div>
</PlaygroundExample>
<PlaygroundExample name='Two Account Card'>
<div style={ { display: 'flex' } }>
<div style={ { margin: '0 0.5em' } }>
<AccountCard
account={ account }
balance={ balance }
/>
</div>
<div style={ { margin: '0 0.5em' } }>
<AccountCard
account={ account }
balance={ balance }
/>
</div>
</div>
</PlaygroundExample>
</div>
);
}
}

View File

@ -58,28 +58,45 @@ export default class AccountCard extends Component {
onFocus={ this.onFocus } onFocus={ this.onFocus }
onKeyDown={ this.handleKeyDown } onKeyDown={ this.handleKeyDown }
> >
<div className={ styles.infoContainer }> <div className={ styles.mainContainer }>
<IdentityIcon address={ address } /> <div className={ styles.infoContainer }>
<div className={ styles.accountInfo }> <IdentityIcon address={ address } />
<div className={ styles.accountName }> <div className={ styles.accountInfo }>
<IdentityName <div className={ styles.accountName }>
address={ address } <IdentityName
name={ name } address={ address }
unknown name={ name }
/> unknown
/>
</div>
{ this.renderDescription(description) }
{ this.renderAddress(address) }
</div> </div>
{ this.renderDescription(description) }
{ this.renderAddress(address) }
</div> </div>
<Balance
balance={ balance }
className={ styles.balance }
showOnlyEth
showZeroValues
/>
</div> </div>
<Tags tags={ tags } /> {
<Balance tags && tags.length > 0
balance={ balance } ? (
className={ styles.balance } <div className={ styles.tagsContainer }>
showOnlyEth <div className={ styles.tags }>
showZeroValues <Tags
/> floating={ false }
horizontal
tags={ tags }
/>
</div>
</div>
) : null
}
</div> </div>
); );
} }

View File

@ -33,7 +33,9 @@ function render (props = {}) {
address: TEST_ADDRESS, address: TEST_ADDRESS,
description: 'testDescription', description: 'testDescription',
name: TEST_NAME, name: TEST_NAME,
meta: {} meta: {
tags: [ 'tag 1', 'tag 2' ]
}
}; };
} }

View File

@ -18,16 +18,39 @@
.tags { .tags {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
position: absolute;
right: 0.25rem; &.floating {
top: 0; position: absolute;
right: 0.25rem;
top: 0;
}
&.horizontal {
flex-direction: column;
}
}
.floating .tag {
margin-top: 0.75em;
}
.horizontal .tag {
margin: 0.25em 0;
.text {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 150%;
}
} }
.tag { .tag {
font-size: 0.75rem; font-size: 0.75rem;
background: rgba(255, 255, 255, 0.07); background: rgba(255, 255, 255, 0.07);
border-radius: 16px; border-radius: 16px;
margin: 0.75em 0.5em 0 0; margin: 0 0.5em;
padding: 0.25em 1em; padding: 0.25em 1em;
opacity: 1; opacity: 1;
transition: opacity 0.2s ease-out; transition: opacity 0.2s ease-out;

View File

@ -22,20 +22,37 @@ import styles from './tags.css';
export default class Tags extends Component { export default class Tags extends Component {
static propTypes = { static propTypes = {
floating: PropTypes.bool,
horizontal: PropTypes.bool,
handleAddSearchToken: PropTypes.func, handleAddSearchToken: PropTypes.func,
setRefs: PropTypes.func, setRefs: PropTypes.func,
tags: arrayOrObjectProptype() tags: arrayOrObjectProptype()
} };
static defaultProps = {
horizontal: false,
floating: true
};
render () { render () {
const { tags } = this.props; const { floating, horizontal, tags } = this.props;
if (!tags || tags.length === 0) { if (!tags || tags.length === 0) {
return null; return null;
} }
const classes = [ styles.tags ];
if (floating) {
classes.push(styles.floating);
}
if (horizontal) {
classes.push(styles.horizontal);
}
return ( return (
<div className={ styles.tags }> <div className={ classes.join(' ') }>
{ this.renderTags() } { this.renderTags() }
</div> </div>
); );
@ -66,7 +83,7 @@ export default class Tags extends Component {
onClick={ onClick } onClick={ onClick }
ref={ setRef } ref={ setRef }
> >
{ tag } <span className={ styles.text }>{ tag }</span>
</div> </div>
); );
}); });

View File

@ -111,10 +111,18 @@ export default class AccountStore {
} }
subscribeDefaultAccount () { subscribeDefaultAccount () {
return this._api.subscribe('parity_defaultAccount', (error, defaultAccount) => { const promiseDefaultAccount = this._api.subscribe('parity_defaultAccount', (error, defaultAccount) => {
if (!error) { if (!error) {
this.setDefaultAccount(defaultAccount); this.setDefaultAccount(defaultAccount);
} }
}); });
const promiseEthAccounts = this._api.subscribe('eth_accounts', (error) => {
if (!error) {
this.loadAccounts();
}
});
return Promise.all([ promiseDefaultAccount, promiseEthAccounts ]);
} }
} }

View File

@ -84,7 +84,6 @@ $modalZ: 10001;
.parityBg { .parityBg {
position: fixed; position: fixed;
transition-property: left, top, right, bottom; transition-property: left, top, right, bottom;
transition-duration: 0.25s; transition-duration: 0.25s;
transition-timing-function: ease; transition-timing-function: ease;
@ -95,20 +94,25 @@ $modalZ: 10001;
} }
} }
.accountsSection {
padding: 0 1em;
width: 920px;
}
.expanded { .expanded {
border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0;
display: flex; display: flex;
flex-direction: column; flex-direction: row;
min-height: 30vh; min-height: 30vh;
max-height: 80vh; max-height: 80vh;
max-width: calc(100vw - 1em); max-width: calc(100vw - 2em);
.content { .content {
flex: 1; flex: 1;
overflow-y: auto; overflow: auto;
overflow-x: hidden;
display: flex; display: flex;
background: rgba(0, 0, 0, 0.8); background: rgba(0, 0, 0, 0.8);
max-width: calc(100vw - 2em);
} }
} }
@ -130,7 +134,8 @@ $modalZ: 10001;
color: white !important; color: white !important;
display: inline-block; display: inline-block;
img, svg { img,
svg {
height: 24px !important; height: 24px !important;
width: 24px !important; width: 24px !important;
margin: 2px 0.5em 0 0; margin: 2px 0.5em 0 0;
@ -160,7 +165,7 @@ $modalZ: 10001;
min-width: 2em !important; min-width: 2em !important;
img { img {
margin: 6px 0.5em 0 0.5em; margin: 6px 0.5em 0;
} }
} }
@ -177,7 +182,7 @@ $modalZ: 10001;
.labelBubble { .labelBubble {
position: absolute; position: absolute;
top: 0px; top: 0;
right: -10px; right: -10px;
} }
@ -187,7 +192,7 @@ $modalZ: 10001;
background: rgba(0, 0, 0, 0.25); background: rgba(0, 0, 0, 0.25);
margin-bottom: 0; margin-bottom: 0;
&:after { &::after {
clear: both; clear: both;
} }
} }
@ -243,11 +248,9 @@ $modalZ: 10001;
width: 1em; width: 1em;
height: 1em; height: 1em;
margin-left: 0.5em; margin-left: 0.5em;
background-color: white; background-color: white;
opacity: 0.25; opacity: 0.25;
border-radius: 50%; border-radius: 50%;
transition-property: opacity; transition-property: opacity;
transition-duration: 0.1s; transition-duration: 0.1s;
transition-timing-function: ease-in-out; transition-timing-function: ease-in-out;

View File

@ -328,6 +328,7 @@ class ParityBar extends Component {
displayType === DISPLAY_ACCOUNTS displayType === DISPLAY_ACCOUNTS
? ( ? (
<SectionList <SectionList
className={ styles.accountsSection }
items={ this.accountStore.accounts } items={ this.accountStore.accounts }
noStretch noStretch
renderItem={ this.renderAccount } renderItem={ this.renderAccount }