From c2c33ff6cdabfd6f766c57c7d6d142074bf305ae Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 10 May 2016 16:51:49 -0700 Subject: ui - redesign - app header + accounts selection --- ui/app/accounts.js | 58 ++++++++++++++++++++++++++++++++++++++++------------ ui/app/app.js | 34 +++++++++++++++++------------- ui/app/css/fonts.css | 46 ++++++++++++++++++++++++++++++++++++++++- ui/app/css/index.css | 36 +++++++++++++++++++------------- ui/app/css/lib.css | 9 ++++++++ 5 files changed, 141 insertions(+), 42 deletions(-) (limited to 'ui') diff --git a/ui/app/accounts.js b/ui/app/accounts.js index 16f37dc67..31aaf7797 100644 --- a/ui/app/accounts.js +++ b/ui/app/accounts.js @@ -3,9 +3,12 @@ const Component = require('react').Component const h = require('react-hyperscript') const connect = require('react-redux').connect const extend = require('xtend') +const Identicon = require('identicon.js') const actions = require('./actions') const AccountPanel = require('./components/account-panel') const valuesFor = require('./util').valuesFor +const addressSummary = require('./util').addressSummary +const formatBalance = require('./util').formatBalance module.exports = connect(mapStateToProps)(AccountsScreen) @@ -40,24 +43,14 @@ AccountsScreen.prototype.render = function() { // subtitle and nav h('.section-title.flex-column.flex-center', [ - h('h2.page-subtitle', 'Accounts'), + h('h2.page-subtitle', 'Select Account'), ]), - // current domain - /* AUDIT - * Temporarily removed - * since accounts are currently injected - * regardless of the current domain. - */ - h('.current-domain-panel.flex-center.font-small', [ - h('span', 'Selected address is visible to all sites you visit.'), - // h('span', state.currentDomain), - ]), + h('hr.horizontal-line'), // identity selection h('section.identity-section.flex-column', { style: { - maxHeight: '290px', overflowY: 'auto', overflowX: 'hidden', } @@ -94,7 +87,46 @@ AccountsScreen.prototype.render = function() { isSelected: false, isFauceting: isFauceting, }) - return h(AccountPanel, componentState) + // return h(AccountPanel, componentState) + + // var identity = state.identity || {} + // var account = state.account || {} + // var isFauceting = state.isFauceting + + var identicon = new Identicon(identity.address, 46).toString() + var identiconSrc = `data:image/png;base64,${identicon}` + + return ( + h('.accounts-list-option.flex-row.flex-space-between', { + style: { + flex: '1 0 auto', + background: isSelected ? 'white' : 'none', + }, + // onClick: state.onClick, + }, [ + + // account identicon + h('.identicon-wrapper.flex-column.flex-center.select-none', [ + h('img.identicon', { + src: identiconSrc, + style: { + border: 'none', + borderRadius: '20px', + } + }), + ]), + + // account address, balance + h('.identity-data.flex-column.flex-justify-center.flex-grow.select-none', [ + + h('span', identity.name), + h('span.font-small', addressSummary(identity.address)), + h('span.font-small', formatBalance(account.balance)), + + ]), + + ]) + ) } } diff --git a/ui/app/app.js b/ui/app/app.js index a4ce40881..0d68a01c0 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -73,9 +73,15 @@ App.prototype.render = function() { h(LoadingIndicator), // top row - h('.app-header.flex-column.flex-center', { + h('.app-header.flex-row.flex-space-between', { }, [ + h('img', { + height: 24, + width: 24, + src: '/images/icon-128.png', + }), h('h1', 'MetaMask'), + h('i.fa.fa-bars'), ]), // panel content @@ -115,19 +121,19 @@ App.prototype.render = function() { }, }), - // toggle - onOffToggle({ - toggleMetamaskActive: this.toggleMetamaskActive.bind(this), - isUnlocked: state.isUnlocked, - }), - - // help - h('i.fa.fa-question.fa-lg.cursor-pointer', { - style: { - opacity: state.isUnlocked ? '1.0' : '0.0', - }, - onClick() { state.dispatch(actions.showInfoPage()) } - }), + // // toggle + // onOffToggle({ + // toggleMetamaskActive: this.toggleMetamaskActive.bind(this), + // isUnlocked: state.isUnlocked, + // }), + + // // help + // h('i.fa.fa-question.fa-lg.cursor-pointer', { + // style: { + // opacity: state.isUnlocked ? '1.0' : '0.0', + // }, + // onClick() { state.dispatch(actions.showInfoPage()) } + // }), ]), ]) ) diff --git a/ui/app/css/fonts.css b/ui/app/css/fonts.css index dd1a755fb..b528cb9ab 100644 --- a/ui/app/css/fonts.css +++ b/ui/app/css/fonts.css @@ -1,2 +1,46 @@ @import url(https://fonts.googleapis.com/css?family=Roboto:300,500); -@import url(https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css); \ No newline at end of file +@import url(https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css); + +@font-face { + font-family: 'Transat Standard'; + src: url('/fonts/Transat Standard/transat_standard-webfont.eot'); + src: url('/fonts/Transat Standard/transat_standard-webfont.eot?#iefix') format('embedded-opentype'), + url('/fonts/Transat Standard/transat_standard-webfont.woff') format('woff'), + url('/fonts/Transat Standard/transat_standard-webfont.ttf') format('truetype'), + url('/fonts/Transat Standard/transat_standard-webfont.svg#ywftsvg') format('svg'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'Transat Black'; + src: url('/fonts/Transat Black/transat_black-webfont.eot'); + src: url('/fonts/Transat Black/transat_black-webfont.eot?#iefix') format('embedded-opentype'), + url('/fonts/Transat Black/transat_black-webfont.woff') format('woff'), + url('/fonts/Transat Black/transat_black-webfont.ttf') format('truetype'), + url('/fonts/Transat Black/transat_black-webfont.svg#ywftsvg') format('svg'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'Transat Medium'; + src: url('/fonts/Transat Medium/transat_medium-webfont.eot'); + src: url('/fonts/Transat Medium/transat_medium-webfont.eot?#iefix') format('embedded-opentype'), + url('/fonts/Transat Medium/transat_medium-webfont.woff') format('woff'), + url('/fonts/Transat Medium/transat_medium-webfont.ttf') format('truetype'), + url('/fonts/Transat Medium/transat_medium-webfont.svg#ywftsvg') format('svg'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'Transat Light'; + src: url('/fonts/Transat Light/transat_light-webfont.eot'); + src: url('/fonts/Transat Light/transat_light-webfont.eot?#iefix') format('embedded-opentype'), + url('/fonts/Transat Light/transat_light-webfont.woff') format('woff'), + url('/fonts/Transat Light/transat_light-webfont.ttf') format('truetype'), + url('/fonts/Transat Light/transat_light-webfont.svg#ywftsvg') format('svg'); + font-weight: normal; + font-style: normal; +} diff --git a/ui/app/css/index.css b/ui/app/css/index.css index 4871a650f..cde130dfe 100644 --- a/ui/app/css/index.css +++ b/ui/app/css/index.css @@ -14,8 +14,7 @@ application specific styles } html, body { - /*font-family: 'Open Sans', Arial, sans-serif;*/ - font-family: 'Roboto', 'Noto', sans-serif; + font-family: 'Transat Standard', Arial; color: #4D4D4D; font-weight: 300; line-height: 1.4em; @@ -98,23 +97,25 @@ button.btn-thin { } .app-header { - padding-top: 20px; + padding: 6px 8px; } .app-header h1 { - font-size: 2em; - font-weight: 300; - height: 42px; + font-family: 'Transat Medium'; + text-transform: uppercase; + color: #AEAEAE; } h2.page-subtitle { + font-family: 'Transat Light'; + text-transform: uppercase; + color: #AEAEAE; font-size: 1em; - font-weight: 500; - height: 24px; - color: #F3C83E; + margin: 12px; } .app-primary { + background: #F7F7F7; } .app-footer { @@ -238,11 +239,19 @@ app sections /* accounts */ .accounts-section { - margin: 0 20px; + margin: 0 0px; } -.current-domain-panel { - border: 1px solid #B7B7B7; +.accounts-section .horizontal-line { + margin: 0px 18px; +} + +.accounts-list-option { + height: 120px; +} + +.accounts-list-option .identicon-wrapper { + width: 100px; } .unconftx-link { @@ -289,8 +298,7 @@ app sections /* accounts screen */ .identity-section { - border: 2px solid #4D4D4D; - margin: 0; + } .identity-section .identity-panel { diff --git a/ui/app/css/lib.css b/ui/app/css/lib.css index b6b26402b..6223a8c06 100644 --- a/ui/app/css/lib.css +++ b/ui/app/css/lib.css @@ -141,3 +141,12 @@ .send-screen section input { width: 100%; } + +hr.horizontal-line { + display: block; + height: 1px; + border: 0; + border-top: 1px solid #ccc; + margin: 1em 0; + padding: 0; +} \ No newline at end of file -- cgit v1.2.3 From 9c91da72f5ab67d06061c80be0f735d222d2f4dd Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 10 May 2016 17:22:09 -0700 Subject: ui - account list - fix select account --- ui/app/account-detail.js | 5 +++++ ui/app/accounts.js | 4 ++-- ui/app/css/index.css | 5 +++++ 3 files changed, 12 insertions(+), 2 deletions(-) (limited to 'ui') diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index 2775e24fb..ae4552df6 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -127,8 +127,13 @@ AccountDetailScreen.prototype.transactionList = function() { var transactions = state.transactions return transactionList(transactions + // only transactions that have a hash + .filter(tx => tx.hash) + // only transactions that are from the current address .filter(tx => tx.txParams.from === state.address) + // only transactions that are on the current network .filter(tx => tx.txParams.metamaskNetworkId === state.networkVersion) + // sort by recency .sort((a, b) => b.time - a.time), state.networkVersion) } diff --git a/ui/app/accounts.js b/ui/app/accounts.js index 31aaf7797..3f0a3e819 100644 --- a/ui/app/accounts.js +++ b/ui/app/accounts.js @@ -97,12 +97,12 @@ AccountsScreen.prototype.render = function() { var identiconSrc = `data:image/png;base64,${identicon}` return ( - h('.accounts-list-option.flex-row.flex-space-between', { + h('.accounts-list-option.flex-row.flex-space-between.cursor-pointer', { style: { flex: '1 0 auto', background: isSelected ? 'white' : 'none', }, - // onClick: state.onClick, + onClick: (event) => actions.onShowDetail(identity.address, event), }, [ // account identicon diff --git a/ui/app/css/index.css b/ui/app/css/index.css index cde130dfe..59577f76c 100644 --- a/ui/app/css/index.css +++ b/ui/app/css/index.css @@ -250,6 +250,11 @@ app sections height: 120px; } +.accounts-list-option:hover { + background: pink; + transform: scale(1.1); +} + .accounts-list-option .identicon-wrapper { width: 100px; } -- cgit v1.2.3 From d9d442ed1f4dd1579deed95bedd1b077e828c972 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 10 May 2016 23:07:01 -0700 Subject: Began adding jazzicons Currently experiencing a few problems: 1. Tons of errors on app start. It's as if Jazzicon is getting called many times at start with some object as its diameter. 2. Weird visual glitches. When leaving a view with a jazzicon, it flashes off its border radius. 3. Messy transitions. Might want to just re-do the transitions. They just look awful, it's barely worthwhile. --- ui/app/accounts.js | 19 +++------------ ui/app/components/account-panel.js | 2 +- ui/app/components/identicon.js | 49 ++++++++++++++++++++++++++++++++++++++ ui/app/components/panel.js | 13 +++------- 4 files changed, 56 insertions(+), 27 deletions(-) create mode 100644 ui/app/components/identicon.js (limited to 'ui') diff --git a/ui/app/accounts.js b/ui/app/accounts.js index 3f0a3e819..18ba1e67d 100644 --- a/ui/app/accounts.js +++ b/ui/app/accounts.js @@ -3,7 +3,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const connect = require('react-redux').connect const extend = require('xtend') -const Identicon = require('identicon.js') +const Identicon = require('./components/identicon') const actions = require('./actions') const AccountPanel = require('./components/account-panel') const valuesFor = require('./util').valuesFor @@ -87,14 +87,6 @@ AccountsScreen.prototype.render = function() { isSelected: false, isFauceting: isFauceting, }) - // return h(AccountPanel, componentState) - - // var identity = state.identity || {} - // var account = state.account || {} - // var isFauceting = state.isFauceting - - var identicon = new Identicon(identity.address, 46).toString() - var identiconSrc = `data:image/png;base64,${identicon}` return ( h('.accounts-list-option.flex-row.flex-space-between.cursor-pointer', { @@ -105,14 +97,9 @@ AccountsScreen.prototype.render = function() { onClick: (event) => actions.onShowDetail(identity.address, event), }, [ - // account identicon h('.identicon-wrapper.flex-column.flex-center.select-none', [ - h('img.identicon', { - src: identiconSrc, - style: { - border: 'none', - borderRadius: '20px', - } + h(Identicon, { + address: identity.address }), ]), diff --git a/ui/app/components/account-panel.js b/ui/app/components/account-panel.js index c1450b516..6bae095d1 100644 --- a/ui/app/components/account-panel.js +++ b/ui/app/components/account-panel.js @@ -4,7 +4,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const addressSummary = require('../util').addressSummary const formatBalance = require('../util').formatBalance -const Identicon = require('identicon.js') +const Identicon = require('./identicon') const Panel = require('./panel') diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js new file mode 100644 index 000000000..8294ce4d5 --- /dev/null +++ b/ui/app/components/identicon.js @@ -0,0 +1,49 @@ +const Component = require('react').Component +const h = require('react-hyperscript') +const inherits = require('util').inherits +const jazzicon = require('jazzicon') +const findDOMNode = require('react-dom').findDOMNode + +module.exports = IdenticonComponent + +inherits(IdenticonComponent, Component) +function IdenticonComponent() { + Component.call(this) + + this.diameter = 46 +} + +IdenticonComponent.prototype.render = function() { + debugger + return ( + h('div', { + key: 'identicon-' + this.props.address, + style: { + display: 'inline-block', + height: this.diameter, + width: this.diameter, + borderRadius: this.diameter / 2, + overflow: 'hidden', + }, + }) + ) +} + +IdenticonComponent.prototype.componentDidMount = function(){ + var state = this.props + var address = state.address + + if (!address) return + console.log('rendering for address ' + address) + var numericRepresentation = jsNumberForAddress(address) + + var container = findDOMNode(this) + var identicon = jazzicon(this.diameter, numericRepresentation) + container.appendChild(identicon) +} + +function jsNumberForAddress(address) { + var addr = address.slice(2, 10) + var seed = parseInt(addr, 16) + return seed +} diff --git a/ui/app/components/panel.js b/ui/app/components/panel.js index 25e6b7f0f..2f5a3715d 100644 --- a/ui/app/components/panel.js +++ b/ui/app/components/panel.js @@ -2,7 +2,7 @@ const inherits = require('util').inherits const ethUtil = require('ethereumjs-util') const Component = require('react').Component const h = require('react-hyperscript') -const Identicon = require('identicon.js') +const Identicon = require('./identicon') module.exports = Panel @@ -19,9 +19,6 @@ Panel.prototype.render = function() { var account = state.account || {} var isFauceting = state.isFauceting - var identicon = new Identicon(state.identiconKey, 46).toString() - var identiconSrc = `data:image/png;base64,${identicon}` - return ( h('.identity-panel.flex-row.flex-space-between', { style: { @@ -32,12 +29,8 @@ Panel.prototype.render = function() { // account identicon h('.identicon-wrapper.flex-column.select-none', [ - h('img.identicon', { - src: identiconSrc, - style: { - border: 'none', - borderRadius: '20px', - } + h(Identicon, { + address: state.identiconKey, }), h('span.font-small', state.identiconLabel), ]), -- cgit v1.2.3 From c8640537e651621a00e66fd020e5e6c55b8b31ff Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 10 May 2016 23:53:07 -0700 Subject: hotfix - identicon jazz bug --- ui/app/components/identicon.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'ui') diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js index 8294ce4d5..3fbf3c699 100644 --- a/ui/app/components/identicon.js +++ b/ui/app/components/identicon.js @@ -14,7 +14,6 @@ function IdenticonComponent() { } IdenticonComponent.prototype.render = function() { - debugger return ( h('div', { key: 'identicon-' + this.props.address, @@ -38,8 +37,13 @@ IdenticonComponent.prototype.componentDidMount = function(){ var numericRepresentation = jsNumberForAddress(address) var container = findDOMNode(this) + // jazzicon with hack to fix inline svg error var identicon = jazzicon(this.diameter, numericRepresentation) - container.appendChild(identicon) + var identiconSrc = identicon.innerHTML + var dataUri = 'data:image/svg+xml;charset=utf-8,'+encodeURIComponent(identiconSrc) + var img = document.createElement('img') + img.src = dataUri + container.appendChild(img) } function jsNumberForAddress(address) { -- cgit v1.2.3 From 2913dcb82c9191881e0a411a33bd6fc32171935c Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 11 May 2016 02:11:31 -0700 Subject: ui - redesign - account details --- ui/app/account-detail.js | 95 +++++++++++++++++++++++++++--------------- ui/app/components/identicon.js | 14 ++++--- ui/app/css/index.css | 6 +-- ui/app/css/lib.css | 22 ++++++++++ 4 files changed, 95 insertions(+), 42 deletions(-) (limited to 'ui') diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index ae4552df6..a71e85da8 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -5,9 +5,12 @@ const h = require('react-hyperscript') const connect = require('react-redux').connect const copyToClipboard = require('copy-to-clipboard') const actions = require('./actions') +const addressSummary = require('./util').addressSummary +const formatBalance = require('./util').formatBalance const ReactCSSTransitionGroup = require('react-addons-css-transition-group') const AccountPanel = require('./components/account-panel') +const Identicon = require('./components/identicon') const transactionList = require('./components/transaction-list') const ExportAccountView = require('./components/account-export') @@ -41,49 +44,80 @@ AccountDetailScreen.prototype.render = function() { h('.account-detail-section.flex-column.flex-grow', { style: { - width: '330px', + width: 330, + 'margin-top': 28, }, }, [ - // subtitle and nav - h('.section-title.flex-row.flex-center', [ - h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { + h('.flex-row.flex-space-between', [ + + // invisible placeholder for later + h('i.fa.fa-users.fa-lg.color-orange', { + style: { + visibility: 'hidden', + }, + }), + + // large identicon + h('.identicon-wrapper.flex-column.flex-center.select-none', [ + h(Identicon, { + diameter: 62, + address: account.address + }), + ]), + + // small accounts nav + h('i.fa.fa-users.fa-lg.cursor-pointer.color-orange', { onClick: this.navigateToAccounts.bind(this), }), - h('h2.page-subtitle', 'Account Detail'), + ]), - // account summary, with embedded action buttons - h(AccountPanel, { - showFullAddress: true, - identity: identity, - account: account, - key: 'accountPanel' - }), + h('h2.font-medium.color-forest.flex-center', { + style: { + 'padding-top': 8, + 'margin-bottom': 32, + }, + }, identity && identity.name), - h('div', { + h('.flex-row.flex-space-between', { style: { - display: 'flex', - } + 'margin-bottom': 16, + }, }, [ - h('button', { - onClick: () => { - copyToClipboard(identity.address) + h('div', { + style: { + 'line-height': 16, }, - }, 'COPY ADDR'), + }, addressSummary(account.address)), - h('button', { - onClick: () => { - this.props.dispatch(actions.showSendPage()) + h('i.fa.fa-download.fa-md.cursor-pointer.color-orange', { + onClick: () => this.requestAccountExport(account.address), + }), + + h('i.fa.fa-qrcode.fa-md.cursor-disabled.color-orange', { + onClick: () => console.warn('QRCode not implented...'), + }), + + h('i.fa.fa-clipboard.fa-md.cursor-pointer.color-orange', { + onClick: () => copyToClipboard(account.address), + }), + + ]), + + h('.flex-row.flex-space-between', [ + + h('div', { + style: { + 'line-height': 50, }, - }, 'SEND'), + }, formatBalance(account.balance)), h('button', { - onClick: () => { - this.requestAccountExport(identity.address) - }, - }, 'EXPORT'), + onClick: () => this.props.dispatch(actions.showSendPage()), + }, 'SEND ETH'), + ]), h(ReactCSSTransitionGroup, { @@ -93,12 +127,7 @@ AccountDetailScreen.prototype.render = function() { }, [ this.subview(), ]), - // transaction table - /* - h('section.flex-column', [ - h('span', 'your transaction history will go here.'), - ]), - */ + ]) ) } diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js index 3fbf3c699..ef625cc62 100644 --- a/ui/app/components/identicon.js +++ b/ui/app/components/identicon.js @@ -10,18 +10,20 @@ inherits(IdenticonComponent, Component) function IdenticonComponent() { Component.call(this) - this.diameter = 46 + this.defaultDiameter = 46 } IdenticonComponent.prototype.render = function() { + var state = this.props + var diameter = state.diameter || this.defaultDiameter return ( h('div', { key: 'identicon-' + this.props.address, style: { display: 'inline-block', - height: this.diameter, - width: this.diameter, - borderRadius: this.diameter / 2, + height: diameter, + width: diameter, + borderRadius: diameter / 2, overflow: 'hidden', }, }) @@ -33,12 +35,12 @@ IdenticonComponent.prototype.componentDidMount = function(){ var address = state.address if (!address) return - console.log('rendering for address ' + address) var numericRepresentation = jsNumberForAddress(address) var container = findDOMNode(this) // jazzicon with hack to fix inline svg error - var identicon = jazzicon(this.diameter, numericRepresentation) + var diameter = state.diameter || this.defaultDiameter + var identicon = jazzicon(diameter, numericRepresentation) var identiconSrc = identicon.innerHTML var dataUri = 'data:image/svg+xml;charset=utf-8,'+encodeURIComponent(identiconSrc) var img = document.createElement('img') diff --git a/ui/app/css/index.css b/ui/app/css/index.css index 59577f76c..9dbfb6518 100644 --- a/ui/app/css/index.css +++ b/ui/app/css/index.css @@ -28,18 +28,18 @@ html, body { } button { + font-family: 'Transat Black'; outline: none; cursor: pointer; margin: 10px; - padding: 6px; + padding: 8px 12px; border: none; - border-radius: 3px; background: #F7861C; - font-weight: 500; color: white; transform-origin: center center; transition: transform 50ms ease-in; } + button:hover { transform: scale(1.1); } diff --git a/ui/app/css/lib.css b/ui/app/css/lib.css index 6223a8c06..14ef272ad 100644 --- a/ui/app/css/lib.css +++ b/ui/app/css/lib.css @@ -1,3 +1,13 @@ +/* color */ + +.color-orange { + color: #F7861C; +} + +.color-forest { + color: #08525D; +} + /* lib */ .full-width { @@ -47,6 +57,10 @@ flex: none; } +.flex-basis-auto { + flex-basis: auto; +} + .flex-grow { flex: 1 1 auto; } @@ -105,6 +119,10 @@ transform: scale(0.95); } +.cursor-disabled { + cursor: not-allowed; +} + .margin-bottom-sml { margin-bottom: 20px; } @@ -125,6 +143,10 @@ font-size: 12px; } +.font-medium { + font-size: 1.2em; +} + /* Send Screen */ .send-screen { margin: 0 20px; -- cgit v1.2.3 From 2978e6e494b004de8dfe4ad8ac49d58ef5a2693f Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 11 May 2016 02:46:41 -0700 Subject: Fixed transitions --- ui/app/css/transitions.css | 48 ++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) (limited to 'ui') diff --git a/ui/app/css/transitions.css b/ui/app/css/transitions.css index e2225a98d..393a944f9 100644 --- a/ui/app/css/transitions.css +++ b/ui/app/css/transitions.css @@ -1,48 +1,42 @@ -/* initial positions */ -.app-primary.from-right .main-enter { - transform: translateX(400px); +/* universal */ +.app-primary .main-enter { position: absolute; width: 100%; - transition: transform 300ms ease-in-out; -} -.app-primary.from-left .main-enter { - transform: translateX(-400px); - position: absolute; - width: 100%; - transition: transform 300ms ease-in-out; } /* center position */ -.app-primary .main-enter.main-enter-active, -.app-primary .main-leave { - transform: translateX(0px); - position: absolute; - width: 100%; - transition: transform 300ms ease-in-out; +.app-primary.from-right .main-enter-active, +.app-primary.from-left .main-enter-active { overflow-x: hidden; + transform: translateX(0px); + transition: transform 300ms ease-in; } -/* final positions */ +/* exited positions */ .app-primary.from-left .main-leave-active { - transform: translateX(400px); - position: absolute; - width: 100%; - transition: transform 300ms ease-in-out; + transform: translateX(360px); + transition: transform 300ms ease-in; } .app-primary.from-right .main-leave-active { - transform: translateX(-400px); - position: absolute; - width: 100%; - transition: transform 300ms ease-in-out; + transform: translateX(-360px); + transition: transform 300ms ease-in; } /* loader transitions */ .loader-enter, .loader-leave-active { opacity: 0.0; - transition: opacity 150 ease-in-out; + transition: opacity 150 ease-in; } .loader-enter-active, .loader-leave { opacity: 1.0; - transition: opacity 150 ease-in-out; + transition: opacity 150 ease-in; +} + +/* entering positions */ +.app-primary.from-right .main-enter:not(.main-enter-active) { + transform: translateX(360px); +} +.app-primary.from-left .main-enter:not(.main-enter-active) { + transform: translateX(-360px); } -- cgit v1.2.3 From f926aa8f85937066eb7f7b53f2570465118129eb Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 11 May 2016 02:56:12 -0700 Subject: Vertically center title bar content --- ui/app/app.js | 3 +++ 1 file changed, 3 insertions(+) (limited to 'ui') diff --git a/ui/app/app.js b/ui/app/app.js index 0d68a01c0..388a067f0 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -74,6 +74,9 @@ App.prototype.render = function() { // top row h('.app-header.flex-row.flex-space-between', { + style: { + alignItems: 'center', + } }, [ h('img', { height: 24, -- cgit v1.2.3 From 57280d4d79ab441b60cb57ca5c96f5b2389402d8 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 11 May 2016 21:06:50 -0700 Subject: Fix css names --- ui/app/account-detail.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'ui') diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index a71e85da8..89ca3003e 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -45,7 +45,7 @@ AccountDetailScreen.prototype.render = function() { h('.account-detail-section.flex-column.flex-grow', { style: { width: 330, - 'margin-top': 28, + 'marginTop': 28, }, }, [ @@ -75,20 +75,20 @@ AccountDetailScreen.prototype.render = function() { h('h2.font-medium.color-forest.flex-center', { style: { - 'padding-top': 8, - 'margin-bottom': 32, + 'paddingTop': 8, + 'marginBottom': 32, }, }, identity && identity.name), h('.flex-row.flex-space-between', { style: { - 'margin-bottom': 16, + 'marginBottom': 16, }, }, [ h('div', { style: { - 'line-height': 16, + 'lineHeight': 16, }, }, addressSummary(account.address)), @@ -110,7 +110,7 @@ AccountDetailScreen.prototype.render = function() { h('div', { style: { - 'line-height': 50, + 'lineHeight': 50, }, }, formatBalance(account.balance)), -- cgit v1.2.3 From b628df017f14c38f68c3048ef503ce8722f07f3b Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 11 May 2016 21:26:09 -0700 Subject: Revert style name fixes that broke styles --- ui/app/account-detail.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'ui') diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index 89ca3003e..a71e85da8 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -45,7 +45,7 @@ AccountDetailScreen.prototype.render = function() { h('.account-detail-section.flex-column.flex-grow', { style: { width: 330, - 'marginTop': 28, + 'margin-top': 28, }, }, [ @@ -75,20 +75,20 @@ AccountDetailScreen.prototype.render = function() { h('h2.font-medium.color-forest.flex-center', { style: { - 'paddingTop': 8, - 'marginBottom': 32, + 'padding-top': 8, + 'margin-bottom': 32, }, }, identity && identity.name), h('.flex-row.flex-space-between', { style: { - 'marginBottom': 16, + 'margin-bottom': 16, }, }, [ h('div', { style: { - 'lineHeight': 16, + 'line-height': 16, }, }, addressSummary(account.address)), @@ -110,7 +110,7 @@ AccountDetailScreen.prototype.render = function() { h('div', { style: { - 'lineHeight': 50, + 'line-height': 50, }, }, formatBalance(account.balance)), -- cgit v1.2.3 From 29facfe4d6194fe519c906983682a655f8fb6406 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 11 May 2016 22:21:10 -0700 Subject: Fix more transition bugs --- ui/app/actions.js | 13 +++++++------ ui/app/app.js | 9 +++------ ui/app/first-time/init-menu.js | 34 ---------------------------------- ui/app/reducers/app.js | 9 ++++++--- ui/app/reducers/metamask.js | 13 ++++++++++--- 5 files changed, 26 insertions(+), 52 deletions(-) (limited to 'ui') diff --git a/ui/app/actions.js b/ui/app/actions.js index dbcf3e577..45af35e67 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -312,19 +312,20 @@ function backToAccountDetail(address) { value: address, } } -function clearSeedWordCache() { +function clearSeedWordCache(account) { return { - type: this.CLEAR_SEED_WORD_CACHE + type: this.CLEAR_SEED_WORD_CACHE, + value: account, } } function confirmSeedWords() { return (dispatch) => { dispatch(this.showLoadingIndication()) - _accountManager.clearSeedWordCache((err, accounts) => { - dispatch(this.clearSeedWordCache()) - console.log('Seed word cache cleared.') - dispatch(this.showAccountDetail(accounts[0].address)) + _accountManager.clearSeedWordCache((err, account) => { + dispatch(this.clearSeedWordCache(account)) + console.log('Seed word cache cleared. ' + account) + dispatch(this.showAccountDetail(account)) }) } } diff --git a/ui/app/app.js b/ui/app/app.js index 388a067f0..cec3a9657 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -157,12 +157,9 @@ App.prototype.toggleMetamaskActive = function(){ App.prototype.renderPrimary = function(state){ var state = this.props - // If seed words haven't been dismissed yet, show them still. - /* if (state.seedWords) { return h(CreateVaultCompleteScreen, {key: 'createVaultComplete'}) } - */ // show initialize screen if (!state.isInitialized) { @@ -176,6 +173,9 @@ App.prototype.renderPrimary = function(state){ case 'restoreVault': return h(RestoreVaultScreen, {key: 'restoreVault'}) + case 'createVaultComplete': + return h(CreateVaultCompleteScreen, {key: 'createVaultComplete'}) + default: return h(InitializeMenuScreen, {key: 'menuScreenInit'}) @@ -190,9 +190,6 @@ App.prototype.renderPrimary = function(state){ // show current view switch (state.currentView.name) { - case 'createVaultComplete': - return h(CreateVaultCompleteScreen, {key: 'created-vault'}) - case 'accounts': return h(AccountsScreen, {key: 'accounts'}) diff --git a/ui/app/first-time/init-menu.js b/ui/app/first-time/init-menu.js index 11b01a88b..6ea2eec90 100644 --- a/ui/app/first-time/init-menu.js +++ b/ui/app/first-time/init-menu.js @@ -29,15 +29,6 @@ InitializeMenuScreen.prototype.render = function() { switch (state.currentView.name) { - case 'createVault': - return h(CreateVaultScreen) - - case 'createVaultComplete': - return h(CreateVaultCompleteScreen) - - case 'restoreVault': - return this.renderRestoreVault() - default: return this.renderMenu() @@ -80,31 +71,6 @@ InitializeMenuScreen.prototype.renderMenu = function() { ) } -InitializeMenuScreen.prototype.renderRestoreVault = function() { - var state = this.props - return ( - - h('.initialize-screen.flex-column.flex-center.flex-grow', [ - - // subtitle and nav - h('.section-title.flex-row.flex-center', [ - h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { - onClick: this.showInitializeMenu.bind(this), - }), - h('h2.page-subtitle', 'Restore Vault'), - ]), - - - h('h3', 'Coming soon....'), - // h('textarea.twelve-word-phrase', { - // value: 'hey ho what the actual hello rubber duck bumbersnatch crumplezone frankenfurter', - // }), - - ]) - - ) -} - // InitializeMenuScreen.prototype.splitWor = function() { // this.props.dispatch(actions.showInitializeMenu()) // } diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index 309351956..0e0740c9d 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -278,10 +278,13 @@ function reduceApp(state, action) { case actions.CLEAR_SEED_WORD_CACHE: return extend(appState, { transForward: true, - currentView: { - name: 'accounts', - }, + currentView: {}, isLoading: false, + accountDetail: { + subview: 'transactions', + accountExport: 'none', + privateKey: '', + }, }) case actions.DISPLAY_WARNING: diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index 9398f1497..8bf5c8aae 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -69,17 +69,24 @@ function reduceMetamask(state, action) { } return newState + case actions.SHOW_NEW_VAULT_SEED: + return extend(metamaskState, { + isUnlocked: true, + isInitialized: false, + }) + case actions.CLEAR_SEED_WORD_CACHE: var newState = extend(metamaskState, { + isUnlocked: true, isInitialized: true, + selectedAccount: action.value, }) delete newState.seedWords return newState - case actions.CREATE_NEW_VAULT_IN_PROGRESS: + case actions.SHOW_ACCOUNT_DETAIL: return extend(metamaskState, { - isUnlocked: true, - isInitialized: true, + selectedAccount: action.value, }) default: -- cgit v1.2.3 From 041b5493dc43c9f8b69dc5a1dde4b319638618a7 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 13 May 2016 01:13:14 -0700 Subject: Streamlined some transition logic Fixes #122 Had used multiple actions for some transitions, which would lead to brief intermediary states. Now making a few actions much more explicit about what they route to, so there is less intermediary logic, and we can transition confidently to the correct view. --- ui/app/account-detail.js | 4 ++-- ui/app/actions.js | 24 +++++++++++++----------- ui/app/reducers/metamask.js | 8 +++++++- 3 files changed, 22 insertions(+), 14 deletions(-) (limited to 'ui') diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index a71e85da8..5c33c3421 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -62,7 +62,7 @@ AccountDetailScreen.prototype.render = function() { h('.identicon-wrapper.flex-column.flex-center.select-none', [ h(Identicon, { diameter: 62, - address: account.address + address: selected, }), ]), @@ -90,7 +90,7 @@ AccountDetailScreen.prototype.render = function() { style: { 'line-height': 16, }, - }, addressSummary(account.address)), + }, addressSummary(selected)), h('i.fa.fa-download.fa-md.cursor-pointer.color-orange', { onClick: () => this.requestAccountExport(account.address), diff --git a/ui/app/actions.js b/ui/app/actions.js index 45af35e67..f489eede7 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -114,7 +114,7 @@ function tryUnlockMetamask(password) { if (err) { dispatch(this.unlockFailed()) } else { - dispatch(this.unlockMetamask()) + dispatch(this.unlockMetamask(selectedAccount)) } }) } @@ -133,12 +133,12 @@ function recoverFromSeed(password, seed) { return (dispatch) => { // dispatch(this.createNewVaultInProgress()) dispatch(this.showLoadingIndication()) - _accountManager.recoverFromSeed(password, seed, (err, selectedAccount) => { + _accountManager.recoverFromSeed(password, seed, (err, metamaskState) => { dispatch(this.hideLoadingIndication()) if (err) return dispatch(this.displayWarning(err.message)) - dispatch(this.goHome()) - dispatch(this.unlockMetamask()) + var account = Object.keys(metamaskState.identities)[0] + dispatch(this.unlockMetamask(account)) }) } } @@ -271,9 +271,10 @@ function unlockFailed() { } } -function unlockMetamask() { +function unlockMetamask(account) { return { type: this.UNLOCK_METAMASK, + value: account, } } @@ -297,11 +298,13 @@ function lockMetamask() { function showAccountDetail(address) { return (dispatch) => { - _accountManager.setSelectedAddress(address) - - dispatch({ - type: this.SHOW_ACCOUNT_DETAIL, - value: address, + dispatch(this.showLoadingIndication()) + _accountManager.setSelectedAddress(address, (err, address) => { + dispatch(this.hideLoadingIndication()) + dispatch({ + type: this.SHOW_ACCOUNT_DETAIL, + value: address, + }) }) } } @@ -323,7 +326,6 @@ function confirmSeedWords() { return (dispatch) => { dispatch(this.showLoadingIndication()) _accountManager.clearSeedWordCache((err, account) => { - dispatch(this.clearSeedWordCache(account)) console.log('Seed word cache cleared. ' + account) dispatch(this.showAccountDetail(account)) }) diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index 8bf5c8aae..8628e84d2 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -29,6 +29,7 @@ function reduceMetamask(state, action) { return extend(metamaskState, { isUnlocked: true, isInitialized: true, + selectedAccount: action.value, }) case actions.LOCK_METAMASK: @@ -85,9 +86,14 @@ function reduceMetamask(state, action) { return newState case actions.SHOW_ACCOUNT_DETAIL: - return extend(metamaskState, { + const newState = extend(metamaskState, { + isUnlocked: true, + isInitialized: true, selectedAccount: action.value, + selectedAddress: action.value, }) + delete newState.seedWords + return newState default: return metamaskState -- cgit v1.2.3 From 3d696420b720898e37450f3711777c015bb1f794 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 13 May 2016 14:45:17 -0700 Subject: clean - remove logging from tx list --- ui/app/components/transaction-list.js | 1 - 1 file changed, 1 deletion(-) (limited to 'ui') diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index 3e153aecf..0c025cae3 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -22,7 +22,6 @@ module.exports = function(transactions, network) { [ transactions.map((transaction) => { - console.dir(transaction) var panelOpts = { key: `tx-${transaction.hash}`, -- cgit v1.2.3 From e0280b0db8e050594995df41afc7be9fdad82a66 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 13 May 2016 14:56:29 -0700 Subject: ui - redesign - remove footer --- ui/app/app.js | 54 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 22 deletions(-) (limited to 'ui') diff --git a/ui/app/app.js b/ui/app/app.js index cec3a9657..9f91aa47a 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -72,19 +72,28 @@ App.prototype.render = function() { h(LoadingIndicator), - // top row + // app bar h('.app-header.flex-row.flex-space-between', { style: { alignItems: 'center', } }, [ + + // mini logo h('img', { height: 24, width: 24, src: '/images/icon-128.png', }), + + // metamask name h('h1', 'MetaMask'), - h('i.fa.fa-bars'), + + // hamburger + h('i.fa.fa-bars.cursor-pointer.color-orange', { + onClick: (event) => state.dispatch(actions.showConfigPage()), + }), + ]), // panel content @@ -104,25 +113,25 @@ App.prototype.render = function() { ]), // footer - h('.app-footer.flex-row.flex-space-around', { - style: { - display: shouldHaveFooter ? 'flex' : 'none', - alignItems: 'center', - height: '56px', - } - }, [ - - // settings icon - h('i.fa.fa-cog.fa-lg' + (view === 'config' ? '.active' : '.cursor-pointer'), { - style: { - opacity: state.isUnlocked ? '1.0' : '0.0', - transition: 'opacity 200ms ease-in', - //transform: `translateX(${state.isUnlocked ? '0px' : '-100px'})`, - }, - onClick: function(ev) { - state.dispatch(actions.showConfigPage()) - }, - }), + // h('.app-footer.flex-row.flex-space-around', { + // style: { + // display: shouldHaveFooter ? 'flex' : 'none', + // alignItems: 'center', + // height: '56px', + // } + // }, [ + + // // settings icon + // h('i.fa.fa-cog.fa-lg' + (view === 'config' ? '.active' : '.cursor-pointer'), { + // style: { + // opacity: state.isUnlocked ? '1.0' : '0.0', + // transition: 'opacity 200ms ease-in', + // //transform: `translateX(${state.isUnlocked ? '0px' : '-100px'})`, + // }, + // onClick: function(ev) { + // state.dispatch(actions.showConfigPage()) + // }, + // }), // // toggle // onOffToggle({ @@ -137,7 +146,8 @@ App.prototype.render = function() { // }, // onClick() { state.dispatch(actions.showInfoPage()) } // }), - ]), + // ]), + ]) ) } -- cgit v1.2.3 From 82db0afb3038962a732c673b818fdfbf4b0b0926 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 13 May 2016 15:12:30 -0700 Subject: ui - accunt-detail - fix style attribute --- ui/app/account-detail.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'ui') diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index 5c33c3421..884a5d9c5 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -45,7 +45,7 @@ AccountDetailScreen.prototype.render = function() { h('.account-detail-section.flex-column.flex-grow', { style: { width: 330, - 'margin-top': 28, + marginTop: 28, }, }, [ @@ -75,20 +75,20 @@ AccountDetailScreen.prototype.render = function() { h('h2.font-medium.color-forest.flex-center', { style: { - 'padding-top': 8, - 'margin-bottom': 32, + paddingTop: 8, + marginBottom: 32, }, }, identity && identity.name), h('.flex-row.flex-space-between', { style: { - 'margin-bottom': 16, + marginBottom: 16, }, }, [ h('div', { style: { - 'line-height': 16, + lineHeight: '16px', }, }, addressSummary(selected)), @@ -110,7 +110,7 @@ AccountDetailScreen.prototype.render = function() { h('div', { style: { - 'line-height': 50, + lineHeight: '50px', }, }, formatBalance(account.balance)), @@ -121,7 +121,7 @@ AccountDetailScreen.prototype.render = function() { ]), h(ReactCSSTransitionGroup, { - transitionName: "main", + transitionName: 'main', transitionEnterTimeout: 300, transitionLeaveTimeout: 300, }, [ -- cgit v1.2.3 From 46f1ab8b4826678241f94f8d9b5fac4f55fc09f4 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 13 May 2016 16:28:46 -0700 Subject: ui - redesign - trans group + + account detail + tx list fixes --- ui/app/account-detail.js | 146 +++++++++++++++++++--------------- ui/app/app.js | 3 +- ui/app/components/panel.js | 11 ++- ui/app/components/transaction-list.js | 86 +++++++++++--------- ui/app/conf-tx.js | 3 +- ui/app/css/index.css | 2 +- ui/app/css/lib.css | 6 +- ui/app/loading.js | 3 +- 8 files changed, 149 insertions(+), 111 deletions(-) (limited to 'ui') diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index 884a5d9c5..663014293 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -42,85 +42,99 @@ AccountDetailScreen.prototype.render = function() { return ( - h('.account-detail-section.flex-column.flex-grow', { - style: { - width: 330, - marginTop: 28, - }, - }, [ + h('.account-detail-section.flex-column.flex-grow', [ - h('.flex-row.flex-space-between', [ + // identicon, label, balance, etc + h('.account-data-subsection.flex-column.flex-grow', { + style: { + margin: '0 20px', + }, + }, [ - // invisible placeholder for later - h('i.fa.fa-users.fa-lg.color-orange', { + // header - identicon + nav + h('.flex-row.flex-space-between', { style: { - visibility: 'hidden', + marginTop: 28, }, - }), + }, [ - // large identicon - h('.identicon-wrapper.flex-column.flex-center.select-none', [ - h(Identicon, { - diameter: 62, - address: selected, + // invisible placeholder for later + h('i.fa.fa-users.fa-lg.color-orange', { + style: { + visibility: 'hidden', + }, }), - ]), - - // small accounts nav - h('i.fa.fa-users.fa-lg.cursor-pointer.color-orange', { - onClick: this.navigateToAccounts.bind(this), - }), - ]), + // large identicon + h('.identicon-wrapper.flex-column.flex-center.select-none', [ + h(Identicon, { + diameter: 62, + address: selected, + }), + ]), + + // small accounts nav + h('i.fa.fa-users.fa-lg.cursor-pointer.color-orange', { + onClick: this.navigateToAccounts.bind(this), + }), - h('h2.font-medium.color-forest.flex-center', { - style: { - paddingTop: 8, - marginBottom: 32, - }, - }, identity && identity.name), + ]), - h('.flex-row.flex-space-between', { - style: { - marginBottom: 16, - }, - }, [ + // account label + h('h2.font-medium.color-forest.flex-center', { + style: { + paddingTop: 8, + marginBottom: 32, + }, + }, identity && identity.name), - h('div', { + // address and getter actions + h('.flex-row.flex-space-between', { style: { - lineHeight: '16px', + marginBottom: 16, }, - }, addressSummary(selected)), + }, [ - h('i.fa.fa-download.fa-md.cursor-pointer.color-orange', { - onClick: () => this.requestAccountExport(account.address), - }), + h('div', { + style: { + lineHeight: '16px', + }, + }, addressSummary(selected)), - h('i.fa.fa-qrcode.fa-md.cursor-disabled.color-orange', { - onClick: () => console.warn('QRCode not implented...'), - }), + h('i.fa.fa-download.fa-md.cursor-pointer.color-orange', { + onClick: () => this.requestAccountExport(account.address), + }), - h('i.fa.fa-clipboard.fa-md.cursor-pointer.color-orange', { - onClick: () => copyToClipboard(account.address), - }), + h('i.fa.fa-qrcode.fa-md.cursor-disabled.color-orange', { + onClick: () => console.warn('QRCode not implented...'), + }), - ]), + h('i.fa.fa-clipboard.fa-md.cursor-pointer.color-orange', { + onClick: () => copyToClipboard(account.address), + }), - h('.flex-row.flex-space-between', [ + ]), - h('div', { - style: { - lineHeight: '50px', - }, - }, formatBalance(account.balance)), + // balance + send + h('.flex-row.flex-space-between', [ + + h('div', { + style: { + lineHeight: '50px', + }, + }, formatBalance(account && account.balance)), - h('button', { - onClick: () => this.props.dispatch(actions.showSendPage()), - }, 'SEND ETH'), + h('button', { + onClick: () => this.props.dispatch(actions.showSendPage()), + }, 'SEND ETH'), + ]), + ]), + // subview (tx history, pk export confirm) h(ReactCSSTransitionGroup, { + className: 'css-transition-group', transitionName: 'main', transitionEnterTimeout: 300, transitionLeaveTimeout: 300, @@ -155,15 +169,17 @@ AccountDetailScreen.prototype.transactionList = function() { var state = this.props var transactions = state.transactions - return transactionList(transactions - // only transactions that have a hash - .filter(tx => tx.hash) - // only transactions that are from the current address - .filter(tx => tx.txParams.from === state.address) - // only transactions that are on the current network - .filter(tx => tx.txParams.metamaskNetworkId === state.networkVersion) - // sort by recency - .sort((a, b) => b.time - a.time), state.networkVersion) + var txsToRender = transactions + // only transactions that are from the current address + .filter(tx => tx.txParams.from === state.address) + // only transactions that are on the current network + .filter(tx => tx.txParams.metamaskNetworkId === state.networkVersion) + // only transactions that have a hash + .filter(tx => tx.hash) + // sort by recency + .sort((a, b) => b.time - a.time) + + return transactionList(txsToRender, state.networkVersion) } AccountDetailScreen.prototype.navigateToAccounts = function(event){ diff --git a/ui/app/app.js b/ui/app/app.js index 9f91aa47a..bd4249956 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -104,7 +104,8 @@ App.prototype.render = function() { } }, [ h(ReactCSSTransitionGroup, { - transitionName: "main", + className: 'css-transition-group', + transitionName: 'main', transitionEnterTimeout: 300, transitionLeaveTimeout: 300, }, [ diff --git a/ui/app/components/panel.js b/ui/app/components/panel.js index 2f5a3715d..5d72d6068 100644 --- a/ui/app/components/panel.js +++ b/ui/app/components/panel.js @@ -18,12 +18,15 @@ Panel.prototype.render = function() { var identity = state.identity || {} var account = state.account || {} var isFauceting = state.isFauceting + var style = { + flex: '1 0 auto', + } + + if (state.onClick) style.cursor = 'pointer' return ( h('.identity-panel.flex-row.flex-space-between', { - style: { - flex: '1 0 auto', - }, + style, onClick: state.onClick, }, [ @@ -42,7 +45,7 @@ Panel.prototype.render = function() { return h('.flex-row.flex-space-between', { key: '' + Math.round(Math.random() * 1000000), }, [ - h('label.font-small', attr.key), + h('label.font-small.no-select', attr.key), h('span.font-small', attr.value), ]) }), diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index 0c025cae3..e10dfecf3 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -5,50 +5,62 @@ const explorerLink = require('../../lib/explorer-link') const Panel = require('./panel') module.exports = function(transactions, network) { - return h('section', [ + return ( - h('.current-domain-panel.flex-center.font-small', [ - h('span', 'Transactions'), - ]), + h('section.transaction-list', [ - h('.tx-list', { + h('h3.flex-center.text-transform-uppercase', { + style: { + background: '#EBEBEB', + }, + }, [ + 'Transactions', + ]), + + h('.tx-list', { style: { overflowY: 'auto', - height: '180px', + height: '204px', + margin: '0 20px', textAlign: 'center', }, - }, + }, ( - [ - - transactions.map((transaction) => { - - var panelOpts = { - key: `tx-${transaction.hash}`, - identiconKey: transaction.txParams.to, + transactions.length ? + transactions.map(renderTransaction) + : + [h('.flex-center', { style: { - cursor: 'pointer', - }, - onClick: (event) => { - var url = explorerLink(transaction.hash, parseInt(network)) - chrome.tabs.create({ url }); + height: '100%', }, - attributes: [ - { - key: 'TO', - value: addressSummary(transaction.txParams.to), - }, - { - key: 'VALUE', - value: formatBalance(transaction.txParams.value), - }, - ] - } - - return h(Panel, panelOpts) - }) - ] - ) - - ]) + }, 'No transaction history...')] + + )) + + ]) + + ) } + +function renderTransaction(transaction){ + var panelOpts = { + key: `tx-${transaction.hash}`, + identiconKey: transaction.txParams.to, + onClick: (event) => { + var url = explorerLink(transaction.hash, parseInt(network)) + chrome.tabs.create({ url }) + }, + attributes: [ + { + key: 'TO', + value: addressSummary(transaction.txParams.to), + }, + { + key: 'VALUE', + value: formatBalance(transaction.txParams.value), + }, + ] + } + + return h(Panel, panelOpts) +} \ No newline at end of file diff --git a/ui/app/conf-tx.js b/ui/app/conf-tx.js index 8ab79c3b9..9092c85c9 100644 --- a/ui/app/conf-tx.js +++ b/ui/app/conf-tx.js @@ -77,7 +77,8 @@ ConfirmTxScreen.prototype.render = function() { warningIfExists(state.warning), h(ReactCSSTransitionGroup, { - transitionName: "main", + className: 'css-transition-group', + transitionName: 'main', transitionEnterTimeout: 300, transitionLeaveTimeout: 300, }, [ diff --git a/ui/app/css/index.css b/ui/app/css/index.css index 9dbfb6518..18d921700 100644 --- a/ui/app/css/index.css +++ b/ui/app/css/index.css @@ -327,7 +327,7 @@ app sections /* account detail screen */ .account-detail-section { - margin: 0 20px; + } /* tx confirm */ diff --git a/ui/app/css/lib.css b/ui/app/css/lib.css index 14ef272ad..22e578ec6 100644 --- a/ui/app/css/lib.css +++ b/ui/app/css/lib.css @@ -100,7 +100,7 @@ } .select-none { - cursor: default; + cursor: inherit; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; @@ -139,6 +139,10 @@ font-weight: bold; } +.text-transform-uppercase { + text-transform: uppercase; +} + .font-small { font-size: 12px; } diff --git a/ui/app/loading.js b/ui/app/loading.js index 9288256de..f6279d5cf 100644 --- a/ui/app/loading.js +++ b/ui/app/loading.js @@ -23,7 +23,8 @@ LoadingIndicator.prototype.render = function() { return ( h(ReactCSSTransitionGroup, { - transitionName: "loader", + className: 'css-transition-group', + transitionName: 'loader', transitionEnterTimeout: 150, transitionLeaveTimeout: 150, }, [ -- cgit v1.2.3 From b8ad7f2cb141e0888505109d8a5a44b93efc19a3 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 13 May 2016 16:31:49 -0700 Subject: ui - fix account-export margin --- ui/app/components/account-export.js | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) (limited to 'ui') diff --git a/ui/app/components/account-export.js b/ui/app/components/account-export.js index f79a533ba..bdfa4c15f 100644 --- a/ui/app/components/account-export.js +++ b/ui/app/components/account-export.js @@ -31,19 +31,28 @@ ExportAccountView.prototype.render = function() { and you should only do it if you know what you're doing.` var confirmation = `If you're absolutely sure, type "I understand" below and submit.` - return h('div', { key: 'exporting' }, [ - h('p.error', warning), - h('p', confirmation), - h('input#exportAccount', { - onKeyPress: this.onExportKeyPress.bind(this), - }), - h('button', { - onClick: () => this.onExportKeyPress({ key: 'Enter', preventDefault: () => {} }), - }, 'Submit'), - h('button', { - onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)) - }, 'Cancel'), - ]) + return ( + + h('div', { + key: 'exporting', + style: { + margin: '0 20px', + }, + }, [ + h('p.error', warning), + h('p', confirmation), + h('input#exportAccount', { + onKeyPress: this.onExportKeyPress.bind(this), + }), + h('button', { + onClick: () => this.onExportKeyPress({ key: 'Enter', preventDefault: () => {} }), + }, 'Submit'), + h('button', { + onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)) + }, 'Cancel'), + ]) + + ) } if (accountExported) { -- cgit v1.2.3 From b55a3295323ae4b89901ea55678e02074148e981 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 13 May 2016 16:33:41 -0700 Subject: ui - copy address fix --- ui/app/account-detail.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ui') diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index 663014293..00d40a9ee 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -102,7 +102,7 @@ AccountDetailScreen.prototype.render = function() { }, addressSummary(selected)), h('i.fa.fa-download.fa-md.cursor-pointer.color-orange', { - onClick: () => this.requestAccountExport(account.address), + onClick: () => this.requestAccountExport(selected), }), h('i.fa.fa-qrcode.fa-md.cursor-disabled.color-orange', { @@ -110,7 +110,7 @@ AccountDetailScreen.prototype.render = function() { }), h('i.fa.fa-clipboard.fa-md.cursor-pointer.color-orange', { - onClick: () => copyToClipboard(account.address), + onClick: () => copyToClipboard(selected), }), ]), -- cgit v1.2.3 From 2365fe114213c6e5fa8230688b9191bd3a1c369f Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 13 May 2016 16:36:04 -0700 Subject: ui - txlist - better scroll bar positioning --- ui/app/components/transaction-list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ui') diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index e10dfecf3..fd6a0b2ff 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -21,7 +21,7 @@ module.exports = function(transactions, network) { style: { overflowY: 'auto', height: '204px', - margin: '0 20px', + padding: '0 20px', textAlign: 'center', }, }, ( -- cgit v1.2.3 From 82504ae965af9db892daa21c7d0c5bd59d099195 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 13 May 2016 17:02:33 -0700 Subject: ui - txList - add time --- ui/app/components/transaction-list.js | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'ui') diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index fd6a0b2ff..2a1442b8c 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -1,4 +1,5 @@ const h = require('react-hyperscript') +const vreme = new (require('vreme')) const formatBalance = require('../util').formatBalance const addressSummary = require('../util').addressSummary const explorerLink = require('../../lib/explorer-link') @@ -12,6 +13,7 @@ module.exports = function(transactions, network) { h('h3.flex-center.text-transform-uppercase', { style: { background: '#EBEBEB', + color: '#AEAEAE', }, }, [ 'Transactions', @@ -43,6 +45,7 @@ module.exports = function(transactions, network) { } function renderTransaction(transaction){ + var panelOpts = { key: `tx-${transaction.hash}`, identiconKey: transaction.txParams.to, @@ -51,6 +54,10 @@ function renderTransaction(transaction){ chrome.tabs.create({ url }) }, attributes: [ + { + key: 'TIME', + value: formatDate(transaction.time), + }, { key: 'TO', value: addressSummary(transaction.txParams.to), @@ -63,4 +70,8 @@ function renderTransaction(transaction){ } return h(Panel, panelOpts) +} + +function formatDate(date){ + return vreme.format(new Date(date), 'March 16 2014 14:30') } \ No newline at end of file -- cgit v1.2.3 From d6a8b0b90a465231c694d6d9e33aa10ba003d80f Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 13 May 2016 17:09:34 -0700 Subject: ui - redesign - send --- ui/app/send.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'ui') diff --git a/ui/app/send.js b/ui/app/send.js index ff8ef4d65..43b4e3a04 100644 --- a/ui/app/send.js +++ b/ui/app/send.js @@ -75,7 +75,10 @@ SendTransactionScreen.prototype.render = function() { h('section.data', [ h('details', [ h('summary', { - style: {cursor: 'pointer'}, + style: { + cursor: 'pointer', + outline: 'none', + }, }, 'Advanced'), h('textarea.txData', { type: 'textarea', -- cgit v1.2.3 From 49e08f9013572e7168f258000ae20b35f337f969 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 13 May 2016 18:07:47 -0700 Subject: ui - redesign - unlock menu --- ui/app/app.js | 89 ++++++++-------- ui/app/css/index.css | 229 +++++++++-------------------------------- ui/app/css/lib.css | 4 +- ui/app/first-time/init-menu.js | 4 +- ui/app/unlock.js | 18 ++-- 5 files changed, 111 insertions(+), 233 deletions(-) (limited to 'ui') diff --git a/ui/app/app.js b/ui/app/app.js index bd4249956..68d34e52f 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -50,15 +50,6 @@ App.prototype.render = function() { var state = this.props var view = state.currentView.name var transForward = state.transForward - var shouldHaveFooter = true - switch (view) { - case 'restoreVault': - shouldHaveFooter = false; - case 'createVault': - shouldHaveFooter = false; - case 'createVaultComplete': - shouldHaveFooter = false; - } return ( @@ -67,34 +58,12 @@ App.prototype.render = function() { // Windows was showing a vertical scroll bar: overflow: 'hidden', } - }, - [ + }, [ h(LoadingIndicator), // app bar - h('.app-header.flex-row.flex-space-between', { - style: { - alignItems: 'center', - } - }, [ - - // mini logo - h('img', { - height: 24, - width: 24, - src: '/images/icon-128.png', - }), - - // metamask name - h('h1', 'MetaMask'), - - // hamburger - h('i.fa.fa-bars.cursor-pointer.color-orange', { - onClick: (event) => state.dispatch(actions.showConfigPage()), - }), - - ]), + this.renderAppBar(), // panel content h('.app-primary.flex-grow' + (transForward ? '.from-right' : '.from-left'), { @@ -153,16 +122,38 @@ App.prototype.render = function() { ) } -App.prototype.toggleMetamaskActive = function(){ - if (!this.props.isUnlocked) { - // currently inactive: redirect to password box - var passwordBox = document.querySelector('input[type=password]') - if (!passwordBox) return - passwordBox.focus() - } else { - // currently active: deactivate - this.props.dispatch(actions.lockMetamask(false)) - } +App.prototype.renderAppBar = function(){ + var state = this.props + + return ( + + h('.app-header.flex-row.flex-space-between', { + style: { + alignItems: 'center', + visibility: state.isUnlocked ? 'visibile' : 'none', + background: state.isUnlocked ? 'white' : 'none', + height: '36px', + }, + }, state.isUnlocked && [ + + // mini logo + h('img', { + height: 24, + width: 24, + src: '/images/icon-128.png', + }), + + // metamask name + h('h1', 'MetaMask'), + + // hamburger + h('i.fa.fa-bars.cursor-pointer.color-orange', { + onClick: (event) => state.dispatch(actions.showConfigPage()), + }), + + ]) + + ) } App.prototype.renderPrimary = function(state){ @@ -231,6 +222,18 @@ App.prototype.renderPrimary = function(state){ } } +App.prototype.toggleMetamaskActive = function(){ + if (!this.props.isUnlocked) { + // currently inactive: redirect to password box + var passwordBox = document.querySelector('input[type=password]') + if (!passwordBox) return + passwordBox.focus() + } else { + // currently active: deactivate + this.props.dispatch(actions.lockMetamask(false)) + } +} + App.prototype.hasPendingTxs = function() { var state = this.props var unconfTxs = state.unconfTxs diff --git a/ui/app/css/index.css b/ui/app/css/index.css index 18d921700..860491a3d 100644 --- a/ui/app/css/index.css +++ b/ui/app/css/index.css @@ -18,6 +18,11 @@ html, body { color: #4D4D4D; font-weight: 300; line-height: 1.4em; + background: #F7F7F7; +} + +input:focus { + outline: none; } #app-content { @@ -47,17 +52,7 @@ button:active { transform: scale(0.95); } -button.primary { - margin: 10px; - padding: 6px; - border: none; - border-radius: 3px; - background: #F7861C; - font-weight: 500; - color: white; -} - -input, textarea { +/*input, textarea { width: 300px; padding: 6px; border-radius: 6px; @@ -65,7 +60,7 @@ input, textarea { outline: none; border: 1px solid #F5A623; background: #FAF6F0; -} +}*/ a { text-decoration: none; @@ -84,6 +79,17 @@ app color: #909090; } +button.primary { + margin: 10px; + padding: 8px 12px; + background: #F7861C; + box-shadow: 0px 3px 6px rgba(247, 134, 28, 0.36); + color: white; + font-size: 1.1em; + font-family: 'Transat Standard'; + text-transform: uppercase; +} + button.btn-thin { border: 1px solid; border-color: #4D4D4D; @@ -115,7 +121,7 @@ h2.page-subtitle { } .app-primary { - background: #F7F7F7; + } .app-footer { @@ -217,23 +223,41 @@ app sections margin: -2px 8px 0px -8px; } -.unlock-screen label { - color: #F3C83E; - font-weight: 500; +.unlock-screen #metamask-mascot-container { + margin-top: 24px; +} + +.unlock-screen h1 { + margin-top: -28px; + margin-bottom: 42px; } .unlock-screen input[type=password] { - width: 60%; - height: 22px; - padding: 2px; - border-radius: 4px; - border: 2px solid #F3C83E; - background: #FAF6F0; + width: 260px; + height: 36px; + margin-bottom: 24px; + padding: 8px; } -.unlock-screen input[type=password]:focus { - outline: none; - border: 3px solid #F3C83E; +/* Webkit */ +.password-box::-webkit-input-placeholder { + text-align: center; + font-size: 1.2em; +} +/* Firefox 18- */ +.password-box:-moz-placeholder { + text-align: center; + font-size: 1.2em; +} +/* Firefox 19+ */ +.password-box::-moz-placeholder { + text-align: center; + font-size: 1.2em; +} +/* IE */ +.password-box:-ms-input-placeholder { + text-align: center; + font-size: 1.2em; } /* accounts */ @@ -251,7 +275,6 @@ app sections } .accounts-list-option:hover { - background: pink; transform: scale(1.1); } @@ -346,157 +369,3 @@ app sections background: #FAF6F0; } - -/* -react toggle -*/ - -/* overrides */ - -.react-toggle-track-check { - display: none; -} -.react-toggle-track-x { - display: none; -} - -/* modified original */ - -.react-toggle { - display: inline-block; - position: relative; - cursor: pointer; - background-color: transparent; - border: 0; - padding: 0; - - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - - -webkit-tap-highlight-color: rgba(0,0,0,0); - -webkit-tap-highlight-color: transparent; -} - -.react-toggle-screenreader-only { - border: 0; - clip: rect(0 0 0 0); - height: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute; - width: 1px; -} - -.react-toggle--disabled { - opacity: 0.5; - -webkit-transition: opacity 0.25s; - transition: opacity 0.25s; -} - -.react-toggle-track { - width: 50px; - height: 24px; - padding: 0; - border-radius: 30px; - background-color: #4D4D4D; - -webkit-transition: all 0.2s ease; - -moz-transition: all 0.2s ease; - transition: all 0.2s ease; -} - -.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track { - background-color: #000000; -} - -.react-toggle--checked .react-toggle-track { - background-color: rgb(255, 174, 41); -} - -.react-toggle.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track { - background-color: rgb(243, 151, 0); -} - -.react-toggle-track-check { - position: absolute; - width: 14px; - height: 10px; - top: 0px; - bottom: 0px; - margin-top: auto; - margin-bottom: auto; - line-height: 0; - left: 8px; - opacity: 0; - -webkit-transition: opacity 0.25s ease; - -moz-transition: opacity 0.25s ease; - transition: opacity 0.25s ease; -} - -.react-toggle--checked .react-toggle-track-check { - opacity: 1; - -webkit-transition: opacity 0.25s ease; - -moz-transition: opacity 0.25s ease; - transition: opacity 0.25s ease; -} - -.react-toggle-track-x { - position: absolute; - width: 10px; - height: 10px; - top: 0px; - bottom: 0px; - margin-top: auto; - margin-bottom: auto; - line-height: 0; - right: 10px; - opacity: 1; - -webkit-transition: opacity 0.25s ease; - -moz-transition: opacity 0.25s ease; - transition: opacity 0.25s ease; -} - -.react-toggle--checked .react-toggle-track-x { - opacity: 0; -} - -.react-toggle-thumb { - transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1) 0ms; - position: absolute; - top: 1px; - left: 1px; - width: 22px; - height: 22px; - border: 1px solid #4D4D4D; - border-radius: 50%; - background-color: #FAFAFA; - - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - - -webkit-transition: all 0.25s ease; - -moz-transition: all 0.25s ease; - transition: all 0.25s ease; -} - -.react-toggle--checked .react-toggle-thumb { - left: 27px; - border-color: #828282; -} -/* - .react-toggle--focus .react-toggle-thumb { - -webkit-box-shadow: 0px 0px 3px 2px #0099E0; - -moz-box-shadow: 0px 0px 3px 2px #0099E0; - box-shadow: 0px 0px 2px 3px #0099E0; - } - - .react-toggle:active .react-toggle-thumb { - -webkit-box-shadow: 0px 0px 5px 5px #0099E0; - -moz-box-shadow: 0px 0px 5px 5px #0099E0; - box-shadow: 0px 0px 5px 5px #0099E0; - } diff --git a/ui/app/css/lib.css b/ui/app/css/lib.css index 22e578ec6..c366a5d5f 100644 --- a/ui/app/css/lib.css +++ b/ui/app/css/lib.css @@ -5,7 +5,7 @@ } .color-forest { - color: #08525D; + color: #0A5448; } /* lib */ @@ -175,4 +175,4 @@ hr.horizontal-line { border-top: 1px solid #ccc; margin: 1em 0; padding: 0; -} \ No newline at end of file +} diff --git a/ui/app/first-time/init-menu.js b/ui/app/first-time/init-menu.js index 6ea2eec90..2d54e7e19 100644 --- a/ui/app/first-time/init-menu.js +++ b/ui/app/first-time/init-menu.js @@ -46,12 +46,12 @@ InitializeMenuScreen.prototype.renderMenu = function() { h('.initialize-screen.flex-column.flex-center.flex-grow', [ - h('h2.page-subtitle', 'Welcome!'), - h(Mascot, { animationEventEmitter: this.animationEventEmitter, }), + h('h2.page-subtitle', 'MetaMask'), + h('button.btn-thin', { onClick: this.showCreateVault.bind(this), }, 'Create New Vault'), diff --git a/ui/app/unlock.js b/ui/app/unlock.js index 8aac1b1ff..512906c67 100644 --- a/ui/app/unlock.js +++ b/ui/app/unlock.js @@ -29,19 +29,25 @@ UnlockScreen.prototype.render = function() { h('.unlock-screen.flex-column.flex-center.flex-grow', [ - h('h2.page-subtitle', 'Welcome!'), - h(Mascot, { animationEventEmitter: this.animationEventEmitter, }), - h('label', { - htmlFor: 'password-box', - }, 'Enter Password:'), + h('h1', { + style: { + fontSize: '1.4em', + textTransform: 'uppercase', + color: '#7F8082', + }, + }, 'MetaMask'), - h('input', { + h('input.password-box', { type: 'password', id: 'password-box', + placeholder: 'enter password', + style: { + + }, onKeyPress: this.onKeyPress.bind(this), onInput: this.inputChanged.bind(this), }), -- cgit v1.2.3 From 06557d7900b77a80eaa7e305d55182a6d0c10db5 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 16 May 2016 11:24:10 -0700 Subject: ui - add new designs --- ui/design/02a-metamask-AccDetails-OverTransaction.jpg | Bin 0 -> 122075 bytes ui/design/02b-metamask-AccDetails-Send.jpg | Bin 0 -> 110143 bytes ui/design/05-metamask-Menu.jpg | Bin 0 -> 130264 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 ui/design/02a-metamask-AccDetails-OverTransaction.jpg create mode 100644 ui/design/02b-metamask-AccDetails-Send.jpg create mode 100644 ui/design/05-metamask-Menu.jpg (limited to 'ui') diff --git a/ui/design/02a-metamask-AccDetails-OverTransaction.jpg b/ui/design/02a-metamask-AccDetails-OverTransaction.jpg new file mode 100644 index 000000000..8a06be6b9 Binary files /dev/null and b/ui/design/02a-metamask-AccDetails-OverTransaction.jpg differ diff --git a/ui/design/02b-metamask-AccDetails-Send.jpg b/ui/design/02b-metamask-AccDetails-Send.jpg new file mode 100644 index 000000000..10f2d27fd Binary files /dev/null and b/ui/design/02b-metamask-AccDetails-Send.jpg differ diff --git a/ui/design/05-metamask-Menu.jpg b/ui/design/05-metamask-Menu.jpg new file mode 100644 index 000000000..0a43d7b2a Binary files /dev/null and b/ui/design/05-metamask-Menu.jpg differ -- cgit v1.2.3 From 877648623e0b483d05291379b17d5a6646375b34 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 18 May 2016 12:13:19 -0700 Subject: ui - redesign - sendTransaction --- ui/app/account-detail.js | 3 + ui/app/css/index.css | 54 +++++++++----- ui/app/css/lib.css | 17 ----- ui/app/send.js | 180 +++++++++++++++++++++++++++++++++++------------ ui/app/unlock.js | 5 +- 5 files changed, 176 insertions(+), 83 deletions(-) (limited to 'ui') diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index 00d40a9ee..2b58fb239 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -126,6 +126,9 @@ AccountDetailScreen.prototype.render = function() { h('button', { onClick: () => this.props.dispatch(actions.showSendPage()), + style: { + margin: 10, + }, }, 'SEND ETH'), ]), diff --git a/ui/app/css/index.css b/ui/app/css/index.css index 860491a3d..75f434da6 100644 --- a/ui/app/css/index.css +++ b/ui/app/css/index.css @@ -21,7 +21,7 @@ html, body { background: #F7F7F7; } -input:focus { +input:focus, textarea:focus { outline: none; } @@ -36,7 +36,7 @@ button { font-family: 'Transat Black'; outline: none; cursor: pointer; - margin: 10px; + /*margin: 10px;*/ padding: 8px 12px; border: none; background: #F7861C; @@ -52,16 +52,6 @@ button:active { transform: scale(0.95); } -/*input, textarea { - width: 300px; - padding: 6px; - border-radius: 6px; - border-style: solid; - outline: none; - border: 1px solid #F5A623; - background: #FAF6F0; -}*/ - a { text-decoration: none; color: inherit; @@ -80,7 +70,6 @@ app } button.primary { - margin: 10px; padding: 8px 12px; background: #F7861C; box-shadow: 0px 3px 6px rgba(247, 134, 28, 0.36); @@ -234,32 +223,43 @@ app sections .unlock-screen input[type=password] { width: 260px; - height: 36px; + /*height: 36px; margin-bottom: 24px; - padding: 8px; + padding: 8px;*/ } /* Webkit */ -.password-box::-webkit-input-placeholder { +.unlock-screen input::-webkit-input-placeholder { text-align: center; font-size: 1.2em; } /* Firefox 18- */ -.password-box:-moz-placeholder { +.unlock-screen input:-moz-placeholder { text-align: center; font-size: 1.2em; } /* Firefox 19+ */ -.password-box::-moz-placeholder { +.unlock-screen input::-moz-placeholder { text-align: center; font-size: 1.2em; } /* IE */ -.password-box:-ms-input-placeholder { +.unlock-screen input:-ms-input-placeholder { text-align: center; font-size: 1.2em; } +input.large-input, textarea.large-input { + /*margin-bottom: 24px;*/ + padding: 8px; +} + +input.large-input { + height: 36px; +} + + + /* accounts */ .accounts-section { @@ -369,3 +369,19 @@ app sections background: #FAF6F0; } +/* Send Screen */ + +.send-screen { + +} + +.send-screen section { + margin: 8px 16px; +} + +.send-screen input { + width: 100%; + font-size: 12px; + letter-spacing: 0.1em; +} + diff --git a/ui/app/css/lib.css b/ui/app/css/lib.css index c366a5d5f..60c56422d 100644 --- a/ui/app/css/lib.css +++ b/ui/app/css/lib.css @@ -151,23 +151,6 @@ font-size: 1.2em; } -/* Send Screen */ -.send-screen { - margin: 0 20px; -} -.send-screen section { - margin: 7px; - display: flex; - flex-direction: row; - justify-content: center; -} -.send-screen details { - width: 100%; -} -.send-screen section input { - width: 100%; -} - hr.horizontal-line { display: block; height: 1px; diff --git a/ui/app/send.js b/ui/app/send.js index 43b4e3a04..56b23ee24 100644 --- a/ui/app/send.js +++ b/ui/app/send.js @@ -2,9 +2,12 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') const connect = require('react-redux').connect +const Identicon = require('./components/identicon') const actions = require('./actions') const util = require('./util') const numericBalance = require('./util').numericBalance +const formatBalance = require('./util').formatBalance +const addressSummary = require('./util').addressSummary const AccountPanel = require('./components/account-panel') const ethUtil = require('ethereumjs-util') @@ -32,78 +35,163 @@ function SendTransactionScreen() { SendTransactionScreen.prototype.render = function() { var state = this.props + var address = state.address var account = state.account var identity = state.identity return ( + h('.send-screen.flex-column.flex-grow', [ - // subtitle and nav - h('.section-title.flex-row.flex-center', [ - h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { - onClick: this.back.bind(this), - }), - h('h2.page-subtitle', 'Send Transaction'), + // + // Sender Profile + // + + h('.account-data-subsection.flex-column.flex-grow', { + style: { + margin: '0 20px', + }, + }, [ + + // header - identicon + nav + h('.flex-row.flex-space-between', { + style: { + marginTop: 28, + }, + }, [ + + // invisible placeholder for later + h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', { + onClick: this.back.bind(this), + }), + + // large identicon + h('.identicon-wrapper.flex-column.flex-center.select-none', [ + h(Identicon, { + diameter: 62, + address: address, + }), + ]), + + // small accounts nav + h('i.fa.fa-users.fa-lg.cursor-pointer.color-orange', { + onClick: this.navigateToAccounts.bind(this), + }), + + ]), + + // account label + h('h2.font-medium.color-forest.flex-center', { + style: { + paddingTop: 8, + marginBottom: 8, + }, + }, identity && identity.name), + + // address and getter actions + h('.flex-row.flex-center', { + style: { + marginBottom: 8, + }, + }, [ + + h('div', { + style: { + lineHeight: '16px', + }, + }, addressSummary(address)), + + ]), + + // balance + h('.flex-row.flex-center', [ + + h('div', formatBalance(account && account.balance)), + + ]), + ]), - h(AccountPanel, { - showFullAddress: true, - identity: identity, - account: account, - }), + // + // Required Fields + // + + h('h3.flex-center.text-transform-uppercase', { + style: { + background: '#EBEBEB', + color: '#AEAEAE', + marginTop: 32, + marginBottom: 16, + }, + }, [ + 'Send Transaction', + ]), - h('section.recipient', [ - h('input.address', { + // 'to' field + h('section.flex-row.flex-center', [ + h('input.address.large-input', { placeholder: 'Recipient Address', }) ]), - h('section.ammount', [ - h('input.ether', { + // 'amount' and send button + h('section.flex-row.flex-center', [ + + h('input.ether.large-input', { placeholder: 'Amount', type: 'number', - style: { marginRight: '6px' } + style: { + marginRight: 6, + }, }), - h('select.currency', { - name: 'currency', - }, [ - h('option', { value: 'ether' }, 'Ether (1e18 wei)'), - h('option', { value: 'wei' }, 'Wei'), - ]), - ]), - h('section.data', [ - h('details', [ - h('summary', { - style: { - cursor: 'pointer', - outline: 'none', - }, - }, 'Advanced'), - h('textarea.txData', { - type: 'textarea', - placeholder: 'Transaction data (optional)', - style: { - height: '100px', - width: '100%', - resize: 'none', - } - }) - ]) + h('button.primary', { + onClick: this.onSubmit.bind(this), + style: { + textTransform: 'uppercase', + }, + }, 'Send') + ]), - h('section', { + // + // Optional Fields + // + + h('h3.flex-center.text-transform-uppercase', { + style: { + background: '#EBEBEB', + color: '#AEAEAE', + marginTop: 16, + marginBottom: 16, + }, }, [ - h('button', { - onClick: this.onSubmit.bind(this), - }, 'Send') + 'Tranasactional Data (optional)', ]), - state.warning ? h('span.error', state.warning.split('.')[0]) : null, + // 'data' field + h('section.flex-row.flex-center', [ + h('input.txData.large-input', { + placeholder: '0x01234', + style: { + width: '100%', + resize: 'none', + } + }), + ]), + + // state.warning ? h('span.error', state.warning.split('.')[0]) : null, + ]) + ) } +SendTransactionScreen.prototype.navigateToAccounts = function(event){ + event.stopPropagation() + this.props.dispatch(actions.showAccountsPage()) +} + SendTransactionScreen.prototype.back = function() { var address = this.props.address this.props.dispatch(actions.backToAccountDetail(address)) diff --git a/ui/app/unlock.js b/ui/app/unlock.js index 512906c67..687bb5e52 100644 --- a/ui/app/unlock.js +++ b/ui/app/unlock.js @@ -41,7 +41,7 @@ UnlockScreen.prototype.render = function() { }, }, 'MetaMask'), - h('input.password-box', { + h('input.large-input', { type: 'password', id: 'password-box', placeholder: 'enter password', @@ -60,6 +60,9 @@ UnlockScreen.prototype.render = function() { h('button.primary.cursor-pointer', { onClick: this.onSubmit.bind(this), + style: { + margin: 10, + }, }, 'Unlock'), ]) -- cgit v1.2.3 From d18d9a8f97216afae4a6c9d8d659952ed5cba765 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 18 May 2016 12:30:03 -0700 Subject: Add animated sandwich button --- ui/app/actions.js | 11 +++++++++++ ui/app/app.js | 14 +++++++++++--- ui/app/reducers/app.js | 6 ++++++ 3 files changed, 28 insertions(+), 3 deletions(-) (limited to 'ui') diff --git a/ui/app/actions.js b/ui/app/actions.js index f489eede7..c08019d9c 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -1,6 +1,9 @@ var actions = { GO_HOME: 'GO_HOME', goHome: goHome, + // menu state + TOGGLE_MENU: 'TOGGLE_MENU', + toggleMenu: toggleMenu, // remote state UPDATE_METAMASK_STATE: 'UPDATE_METAMASK_STATE', updateMetamaskState: updateMetamaskState, @@ -105,6 +108,14 @@ function goHome() { } } +// menu state + +function toggleMenu() { + return { + type: this.TOGGLE_MENU, + } +} + // async actions function tryUnlockMetamask(password) { diff --git a/ui/app/app.js b/ui/app/app.js index 68d34e52f..ec869145e 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -24,6 +24,8 @@ const ConfigScreen = require('./config') const InfoScreen = require('./info') const LoadingIndicator = require('./loading') const txHelper = require('../lib/tx-helper') +const SandwichExpando = require('sandwich-expando') +const MenuDroppo = require('menu-droppo') module.exports = connect(mapStateToProps)(App) @@ -42,6 +44,7 @@ function mapStateToProps(state) { seedWords: state.metamask.seedWords, unconfTxs: state.metamask.unconfTxs, unconfMsgs: state.metamask.unconfMsgs, + menuOpen: state.appState.menuOpen, } } @@ -143,12 +146,17 @@ App.prototype.renderAppBar = function(){ src: '/images/icon-128.png', }), - // metamask name + // metamask namlterChangese h('h1', 'MetaMask'), // hamburger - h('i.fa.fa-bars.cursor-pointer.color-orange', { - onClick: (event) => state.dispatch(actions.showConfigPage()), + h(SandwichExpando, { + width: 16, + barHeight: 2, + padding: 0, + isOpen: state.menuOpen, + color: 'rgb(247,146,30)', + onClick: () => this.props.dispatch(actions.toggleMenu()), }), ]) diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index 0e0740c9d..a7429c8fb 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -22,6 +22,7 @@ function reduceApp(state, action) { var seedWords = state.metamask.seedWords var appState = extend({ + menuOpen: false, currentView: seedWords ? seedConfView : defaultView, accountDetail: { subview: 'transactions', @@ -34,6 +35,11 @@ function reduceApp(state, action) { switch (action.type) { + case actions.TOGGLE_MENU: + return extend(appState, { + menuOpen: !appState.menuOpen, + }) + // intialize case actions.SHOW_CREATE_VAULT: -- cgit v1.2.3 From 6ae0a90d7b9ee3bfca359c1291efe86c5142c7b5 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 18 May 2016 13:41:08 -0700 Subject: ui - redesign - ether amount component --- ui/app/account-detail.js | 7 ++++--- ui/app/accounts.js | 7 +++++-- ui/app/components/eth-balance.js | 40 ++++++++++++++++++++++++++++++++++++++++ ui/app/css/index.css | 9 +++++++++ ui/app/send.js | 7 +++++-- ui/app/util.js | 25 ++++++++++++++++++++----- 6 files changed, 83 insertions(+), 12 deletions(-) create mode 100644 ui/app/components/eth-balance.js (limited to 'ui') diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index 2b58fb239..263e48441 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -6,11 +6,11 @@ const connect = require('react-redux').connect const copyToClipboard = require('copy-to-clipboard') const actions = require('./actions') const addressSummary = require('./util').addressSummary -const formatBalance = require('./util').formatBalance const ReactCSSTransitionGroup = require('react-addons-css-transition-group') const AccountPanel = require('./components/account-panel') const Identicon = require('./components/identicon') +const EtherBalance = require('./components/eth-balance') const transactionList = require('./components/transaction-list') const ExportAccountView = require('./components/account-export') @@ -118,11 +118,12 @@ AccountDetailScreen.prototype.render = function() { // balance + send h('.flex-row.flex-space-between', [ - h('div', { + h(EtherBalance, { + value: account && account.balance, style: { lineHeight: '50px', }, - }, formatBalance(account && account.balance)), + }), h('button', { onClick: () => this.props.dispatch(actions.showSendPage()), diff --git a/ui/app/accounts.js b/ui/app/accounts.js index 18ba1e67d..e609e7424 100644 --- a/ui/app/accounts.js +++ b/ui/app/accounts.js @@ -5,7 +5,7 @@ const connect = require('react-redux').connect const extend = require('xtend') const Identicon = require('./components/identicon') const actions = require('./actions') -const AccountPanel = require('./components/account-panel') +const EtherBalance = require('./components/eth-balance') const valuesFor = require('./util').valuesFor const addressSummary = require('./util').addressSummary const formatBalance = require('./util').formatBalance @@ -108,7 +108,10 @@ AccountsScreen.prototype.render = function() { h('span', identity.name), h('span.font-small', addressSummary(identity.address)), - h('span.font-small', formatBalance(account.balance)), + // h('span.font-small', formatBalance(account.balance)), + h(EtherBalance, { + value: account.balance, + }), ]), diff --git a/ui/app/components/eth-balance.js b/ui/app/components/eth-balance.js new file mode 100644 index 000000000..3f88ef2d4 --- /dev/null +++ b/ui/app/components/eth-balance.js @@ -0,0 +1,40 @@ +const Component = require('react').Component +const h = require('react-hyperscript') +const inherits = require('util').inherits +const parseBalance = require('../util').parseBalance + +module.exports = EthBalanceComponent + +inherits(EthBalanceComponent, Component) +function EthBalanceComponent() { + Component.call(this) +} + +EthBalanceComponent.prototype.render = function() { + var state = this.props + var parsedAmount = parseBalance(state.value) + var beforeDecimal = parsedAmount[0] + var afterDecimal = parsedAmount[1] + var value = beforeDecimal+(afterDecimal ? '.'+afterDecimal : '') + var style = state.style + + return ( + + h('.ether-balance', { + style: style, + }, [ + h('.ether-balance-amount', { + style: { + display: 'inline', + }, + }, value), + h('.ether-balance-label', { + style: { + display: 'inline', + marginLeft: 6, + }, + }, 'ETH'), + ]) + + ) +} diff --git a/ui/app/css/index.css b/ui/app/css/index.css index 75f434da6..060ddce91 100644 --- a/ui/app/css/index.css +++ b/ui/app/css/index.css @@ -385,3 +385,12 @@ input.large-input { letter-spacing: 0.1em; } +/* Ether Balance Widget */ + +.ether-balance-amount { + color: #F7861C; +} + +.ether-balance-label { + color: #ABA9AA; +} \ No newline at end of file diff --git a/ui/app/send.js b/ui/app/send.js index 56b23ee24..1442db8cc 100644 --- a/ui/app/send.js +++ b/ui/app/send.js @@ -8,7 +8,7 @@ const util = require('./util') const numericBalance = require('./util').numericBalance const formatBalance = require('./util').formatBalance const addressSummary = require('./util').addressSummary -const AccountPanel = require('./components/account-panel') +const EtherBalance = require('./components/eth-balance') const ethUtil = require('ethereumjs-util') module.exports = connect(mapStateToProps)(SendTransactionScreen) @@ -106,7 +106,10 @@ SendTransactionScreen.prototype.render = function() { // balance h('.flex-row.flex-center', [ - h('div', formatBalance(account && account.balance)), + // h('div', formatBalance(account && account.balance)), + h(EtherBalance, { + value: account && account.balance, + }) ]), diff --git a/ui/app/util.js b/ui/app/util.js index 5dbcffa7e..0f3f191aa 100644 --- a/ui/app/util.js +++ b/ui/app/util.js @@ -22,6 +22,7 @@ module.exports = { valuesFor: valuesFor, addressSummary: addressSummary, numericBalance: numericBalance, + parseBalance: parseBalance, formatBalance: formatBalance, dataSize: dataSize, readableDate: readableDate, @@ -65,16 +66,30 @@ function weiToEth(bn) { return eth } -var decimalsToKeep = 4 -function formatBalance(balance) { - if (!balance || balance === '0x0') return 'None' +// Takes hex, returns [beforeDecimal, afterDecimal] +function parseBalance(balance, decimalsToKeep) { + if (decimalsToKeep === undefined) decimalsToKeep = 4 + if (!balance || balance === '0x0') return ['0', ''] var wei = numericBalance(balance) var padded = wei.toString(10) var len = padded.length - var nonZeroIndex = padded.match(/[^0]/) && padded.match(/[^0]/).index + var match = padded.match(/[^0]/) + var nonZeroIndex = match && match.index var beforeDecimal = padded.substr(nonZeroIndex ? nonZeroIndex : 0, len - 18) || '0' var afterDecimal = padded.substr(len - 18, decimalsToKeep) - return `${beforeDecimal}.${afterDecimal} ETH` + return [beforeDecimal, afterDecimal] +} + +// Takes wei hex, returns "None" or "${formattedAmount} ETH" +function formatBalance(balance) { + var parsed = parseBalance(balance) + var beforeDecimal = parsed[0] + var afterDecimal = parsed[1] + if (beforeDecimal === '0' && afterDecimal === '') return 'None' + var result = beforeDecimal + if (afterDecimal) result += '.'+afterDecimal + result += ' ETH' + return result } function dataSize(data) { -- cgit v1.2.3 From 6eebda73cfe77f0a62fe42b7eb1e4a9b9bf37bcb Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 18 May 2016 13:55:43 -0700 Subject: ui - sendTx - re-add warning and fix form parsing --- ui/app/send.js | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'ui') diff --git a/ui/app/send.js b/ui/app/send.js index 56b23ee24..ae57b9677 100644 --- a/ui/app/send.js +++ b/ui/app/send.js @@ -21,6 +21,8 @@ function mapStateToProps(state) { warning: state.appState.warning, } + result.error = result.warning && result.warning.split('.')[0] + result.account = result.accounts[result.address] result.identity = result.identities[result.address] result.balance = result.account ? numericBalance(result.account.balance) : null @@ -127,9 +129,13 @@ SendTransactionScreen.prototype.render = function() { 'Send Transaction', ]), + // error message + state.error && h('span.error.flex-center', state.error), + // 'to' field h('section.flex-row.flex-center', [ - h('input.address.large-input', { + h('input.large-input', { + name: 'address', placeholder: 'Recipient Address', }) ]), @@ -137,7 +143,8 @@ SendTransactionScreen.prototype.render = function() { // 'amount' and send button h('section.flex-row.flex-center', [ - h('input.ether.large-input', { + h('input.large-input', { + name: 'amount', placeholder: 'Amount', type: 'number', style: { @@ -171,7 +178,8 @@ SendTransactionScreen.prototype.render = function() { // 'data' field h('section.flex-row.flex-center', [ - h('input.txData.large-input', { + h('input.large-input', { + name: 'txData', placeholder: '0x01234', style: { width: '100%', @@ -180,8 +188,6 @@ SendTransactionScreen.prototype.render = function() { }), ]), - // state.warning ? h('span.error', state.warning.split('.')[0]) : null, - ]) ) @@ -198,11 +204,10 @@ SendTransactionScreen.prototype.back = function() { } SendTransactionScreen.prototype.onSubmit = function(event) { - var recipient = document.querySelector('input.address').value + var recipient = document.querySelector('input[name="address"]').value - var inputAmount = parseFloat(document.querySelector('input.ether').value) - var currency = document.querySelector('select.currency').value - var value = util.normalizeNumberToWei(inputAmount, currency) + var inputAmount = parseFloat(document.querySelector('input[name="amount"]').value) + var value = util.normalizeNumberToWei(inputAmount, 'ether') var balance = this.props.balance @@ -224,7 +229,7 @@ SendTransactionScreen.prototype.onSubmit = function(event) { value: '0x' + value.toString(16), } - var txData = document.querySelector('textarea.txData').value + var txData = document.querySelector('input[name="txData"]').value if (txData) txParams.data = txData this.props.dispatch(actions.signTx(txParams)) -- cgit v1.2.3 From d0b0526765000ab6f56e8c35545d66a760ed7b61 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 18 May 2016 14:36:35 -0700 Subject: Add dynamic list item styles --- ui/app/actions.js | 9 +++ ui/app/app.js | 107 ++++++++++++++++++++++++++---------- ui/app/components/drop-menu-item.js | 31 +++++++++++ ui/app/reducers/app.js | 5 ++ 4 files changed, 123 insertions(+), 29 deletions(-) create mode 100644 ui/app/components/drop-menu-item.js (limited to 'ui') diff --git a/ui/app/actions.js b/ui/app/actions.js index c08019d9c..ee5e417d4 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -4,6 +4,8 @@ var actions = { // menu state TOGGLE_MENU: 'TOGGLE_MENU', toggleMenu: toggleMenu, + SET_MENU_STATE: 'SET_MENU_STATE', + closeMenu: closeMenu, // remote state UPDATE_METAMASK_STATE: 'UPDATE_METAMASK_STATE', updateMetamaskState: updateMetamaskState, @@ -116,6 +118,13 @@ function toggleMenu() { } } +function closeMenu() { + return { + type: this.SET_MENU_STATE, + value: false, + } +} + // async actions function tryUnlockMetamask(password) { diff --git a/ui/app/app.js b/ui/app/app.js index ec869145e..2f4136b78 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -26,6 +26,7 @@ const LoadingIndicator = require('./loading') const txHelper = require('../lib/tx-helper') const SandwichExpando = require('sandwich-expando') const MenuDroppo = require('menu-droppo') +const DropMenuItem = require('./components/drop-menu-item') module.exports = connect(mapStateToProps)(App) @@ -130,37 +131,85 @@ App.prototype.renderAppBar = function(){ return ( - h('.app-header.flex-row.flex-space-between', { - style: { - alignItems: 'center', - visibility: state.isUnlocked ? 'visibile' : 'none', - background: state.isUnlocked ? 'white' : 'none', - height: '36px', - }, - }, state.isUnlocked && [ - - // mini logo - h('img', { - height: 24, - width: 24, - src: '/images/icon-128.png', - }), - - // metamask namlterChangese - h('h1', 'MetaMask'), - - // hamburger - h(SandwichExpando, { - width: 16, - barHeight: 2, - padding: 0, - isOpen: state.menuOpen, - color: 'rgb(247,146,30)', - onClick: () => this.props.dispatch(actions.toggleMenu()), - }), + h('div', [ - ]) + h('.app-header.flex-row.flex-space-between', { + style: { + alignItems: 'center', + visibility: state.isUnlocked ? 'visibile' : 'none', + background: state.isUnlocked ? 'white' : 'none', + height: '36px', + }, + }, state.isUnlocked && [ + + // mini logo + h('img', { + height: 24, + width: 24, + src: '/images/icon-128.png', + }), + + // metamask namlterChangese + h('h1', 'MetaMask'), + + // hamburger + h(SandwichExpando, { + width: 16, + barHeight: 2, + padding: 0, + isOpen: state.menuOpen, + color: 'rgb(247,146,30)', + onClick: (event) => { + event.preventDefault() + event.stopPropagation() + this.props.dispatch(actions.toggleMenu()) + }, + }), + ]), + h(MenuDroppo, { + style: { + right: '0px', + }, + innerStyle: { + background: 'white', + + // This shadow is hidden by the surrounding bounding box. + // Maybe worth revealing in the future: + boxShadow: '1px 1px 2px rgba(0,0,0,0.1)', + float: 'right', + }, + isOpen: state.menuOpen, + onClickOutside: (event) => { + this.props.dispatch(actions.closeMenu()) + }, + }, [ // DROP MENU ITEMS + h('menu', [ + h('style', '.drop-menu-item:hover { background:rgb(235, 235, 235); }'), + + h(DropMenuItem, { + closeMenu:() => this.props.dispatch(actions.closeMenu()), + action:() => this.props.dispatch(actions.showConfigPage()), + icon: null, + label: 'Settings' + }), + + h(DropMenuItem, { + closeMenu:() => this.props.dispatch(actions.closeMenu()), + action:() => this.props.dispatch(actions.lockMetamask()), + icon: null, + label: 'Lock Account' + }), + + h(DropMenuItem, { + closeMenu:() => this.props.dispatch(actions.closeMenu()), + action:() => this.props.dispatch(actions.showInfoPage()), + icon: null, + label: 'Help' + }), + ]), + ]), + ]) ) } diff --git a/ui/app/components/drop-menu-item.js b/ui/app/components/drop-menu-item.js new file mode 100644 index 000000000..1adbba519 --- /dev/null +++ b/ui/app/components/drop-menu-item.js @@ -0,0 +1,31 @@ +const Component = require('react').Component +const h = require('react-hyperscript') +const inherits = require('util').inherits + +module.exports = DropMenuItem + + +inherits(DropMenuItem, Component) +function DropMenuItem() { + Component.call(this) +} + +DropMenuItem.prototype.render = function() { + + return h('li.drop-menu-item', { + onClick:() => { + this.props.closeMenu() + this.props.action() + }, + style: { + listStyle: 'none', + padding: '6px 10px 6px 17px', + fontFamily: 'Transat Medium', + color: 'rgb(125, 128, 130)', + cursor: 'pointer', + }, + }, [ + this.props.icon, + this.props.label, + ]) +} diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index a7429c8fb..2cdbaf6f3 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -40,6 +40,11 @@ function reduceApp(state, action) { menuOpen: !appState.menuOpen, }) + case actions.SET_MENU_STATE: + return extend(appState, { + menuOpen: action.value, + }) + // intialize case actions.SHOW_CREATE_VAULT: -- cgit v1.2.3 From 9d0cad0e16414a4334e92fc7e06c48e7730deae6 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 18 May 2016 17:32:26 -0700 Subject: Finish clean implementation of drop-down menu --- ui/app/app.js | 105 +++++++++++++++++++----------------- ui/app/components/drop-menu-item.js | 2 +- 2 files changed, 56 insertions(+), 51 deletions(-) (limited to 'ui') diff --git a/ui/app/app.js b/ui/app/app.js index 2f4136b78..66f42c5cc 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -68,6 +68,7 @@ App.prototype.render = function() { // app bar this.renderAppBar(), + this.renderDropdown(), // panel content h('.app-primary.flex-grow' + (transForward ? '.from-right' : '.from-left'), { @@ -139,6 +140,8 @@ App.prototype.renderAppBar = function(){ visibility: state.isUnlocked ? 'visibile' : 'none', background: state.isUnlocked ? 'white' : 'none', height: '36px', + position: 'relative', + zIndex: 1, }, }, state.isUnlocked && [ @@ -166,65 +169,67 @@ App.prototype.renderAppBar = function(){ }, }), ]), - - h(MenuDroppo, { - style: { - right: '0px', - }, - innerStyle: { - background: 'white', - - // This shadow is hidden by the surrounding bounding box. - // Maybe worth revealing in the future: - boxShadow: '1px 1px 2px rgba(0,0,0,0.1)', - float: 'right', - }, - isOpen: state.menuOpen, - onClickOutside: (event) => { - this.props.dispatch(actions.closeMenu()) - }, - }, [ // DROP MENU ITEMS - h('menu', [ - h('style', '.drop-menu-item:hover { background:rgb(235, 235, 235); }'), - - h(DropMenuItem, { - closeMenu:() => this.props.dispatch(actions.closeMenu()), - action:() => this.props.dispatch(actions.showConfigPage()), - icon: null, - label: 'Settings' - }), - - h(DropMenuItem, { - closeMenu:() => this.props.dispatch(actions.closeMenu()), - action:() => this.props.dispatch(actions.lockMetamask()), - icon: null, - label: 'Lock Account' - }), - - h(DropMenuItem, { - closeMenu:() => this.props.dispatch(actions.closeMenu()), - action:() => this.props.dispatch(actions.showInfoPage()), - icon: null, - label: 'Help' - }), - ]), - ]), ]) ) } -App.prototype.renderPrimary = function(state){ - var state = this.props +App.prototype.renderDropdown = function() { + const props = this.props + return h(MenuDroppo, { + isOpen: props.menuOpen, + onClickOutside: (event) => { + this.props.dispatch(actions.closeMenu()) + }, + style: { + position: 'fixed', + right: 0, + zIndex: 0, + }, + innerStyle: { + background: 'white', + boxShadow: '1px 1px 2px rgba(0,0,0,0.1)', + }, + }, [ // DROP MENU ITEMS + h('style', ` + .drop-menu-item:hover { background:rgb(235, 235, 235); } + .drop-menu-item i { margin: 11px; } + `), + + h(DropMenuItem, { + label: 'Settings', + closeMenu:() => this.props.dispatch(actions.closeMenu()), + action:() => this.props.dispatch(actions.showConfigPage()), + icon: h('i.fa.fa-gear.fa-lg', { ariaHidden: true }), + }), + + h(DropMenuItem, { + label: 'Lock Account', + closeMenu:() => this.props.dispatch(actions.closeMenu()), + action:() => this.props.dispatch(actions.lockMetamask()), + icon: h('i.fa.fa-lock.fa-lg', { ariaHidden: true }), + }), + + h(DropMenuItem, { + label: 'Help', + closeMenu:() => this.props.dispatch(actions.closeMenu()), + action:() => this.props.dispatch(actions.showInfoPage()), + icon: h('i.fa.fa-question.fa-lg', { ariaHidden: true }), + }), + ]) +} + +App.prototype.renderPrimary = function(){ + var props = this.props - if (state.seedWords) { + if (props.seedWords) { return h(CreateVaultCompleteScreen, {key: 'createVaultComplete'}) } // show initialize screen - if (!state.isInitialized) { + if (!props.isInitialized) { // show current view - switch (state.currentView.name) { + switch (props.currentView.name) { case 'createVault': return h(CreateVaultScreen, {key: 'createVault'}) @@ -242,12 +247,12 @@ App.prototype.renderPrimary = function(state){ } // show unlock screen - if (!state.isUnlocked) { + if (!props.isUnlocked) { return h(UnlockScreen, {key: 'locked'}) } // show current view - switch (state.currentView.name) { + switch (props.currentView.name) { case 'accounts': return h(AccountsScreen, {key: 'accounts'}) diff --git a/ui/app/components/drop-menu-item.js b/ui/app/components/drop-menu-item.js index 1adbba519..c8e61278c 100644 --- a/ui/app/components/drop-menu-item.js +++ b/ui/app/components/drop-menu-item.js @@ -19,7 +19,7 @@ DropMenuItem.prototype.render = function() { }, style: { listStyle: 'none', - padding: '6px 10px 6px 17px', + padding: '6px 16px 6px 5px', fontFamily: 'Transat Medium', color: 'rgb(125, 128, 130)', cursor: 'pointer', -- cgit v1.2.3 From e64e3bbea54eeb946eeae70ced1c381ed52fa4e3 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 18 May 2016 17:47:30 -0700 Subject: Fix typos --- ui/app/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ui') diff --git a/ui/app/app.js b/ui/app/app.js index 66f42c5cc..511012fab 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -137,7 +137,7 @@ App.prototype.renderAppBar = function(){ h('.app-header.flex-row.flex-space-between', { style: { alignItems: 'center', - visibility: state.isUnlocked ? 'visibile' : 'none', + visibility: state.isUnlocked ? 'visible' : 'none', background: state.isUnlocked ? 'white' : 'none', height: '36px', position: 'relative', @@ -152,7 +152,7 @@ App.prototype.renderAppBar = function(){ src: '/images/icon-128.png', }), - // metamask namlterChangese + // metamask name h('h1', 'MetaMask'), // hamburger -- cgit v1.2.3 From 8c6a451ac76572a6566dff594b586db718b68784 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 18 May 2016 17:48:50 -0700 Subject: ui - redesign - txList improved --- ui/app/components/transaction-list.js | 108 ++++++++++++++++++++++++++-------- 1 file changed, 83 insertions(+), 25 deletions(-) (limited to 'ui') diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index 2a1442b8c..40a4593fe 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -4,12 +4,25 @@ const formatBalance = require('../util').formatBalance const addressSummary = require('../util').addressSummary const explorerLink = require('../../lib/explorer-link') const Panel = require('./panel') +const Identicon = require('./identicon') +const EtherBalance = require('./eth-balance') + module.exports = function(transactions, network) { return ( h('section.transaction-list', [ + h('style', ` + .transaction-list .transaction-list-item:not(:last-of-type) { + border-bottom: 1px solid #D4D4D4; + } + .transaction-list .transaction-list-item .ether-balance-label { + display: block !important; + font-size: small; + } + `), + h('h3.flex-center.text-transform-uppercase', { style: { background: '#EBEBEB', @@ -42,35 +55,80 @@ module.exports = function(transactions, network) { ]) ) - } -function renderTransaction(transaction){ - - var panelOpts = { - key: `tx-${transaction.hash}`, - identiconKey: transaction.txParams.to, - onClick: (event) => { - var url = explorerLink(transaction.hash, parseInt(network)) - chrome.tabs.create({ url }) - }, - attributes: [ - { - key: 'TIME', - value: formatDate(transaction.time), - }, - { - key: 'TO', - value: addressSummary(transaction.txParams.to), - }, - { - key: 'VALUE', - value: formatBalance(transaction.txParams.value), + + function renderTransaction(transaction){ + + var panelOpts = { + key: `tx-${transaction.hash}`, + identiconKey: transaction.txParams.to, + onClick: (event) => { + var url = explorerLink(transaction.hash, parseInt(network)) + chrome.tabs.create({ url }) }, - ] + attributes: [ + { + key: 'TIME', + value: formatDate(transaction.time), + }, + { + key: 'TO', + value: addressSummary(transaction.txParams.to), + }, + { + key: 'VALUE', + value: formatBalance(transaction.txParams.value), + }, + ] + } + + var txParams = transaction.txParams + var date = formatDate(transaction.time) + + return ( + + h('.transaction-list-item.flex-row.flex-space-between.cursor-pointer', { + key: `tx-${transaction.hash}`, + onClick: (event) => { + var url = explorerLink(transaction.hash, parseInt(network)) + chrome.tabs.create({ url }) + }, + style: { + padding: '20px 0', + }, + }, [ + + // large identicon + h('.identicon-wrapper.flex-column.flex-center.select-none', [ + h(Identicon, { + diameter: 24, + address: txParams.to, + }), + ]), + + h('.flex-column', [ + + h('div', date), + + h('div', { + style: { + fontSize: 'small', + color: '#ABA9AA', + }, + }, addressSummary(txParams.to)), + + ]), + + h(EtherBalance, { + value: txParams.value, + }), + + ]) + + ) } - return h(Panel, panelOpts) -} + } function formatDate(date){ return vreme.format(new Date(date), 'March 16 2014 14:30') -- cgit v1.2.3 From e5034ade243d1bf2258f39aabcfe09b9ac602924 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 18 May 2016 23:50:15 -0700 Subject: Make accounts page transition forward from account detail --- ui/app/reducers/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ui') diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index 2cdbaf6f3..1c0154cd5 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -165,7 +165,7 @@ function reduceApp(state, action) { accountExport: 'none', privateKey: '', }, - transForward: true, + transForward: false, }) case actions.BACK_TO_ACCOUNT_DETAIL: @@ -188,7 +188,7 @@ function reduceApp(state, action) { currentView: { name: seedWords ? 'createVaultComplete' : 'accounts', }, - transForward: appState.currentView.name == 'locked', + transForward: true, isLoading: false, warning: null, }) -- cgit v1.2.3 From 685a1881b86c19fe52a7cd82ed4e2b34617429ff Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 19 May 2016 11:28:58 -0700 Subject: Allow txs with no recipient when they have a data field --- ui/app/send.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'ui') diff --git a/ui/app/send.js b/ui/app/send.js index 52e56132c..67dd15f81 100644 --- a/ui/app/send.js +++ b/ui/app/send.js @@ -206,20 +206,21 @@ SendTransactionScreen.prototype.back = function() { this.props.dispatch(actions.backToAccountDetail(address)) } -SendTransactionScreen.prototype.onSubmit = function(event) { - var recipient = document.querySelector('input[name="address"]').value +SendTransactionScreen.prototype.onSubmit = function() { - var inputAmount = parseFloat(document.querySelector('input[name="amount"]').value) - var value = util.normalizeNumberToWei(inputAmount, 'ether') - - var balance = this.props.balance + const recipient = document.querySelector('input[name="address"]').value + const inputAmount = parseFloat(document.querySelector('input[name="amount"]').value) + const value = util.normalizeNumberToWei(inputAmount, 'ether') + const txData = document.querySelector('input[name="txData"]').value + const balance = this.props.balance if (value.gt(balance)) { var message = 'Insufficient funds.' return this.props.dispatch(actions.displayWarning(message)) } - if (recipient.length !== 42) { - var message = 'Recipient address is the incorrect length.' + + if ((recipient.length !== 42 && !txData) || (!recipient && !txData)) { + var message = 'Recipient address is invalid.' return this.props.dispatch(actions.displayWarning(message)) } @@ -232,7 +233,6 @@ SendTransactionScreen.prototype.onSubmit = function(event) { value: '0x' + value.toString(16), } - var txData = document.querySelector('input[name="txData"]').value if (txData) txParams.data = txData this.props.dispatch(actions.signTx(txParams)) -- cgit v1.2.3 From c8deb355f7d1e4d1e10868a7d960fa460a7c51db Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 19 May 2016 12:06:45 -0700 Subject: Add address capitalization checksumming --- ui/app/account-detail.js | 5 +++-- ui/app/send.js | 2 +- ui/app/util.js | 16 +++++++++++++++- 3 files changed, 19 insertions(+), 4 deletions(-) (limited to 'ui') diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index 263e48441..489392473 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -13,6 +13,7 @@ const Identicon = require('./components/identicon') const EtherBalance = require('./components/eth-balance') const transactionList = require('./components/transaction-list') const ExportAccountView = require('./components/account-export') +const ethUtil = require('ethereumjs-util') module.exports = connect(mapStateToProps)(AccountDetailScreen) @@ -110,7 +111,7 @@ AccountDetailScreen.prototype.render = function() { }), h('i.fa.fa-clipboard.fa-md.cursor-pointer.color-orange', { - onClick: () => copyToClipboard(selected), + onClick: () => copyToClipboard(ethUtil.toChecksumAddress(selected)), }), ]), @@ -133,7 +134,7 @@ AccountDetailScreen.prototype.render = function() { }, 'SEND ETH'), ]), - + ]), // subview (tx history, pk export confirm) diff --git a/ui/app/send.js b/ui/app/send.js index 67dd15f81..044311b94 100644 --- a/ui/app/send.js +++ b/ui/app/send.js @@ -219,7 +219,7 @@ SendTransactionScreen.prototype.onSubmit = function() { return this.props.dispatch(actions.displayWarning(message)) } - if ((recipient.length !== 42 && !txData) || (!recipient && !txData)) { + if ((util.isValidAddress(recipient) && !txData) || (!recipient && !txData)) { var message = 'Recipient address is invalid.' return this.props.dispatch(actions.displayWarning(message)) } diff --git a/ui/app/util.js b/ui/app/util.js index 0f3f191aa..d8a0313ea 100644 --- a/ui/app/util.js +++ b/ui/app/util.js @@ -21,6 +21,8 @@ for (var currency in valueTable) { module.exports = { valuesFor: valuesFor, addressSummary: addressSummary, + isAllOneCase: isAllOneCase, + isValidAddress: isValidAddress, numericBalance: numericBalance, parseBalance: parseBalance, formatBalance: formatBalance, @@ -42,7 +44,19 @@ function valuesFor(obj) { } function addressSummary(address) { - return address ? address.slice(0,2+8)+'...'+address.slice(-4) : '...' + var checked = ethUtil.toChecksumAddress(address) + return checked ? checked.slice(0,2+8)+'...'+checked.slice(-4) : '...' +} + +function isValidAddress(address) { + var prefixed = ethUtil.addHexPrefix(address) + return isAllOneCase(prefixed) && ethUtil.isValidAddress(prefixed) || ethUtil.isValidChecksumAddress(prefixed) +} + +function isAllOneCase(address) { + var lower = address.toLowerCase() + var upper = address.toUpperCase() + return address === lower || address === upper } // Takes wei Hex, returns wei BN, even if input is null -- cgit v1.2.3 From 22a77b80411350bd844313b51ea58312940b9738 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 19 May 2016 14:21:35 -0700 Subject: Increase send value precision --- ui/app/send.js | 2 +- ui/app/util.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'ui') diff --git a/ui/app/send.js b/ui/app/send.js index 044311b94..ea9dd7c0c 100644 --- a/ui/app/send.js +++ b/ui/app/send.js @@ -219,7 +219,7 @@ SendTransactionScreen.prototype.onSubmit = function() { return this.props.dispatch(actions.displayWarning(message)) } - if ((util.isValidAddress(recipient) && !txData) || (!recipient && !txData)) { + if ((!util.isValidAddress(recipient) && !txData) || (!recipient && !txData)) { var message = 'Recipient address is invalid.' return this.props.dispatch(actions.displayWarning(message)) } diff --git a/ui/app/util.js b/ui/app/util.js index d8a0313ea..7597c2df8 100644 --- a/ui/app/util.js +++ b/ui/app/util.js @@ -120,9 +120,9 @@ function normalizeToWei(amount, currency) { return amount } -var multiple = new ethUtil.BN('1000', 10) +var multiple = new ethUtil.BN('10000', 10) function normalizeNumberToWei(n, currency) { - var enlarged = n * 1000 + var enlarged = n * 10000 var amount = new ethUtil.BN(String(enlarged), 10) return normalizeToWei(amount, currency).div(multiple) } -- cgit v1.2.3 From 60270de53d214edffad7b90356bbe06081a55443 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 19 May 2016 14:46:50 -0700 Subject: Add full precision to send tx value field. --- ui/app/send.js | 4 ++-- ui/app/util.js | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'ui') diff --git a/ui/app/send.js b/ui/app/send.js index ea9dd7c0c..926c3e29a 100644 --- a/ui/app/send.js +++ b/ui/app/send.js @@ -209,8 +209,8 @@ SendTransactionScreen.prototype.back = function() { SendTransactionScreen.prototype.onSubmit = function() { const recipient = document.querySelector('input[name="address"]').value - const inputAmount = parseFloat(document.querySelector('input[name="amount"]').value) - const value = util.normalizeNumberToWei(inputAmount, 'ether') + const input = document.querySelector('input[name="amount"]').value + const value = util.normalizeEthStringToWei(input) const txData = document.querySelector('input[name="txData"]').value const balance = this.props.balance diff --git a/ui/app/util.js b/ui/app/util.js index 7597c2df8..31c147877 100644 --- a/ui/app/util.js +++ b/ui/app/util.js @@ -31,6 +31,7 @@ module.exports = { ethToWei: ethToWei, weiToEth: weiToEth, normalizeToWei: normalizeToWei, + normalizeEthStringToWei: normalizeEthStringToWei, normalizeNumberToWei: normalizeNumberToWei, valueTable: valueTable, bnTable: bnTable, @@ -120,6 +121,20 @@ function normalizeToWei(amount, currency) { return amount } +function normalizeEthStringToWei(str) { + const parts = str.split('.') + let eth = new ethUtil.BN(parts[0], 10).mul(bnTable.wei) + if (parts[1]) { + var decimal = parts[1] + while(decimal.length < 18) { + decimal += '0' + } + const decimalBN = new ethUtil.BN(decimal, 10) + eth = eth.add(decimalBN) + } + return eth +} + var multiple = new ethUtil.BN('10000', 10) function normalizeNumberToWei(n, currency) { var enlarged = n * 10000 -- cgit v1.2.3 From 47540ad0b3c92df8061bb9c73159670ca2bc03ba Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 19 May 2016 16:14:16 -0700 Subject: Allow empty recipient fields on tx --- ui/app/send.js | 2 +- ui/app/util.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'ui') diff --git a/ui/app/send.js b/ui/app/send.js index 926c3e29a..ba4e5bfff 100644 --- a/ui/app/send.js +++ b/ui/app/send.js @@ -228,11 +228,11 @@ SendTransactionScreen.prototype.onSubmit = function() { this.props.dispatch(actions.showLoadingIndication()) var txParams = { - to: recipient, from: this.props.address, value: '0x' + value.toString(16), } + if (recipient) txParams.to = ethUtil.addHexPrefix(recipient) if (txData) txParams.data = txData this.props.dispatch(actions.signTx(txParams)) diff --git a/ui/app/util.js b/ui/app/util.js index 31c147877..81a029350 100644 --- a/ui/app/util.js +++ b/ui/app/util.js @@ -45,6 +45,7 @@ function valuesFor(obj) { } function addressSummary(address) { + if (!address) return '' var checked = ethUtil.toChecksumAddress(address) return checked ? checked.slice(0,2+8)+'...'+checked.slice(-4) : '...' } @@ -55,6 +56,7 @@ function isValidAddress(address) { } function isAllOneCase(address) { + if (!address) return true var lower = address.toLowerCase() var upper = address.toUpperCase() return address === lower || address === upper -- cgit v1.2.3 From d861c6ceca5ce64191a6922c7694a8c8607a52ca Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 19 May 2016 17:45:58 -0700 Subject: Add special rendering for contracts in transaction list --- ui/app/components/transaction-list.js | 53 ++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 14 deletions(-) (limited to 'ui') diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index 40a4593fe..5e9ec8b87 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -85,7 +85,7 @@ module.exports = function(transactions, network) { var txParams = transaction.txParams var date = formatDate(transaction.time) - return ( + return ( h('.transaction-list-item.flex-row.flex-space-between.cursor-pointer', { key: `tx-${transaction.hash}`, @@ -100,36 +100,61 @@ module.exports = function(transactions, network) { // large identicon h('.identicon-wrapper.flex-column.flex-center.select-none', [ - h(Identicon, { - diameter: 24, - address: txParams.to, - }), + identicon(txParams, transaction), ]), h('.flex-column', [ h('div', date), - h('div', { - style: { - fontSize: 'small', - color: '#ABA9AA', - }, - }, addressSummary(txParams.to)), + recipientField(txParams), ]), h(EtherBalance, { value: txParams.value, }), - ]) ) } +} + +function recipientField(txParams) { + if (txParams.to) { + return h('div', { + style: { + fontSize: 'small', + color: '#ABA9AA', + }, + }, addressSummary(txParams.to)) - } + } else { + + return h('div', { + style: { + fontSize: 'small', + color: '#ABA9AA', + }, + }, 'Contract Published') + } +} function formatDate(date){ return vreme.format(new Date(date), 'March 16 2014 14:30') -} \ No newline at end of file +} + +function identicon(txParams, transaction) { + if (txParams.to) { + return h(Identicon, { + diameter: 24, + address: txParams.to || transaction.hash, + }) + } else { + return h('i.fa.fa-file-text-o.fa-lg', { + style: { + width: '24px', + } + }) + } +} -- cgit v1.2.3 From ff20543c598ac1534adc531e030373b57e88c891 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 19 May 2016 19:00:14 -0700 Subject: Render failed tx in tx list --- ui/app/account-detail.js | 2 -- ui/app/components/transaction-list.js | 35 ++++++++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 9 deletions(-) (limited to 'ui') diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index 489392473..c708580c4 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -179,8 +179,6 @@ AccountDetailScreen.prototype.transactionList = function() { .filter(tx => tx.txParams.from === state.address) // only transactions that are on the current network .filter(tx => tx.txParams.metamaskNetworkId === state.networkVersion) - // only transactions that have a hash - .filter(tx => tx.hash) // sort by recency .sort((a, b) => b.time - a.time) diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index 5e9ec8b87..e912e36f6 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -57,10 +57,10 @@ module.exports = function(transactions, network) { ) - function renderTransaction(transaction){ + function renderTransaction(transaction, i){ var panelOpts = { - key: `tx-${transaction.hash}`, + key: `tx-${transaction.id + i}`, identiconKey: transaction.txParams.to, onClick: (event) => { var url = explorerLink(transaction.hash, parseInt(network)) @@ -88,7 +88,7 @@ module.exports = function(transactions, network) { return ( h('.transaction-list-item.flex-row.flex-space-between.cursor-pointer', { - key: `tx-${transaction.hash}`, + key: `tx-${transaction.id + i}`, onClick: (event) => { var url = explorerLink(transaction.hash, parseInt(network)) chrome.tabs.create({ url }) @@ -107,7 +107,7 @@ module.exports = function(transactions, network) { h('div', date), - recipientField(txParams), + recipientField(txParams, transaction), ]), @@ -120,14 +120,17 @@ module.exports = function(transactions, network) { } } -function recipientField(txParams) { +function recipientField(txParams, transaction) { if (txParams.to) { return h('div', { style: { fontSize: 'small', color: '#ABA9AA', }, - }, addressSummary(txParams.to)) + }, [ + addressSummary(txParams.to), + failIfFailed(transaction), + ]) } else { @@ -136,7 +139,11 @@ function recipientField(txParams) { fontSize: 'small', color: '#ABA9AA', }, - }, 'Contract Published') + },[ + 'Contract Published', + failIfFailed(transaction), + ]) + } } @@ -145,6 +152,14 @@ function formatDate(date){ } function identicon(txParams, transaction) { + if (transaction.status === 'rejected') { + return h('i.fa.fa-exclamation-triangle.fa-lg.error', { + style: { + width: '24px', + } + }) + } + if (txParams.to) { return h(Identicon, { diameter: 24, @@ -158,3 +173,9 @@ function identicon(txParams, transaction) { }) } } + +function failIfFailed(transaction) { + if (transaction.status === 'rejected') { + return h('span.error', ' (Failed)') + } +} -- cgit v1.2.3 From d71ee6927f3b380c324c62f0b557cadaad54b037 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 19 May 2016 19:06:06 -0700 Subject: Do not forward to null tx explorer page --- ui/app/components/transaction-list.js | 1 + 1 file changed, 1 insertion(+) (limited to 'ui') diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index e912e36f6..6cc35243f 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -63,6 +63,7 @@ module.exports = function(transactions, network) { key: `tx-${transaction.id + i}`, identiconKey: transaction.txParams.to, onClick: (event) => { + if (!transaction.hash) return var url = explorerLink(transaction.hash, parseInt(network)) chrome.tabs.create({ url }) }, -- cgit v1.2.3 From 2a6d6fcd158d0e108b50c51a6deb5405505eeda6 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 19 May 2016 19:11:53 -0700 Subject: Improve tx list style Tx list no longer enlarges on hover, and failed transactions no longer have hover styles nor direct to an explorer page. --- ui/app/components/transaction-list.js | 27 ++------------------------- ui/app/css/lib.css | 5 ++++- 2 files changed, 6 insertions(+), 26 deletions(-) (limited to 'ui') diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index 6cc35243f..f85aab70f 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -59,38 +59,15 @@ module.exports = function(transactions, network) { function renderTransaction(transaction, i){ - var panelOpts = { - key: `tx-${transaction.id + i}`, - identiconKey: transaction.txParams.to, - onClick: (event) => { - if (!transaction.hash) return - var url = explorerLink(transaction.hash, parseInt(network)) - chrome.tabs.create({ url }) - }, - attributes: [ - { - key: 'TIME', - value: formatDate(transaction.time), - }, - { - key: 'TO', - value: addressSummary(transaction.txParams.to), - }, - { - key: 'VALUE', - value: formatBalance(transaction.txParams.value), - }, - ] - } - var txParams = transaction.txParams var date = formatDate(transaction.time) return ( - h('.transaction-list-item.flex-row.flex-space-between.cursor-pointer', { + h(`.transaction-list-item.flex-row.flex-space-between${transaction.hash ? '.pointer' : ''}`, { key: `tx-${transaction.id + i}`, onClick: (event) => { + if (!transaction.hash) return var url = explorerLink(transaction.hash, parseInt(network)) chrome.tabs.create({ url }) }, diff --git a/ui/app/css/lib.css b/ui/app/css/lib.css index 60c56422d..1eba7465b 100644 --- a/ui/app/css/lib.css +++ b/ui/app/css/lib.css @@ -5,7 +5,7 @@ } .color-forest { - color: #0A5448; + color: #0A5448; } /* lib */ @@ -107,6 +107,9 @@ user-select: none; } +.pointer { + cursor: pointer; +} .cursor-pointer { cursor: pointer; transform-origin: center center; -- cgit v1.2.3 From 7d5aaaa5bd8a0f34694eb3e8ce5ba6bbecf03d71 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 20 May 2016 12:40:44 -0700 Subject: Add ability to add account to vault Scrolling to the bottom of the accounts page now reveals a downward-facing chevron button. Pressing this button shows loading indication, adds a new account to the identity vault, displays it in the list, and scrolls the list to the bottom of the page. Any number of accounts can be generated in this way, and the UX feels intuitive without having to overly explain how HD paths work. --- ui/app/accounts.js | 55 +++++++++++++++++++++++++++++++++++++++++++------- ui/app/actions.js | 15 ++++++++++++++ ui/app/css/lib.css | 4 ++++ ui/app/reducers/app.js | 6 ++++++ 4 files changed, 73 insertions(+), 7 deletions(-) (limited to 'ui') diff --git a/ui/app/accounts.js b/ui/app/accounts.js index e609e7424..0f3030829 100644 --- a/ui/app/accounts.js +++ b/ui/app/accounts.js @@ -9,6 +9,7 @@ const EtherBalance = require('./components/eth-balance') const valuesFor = require('./util').valuesFor const addressSummary = require('./util').addressSummary const formatBalance = require('./util').formatBalance +const findDOMNode = require('react-dom').findDOMNode module.exports = connect(mapStateToProps)(AccountsScreen) @@ -20,6 +21,7 @@ function mapStateToProps(state) { unconfTxs: state.metamask.unconfTxs, selectedAddress: state.metamask.selectedAddress, currentDomain: state.appState.currentDomain, + scrollToBottom: state.appState.scrollToBottom, } } @@ -36,13 +38,19 @@ AccountsScreen.prototype.render = function() { var actions = { onSelect: this.onSelect.bind(this), onShowDetail: this.onShowDetail.bind(this), + revealAccount: this.onRevealAccount.bind(this), } return ( - h('.accounts-section.flex-column.flex-grow', [ + h('.accounts-section.flex-grow', [ // subtitle and nav - h('.section-title.flex-column.flex-center', [ + h('.section-title.flex-center', [ + h('i.fa.fa-arrow-left.fa-lg.pointer.hover-white', { + onClick: (event) => { + state.dispatch(actions.goHome()) + } + }), h('h2.page-subtitle', 'Select Account'), ]), @@ -51,12 +59,32 @@ AccountsScreen.prototype.render = function() { // identity selection h('section.identity-section.flex-column', { style: { + height: '418px', overflowY: 'auto', overflowX: 'hidden', } }, - identityList.map(renderAccountPanel) - ), + [ + identityList.map(renderAccountPanel), + + h('hr.horizontal-line', {key: 'horizontal-line1'}), + h('div.footer.hover-white.pointer', { + key: 'reveal-account-bar', + onClick:() => { + actions.revealAccount() + }, + style: { + display: 'flex', + flex: '1 0 auto', + height: '40px', + paddint: '10px', + justifyContent: 'center', + alignItems: 'center', + } + }, [ + h('i.fa.fa-chevron-down.fa-lg', {key: ''}), + ]), + ]), unconfTxList.length ? ( @@ -70,10 +98,7 @@ AccountsScreen.prototype.render = function() { ) : ( null ), - - ]) - ) function renderAccountPanel(identity){ @@ -90,6 +115,7 @@ AccountsScreen.prototype.render = function() { return ( h('.accounts-list-option.flex-row.flex-space-between.cursor-pointer', { + key: `account-panel-${identity.address}`, style: { flex: '1 0 auto', background: isSelected ? 'white' : 'none', @@ -120,6 +146,17 @@ AccountsScreen.prototype.render = function() { } } +// If a new account was revealed, scroll to the bottom +AccountsScreen.prototype.componentDidUpdate = function(){ + const scrollToBottom = this.props.scrollToBottom + + if (scrollToBottom) { + var container = findDOMNode(this) + var scrollable = container.querySelector('.identity-section') + scrollable.scrollTop = scrollable.scrollHeight + } +} + AccountsScreen.prototype.navigateToConfTx = function(){ event.stopPropagation() this.props.dispatch(actions.showConfTxPage()) @@ -136,3 +173,7 @@ AccountsScreen.prototype.onShowDetail = function(address, event){ event.stopPropagation() this.props.dispatch(actions.showAccountDetail(address)) } + +AccountsScreen.prototype.onRevealAccount = function() { + this.props.dispatch(actions.revealAccount()) +} diff --git a/ui/app/actions.js b/ui/app/actions.js index ee5e417d4..5d6f503e2 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -48,6 +48,8 @@ var actions = { SHOW_ACCOUNTS_PAGE: 'SHOW_ACCOUNTS_PAGE', SHOW_CONF_TX_PAGE: 'SHOW_CONF_TX_PAGE', SHOW_CONF_MSG_PAGE: 'SHOW_CONF_MSG_PAGE', + REVEAL_ACCOUNT: 'REVEAL_ACCOUNT', + revealAccount: revealAccount, // account detail screen SHOW_SEND_PAGE: 'SHOW_SEND_PAGE', showSendPage: showSendPage, @@ -175,6 +177,19 @@ function setSelectedAddress(address) { } } +function revealAccount() { + return (dispatch) => { + dispatch(this.showLoadingIndication()) + _accountManager.revealAccount((err) => { + dispatch(this.hideLoadingIndication()) + if (err) return dispatch(this.displayWarning(err.message)) + dispatch({ + type: this.REVEAL_ACCOUNT, + }) + }) + } +} + function signMsg(msgData) { return (dispatch) => { dispatch(this.showLoadingIndication()) diff --git a/ui/app/css/lib.css b/ui/app/css/lib.css index 1eba7465b..97ff02c46 100644 --- a/ui/app/css/lib.css +++ b/ui/app/css/lib.css @@ -107,6 +107,10 @@ user-select: none; } +.hover-white:hover { + background: white; +} + .pointer { cursor: pointer; } diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index 1c0154cd5..a29a8f79c 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -191,6 +191,12 @@ function reduceApp(state, action) { transForward: true, isLoading: false, warning: null, + scrollToBottom: false, + }) + + case actions.REVEAL_ACCOUNT: + return extend(appState, { + scrollToBottom: true, }) case actions.SHOW_CONF_TX_PAGE: -- cgit v1.2.3 From 18304fa46c9c172336e5402e273d8078c1e16db7 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 20 May 2016 12:49:33 -0700 Subject: Made account list hover styles more consistent --- ui/app/accounts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ui') diff --git a/ui/app/accounts.js b/ui/app/accounts.js index 0f3030829..45594f3c0 100644 --- a/ui/app/accounts.js +++ b/ui/app/accounts.js @@ -46,7 +46,7 @@ AccountsScreen.prototype.render = function() { // subtitle and nav h('.section-title.flex-center', [ - h('i.fa.fa-arrow-left.fa-lg.pointer.hover-white', { + h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { onClick: (event) => { state.dispatch(actions.goHome()) } @@ -114,7 +114,7 @@ AccountsScreen.prototype.render = function() { }) return ( - h('.accounts-list-option.flex-row.flex-space-between.cursor-pointer', { + h('.accounts-list-option.flex-row.flex-space-between.pointer.hover-white', { key: `account-panel-${identity.address}`, style: { flex: '1 0 auto', -- cgit v1.2.3 From 24fc5f9ea3a8cddfbf3993bdf0b18187a0787a64 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 20 May 2016 14:11:59 -0700 Subject: Fix up accounts list Fix hover styles to not grow. Fix back button on accounts list. --- ui/app/accounts.js | 13 ++++++++----- ui/app/css/index.css | 14 ++++++-------- ui/app/css/lib.css | 8 ++++---- 3 files changed, 18 insertions(+), 17 deletions(-) (limited to 'ui') diff --git a/ui/app/accounts.js b/ui/app/accounts.js index 45594f3c0..dbf4ee0fa 100644 --- a/ui/app/accounts.js +++ b/ui/app/accounts.js @@ -39,6 +39,7 @@ AccountsScreen.prototype.render = function() { onSelect: this.onSelect.bind(this), onShowDetail: this.onShowDetail.bind(this), revealAccount: this.onRevealAccount.bind(this), + goHome: this.goHome.bind(this), } return ( @@ -47,9 +48,7 @@ AccountsScreen.prototype.render = function() { // subtitle and nav h('.section-title.flex-center', [ h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { - onClick: (event) => { - state.dispatch(actions.goHome()) - } + onClick: actions.goHome, }), h('h2.page-subtitle', 'Select Account'), ]), @@ -112,13 +111,13 @@ AccountsScreen.prototype.render = function() { isSelected: false, isFauceting: isFauceting, }) + const selectedClass = isSelected ? '.selected' : '' return ( - h('.accounts-list-option.flex-row.flex-space-between.pointer.hover-white', { + h(`.accounts-list-option.flex-row.flex-space-between.pointer.hover-white${selectedClass}`, { key: `account-panel-${identity.address}`, style: { flex: '1 0 auto', - background: isSelected ? 'white' : 'none', }, onClick: (event) => actions.onShowDetail(identity.address, event), }, [ @@ -177,3 +176,7 @@ AccountsScreen.prototype.onShowDetail = function(address, event){ AccountsScreen.prototype.onRevealAccount = function() { this.props.dispatch(actions.revealAccount()) } + +AccountsScreen.prototype.goHome = function() { + this.props.dispatch(actions.goHome()) +} diff --git a/ui/app/css/index.css b/ui/app/css/index.css index 060ddce91..d6d1f91ac 100644 --- a/ui/app/css/index.css +++ b/ui/app/css/index.css @@ -274,10 +274,6 @@ input.large-input { height: 120px; } -.accounts-list-option:hover { - transform: scale(1.1); -} - .accounts-list-option .identicon-wrapper { width: 100px; } @@ -334,9 +330,6 @@ input.large-input { border-bottom: 1px solid #B1B1B1; cursor: pointer; } -.identity-section .identity-panel:hover { - background: #F9F9F9; -} .identity-section .identity-panel.selected { background: white; @@ -347,6 +340,11 @@ input.large-input { border-color: orange; } +.identity-section .accounts-list-option:hover, +.identity-section .accounts-list-option.selected { + background:white; +} + /* account detail screen */ .account-detail-section { @@ -393,4 +391,4 @@ input.large-input { .ether-balance-label { color: #ABA9AA; -} \ No newline at end of file +} diff --git a/ui/app/css/lib.css b/ui/app/css/lib.css index 97ff02c46..d9719b1e3 100644 --- a/ui/app/css/lib.css +++ b/ui/app/css/lib.css @@ -107,10 +107,6 @@ user-select: none; } -.hover-white:hover { - background: white; -} - .pointer { cursor: pointer; } @@ -166,3 +162,7 @@ hr.horizontal-line { margin: 1em 0; padding: 0; } + +.hover-white:hover { + background: white; +} -- cgit v1.2.3 From 95a3cfe3fcffee2ffabd4cf71e568ae94693b10f Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 20 May 2016 16:18:54 -0700 Subject: Added ability to nickname wallets locally The changes are persisted to localstorage, so they cannot be restored on a new computer, but for right now it's a nice organizational feature. --- ui/app/account-detail.js | 40 ++++++++++++++++++---------- ui/app/actions.js | 18 +++++++++++++ ui/app/components/editable-label.js | 52 +++++++++++++++++++++++++++++++++++++ ui/app/reducers/metamask.js | 8 ++++++ 4 files changed, 104 insertions(+), 14 deletions(-) create mode 100644 ui/app/components/editable-label.js (limited to 'ui') diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index c708580c4..bae44ec85 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -8,12 +8,12 @@ const actions = require('./actions') const addressSummary = require('./util').addressSummary const ReactCSSTransitionGroup = require('react-addons-css-transition-group') -const AccountPanel = require('./components/account-panel') const Identicon = require('./components/identicon') const EtherBalance = require('./components/eth-balance') const transactionList = require('./components/transaction-list') const ExportAccountView = require('./components/account-export') const ethUtil = require('ethereumjs-util') +const EditableLabel = require('./components/editable-label') module.exports = connect(mapStateToProps)(AccountDetailScreen) @@ -34,12 +34,12 @@ function AccountDetailScreen() { } AccountDetailScreen.prototype.render = function() { - var state = this.props - var selected = state.address || Object.keys(state.accounts)[0] - var identity = state.identities[selected] - var account = state.accounts[selected] - var accountDetail = state.accountDetail - var transactions = state.transactions + var props = this.props + var selected = props.address || Object.keys(props.accounts)[0] + var identity = props.identities[selected] + var account = props.accounts[selected] + var accountDetail = props.accountDetail + var transactions = props.transactions return ( @@ -78,16 +78,28 @@ AccountDetailScreen.prototype.render = function() { h('i.fa.fa-users.fa-lg.cursor-pointer.color-orange', { onClick: this.navigateToAccounts.bind(this), }), - ]), - // account label - h('h2.font-medium.color-forest.flex-center', { + h('.flex-center', { style: { - paddingTop: 8, - marginBottom: 32, - }, - }, identity && identity.name), + height: '62px', + paddingTop: '8px', + } + }, [ + h(EditableLabel, { + textValue: identity ? identity.name : '', + state: { + isEditingLabel: false, + }, + saveText: (text) => { + props.dispatch(actions.saveAccountLabel(selected, text)) + }, + }, [ + + // What is shown when not editing: + h('h2.font-medium.color-forest', identity && identity.name) + ]), + ]), // address and getter actions h('.flex-row.flex-space-between', { diff --git a/ui/app/actions.js b/ui/app/actions.js index 5d6f503e2..9ff05c460 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -59,6 +59,8 @@ var actions = { exportAccount: exportAccount, SHOW_PRIVATE_KEY: 'SHOW_PRIVATE_KEY', showPrivateKey: showPrivateKey, + SAVE_ACCOUNT_LABEL: 'SAVE_ACCOUNT_LABEL', + saveAccountLabel: saveAccountLabel, // tx conf screen COMPLETED_TX: 'COMPLETED_TX', TRANSACTION_ERROR: 'TRANSACTION_ERROR', @@ -481,6 +483,22 @@ function showPrivateKey(key) { } } +function saveAccountLabel(account, label) { + return (dispatch) => { + dispatch(this.showLoadingIndication()) + _accountManager.saveAccountLabel(account, label, (err) => { + dispatch(this.hideLoadingIndication()) + if (err) { + return dispatch(this.showWarning(err.message)) + } + dispatch({ + type: this.SAVE_ACCOUNT_LABEL, + value: { account, label }, + }) + }) + } +} + function showSendPage() { return { type: this.SHOW_SEND_PAGE, diff --git a/ui/app/components/editable-label.js b/ui/app/components/editable-label.js new file mode 100644 index 000000000..20e24a9c7 --- /dev/null +++ b/ui/app/components/editable-label.js @@ -0,0 +1,52 @@ +const Component = require('react').Component +const h = require('react-hyperscript') +const inherits = require('util').inherits +const findDOMNode = require('react-dom').findDOMNode + +module.exports = EditableLabel + + +inherits(EditableLabel, Component) +function EditableLabel() { + Component.call(this) +} + +EditableLabel.prototype.render = function() { + const props = this.props + let state = this.state + + if (state && state.isEditingLabel) { + + return h('div.editable-label', [ + h('input', { + defaultValue: props.textValue, + onKeyPress:(event) => { + this.saveIfEnter(event) + }, + }), + h('button', { + onClick:() => this.saveText(), + }, 'Save') + ]) + + } else { + return h('div', { + onClick:(event) => { + this.setState({ isEditingLabel: true }) + }, + }, this.props.children) + } +} + +EditableLabel.prototype.saveIfEnter = function(event) { + if (event.key === 'Enter') { + this.saveText() + } +} + +EditableLabel.prototype.saveText = function() { + var container = findDOMNode(this) + var text = container.querySelector('.editable-label input').value + this.props.saveText(text) + this.setState({ isEditingLabel: false, textLabel: text }) +} diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index 8628e84d2..a45327189 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -95,6 +95,14 @@ function reduceMetamask(state, action) { delete newState.seedWords return newState + case actions.SAVE_ACCOUNT_LABEL: + const account = action.value.account + const name = action.value.label + var id = {} + id[account] = extend(metamaskState.identities[account], { name }) + var identities = extend(metamaskState.identities, id) + return extend(metamaskState, { identities }) + default: return metamaskState -- cgit v1.2.3 From 41df7bb8f622e1fdd9e1bb2b1687347e5f359c47 Mon Sep 17 00:00:00 2001 From: kumavis Date: Sun, 22 May 2016 18:01:47 -0700 Subject: bugfix - exportAccount - fix copyToClipboard --- ui/app/components/account-export.js | 1 + 1 file changed, 1 insertion(+) (limited to 'ui') diff --git a/ui/app/components/account-export.js b/ui/app/components/account-export.js index bdfa4c15f..eab9baf65 100644 --- a/ui/app/components/account-export.js +++ b/ui/app/components/account-export.js @@ -1,6 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits +const copyToClipboard = require('copy-to-clipboard') const actions = require('../actions') module.exports = ExportAccountView -- cgit v1.2.3