aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app
diff options
context:
space:
mode:
Diffstat (limited to 'ui/app')
-rw-r--r--ui/app/account-detail.js146
-rw-r--r--ui/app/accounts.js45
-rw-r--r--ui/app/actions.js35
-rw-r--r--ui/app/app.js152
-rw-r--r--ui/app/components/account-export.js35
-rw-r--r--ui/app/components/account-panel.js2
-rw-r--r--ui/app/components/identicon.js55
-rw-r--r--ui/app/components/panel.js22
-rw-r--r--ui/app/components/transaction-list.js98
-rw-r--r--ui/app/conf-tx.js3
-rw-r--r--ui/app/css/fonts.css46
-rw-r--r--ui/app/css/index.css274
-rw-r--r--ui/app/css/lib.css37
-rw-r--r--ui/app/css/transitions.css48
-rw-r--r--ui/app/first-time/init-menu.js38
-rw-r--r--ui/app/loading.js3
-rw-r--r--ui/app/reducers/app.js9
-rw-r--r--ui/app/reducers/metamask.js17
-rw-r--r--ui/app/send.js5
-rw-r--r--ui/app/unlock.js18
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),
}),