diff --git a/src/Accounts/CreateAccount/AccountConfirm/AccountConfirm.js b/src/Accounts/CreateAccount/AccountConfirm/AccountConfirm.js index cb5f350ff8e2f37d0f951b1078b1fb187eb2810c..61981dbeb94fe3f99f7110ca4a022defb4b4363a 100644 --- a/src/Accounts/CreateAccount/AccountConfirm/AccountConfirm.js +++ b/src/Accounts/CreateAccount/AccountConfirm/AccountConfirm.js @@ -27,7 +27,7 @@ class AccountConfirm extends Component { diff --git a/src/Accounts/CreateAccount/AccountWritePhrase/AccountWritePhrase.js b/src/Accounts/CreateAccount/AccountWritePhrase/AccountWritePhrase.js index bffd03e5ff50c8c20691200606b288f69be50547..fd0384856efdd12eec8e7322fa46b08d1096d19a 100644 --- a/src/Accounts/CreateAccount/AccountWritePhrase/AccountWritePhrase.js +++ b/src/Accounts/CreateAccount/AccountWritePhrase/AccountWritePhrase.js @@ -76,7 +76,11 @@ class AccountWritePhrase extends Component { // If we are importing an existing account, the button sets the phrase return ( - ); diff --git a/src/App/App.css b/src/App/App.css index b37fda16d199a5ad2b68d0524d271fe6ef1fafb8..937e3aab3ec08ba49a6e976ecf95590ddb6367b0 100644 --- a/src/App/App.css +++ b/src/App/App.css @@ -831,6 +831,11 @@ a, a:link, a:visited { .button:active { background-color: #1209ed; color: #f9f9f9; } + .button:disabled { + opacity: 0.5; + border-color: #ddd; + background-color: #ddd; + color: #888; } .button.-tiny { font-size: 0.69444rem; text-transform: none; @@ -863,7 +868,13 @@ a, a:link, a:visited { opacity: 0.9; } .button.-utility:active { opacity: 1.0; } - .button.-footer { + .button.-utility.-good { + background-color: #3ec28f; + color: #f9f9f9; } + .button.-utility.-bad { + background-color: #C2473E; + color: #f9f9f9; } + .button.-cancel { font-size: 0.69444rem; border-width: 0; background-color: #ddd; @@ -871,10 +882,28 @@ a, a:link, a:visited { padding: 0.25rem 0.75rem; opacity: 0.8; border-radius: 1rem; } - .button.-footer:hover { + .button.-cancel:hover { opacity: 0.9; } - .button.-footer:active { + .button.-cancel:active { opacity: 1.0; } + .button.-icon { + text-indent: -9999rem; + background-size: 0.83333rem auto; + background-position: center center; + background-repeat: no-repeat; + border-radius: 0; + border: 0; + opacity: 0.25; } + .button.-icon:hover { + background-color: transparent; + opacity: 0.5; } + .button.-icon:active { + background-color: transparent; + opacity: 1; } + .button.-icon.-clear { + background-image: url("../assets/img/icons/close.svg"); } + .button.-icon:disabled { + opacity: 0; } .form_field { margin: 0.5rem 0; @@ -888,14 +917,24 @@ a, a:link, a:visited { opacity: 0.75; padding: 0.5rem 0.5rem 0; display: block; } + .form_field .form_field_value { + font-size: 0.83333rem; + font-weight: 400; + font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; + line-height: 1.3rem; + opacity: 0.75; + margin: 0.25rem 0.5rem 0; + padding-bottom: 0.5rem; + overflow: hidden; + word-wrap: break-word; } .form_field input[type="text"], .form_field input[type="number"], .form_field input[type="tel"], .form_field input[type="email"], .form_field input[type="password"], .form_field textarea { border: 0; background: transparent; font-size: 1rem; font-weight: 400; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; line-height: 1.3rem; - width: 100%; + width: calc(100% - 1rem); opacity: 0.75; padding: 0.5rem; margin-top: -0.25rem; } @@ -934,8 +973,8 @@ a, a:link, a:visited { height: 8rem; } input.form_field_amount[type='number'] { - font-size: 4.29982rem; - line-height: 4.7298rem; + font-size: 2.98598rem; + line-height: 3.28458rem; font-weight: 200; text-align: center; -webkit-appearance: none; } @@ -1037,9 +1076,8 @@ nav.range-nav { border-radius: 0.25rem; overflow: hidden; box-shadow: 0 0.125rem 0.75rem rgba(34, 34, 34, 0.175), 0 0.125rem 0.125rem rgba(34, 34, 34, 0.1); } - .wrapper .content .window .window_content.-modal { - border-top: 0; - border-bottom: 0; } + .wrapper .content .window .window_content { + min-height: 7.5rem; } .debug-nav { background-color: rgba(34, 34, 34, 0.125); @@ -1079,9 +1117,11 @@ nav.range-nav { overflow: hidden; } .token { - display: flex; } + display: flex; + align-items: center; + align-content: center; + justify-content: center; } .token .token_icon { - margin: -0.5rem 0 -0.5rem -0.425rem; width: 2.3rem; height: 2.3rem; display: flex; @@ -1091,20 +1131,27 @@ nav.range-nav { align-items: center; align-content: center; } .token .token_icon img { + display: block; + margin: 0; height: 1.3rem; width: auto; } .token .token_name { padding-left: 0.325rem; + height: 1.3rem; flex-grow: 1; color: #222; font-weight: 500; } .token .token_balance { font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; - color: #888; } + color: #888; + height: 1.3rem; } .token .token_symbol { + height: 1.3rem; font-size: 0.69444rem; } .token .token_symbol:before { content: ' '; } + .token .token_buttons { + padding-left: 0.5rem; } .account { display: flex; } @@ -1119,7 +1166,6 @@ nav.range-nav { align-content: center; } .account .account_avatar canvas { display: block; - width: 2.3rem !important; height: 2.3rem !important; width: auto !important; } .account .account_information { @@ -1247,6 +1293,8 @@ nav.range-nav { .footer-nav { display: flex; + height: 3.5rem; + overflow: hidden; justify-content: space-between; } .footer-nav .footer-nav_status { padding: 1rem; @@ -1317,3 +1365,49 @@ nav.range-nav { padding-top: 0.5rem; display: flex; justify-content: center; } + .form-nav.-binary { + justify-content: space-between; } + +.alert-screen { + height: 22rem; + display: flex; + align-items: center; + justify-content: center; } + .alert-screen .alert-screen_image { + display: flex; + align-items: center; + justify-content: center; } + .alert-screen .alert-screen_image img { + display: block; + width: 4rem; + height: auto; } + .alert-screen .alert-screen_text { + margin-top: 1rem; + text-align: center; } + .alert-screen .alert-screen_text h1, .alert-screen .alert-screen_text h2, .alert-screen .alert-screen_text big, .alert-screen .alert-screen_text strong { + font-weight: 600; } + +.search-form { + display: flex; + justify-content: space-between; + padding: 0; + border-radius: 0.25rem; + background-color: #fff; + border: 0px solid #fff; + overflow: hidden; + box-shadow: 0 0.125rem 0.5rem rgba(34, 34, 34, 0.125); } + .search-form input[type='text'] { + border: 0; + background: transparent; + font-size: 0.83333rem; + font-weight: 400; + font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; + line-height: 1.3rem; + width: calc(100% - 2rem); + opacity: 0.75; + padding: 0.6rem 0.5rem 0.5rem; } + .search-form input[type='text']:focus { + opacity: 1; } + .search-form button { + width: 2.349375rem; + height: 2.349375rem; } diff --git a/src/App/App.sass b/src/App/App.sass index fce8707a90f47af3478b1086181daf7125dd0d95..d842327f8acb82f166c6c6c0f5d9b6bab3111344 100644 --- a/src/App/App.sass +++ b/src/App/App.sass @@ -28,4 +28,6 @@ @import '../assets/sass/components/footer-nav' @import '../assets/sass/components/progress-indicator' @import '../assets/sass/components/form-nav' +@import '../assets/sass/components/alert-screen' +@import '../assets/sass/components/search-form' diff --git a/src/Loading/Loading.js b/src/Loading/Loading.js index cd9f00622d13d4c7d71886bca207ece4b12f6322..57e1b1f5a8022ede1d92da26e2bef0add1e429d6 100644 --- a/src/Loading/Loading.js +++ b/src/Loading/Loading.js @@ -4,10 +4,9 @@ // SPDX-License-Identifier: MIT import React, { Component } from 'react'; +import loading from '../assets/img/icons/loading.svg'; import { inject, observer } from 'mobx-react'; -import { Link, Redirect } from 'react-router-dom'; - -import Health from '../Health'; +import { Redirect } from 'react-router-dom'; @inject('parityStore') @observer @@ -20,21 +19,16 @@ class Loading extends Component { } return ( -
-

- This is the Loading page.
-

- - +
); } diff --git a/src/Send/Send.js b/src/Send/Send.js index 06e7a816bd6c9a168bc348b340924e0c4801ca26..d4e4549c503c390862434e0eeaccc74197cc457b 100644 --- a/src/Send/Send.js +++ b/src/Send/Send.js @@ -52,11 +52,11 @@ class Send extends PureComponent { diff --git a/src/Send/Signer/Signer.js b/src/Send/Signer/Signer.js index 2dad86d91d128904d06850d14a6066912ae99801..e354c7a55615681ff4a9ee6de5a660d483cc5791 100644 --- a/src/Send/Signer/Signer.js +++ b/src/Send/Signer/Signer.js @@ -4,12 +4,22 @@ // SPDX-License-Identifier: MIT import React, { Component } from 'react'; +import { Link } from 'react-router-dom'; +import { map } from 'rxjs/operators'; import { fromWei } from '@parity/api/lib/util/wei'; import { inject, observer } from 'mobx-react'; -import { post$ } from '@parity/light.js'; +import { defaultAccount$, myBalance$, post$ } from '@parity/light.js'; + +import ethereumIcon from '../../assets/img/tokens/ethereum.png'; +import light from '../../hoc'; @inject('signerStore') @observer + +@light({ + balance: () => myBalance$().pipe(map(value => +fromWei(value))), + me: defaultAccount$ +}) class Signer extends Component { state = { password: '', @@ -62,55 +72,83 @@ class Signer extends Component { }; render () { - const { location: { state: tx } } = this.props; - const { password, status } = this.state; + const { balance, location: { state: tx } } = this.props; + const { password } = this.state; return ( -
-

- Request number {this.requestId} -

-

- From: {tx.from} -

-

- To: {tx.to} -

-

- Amount: {+fromWei(tx.value)}ETH -

-

- Gas: {+tx.gas} -

- {status && status.requested - ?
- -
- {' '} - -
- - @brian, for now for errors look in console, e.g. when nothing - happens when you click on Accept - + +
+ + +
+
+
+
+
+ ethereum +
+
Ethereum
+
+ {balance} + ETH +
+
+
+
+ +
+ {+fromWei(tx.value)} ETH +
+
+
+ +
+ {tx.to} +
+
+
+
+
+

Enter your password to confirm this transaction.

+
+
+ + +
+ +
+
- :

Loading...

} -
-
-

- Status: {JSON.stringify(status)} -

- +
+
); } } diff --git a/src/Tokens/NewToken/NewTokenItem/NewTokenItem.js b/src/Settings/NewTokenItem/NewTokenItem.js similarity index 68% rename from src/Tokens/NewToken/NewTokenItem/NewTokenItem.js rename to src/Settings/NewTokenItem/NewTokenItem.js index 049622acd7635831b59422fc1ee8b33746b9213d..10b2c281397e75da61b29b3f45e60e037760d53a 100644 --- a/src/Tokens/NewToken/NewTokenItem/NewTokenItem.js +++ b/src/Settings/NewTokenItem/NewTokenItem.js @@ -12,15 +12,15 @@ import { withRouter } from 'react-router-dom'; @withRouter class NewTokenItem extends Component { handleAddToken = () => { - const { history, token, tokensStore } = this.props; + const { token, tokensStore } = this.props; tokensStore.addToken(token.address, token); - history.goBack(); + this.forceUpdate(); // TODO: I assume this is not the preferred way to do this! }; handleRemoveToken = () => { - const { history, token, tokensStore } = this.props; + const { token, tokensStore } = this.props; tokensStore.removeToken(token.address); - history.goBack(); + this.forceUpdate(); }; render () { @@ -40,9 +40,11 @@ class NewTokenItem extends Component { {token.symbol}
- {tokens.has(token.address) - ? - : } +
+ {tokens.has(token.address) + ? + : } +
); diff --git a/src/Tokens/NewToken/NewTokenItem/index.js b/src/Settings/NewTokenItem/index.js similarity index 100% rename from src/Tokens/NewToken/NewTokenItem/index.js rename to src/Settings/NewTokenItem/index.js diff --git a/src/Settings/Settings.js b/src/Settings/Settings.js index a92506d595582a3e85b9579d2f3de0df626b3549..918d4977d52a13645580d165f3f28ce0485bf9c9 100644 --- a/src/Settings/Settings.js +++ b/src/Settings/Settings.js @@ -3,33 +3,138 @@ // // SPDX-License-Identifier: MIT -import React, { PureComponent } from 'react'; +import React, { Component } from 'react'; +import { chainName$ } from '@parity/light.js'; +import debounce from 'lodash/debounce'; +import { inject, observer } from 'mobx-react'; import { Link } from 'react-router-dom'; -import Health from '../Health'; +import light from '../hoc'; +import NewTokenItem from './NewTokenItem'; + +@light({ + chainName: chainName$ +}) +@inject('tokensStore') +@observer +class Settings extends Component { + state = { + db: null, + dbMap: null, + matches: this.props.tokensStore.tokensArrayWithoutEth, + search: '' + }; + + calculateMatches = debounce(() => { + const { tokensStore: { tokensArrayWithoutEth } } = this.props; + const { db, search } = this.state; + + if (search.length <= 1) { + this.setState({ matches: tokensArrayWithoutEth }); + return; + } + + const matches = db + ? db.filter( + ({ name, symbol }) => + name.toLowerCase().includes(search.toLowerCase()) || + symbol.toLowerCase().includes(search.toLowerCase()) + ) + : []; + this.setState({ matches }); + }, 500); + + componentDidMount () { + if (this.props.chainName) { + this.fetchTokensDb(); + } + } + + componentDidUpdate (prevProps) { + if (this.props.chainName && !prevProps.chainName) { + this.fetchTokensDb(); + } + } + + fetchTokensDb = async () => { + if (this.state.db) { + // Don't fetch again if it's already fetched + return; + } + + // We only fetch this huge json if the user visits this NewToken page. We + // try to avoid it as much as possible. All other tokens info (used in the + // homepage) are stored in localStorage. + let db; + try { + db = await import(`../assets/tokens/${this.props.chainName}.json`); + } catch (e) { + db = await import(`../assets/tokens/foundation.json`); + } + + // We create a address=>token mapping here + const dbMap = {}; + db.forEach(token => (dbMap[token.address] = token)); + + // Commit this into the state + this.setState({ db, dbMap }); + }; + + handleSearch = ({ target: { value } }) => { + this.setState({ search: value }); + this.calculateMatches(); + }; + + handleClear = () => { + this.setState({ search: '' }); + this.calculateMatches(); + }; -class Settings extends PureComponent { render () { + const { matches, search } = this.state; + return (
-

Settings page

-
- - +
); } diff --git a/src/Tokens/NewToken/NewToken.js b/src/Tokens/NewToken/NewToken.js deleted file mode 100644 index 6b75b5806c5c3af93a228834396602fe40120de5..0000000000000000000000000000000000000000 --- a/src/Tokens/NewToken/NewToken.js +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. -// -// SPDX-License-Identifier: MIT - -import React, { Component } from 'react'; -import { chainName$ } from '@parity/light.js'; -import debounce from 'lodash/debounce'; -import { inject, observer } from 'mobx-react'; - -import light from '../../hoc'; -import NewTokenItem from './NewTokenItem'; - -@light({ - chainName: chainName$ -}) -@inject('tokensStore') -@observer -class NewToken extends Component { - state = { - db: null, - dbMap: null, - matches: this.props.tokensStore.tokensArrayWithoutEth, - search: '' - }; - - calculateMatches = debounce(() => { - const { tokensStore: { tokensArrayWithoutEth } } = this.props; - const { db, search } = this.state; - - if (search.length <= 1) { - this.setState({ matches: tokensArrayWithoutEth }); - return; - } - - const matches = db - ? db.filter( - ({ name, symbol }) => - name.toLowerCase().includes(search.toLowerCase()) || - symbol.toLowerCase().includes(search.toLowerCase()) - ) - : []; - this.setState({ matches }); - }, 500); - - componentDidMount () { - if (this.props.chainName) { - this.fetchTokensDb(); - } - } - - componentDidUpdate (prevProps) { - if (this.props.chainName && !prevProps.chainName) { - this.fetchTokensDb(); - } - } - - fetchTokensDb = async () => { - if (this.state.db) { - // Don't fetch again if it's already fetched - return; - } - - // We only fetch this huge json if the user visits this NewToken page. We - // try to avoid it as much as possible. All other tokens info (used in the - // homepage) are stored in localStorage. - let db; - try { - db = await import(`../../assets/tokens/${this.props.chainName}.json`); - } catch (e) { - db = await import(`../../assets/tokens/foundation.json`); - } - - // We create a address=>token mapping here - const dbMap = {}; - db.forEach(token => (dbMap[token.address] = token)); - - // Commit this into the state - this.setState({ db, dbMap }); - }; - - handleSearch = ({ target: { value } }) => { - this.setState({ search: value }); - this.calculateMatches(); - }; - - render () { - const { matches, search } = this.state; - - return ( -
- -
- -
-
- ); - } -} - -export default NewToken; diff --git a/src/Tokens/NewToken/index.js b/src/Tokens/NewToken/index.js deleted file mode 100644 index 59270b252fc3fb7f5ffa6963e56bd12deece95d8..0000000000000000000000000000000000000000 --- a/src/Tokens/NewToken/index.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. -// -// SPDX-License-Identifier: MIT - -import NewToken from './NewToken'; - -export default NewToken; diff --git a/src/Tokens/Tokens.js b/src/Tokens/Tokens.js index 5b07fb1efcd3421a639d3a1f942a10b417bc2637..06976c5ef931f441c6f775607f912988d5302796 100644 --- a/src/Tokens/Tokens.js +++ b/src/Tokens/Tokens.js @@ -5,11 +5,10 @@ import React, { PureComponent } from 'react'; import { accountsInfo$, defaultAccount$ } from '@parity/light.js'; -import { Link, Route, Switch } from 'react-router-dom'; +import { Link } from 'react-router-dom'; import Health from '../Health'; import light from '../hoc'; -import NewToken from './NewToken'; import TokensList from './TokensList'; @light({ @@ -38,17 +37,14 @@ class Tokens extends PureComponent {
- - - - +