Ui 2 styling adjustments (#5534)
* Stateless components * Adjust borders * Stateless for status * Externalise link colors * css lint * stateless * Create ui/IconCache, replacing redux * Update Signer buttons * Requests background * Adjust request styling * Stateless components * ParityBar background alignment
This commit is contained in:
parent
b57e8f6f0d
commit
e7484d07aa
@ -17,7 +17,7 @@
|
|||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
|
||||||
import styles from './header.css';
|
import styles from './header.css';
|
||||||
import blocks from '../../../../assets/images/dapps/blocks-350.jpg';
|
import blocks from '~/../assets/images/dapps/blocks-350.jpg';
|
||||||
|
|
||||||
export default class Header extends Component {
|
export default class Header extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -16,14 +16,12 @@
|
|||||||
|
|
||||||
import { newError } from '~/ui/Errors/actions';
|
import { newError } from '~/ui/Errors/actions';
|
||||||
|
|
||||||
import { setAddressImage } from './providers/imagesActions';
|
|
||||||
import { openSnackbar, showSnackbar } from './providers/snackbarActions';
|
import { openSnackbar, showSnackbar } from './providers/snackbarActions';
|
||||||
import { toggleStatusRefresh } from './providers/statusActions';
|
import { toggleStatusRefresh } from './providers/statusActions';
|
||||||
import { toggleView } from './providers/settings/actions';
|
import { toggleView } from './providers/settings/actions';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
newError,
|
newError,
|
||||||
setAddressImage,
|
|
||||||
openSnackbar,
|
openSnackbar,
|
||||||
showSnackbar,
|
showSnackbar,
|
||||||
toggleStatusRefresh,
|
toggleStatusRefresh,
|
||||||
|
@ -22,7 +22,6 @@ export Status from './status';
|
|||||||
export apiReducer from './apiReducer';
|
export apiReducer from './apiReducer';
|
||||||
export balancesReducer from './balancesReducer';
|
export balancesReducer from './balancesReducer';
|
||||||
export workerReducer from './workerReducer';
|
export workerReducer from './workerReducer';
|
||||||
export imagesReducer from './imagesReducer';
|
|
||||||
export personalReducer from './personalReducer';
|
export personalReducer from './personalReducer';
|
||||||
export requestsReducer from './requestsReducer';
|
export requestsReducer from './requestsReducer';
|
||||||
export settingsReducer from './settings/reducers';
|
export settingsReducer from './settings/reducers';
|
||||||
|
@ -18,10 +18,10 @@ import { uniq } from 'lodash';
|
|||||||
|
|
||||||
import Contracts from '~/contracts';
|
import Contracts from '~/contracts';
|
||||||
import { LOG_KEYS, getLogger } from '~/config';
|
import { LOG_KEYS, getLogger } from '~/config';
|
||||||
|
import { IconCache } from '~/ui';
|
||||||
import { fetchTokenIds, fetchTokenInfo } from '~/util/tokens';
|
import { fetchTokenIds, fetchTokenInfo } from '~/util/tokens';
|
||||||
|
|
||||||
import { updateTokensFilter } from './balancesActions';
|
import { updateTokensFilter } from './balancesActions';
|
||||||
import { setAddressImage } from './imagesActions';
|
|
||||||
|
|
||||||
const log = getLogger(LOG_KEYS.Balances);
|
const log = getLogger(LOG_KEYS.Balances);
|
||||||
|
|
||||||
@ -54,8 +54,9 @@ export function fetchTokens (_tokenIndexes, options = {}) {
|
|||||||
const tokenIndexes = uniq(_tokenIndexes || []);
|
const tokenIndexes = uniq(_tokenIndexes || []);
|
||||||
|
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const { api, images } = getState();
|
const { api } = getState();
|
||||||
const { tokenReg } = Contracts.get(api);
|
const { tokenReg } = Contracts.get(api);
|
||||||
|
const iconCache = IconCache.get();
|
||||||
|
|
||||||
return tokenReg.getInstance()
|
return tokenReg.getInstance()
|
||||||
.then((tokenRegInstance) => {
|
.then((tokenRegInstance) => {
|
||||||
@ -69,8 +70,8 @@ export function fetchTokens (_tokenIndexes, options = {}) {
|
|||||||
const { id, image, address } = token;
|
const { id, image, address } = token;
|
||||||
|
|
||||||
// dispatch only the changed images
|
// dispatch only the changed images
|
||||||
if (images[address] !== image) {
|
if (iconCache.images[address] !== image) {
|
||||||
dispatch(setAddressImage(address, image, true));
|
iconCache.add(address, image, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens[id] = token;
|
tokens[id] = token;
|
||||||
|
@ -19,7 +19,7 @@ import { routerReducer } from 'react-router-redux';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
apiReducer, balancesReducer,
|
apiReducer, balancesReducer,
|
||||||
workerReducer, imagesReducer, personalReducer, requestsReducer,
|
workerReducer, personalReducer, requestsReducer,
|
||||||
settingsReducer, signerReducer, statusReducer as nodeStatusReducer,
|
settingsReducer, signerReducer, statusReducer as nodeStatusReducer,
|
||||||
snackbarReducer, tokensReducer, walletReducer
|
snackbarReducer, tokensReducer, walletReducer
|
||||||
} from './providers';
|
} from './providers';
|
||||||
@ -39,7 +39,6 @@ export default function () {
|
|||||||
|
|
||||||
balances: balancesReducer,
|
balances: balancesReducer,
|
||||||
certifications: certificationsReducer,
|
certifications: certificationsReducer,
|
||||||
images: imagesReducer,
|
|
||||||
nodeStatus: nodeStatusReducer,
|
nodeStatus: nodeStatusReducer,
|
||||||
personal: personalReducer,
|
personal: personalReducer,
|
||||||
registry: registryReducer,
|
registry: registryReducer,
|
||||||
|
@ -14,10 +14,8 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import { hashToImageUrl } from './providers/imagesReducer';
|
|
||||||
import { withError } from '~/ui/Errors/middleware';
|
import { withError } from '~/ui/Errors/middleware';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
hashToImageUrl,
|
|
||||||
withError
|
withError
|
||||||
};
|
};
|
||||||
|
@ -15,9 +15,9 @@
|
|||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$baseColor: 18;
|
$baseColor: 255;
|
||||||
$baseOpacity: 0.95;
|
$baseOpacity: 0.95;
|
||||||
$borderColor: rgba($baseColor, $baseColor, $baseColor, 0.25);
|
$borderColor: rgba(0, 0, 0, 0.15);
|
||||||
|
|
||||||
.requests {
|
.requests {
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
|
@ -14,13 +14,12 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import styles from '../firstRun.css';
|
import styles from '../firstRun.css';
|
||||||
|
|
||||||
export default class Completed extends Component {
|
export default function Completed () {
|
||||||
render () {
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.completed }>
|
<div className={ styles.completed }>
|
||||||
<p>
|
<p>
|
||||||
@ -38,4 +37,3 @@ export default class Completed extends Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -14,21 +14,13 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { Checkbox } from 'material-ui';
|
import { Checkbox } from 'material-ui';
|
||||||
|
|
||||||
import styles from '../firstRun.css';
|
import styles from '../firstRun.css';
|
||||||
|
|
||||||
export default class TnC extends Component {
|
export default function TnC ({ hasAccepted, onAccept }) {
|
||||||
static propTypes = {
|
|
||||||
hasAccepted: PropTypes.bool.isRequired,
|
|
||||||
onAccept: PropTypes.func.isRequired
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { hasAccepted, onAccept } = this.props;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.tnc }>
|
<div className={ styles.tnc }>
|
||||||
<h1>SECURITY WARNINGS</h1>
|
<h1>SECURITY WARNINGS</h1>
|
||||||
@ -178,4 +170,8 @@ export default class TnC extends Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
TnC.propTypes = {
|
||||||
|
hasAccepted: PropTypes.bool.isRequired,
|
||||||
|
onAccept: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import imagesEthcore from '~/../assets/images/parity-logo-white.svg';
|
import imagesEthcore from '~/../assets/images/parity-logo-white.svg';
|
||||||
@ -28,8 +28,7 @@ const LOGO_STYLE = {
|
|||||||
margin: '0 1.5em'
|
margin: '0 1.5em'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class FirstRun extends Component {
|
export default function FirstRun () {
|
||||||
render () {
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.welcome }>
|
<div className={ styles.welcome }>
|
||||||
<img
|
<img
|
||||||
@ -80,4 +79,3 @@ export default class FirstRun extends Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -51,7 +51,7 @@ $modalZ: 10001;
|
|||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
background: rgba(255, 255, 255, 0.5);
|
background: rgba(0, 0, 0, 0.35);
|
||||||
z-index: $overlayZ;
|
z-index: $overlayZ;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
@ -25,10 +25,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.signerIcon {
|
.signerIcon {
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-left: 12px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.passwordHint {
|
.passwordHint {
|
||||||
|
@ -15,13 +15,12 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import keycode from 'keycode';
|
import keycode from 'keycode';
|
||||||
import RaisedButton from 'material-ui/RaisedButton';
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import ReactTooltip from 'react-tooltip';
|
import ReactTooltip from 'react-tooltip';
|
||||||
|
|
||||||
import { Form, Input, IdentityIcon, QrCode, QrScan } from '~/ui';
|
import { Button, Form, Input, IdentityIcon, QrCode, QrScan } from '~/ui';
|
||||||
import { generateTxQr, generateDataQr } from '~/util/qrscan';
|
import { generateTxQr, generateDataQr } from '~/util/qrscan';
|
||||||
|
|
||||||
import styles from './transactionPendingFormConfirm.css';
|
import styles from './transactionPendingFormConfirm.css';
|
||||||
@ -131,7 +130,7 @@ export default class TransactionPendingFormConfirm extends Component {
|
|||||||
data-place='bottom'
|
data-place='bottom'
|
||||||
data-tip
|
data-tip
|
||||||
>
|
>
|
||||||
<RaisedButton
|
<Button
|
||||||
className={ styles.confirmButton }
|
className={ styles.confirmButton }
|
||||||
disabled={ disabled || isSending || !isWalletOk }
|
disabled={ disabled || isSending || !isWalletOk }
|
||||||
fullWidth
|
fullWidth
|
||||||
@ -143,8 +142,7 @@ export default class TransactionPendingFormConfirm extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
label={ confirmText }
|
label={ confirmText }
|
||||||
onTouchTap={ this.onConfirm }
|
onClick={ this.onConfirm }
|
||||||
primary
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import RaisedButton from 'material-ui/RaisedButton';
|
import { Button } from '~/ui';
|
||||||
|
|
||||||
import styles from './transactionPendingFormReject.css';
|
import styles from './transactionPendingFormReject.css';
|
||||||
|
|
||||||
@ -45,8 +45,8 @@ export default class TransactionPendingFormReject extends Component {
|
|||||||
/>
|
/>
|
||||||
</strong>
|
</strong>
|
||||||
</div>
|
</div>
|
||||||
<RaisedButton
|
<Button
|
||||||
onTouchTap={ onReject }
|
onClick={ onReject }
|
||||||
className={ styles.rejectButton }
|
className={ styles.rejectButton }
|
||||||
fullWidth
|
fullWidth
|
||||||
label={
|
label={
|
||||||
|
@ -19,18 +19,19 @@ import { Button as SemButton } from 'semantic-ui-react';
|
|||||||
|
|
||||||
import { nodeOrStringProptype } from '~/util/proptypes';
|
import { nodeOrStringProptype } from '~/util/proptypes';
|
||||||
|
|
||||||
export default function Button ({ active, animated, basic, className, color, disabled, icon, label, onClick, primary, size, toggle }) {
|
export default function Button ({ active, animated, basic, className, color, disabled, fullWidth, icon, label, onClick, primary, size, toggle }) {
|
||||||
return (
|
return (
|
||||||
<SemButton
|
<SemButton
|
||||||
active={ active }
|
active={ active }
|
||||||
animated={ animated }
|
animated={ animated }
|
||||||
basic={ basic }
|
basic={ basic }
|
||||||
className={ className }
|
className={ className }
|
||||||
|
content={ label }
|
||||||
color={ color }
|
color={ color }
|
||||||
disabled={ disabled }
|
disabled={ disabled }
|
||||||
|
fluid={ fullWidth }
|
||||||
icon={ icon }
|
icon={ icon }
|
||||||
content={ label }
|
onTouchTap={ onClick }
|
||||||
onClick={ onClick }
|
|
||||||
primary={ primary }
|
primary={ primary }
|
||||||
size={ size }
|
size={ size }
|
||||||
toggle={ toggle }
|
toggle={ toggle }
|
||||||
@ -46,6 +47,7 @@ Button.propTypes = {
|
|||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
color: PropTypes.string,
|
color: PropTypes.string,
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
|
fullWidth: PropTypes.bool,
|
||||||
icon: PropTypes.node,
|
icon: PropTypes.node,
|
||||||
label: nodeOrStringProptype(),
|
label: nodeOrStringProptype(),
|
||||||
onClick: PropTypes.func,
|
onClick: PropTypes.func,
|
||||||
|
@ -17,9 +17,8 @@
|
|||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { hashToImageUrl } from '~/redux/providers/imagesReducer';
|
|
||||||
|
|
||||||
import defaultIcon from '~/../assets/images/certifications/unknown.svg';
|
import defaultIcon from '~/../assets/images/certifications/unknown.svg';
|
||||||
|
import IconCache from '~/ui/IconCache';
|
||||||
|
|
||||||
import styles from './certifications.css';
|
import styles from './certifications.css';
|
||||||
|
|
||||||
@ -68,7 +67,7 @@ class Certifications extends Component {
|
|||||||
className={ styles.icon }
|
className={ styles.icon }
|
||||||
src={
|
src={
|
||||||
icon
|
icon
|
||||||
? `${dappsUrl}${hashToImageUrl(icon)}`
|
? `${dappsUrl}${IconCache.hashToImage(icon)}`
|
||||||
: defaultIcon
|
: defaultIcon
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@import '../_colors.css';
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -41,7 +43,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.titleLink {
|
.titleLink {
|
||||||
color: rgb(0, 151, 167);
|
color: $linkColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.author {
|
.author {
|
||||||
|
@ -14,24 +14,12 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
|
|
||||||
import styles from './dappIcon.css';
|
import styles from './dappIcon.css';
|
||||||
|
|
||||||
export default class DappIcon extends Component {
|
export default function DappIcon ({ app, className, small }, context) {
|
||||||
static contextTypes = {
|
const { dappsUrl } = context.api;
|
||||||
api: PropTypes.object.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
app: PropTypes.object.isRequired,
|
|
||||||
className: PropTypes.string,
|
|
||||||
small: PropTypes.bool
|
|
||||||
};
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { dappsUrl } = this.context.api;
|
|
||||||
const { app, className, small } = this.props;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
@ -46,4 +34,13 @@ export default class DappIcon extends Component {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
DappIcon.contextTypes = {
|
||||||
|
api: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
DappIcon.propTypes = {
|
||||||
|
app: PropTypes.object.isRequired,
|
||||||
|
className: PropTypes.string,
|
||||||
|
small: PropTypes.bool
|
||||||
|
};
|
||||||
|
@ -15,7 +15,9 @@
|
|||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@import '../_colors.css';
|
||||||
|
|
||||||
.link {
|
.link {
|
||||||
color: rgb(0, 151, 167);
|
color: $linkColor;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
@ -14,30 +14,41 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import { handleActions } from 'redux-actions';
|
import { action, observable } from 'mobx';
|
||||||
|
|
||||||
import { bytesToHex } from '@parity/api/util/format';
|
import { bytesToHex } from '@parity/api/util/format';
|
||||||
|
|
||||||
const ZERO = '0x0000000000000000000000000000000000000000000000000000000000000000';
|
const ZERO = '0x0000000000000000000000000000000000000000000000000000000000000000';
|
||||||
|
const API_PATH = '/api/content/';
|
||||||
|
|
||||||
const initialState = {
|
let instance = null;
|
||||||
images: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
export function hashToImageUrl (hashArray) {
|
export default class IconCache {
|
||||||
const hash = hashArray ? bytesToHex(hashArray) : ZERO;
|
@observable images = {};
|
||||||
|
|
||||||
return hash === ZERO ? null : `/api/content/${hash.substr(2)}`;
|
@action add (address, imageOrHash, isImage = false) {
|
||||||
}
|
this.images = Object.assign({}, this.images, {
|
||||||
|
[address]: isImage
|
||||||
export default handleActions({
|
? imageOrHash
|
||||||
setAddressImage (state, action) {
|
: IconCache.hashToImage(imageOrHash)
|
||||||
const { address, hashArray, converted } = action;
|
|
||||||
|
|
||||||
const image = converted ? hashArray : hashToImageUrl(hashArray);
|
|
||||||
|
|
||||||
return Object.assign({}, state, {
|
|
||||||
[address]: image
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, initialState);
|
|
||||||
|
static hashToImage (_hash) {
|
||||||
|
const hash = _hash
|
||||||
|
? bytesToHex(_hash)
|
||||||
|
: ZERO;
|
||||||
|
|
||||||
|
return hash === ZERO
|
||||||
|
? null
|
||||||
|
: `${API_PATH}${hash.substr(2)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get (force = false) {
|
||||||
|
if (!instance || force) {
|
||||||
|
instance = new IconCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
@ -14,11 +14,4 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
export function setAddressImage (address, hashArray, converted = false) {
|
export default from './iconCache';
|
||||||
return {
|
|
||||||
type: 'setAddressImage',
|
|
||||||
address,
|
|
||||||
hashArray,
|
|
||||||
converted
|
|
||||||
};
|
|
||||||
}
|
|
@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
.button {
|
.button {
|
||||||
display: inline;
|
display: inline;
|
||||||
width: 24px;
|
width: 1em;
|
||||||
height: 24px;
|
height: 1em;
|
||||||
margin: 6px 0.25em 0 12px;
|
margin: 0 0.25em;
|
||||||
}
|
}
|
||||||
|
@ -15,16 +15,18 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import { createIdentityImg } from '@parity/api/util/identity';
|
import { createIdentityImg } from '@parity/api/util/identity';
|
||||||
|
|
||||||
import { isNullAddress } from '~/util/validation';
|
import { isNullAddress } from '~/util/validation';
|
||||||
import { CancelIcon, ContractIcon } from '../Icons';
|
import IconCache from '~/ui/IconCache';
|
||||||
|
import { CancelIcon, ContractIcon } from '~/ui/Icons';
|
||||||
|
|
||||||
import styles from './identityIcon.css';
|
import styles from './identityIcon.css';
|
||||||
|
|
||||||
class IdentityIcon extends Component {
|
const iconCache = IconCache.get();
|
||||||
|
|
||||||
|
export default class IdentityIcon extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
api: PropTypes.object.isRequired
|
api: PropTypes.object.isRequired
|
||||||
}
|
}
|
||||||
@ -35,7 +37,6 @@ class IdentityIcon extends Component {
|
|||||||
center: PropTypes.bool,
|
center: PropTypes.bool,
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
images: PropTypes.object.isRequired,
|
|
||||||
inline: PropTypes.bool,
|
inline: PropTypes.bool,
|
||||||
padded: PropTypes.bool,
|
padded: PropTypes.bool,
|
||||||
tiny: PropTypes.bool
|
tiny: PropTypes.bool
|
||||||
@ -46,26 +47,23 @@ class IdentityIcon extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this.updateIcon(this.props.address, this.props.images);
|
this.updateIcon(this.props.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps (newProps) {
|
componentWillReceiveProps (newProps) {
|
||||||
const sameAddress = newProps.address === this.props.address;
|
if (newProps.address === this.props.address) {
|
||||||
const sameImages = Object.keys(newProps.images).length === Object.keys(this.props.images).length;
|
|
||||||
|
|
||||||
if (sameAddress && sameImages) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateIcon(newProps.address, newProps.images);
|
this.updateIcon(newProps.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateIcon (_address, images) {
|
updateIcon (_address) {
|
||||||
const { api } = this.context;
|
const { api } = this.context;
|
||||||
const { button, inline, tiny } = this.props;
|
const { button, inline, tiny } = this.props;
|
||||||
|
|
||||||
if (images[_address]) {
|
if (iconCache[_address]) {
|
||||||
this.setState({ iconsrc: `${api.dappsUrl}${images[_address]}` });
|
this.setState({ iconsrc: `${api.dappsUrl}${iconCache[_address]}` });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,14 +143,3 @@ class IdentityIcon extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
|
||||||
const { images } = state;
|
|
||||||
|
|
||||||
return { images };
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(
|
|
||||||
mapStateToProps,
|
|
||||||
null
|
|
||||||
)(IdentityIcon);
|
|
||||||
|
@ -16,15 +16,16 @@
|
|||||||
|
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import sinon from 'sinon';
|
|
||||||
|
|
||||||
import IdentityIcon from './';
|
import IdentityIcon from './';
|
||||||
|
import IconCache from '../IconCache';
|
||||||
|
|
||||||
const ADDRESS0 = '0x0000000000000000000000000000000000000000';
|
const ADDRESS0 = '0x0000000000000000000000000000000000000000';
|
||||||
const ADDRESS1 = '0x0123456789012345678901234567890123456789';
|
const ADDRESS1 = '0x0123456789012345678901234567890123456789';
|
||||||
const ADDRESS2 = '0x9876543210987654321098765432109876543210';
|
const ADDRESS2 = '0x9876543210987654321098765432109876543210';
|
||||||
|
|
||||||
let component;
|
let component;
|
||||||
|
let iconCache;
|
||||||
let instance;
|
let instance;
|
||||||
|
|
||||||
function createApi () {
|
function createApi () {
|
||||||
@ -33,20 +34,6 @@ function createApi () {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createRedux () {
|
|
||||||
return {
|
|
||||||
dispatch: sinon.stub(),
|
|
||||||
subscribe: sinon.stub(),
|
|
||||||
getState: () => {
|
|
||||||
return {
|
|
||||||
images: {
|
|
||||||
[ADDRESS2]: 'reduxImage'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function render (props = {}) {
|
function render (props = {}) {
|
||||||
if (props && props.address === undefined) {
|
if (props && props.address === undefined) {
|
||||||
props.address = ADDRESS1;
|
props.address = ADDRESS1;
|
||||||
@ -54,12 +41,15 @@ function render (props = {}) {
|
|||||||
|
|
||||||
component = shallow(
|
component = shallow(
|
||||||
<IdentityIcon { ...props } />,
|
<IdentityIcon { ...props } />,
|
||||||
{ context: { store: createRedux() } }
|
{ context: { api: createApi() } }
|
||||||
).find('IdentityIcon').shallow({ context: { api: createApi() } });
|
);
|
||||||
|
|
||||||
instance = component.instance();
|
instance = component.instance();
|
||||||
instance.componentDidMount();
|
instance.componentDidMount();
|
||||||
|
|
||||||
|
iconCache = IconCache.get(true);
|
||||||
|
iconCache.add(ADDRESS2, 'cachedImage');
|
||||||
|
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,11 +66,11 @@ describe('ui/IdentityIcon', () => {
|
|||||||
expect(img.props().src).to.equal('test-createIdentityImg');
|
expect(img.props().src).to.equal('test-createIdentityImg');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an <img> with redux source when available', () => {
|
it('renders an <img> with cache source when available', () => {
|
||||||
const img = render({ address: ADDRESS2 }).find('img');
|
const img = render({ address: ADDRESS2 }).find('img');
|
||||||
|
|
||||||
expect(img).to.have.length(1);
|
expect(img).to.have.length(1);
|
||||||
expect(img.props().src).to.equal('dappsUrl/reduxImage');
|
expect(img.props().src).to.equal('dappsUrl/cachedImage');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an <ContractIcon> with no address specified', () => {
|
it('renders an <ContractIcon> with no address specified', () => {
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
@ -34,20 +34,7 @@ const defaultNameNull = (
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
export class IdentityName extends Component {
|
export function IdentityName ({ account, address, className, empty, name, shorten, unknown }) {
|
||||||
static propTypes = {
|
|
||||||
account: PropTypes.object,
|
|
||||||
address: PropTypes.string,
|
|
||||||
className: PropTypes.string,
|
|
||||||
empty: PropTypes.bool,
|
|
||||||
name: PropTypes.string,
|
|
||||||
shorten: PropTypes.bool,
|
|
||||||
unknown: PropTypes.bool
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { account, address, className, empty, name, shorten, unknown } = this.props;
|
|
||||||
|
|
||||||
if (!account && empty) {
|
if (!account && empty) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -72,7 +59,16 @@ export class IdentityName extends Component {
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
IdentityName.propTypes = {
|
||||||
|
account: PropTypes.object,
|
||||||
|
address: PropTypes.string,
|
||||||
|
className: PropTypes.string,
|
||||||
|
empty: PropTypes.bool,
|
||||||
|
name: PropTypes.string,
|
||||||
|
shorten: PropTypes.bool,
|
||||||
|
unknown: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
function mapStateToProps (state, props) {
|
function mapStateToProps (state, props) {
|
||||||
const { address } = props;
|
const { address } = props;
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@import '../_colors.css';
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -69,7 +71,7 @@
|
|||||||
filter: none;
|
filter: none;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
background: rgb(0, 151, 167);
|
background: $linkColor;
|
||||||
content: '';
|
content: '';
|
||||||
height: 4px;
|
height: 4px;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -15,13 +15,15 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import unknownImage from '~/../assets/images/contracts/unknown-64x64.png';
|
import unknownImage from '~/../assets/images/contracts/unknown-64x64.png';
|
||||||
|
import IconCache from '~/ui/IconCache';
|
||||||
|
|
||||||
function TokenImage ({ image, token }, context) {
|
const iconCache = IconCache.get();
|
||||||
|
|
||||||
|
export default function TokenImage ({ token }, context) {
|
||||||
const { api } = context;
|
const { api } = context;
|
||||||
const imageurl = token.image || image;
|
const imageurl = token.image || iconCache.images[token.address];
|
||||||
let imagesrc = unknownImage;
|
let imagesrc = unknownImage;
|
||||||
|
|
||||||
if (imageurl) {
|
if (imageurl) {
|
||||||
@ -45,24 +47,8 @@ TokenImage.contextTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TokenImage.propTypes = {
|
TokenImage.propTypes = {
|
||||||
image: PropTypes.string,
|
|
||||||
token: PropTypes.shape({
|
token: PropTypes.shape({
|
||||||
image: PropTypes.string,
|
image: PropTypes.string,
|
||||||
address: PropTypes.string
|
address: PropTypes.string
|
||||||
}).isRequired
|
}).isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
function mapStateToProps (iniState) {
|
|
||||||
const { images } = iniState;
|
|
||||||
|
|
||||||
return (_, props) => {
|
|
||||||
const { token } = props;
|
|
||||||
|
|
||||||
return { image: images[token.address] };
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(
|
|
||||||
mapStateToProps,
|
|
||||||
null
|
|
||||||
)(TokenImage);
|
|
||||||
|
18
js/src/ui/_colors.css
Normal file
18
js/src/ui/_colors.css
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$linkColor: #4183c4;
|
@ -36,6 +36,7 @@ export Features, { FEATURES, FeaturesStore } from './Features';
|
|||||||
export Form, { AddressSelect, DappUrlInput, FileSelect, FormWrap, Input, InputAddress, InputAddressSelect, InputChip, InputDate, InputInline, InputTime, Label, RadioButtons, Select, TypedInput, VaultSelect } from './Form';
|
export Form, { AddressSelect, DappUrlInput, FileSelect, FormWrap, Input, InputAddress, InputAddressSelect, InputChip, InputDate, InputInline, InputTime, Label, RadioButtons, Select, TypedInput, VaultSelect } from './Form';
|
||||||
export GasPriceEditor from './GasPriceEditor';
|
export GasPriceEditor from './GasPriceEditor';
|
||||||
export GasPriceSelector from './GasPriceSelector';
|
export GasPriceSelector from './GasPriceSelector';
|
||||||
|
export IconCache from './IconCache';
|
||||||
export Icons from './Icons';
|
export Icons from './Icons';
|
||||||
export IdentityIcon from './IdentityIcon';
|
export IdentityIcon from './IdentityIcon';
|
||||||
export IdentityName from './IdentityName';
|
export IdentityName from './IdentityName';
|
||||||
|
@ -20,10 +20,9 @@ import { pick, range, uniq } from 'lodash';
|
|||||||
import { bytesToHex } from '@parity/api/util/format';
|
import { bytesToHex } from '@parity/api/util/format';
|
||||||
|
|
||||||
import Contracts from '~/contracts';
|
import Contracts from '~/contracts';
|
||||||
import { hashToImageUrl } from '~/redux/util';
|
|
||||||
|
|
||||||
import builtinJson from '~/config/dappsBuiltin.json';
|
import builtinJson from '~/config/dappsBuiltin.json';
|
||||||
import viewsJson from '~/config/dappsViews.json';
|
import viewsJson from '~/config/dappsViews.json';
|
||||||
|
import { IconCache } from '~/ui';
|
||||||
|
|
||||||
const builtinApps = [].concat(
|
const builtinApps = [].concat(
|
||||||
viewsJson.map((app) => {
|
viewsJson.map((app) => {
|
||||||
@ -105,7 +104,7 @@ export function fetchBuiltinApps (api) {
|
|||||||
app.type = app.isView
|
app.type = app.isView
|
||||||
? 'view'
|
? 'view'
|
||||||
: 'builtin';
|
: 'builtin';
|
||||||
app.image = hashToImageUrl(imageIds[index]);
|
app.image = IconCache.hashToImage(imageIds[index]);
|
||||||
return app;
|
return app;
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@ -169,7 +168,7 @@ export function fetchRegistryApp (api, dappReg, appId) {
|
|||||||
.then(([ imageId, contentId, manifestId ]) => {
|
.then(([ imageId, contentId, manifestId ]) => {
|
||||||
const app = {
|
const app = {
|
||||||
id: appId,
|
id: appId,
|
||||||
image: hashToImageUrl(imageId),
|
image: IconCache.hashToImage(imageId),
|
||||||
contentHash: bytesToHex(contentId).substr(2),
|
contentHash: bytesToHex(contentId).substr(2),
|
||||||
manifestHash: bytesToHex(manifestId).substr(2),
|
manifestHash: bytesToHex(manifestId).substr(2),
|
||||||
type: 'network',
|
type: 'network',
|
||||||
|
@ -20,7 +20,7 @@ import BigNumber from 'bignumber.js';
|
|||||||
import { sha3 } from '@parity/api/util/sha3';
|
import { sha3 } from '@parity/api/util/sha3';
|
||||||
|
|
||||||
import imagesEthereum from '~/../assets/images/contracts/ethereum-black-64x64.png';
|
import imagesEthereum from '~/../assets/images/contracts/ethereum-black-64x64.png';
|
||||||
import { hashToImageUrl } from '~/redux/util';
|
import { IconCache } from '~/ui';
|
||||||
|
|
||||||
const BALANCEOF_SIGNATURE = sha3('balanceOf(address)');
|
const BALANCEOF_SIGNATURE = sha3('balanceOf(address)');
|
||||||
const ADDRESS_PADDING = range(24).map(() => '0').join('');
|
const ADDRESS_PADDING = range(24).map(() => '0').join('');
|
||||||
@ -57,7 +57,7 @@ export function fetchTokenInfo (api, tokenregInstace, tokenIndex) {
|
|||||||
const token = {
|
const token = {
|
||||||
format: format.toString(),
|
format: format.toString(),
|
||||||
index: tokenIndex,
|
index: tokenIndex,
|
||||||
image: hashToImageUrl(image),
|
image: IconCache.hashToImage(image),
|
||||||
id: sha3(address + tokenIndex).slice(0, 10),
|
id: sha3(address + tokenIndex).slice(0, 10),
|
||||||
address,
|
address,
|
||||||
name,
|
name,
|
||||||
|
@ -34,7 +34,6 @@ function createRedux () {
|
|||||||
[ADDRESS]: {}
|
[ADDRESS]: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
images: {},
|
|
||||||
nodeStatus: {
|
nodeStatus: {
|
||||||
netVersion: '1',
|
netVersion: '1',
|
||||||
traceMode: false
|
traceMode: false
|
||||||
|
Loading…
Reference in New Issue
Block a user