diff options
Diffstat (limited to 'ui/app')
-rw-r--r-- | ui/app/account-detail.js | 146 | ||||
-rw-r--r-- | ui/app/accounts.js | 45 | ||||
-rw-r--r-- | ui/app/actions.js | 35 | ||||
-rw-r--r-- | ui/app/app.js | 152 | ||||
-rw-r--r-- | ui/app/components/account-export.js | 35 | ||||
-rw-r--r-- | ui/app/components/account-panel.js | 2 | ||||
-rw-r--r-- | ui/app/components/identicon.js | 55 | ||||
-rw-r--r-- | ui/app/components/panel.js | 22 | ||||
-rw-r--r-- | ui/app/components/transaction-list.js | 98 | ||||
-rw-r--r-- | ui/app/conf-tx.js | 3 | ||||
-rw-r--r-- | ui/app/css/fonts.css | 46 | ||||
-rw-r--r-- | ui/app/css/index.css | 274 | ||||
-rw-r--r-- | ui/app/css/lib.css | 37 | ||||
-rw-r--r-- | ui/app/css/transitions.css | 48 | ||||
-rw-r--r-- | ui/app/first-time/init-menu.js | 38 | ||||
-rw-r--r-- | ui/app/loading.js | 3 | ||||
-rw-r--r-- | ui/app/reducers/app.js | 9 | ||||
-rw-r--r-- | ui/app/reducers/metamask.js | 17 | ||||
-rw-r--r-- | ui/app/send.js | 5 | ||||
-rw-r--r-- | ui/app/unlock.js | 18 |
20 files changed, 605 insertions, 483 deletions
diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index 2775e24fb..00d40a9ee 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') @@ -39,66 +42,106 @@ AccountDetailScreen.prototype.render = function() { return ( - h('.account-detail-section.flex-column.flex-grow', { - style: { - width: '330px', - }, - }, [ - - // subtitle and nav - h('.section-title.flex-row.flex-center', [ - h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { - 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('.account-detail-section.flex-column.flex-grow', [ - h('div', { + // identicon, label, balance, etc + h('.account-data-subsection.flex-column.flex-grow', { style: { - display: 'flex', - } + margin: '0 20px', + }, }, [ - h('button', { - onClick: () => { - copyToClipboard(identity.address) + // header - identicon + nav + h('.flex-row.flex-space-between', { + style: { + marginTop: 28, }, - }, 'COPY ADDR'), - - h('button', { - onClick: () => { - this.props.dispatch(actions.showSendPage()) + }, [ + + // 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: selected, + }), + ]), + + // 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: 32, }, - }, 'SEND'), + }, identity && identity.name), - h('button', { - onClick: () => { - this.requestAccountExport(identity.address) + // address and getter actions + h('.flex-row.flex-space-between', { + style: { + marginBottom: 16, }, - }, 'EXPORT'), + }, [ + + h('div', { + style: { + lineHeight: '16px', + }, + }, addressSummary(selected)), + + h('i.fa.fa-download.fa-md.cursor-pointer.color-orange', { + onClick: () => this.requestAccountExport(selected), + }), + + 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(selected), + }), + + ]), + + // 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'), + + ]), + ]), + // subview (tx history, pk export confirm) h(ReactCSSTransitionGroup, { - transitionName: "main", + className: 'css-transition-group', + transitionName: 'main', transitionEnterTimeout: 300, transitionLeaveTimeout: 300, }, [ this.subview(), ]), - // transaction table - /* - h('section.flex-column', [ - h('span', 'your transaction history will go here.'), - ]), - */ + ]) ) } @@ -126,10 +169,17 @@ AccountDetailScreen.prototype.transactionList = function() { var state = this.props var transactions = state.transactions - return transactionList(transactions - .filter(tx => tx.txParams.from === state.address) - .filter(tx => tx.txParams.metamaskNetworkId === state.networkVersion) - .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/accounts.js b/ui/app/accounts.js index 16f37dc67..18ba1e67d 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('./components/identicon') 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,33 @@ AccountsScreen.prototype.render = function() { isSelected: false, isFauceting: isFauceting, }) - return h(AccountPanel, componentState) + + return ( + h('.accounts-list-option.flex-row.flex-space-between.cursor-pointer', { + style: { + flex: '1 0 auto', + background: isSelected ? 'white' : 'none', + }, + onClick: (event) => actions.onShowDetail(identity.address, event), + }, [ + + h('.identicon-wrapper.flex-column.flex-center.select-none', [ + h(Identicon, { + address: identity.address + }), + ]), + + // 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/actions.js b/ui/app/actions.js index dbcf3e577..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, + }) }) } } @@ -312,19 +315,19 @@ 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) => { + console.log('Seed word cache cleared. ' + account) + dispatch(this.showAccountDetail(account)) }) } } diff --git a/ui/app/app.js b/ui/app/app.js index a4ce40881..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,16 +58,12 @@ App.prototype.render = function() { // Windows was showing a vertical scroll bar: overflow: 'hidden', } - }, - [ + }, [ h(LoadingIndicator), - // top row - h('.app-header.flex-column.flex-center', { - }, [ - h('h1', 'MetaMask'), - ]), + // app bar + this.renderAppBar(), // panel content h('.app-primary.flex-grow' + (transForward ? '.from-right' : '.from-left'), { @@ -86,7 +73,8 @@ App.prototype.render = function() { } }, [ h(ReactCSSTransitionGroup, { - transitionName: "main", + className: 'css-transition-group', + transitionName: 'main', transitionEnterTimeout: 300, transitionLeaveTimeout: 300, }, [ @@ -95,65 +83,85 @@ 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()) - }, - }), - - // toggle - onOffToggle({ - toggleMetamaskActive: this.toggleMetamaskActive.bind(this), - isUnlocked: state.isUnlocked, - }), + // 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({ + // 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()) } + // }), + // ]), - // help - h('i.fa.fa-question.fa-lg.cursor-pointer', { - style: { - opacity: state.isUnlocked ? '1.0' : '0.0', - }, - onClick() { state.dispatch(actions.showInfoPage()) } - }), - ]), ]) ) } -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){ 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) { @@ -167,6 +175,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'}) @@ -181,9 +192,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'}) @@ -214,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/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) { 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..ef625cc62 --- /dev/null +++ b/ui/app/components/identicon.js @@ -0,0 +1,55 @@ +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.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: diameter, + width: diameter, + borderRadius: diameter / 2, + overflow: 'hidden', + }, + }) + ) +} + +IdenticonComponent.prototype.componentDidMount = function(){ + var state = this.props + var address = state.address + + if (!address) return + var numericRepresentation = jsNumberForAddress(address) + + var container = findDOMNode(this) + // jazzicon with hack to fix inline svg error + 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') + img.src = dataUri + container.appendChild(img) +} + +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..5d72d6068 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 @@ -18,26 +18,22 @@ Panel.prototype.render = function() { var identity = state.identity || {} var account = state.account || {} var isFauceting = state.isFauceting + var style = { + flex: '1 0 auto', + } - var identicon = new Identicon(state.identiconKey, 46).toString() - var identiconSrc = `data:image/png;base64,${identicon}` + if (state.onClick) style.cursor = 'pointer' return ( h('.identity-panel.flex-row.flex-space-between', { - style: { - flex: '1 0 auto', - }, + style, onClick: state.onClick, }, [ // 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), ]), @@ -49,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 3e153aecf..2a1442b8c 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -1,55 +1,77 @@ 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') 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', + color: '#AEAEAE', + }, + }, [ + 'Transactions', + ]), + + h('.tx-list', { style: { overflowY: 'auto', - height: '180px', + height: '204px', + padding: '0 20px', textAlign: 'center', }, - }, - - [ + }, ( - transactions.map((transaction) => { - console.dir(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: 'TIME', + value: formatDate(transaction.time), + }, + { + key: 'TO', + value: addressSummary(transaction.txParams.to), + }, + { + key: 'VALUE', + value: formatBalance(transaction.txParams.value), + }, + ] + } + + return h(Panel, panelOpts) +} + +function formatDate(date){ + return vreme.format(new Date(date), 'March 16 2014 14:30') +}
\ 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/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..860491a3d 100644 --- a/ui/app/css/index.css +++ b/ui/app/css/index.css @@ -14,11 +14,15 @@ 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; + background: #F7F7F7; +} + +input:focus { + outline: none; } #app-content { @@ -29,18 +33,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); } @@ -48,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; @@ -66,7 +60,7 @@ input, textarea { outline: none; border: 1px solid #F5A623; background: #FAF6F0; -} +}*/ a { text-decoration: none; @@ -85,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; @@ -98,23 +103,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 { + } .app-footer { @@ -216,33 +223,63 @@ 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 */ .accounts-section { - margin: 0 20px; + margin: 0 0px; +} + +.accounts-section .horizontal-line { + margin: 0px 18px; +} + +.accounts-list-option { + height: 120px; +} + +.accounts-list-option:hover { + transform: scale(1.1); } -.current-domain-panel { - border: 1px solid #B7B7B7; +.accounts-list-option .identicon-wrapper { + width: 100px; } .unconftx-link { @@ -289,8 +326,7 @@ app sections /* accounts screen */ .identity-section { - border: 2px solid #4D4D4D; - margin: 0; + } .identity-section .identity-panel { @@ -314,7 +350,7 @@ app sections /* account detail screen */ .account-detail-section { - margin: 0 20px; + } /* tx confirm */ @@ -333,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 b6b26402b..c366a5d5f 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: #0A5448; +} + /* lib */ .full-width { @@ -47,6 +57,10 @@ flex: none; } +.flex-basis-auto { + flex-basis: auto; +} + .flex-grow { flex: 1 1 auto; } @@ -86,7 +100,7 @@ } .select-none { - cursor: default; + cursor: inherit; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; @@ -105,6 +119,10 @@ transform: scale(0.95); } +.cursor-disabled { + cursor: not-allowed; +} + .margin-bottom-sml { margin-bottom: 20px; } @@ -121,10 +139,18 @@ font-weight: bold; } +.text-transform-uppercase { + text-transform: uppercase; +} + .font-small { font-size: 12px; } +.font-medium { + font-size: 1.2em; +} + /* Send Screen */ .send-screen { margin: 0 20px; @@ -141,3 +167,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; +} 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); } diff --git a/ui/app/first-time/init-menu.js b/ui/app/first-time/init-menu.js index 11b01a88b..2d54e7e19 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() @@ -55,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'), @@ -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/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, }, [ 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..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: @@ -69,18 +70,30 @@ 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: - return extend(metamaskState, { + case actions.SHOW_ACCOUNT_DETAIL: + const newState = extend(metamaskState, { isUnlocked: true, isInitialized: true, + selectedAccount: action.value, + selectedAddress: action.value, }) + delete newState.seedWords + return newState default: return metamaskState 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', 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), }), |