aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app
diff options
context:
space:
mode:
Diffstat (limited to 'ui/app')
-rw-r--r--ui/app/account-detail.js120
-rw-r--r--ui/app/accounts/account-list-item.js91
-rw-r--r--ui/app/accounts/index.js164
-rw-r--r--ui/app/add-token.js2
-rw-r--r--ui/app/app.js272
-rw-r--r--ui/app/components/account-dropdowns.js227
-rw-r--r--ui/app/components/account-info-link.js41
-rw-r--r--ui/app/components/drop-menu-item.js59
-rw-r--r--ui/app/components/dropdown.js89
-rw-r--r--ui/app/components/editable-label.js7
-rw-r--r--ui/app/components/pending-tx.js2
-rw-r--r--ui/app/components/transaction-list.js8
-rw-r--r--ui/app/css/index.css15
-rw-r--r--ui/app/css/lib.css4
-rw-r--r--ui/app/info.js10
-rw-r--r--ui/app/keychains/hd/create-vault-complete.js2
16 files changed, 537 insertions, 576 deletions
diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js
index bed05a7fb..18c867153 100644
--- a/ui/app/account-detail.js
+++ b/ui/app/account-detail.js
@@ -3,21 +3,18 @@ const extend = require('xtend')
const Component = require('react').Component
const h = require('react-hyperscript')
const connect = require('react-redux').connect
-const CopyButton = require('./components/copyButton')
-const AccountInfoLink = require('./components/account-info-link')
const actions = require('./actions')
const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
const valuesFor = require('./util').valuesFor
-
const Identicon = require('./components/identicon')
const EthBalance = 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')
-const Tooltip = require('./components/tooltip')
const TabBar = require('./components/tab-bar')
const TokenList = require('./components/token-list')
+const AccountDropdowns = require('./components/account-dropdowns').AccountDropdowns
module.exports = connect(mapStateToProps)(AccountDetailScreen)
@@ -54,12 +51,18 @@ AccountDetailScreen.prototype.render = function () {
return (
- h('.account-detail-section', [
+ h('.account-detail-section', {
+ style: {
+ height: '100%',
+ maxWidth: '850px',
+ },
+ }, [
// identicon, label, balance, etc
h('.account-data-subsection', {
style: {
margin: '0 20px',
+ flex: '1 0 auto',
},
}, [
@@ -84,6 +87,7 @@ AccountDetailScreen.prototype.render = function () {
style: {
lineHeight: '10px',
marginLeft: '15px',
+ width: '100%',
},
}, [
h(EditableLabel, {
@@ -98,7 +102,42 @@ AccountDetailScreen.prototype.render = function () {
// What is shown when not editing + edit text:
h('label.editing-label', [h('.edit-text', 'edit')]),
- h('h2.font-medium.color-forest', {name: 'edit'}, identity && identity.name),
+ h(
+ 'div',
+ {
+ style: {
+ display: 'flex',
+ justifyContent: 'flex-start',
+ alignItems: 'center',
+ },
+ },
+ [
+ h(
+ 'h2.font-medium.color-forest',
+ {
+ name: 'edit',
+ style: {
+ },
+ },
+ [
+ identity && identity.name,
+ ]
+ ),
+ h(
+ AccountDropdowns,
+ {
+ style: {
+ marginRight: '8px',
+ marginLeft: 'auto',
+ cursor: 'pointer',
+ },
+ selected,
+ network,
+ identities: props.identities,
+ },
+ ),
+ ]
+ ),
]),
h('.flex-row', {
style: {
@@ -124,56 +163,6 @@ AccountDetailScreen.prototype.render = function () {
color: '#AEAEAE',
},
}, checksumAddress),
-
- // copy and export
-
- h('.flex-row', {
- style: {
- justifyContent: 'flex-end',
- },
- }, [
-
- h(AccountInfoLink, { selected, network }),
-
- h(CopyButton, {
- value: checksumAddress,
- }),
-
- h(Tooltip, {
- title: 'QR Code',
- }, [
- h('i.fa.fa-qrcode.pointer.pop-hover', {
- onClick: () => props.dispatch(actions.showQrView(selected, identity ? identity.name : '')),
- style: {
- fontSize: '18px',
- position: 'relative',
- color: 'rgb(247, 134, 28)',
- top: '5px',
- marginLeft: '3px',
- marginRight: '3px',
- },
- }),
- ]),
-
- h(Tooltip, {
- title: 'Export Private Key',
- }, [
- h('div', {
- style: {
- display: 'flex',
- alignItems: 'center',
- },
- }, [
- h('img.cursor-pointer.color-orange', {
- src: 'images/key-32.png',
- onClick: () => this.requestAccountExport(selected),
- style: {
- height: '19px',
- },
- }),
- ]),
- ]),
- ]),
]),
// account ballence
@@ -197,14 +186,11 @@ AccountDetailScreen.prototype.render = function () {
},
}),
+ h('.flex-grow'),
+
h('button', {
onClick: () => props.dispatch(actions.buyEthView(selected)),
- style: {
- marginBottom: '20px',
- marginRight: '8px',
- position: 'absolute',
- left: '219px',
- },
+ style: { marginRight: '10px' },
}, 'BUY'),
h('button', {
@@ -254,7 +240,11 @@ AccountDetailScreen.prototype.subview = function () {
AccountDetailScreen.prototype.tabSections = function () {
const { currentAccountTab } = this.props
- return h('section.tabSection', [
+ return h('section.tabSection', {
+ style: {
+ height: '100%',
+ },
+ }, [
h(TabBar, {
tabs: [
@@ -305,7 +295,3 @@ AccountDetailScreen.prototype.transactionList = function () {
},
})
}
-
-AccountDetailScreen.prototype.requestAccountExport = function () {
- this.props.dispatch(actions.requestExportAccount())
-}
diff --git a/ui/app/accounts/account-list-item.js b/ui/app/accounts/account-list-item.js
deleted file mode 100644
index 10a0b6cc7..000000000
--- a/ui/app/accounts/account-list-item.js
+++ /dev/null
@@ -1,91 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const ethUtil = require('ethereumjs-util')
-
-const EthBalance = require('../components/eth-balance')
-const CopyButton = require('../components/copyButton')
-const Identicon = require('../components/identicon')
-
-module.exports = AccountListItem
-
-inherits(AccountListItem, Component)
-function AccountListItem () {
- Component.call(this)
-}
-
-AccountListItem.prototype.render = function () {
- const { identity, selectedAddress, accounts, onShowDetail,
- conversionRate, currentCurrency } = this.props
-
- const checksumAddress = identity && identity.address && ethUtil.toChecksumAddress(identity.address)
- const isSelected = selectedAddress === identity.address
- const account = accounts[identity.address]
- const selectedClass = isSelected ? '.selected' : ''
-
- return (
- h(`.accounts-list-option.flex-row.flex-space-between.pointer.hover-white${selectedClass}`, {
- key: `account-panel-${identity.address}`,
- onClick: (event) => onShowDetail(identity.address, event),
- }, [
-
- h('.identicon-wrapper.flex-column.flex-center.select-none', [
- this.pendingOrNot(),
- this.indicateIfLoose(),
- h(Identicon, {
- address: identity.address,
- imageify: true,
- }),
- ]),
-
- // account address, balance
- h('.identity-data.flex-column.flex-justify-center.flex-grow.select-none', {
- style: {
- width: '200px',
- },
- }, [
- h('span', identity.name),
- h('span.font-small', {
- style: {
- overflow: 'hidden',
- textOverflow: 'ellipsis',
- },
- }, checksumAddress),
- h(EthBalance, {
- value: account && account.balance,
- currentCurrency,
- conversionRate,
- style: {
- lineHeight: '7px',
- marginTop: '10px',
- },
- }),
- ]),
-
- // copy button
- h('.identity-copy.flex-column', {
- style: {
- margin: '0 20px',
- },
- }, [
- h(CopyButton, {
- value: checksumAddress,
- }),
- ]),
- ])
- )
-}
-
-AccountListItem.prototype.indicateIfLoose = function () {
- try { // Sometimes keyrings aren't loaded yet:
- const type = this.props.keyring.type
- const isLoose = type !== 'HD Key Tree'
- return isLoose ? h('.keyring-label', 'LOOSE') : null
- } catch (e) { return }
-}
-
-AccountListItem.prototype.pendingOrNot = function () {
- const pending = this.props.pending
- if (pending.length === 0) return null
- return h('.pending-dot', pending.length)
-}
diff --git a/ui/app/accounts/index.js b/ui/app/accounts/index.js
deleted file mode 100644
index ac2615cd7..000000000
--- a/ui/app/accounts/index.js
+++ /dev/null
@@ -1,164 +0,0 @@
-const inherits = require('util').inherits
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const connect = require('react-redux').connect
-const actions = require('../actions')
-const valuesFor = require('../util').valuesFor
-const findDOMNode = require('react-dom').findDOMNode
-const AccountListItem = require('./account-list-item')
-
-module.exports = connect(mapStateToProps)(AccountsScreen)
-
-function mapStateToProps (state) {
- const pendingTxs = valuesFor(state.metamask.unapprovedTxs)
- .filter(txMeta => txMeta.metamaskNetworkId === state.metamask.network)
- const pendingMsgs = valuesFor(state.metamask.unapprovedMsgs)
- const pending = pendingTxs.concat(pendingMsgs)
-
- return {
- accounts: state.metamask.accounts,
- identities: state.metamask.identities,
- unapprovedTxs: state.metamask.unapprovedTxs,
- selectedAddress: state.metamask.selectedAddress,
- scrollToBottom: state.appState.scrollToBottom,
- pending,
- keyrings: state.metamask.keyrings,
- conversionRate: state.metamask.conversionRate,
- currentCurrency: state.metamask.currentCurrency,
- }
-}
-
-inherits(AccountsScreen, Component)
-function AccountsScreen () {
- Component.call(this)
-}
-
-AccountsScreen.prototype.render = function () {
- const props = this.props
- const { keyrings, conversionRate, currentCurrency } = props
- const identityList = valuesFor(props.identities)
- const unapprovedTxList = valuesFor(props.unapprovedTxs)
-
- return (
-
- h('.accounts-section.flex-grow', [
-
- // subtitle and nav
- h('.section-title.flex-center', [
- h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
- onClick: this.goHome.bind(this),
- }),
- h('h2.page-subtitle', 'Select Account'),
- ]),
-
- h('hr.horizontal-line'),
-
- // identity selection
- h('section.identity-section', {
- style: {
- height: '418px',
- overflowY: 'auto',
- overflowX: 'hidden',
- },
- },
- [
- identityList.map((identity) => {
- const pending = this.props.pending.filter((txOrMsg) => {
- if ('txParams' in txOrMsg) {
- return txOrMsg.txParams.from === identity.address
- } else if ('msgParams' in txOrMsg) {
- return txOrMsg.msgParams.from === identity.address
- } else {
- return false
- }
- })
-
- const simpleAddress = identity.address.substring(2).toLowerCase()
- const keyring = keyrings.find((kr) => {
- return kr.accounts.includes(simpleAddress) ||
- kr.accounts.includes(identity.address)
- })
-
- return h(AccountListItem, {
- key: `acct-panel-${identity.address}`,
- identity,
- selectedAddress: this.props.selectedAddress,
- conversionRate,
- currentCurrency,
- accounts: this.props.accounts,
- onShowDetail: this.onShowDetail.bind(this),
- pending,
- keyring,
- })
- }),
-
- h('hr.horizontal-line'),
- h('div.footer.hover-white.pointer', {
- key: 'reveal-account-bar',
- onClick: () => {
- this.addNewAccount()
- },
- style: {
- display: 'flex',
- height: '40px',
- padding: '10px',
- justifyContent: 'center',
- alignItems: 'center',
- },
- }, [
- h('i.fa.fa-plus.fa-lg', {key: ''}),
- ]),
- h('hr.horizontal-line'),
- ]),
-
- unapprovedTxList.length ? (
-
- h('.unconftx-link.flex-row.flex-center', {
- onClick: this.navigateToConfTx.bind(this),
- }, [
- h('span', 'Unconfirmed Txs'),
- h('i.fa.fa-arrow-right.fa-lg'),
- ])
-
- ) : (
- null
- ),
- ])
- )
-}
-
-// 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())
-}
-
-AccountsScreen.prototype.onShowDetail = function (address, event) {
- event.stopPropagation()
- this.props.dispatch(actions.showAccountDetail(address))
-}
-
-AccountsScreen.prototype.addNewAccount = function () {
- this.props.dispatch(actions.addNewAccount(0))
-}
-
-/* An optional view proposed in this design:
- * https://consensys.quip.com/zZVrAysM5znY
-AccountsScreen.prototype.addNewAccount = function () {
- this.props.dispatch(actions.navigateToNewAccountScreen())
-}
-*/
-
-AccountsScreen.prototype.goHome = function () {
- this.props.dispatch(actions.goHome())
-}
diff --git a/ui/app/add-token.js b/ui/app/add-token.js
index 15ef7a852..b303b5c0d 100644
--- a/ui/app/add-token.js
+++ b/ui/app/add-token.js
@@ -86,7 +86,7 @@ AddTokenScreen.prototype.render = function () {
h('div', [
h('span', {
style: { fontWeight: 'bold', paddingRight: '10px'},
- }, 'Token Symbol'),
+ }, 'Token Sybmol'),
]),
h('div', { style: {display: 'flex'} }, [
diff --git a/ui/app/app.js b/ui/app/app.js
index 1a63002e1..d1a20f079 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -10,7 +10,6 @@ const NewKeyChainScreen = require('./new-keychain')
// unlock
const UnlockScreen = require('./unlock')
// accounts
-const AccountsScreen = require('./accounts')
const AccountDetailScreen = require('./account-detail')
const SendTransactionScreen = require('./send')
const ConfirmTxScreen = require('./conf-tx')
@@ -24,10 +23,9 @@ const Import = require('./accounts/import')
const InfoScreen = require('./info')
const Loading = require('./components/loading')
const SandwichExpando = require('sandwich-expando')
-const MenuDroppo = require('menu-droppo')
-const DropMenuItem = require('./components/drop-menu-item')
+const Dropdown = require('./components/dropdown').Dropdown
+const DropdownMenuItem = require('./components/dropdown').DropdownMenuItem
const NetworkIndicator = require('./components/network')
-const Tooltip = require('./components/tooltip')
const BuyView = require('./components/buy-button-subview')
const QrView = require('./components/qr-code')
const HDCreateVaultComplete = require('./keychains/hd/create-vault-complete')
@@ -79,6 +77,8 @@ App.prototype.render = function () {
// Windows was showing a vertical scroll bar:
overflow: 'hidden',
position: 'relative',
+ height: '100%',
+ alignItems: 'center',
},
}, [
@@ -95,8 +95,8 @@ App.prototype.render = function () {
// panel content
h('.app-primary.flex-grow' + (transForward ? '.from-right' : '.from-left'), {
style: {
- height: '380px',
- width: '360px',
+ height: '100%',
+ maxWidth: '850px',
},
}, [
h(ReactCSSTransitionGroup, {
@@ -123,14 +123,18 @@ App.prototype.renderAppBar = function () {
return (
- h('div', [
+ h('div', {
+ style: {
+ width: '100%'
+ },
+ }, [
h('.app-header.flex-row.flex-space-between', {
style: {
alignItems: 'center',
visibility: props.isUnlocked ? 'visible' : 'none',
background: props.isUnlocked ? 'white' : 'none',
- height: '36px',
+ height: '38px',
position: 'relative',
zIndex: 12,
},
@@ -178,21 +182,6 @@ App.prototype.renderAppBar = function () {
},
}, [
- // small accounts nav
- props.isUnlocked && h(Tooltip, { title: 'Switch Accounts' }, [
- h('img.cursor-pointer.color-orange', {
- src: 'images/switch_acc.svg',
- style: {
- width: '23.5px',
- marginRight: '8px',
- },
- onClick: (event) => {
- event.stopPropagation()
- this.props.dispatch(actions.showAccountsPage())
- },
- }),
- ]),
-
// hamburger
props.isUnlocked && h(SandwichExpando, {
width: 16,
@@ -214,11 +203,12 @@ App.prototype.renderAppBar = function () {
App.prototype.renderNetworkDropdown = function () {
const props = this.props
+ const { provider: { type: providerType, rpcTarget: activeNetwork } } = props
const rpcList = props.frequentRpcList
const state = this.state || {}
const isOpen = state.isNetworkMenuOpen
- return h(MenuDroppo, {
+ return h(Dropdown, {
isOpen,
onClickOutside: (event) => {
this.setState({ isNetworkMenuOpen: !isOpen })
@@ -226,72 +216,92 @@ App.prototype.renderNetworkDropdown = function () {
zIndex: 11,
style: {
position: 'absolute',
- left: 0,
+ left: '2px',
top: '36px',
},
- 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: 'Main Ethereum Network',
- closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
- action: () => props.dispatch(actions.setProviderType('mainnet')),
- icon: h('.menu-icon.diamond'),
- activeNetworkRender: props.network,
- provider: props.provider,
- }),
-
- h(DropMenuItem, {
- label: 'Ropsten Test Network',
- closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
- action: () => props.dispatch(actions.setProviderType('ropsten')),
- icon: h('.menu-icon.red-dot'),
- activeNetworkRender: props.network,
- provider: props.provider,
- }),
-
- h(DropMenuItem, {
- label: 'Kovan Test Network',
- closeMenu: () => this.setState({ isNetworkMenuOpen: false}),
- action: () => props.dispatch(actions.setProviderType('kovan')),
- icon: h('.menu-icon.hollow-diamond'),
- activeNetworkRender: props.network,
- provider: props.provider,
- }),
-
- h(DropMenuItem, {
- label: 'Rinkeby Test Network',
- closeMenu: () => this.setState({ isNetworkMenuOpen: false}),
- action: () => props.dispatch(actions.setProviderType('rinkeby')),
- icon: h('.menu-icon.golden-square'),
- activeNetworkRender: props.network,
- provider: props.provider,
- }),
-
- h(DropMenuItem, {
- label: 'Localhost 8545',
- closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
- action: () => props.dispatch(actions.setDefaultRpcTarget(rpcList)),
- icon: h('i.fa.fa-question-circle.fa-lg'),
- activeNetworkRender: props.provider.rpcTarget,
- }),
+ innerStyle: {},
+ }, [
+
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
+ onClick: () => props.dispatch(actions.setProviderType('mainnet')),
+ },
+ [
+ h('.menu-icon.diamond'),
+ 'Main Ethereum Network',
+ providerType === 'mainnet' ? h('.check', '✓') : null,
+ ]
+ ),
+
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
+ onClick: () => props.dispatch(actions.setProviderType('ropsten')),
+ },
+ [
+ h('.menu-icon.red-dot'),
+ 'Ropsten Test Network',
+ providerType === 'ropsten' ? h('.check', '✓') : null,
+ ]
+ ),
+
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
+ onClick: () => props.dispatch(actions.setProviderType('kovan')),
+ },
+ [
+ h('.menu-icon.hollow-diamond'),
+ 'Kovan Test Network',
+ providerType === 'kovan' ? h('.check', '✓') : null,
+ ]
+ ),
+
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
+ onClick: () => props.dispatch(actions.setProviderType('rinkeby')),
+ },
+ [
+ h('.menu-icon.golden-square'),
+ 'Rinkeby Test Network',
+ providerType === 'rinkeby' ? h('.check', '✓') : null,
+ ]
+ ),
+
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
+ onClick: () => props.dispatch(actions.setDefaultRpcTarget(rpcList)),
+ },
+ [
+ h('i.fa.fa-question-circle.fa-lg.menu-icon'),
+ 'Localhost 8545',
+ activeNetwork === 'http://localhost:8545' ? h('.check', '✓') : null,
+ ]
+ ),
this.renderCustomOption(props.provider),
this.renderCommonRpc(rpcList, props.provider),
- h(DropMenuItem, {
- label: 'Custom RPC',
- closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
- action: () => this.props.dispatch(actions.showConfigPage()),
- icon: h('i.fa.fa-question-circle.fa-lg'),
- }),
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
+ onClick: () => this.props.dispatch(actions.showConfigPage()),
+ },
+ [
+ h('i.fa.fa-question-circle.fa-lg.menu-icon'),
+ 'Custom RPC',
+ activeNetwork === 'custom' ? h('.check', '✓') : null,
+ ]
+ ),
])
}
@@ -300,7 +310,7 @@ App.prototype.renderDropdown = function () {
const state = this.state || {}
const isOpen = state.isMainMenuOpen
- return h(MenuDroppo, {
+ return h(Dropdown, {
isOpen: isOpen,
zIndex: 11,
onClickOutside: (event) => {
@@ -308,46 +318,30 @@ App.prototype.renderDropdown = function () {
},
style: {
position: 'absolute',
- right: 0,
- top: '36px',
+ right: '2px',
+ top: '38px',
},
- 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',
+ innerStyle: {},
+ }, [
+ h(DropdownMenuItem, {
closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }),
- action: () => this.props.dispatch(actions.showConfigPage()),
- icon: h('i.fa.fa-gear.fa-lg'),
- }),
+ onClick: () => { this.props.dispatch(actions.showConfigPage()) },
+ }, 'Settings'),
- h(DropMenuItem, {
- label: 'Import Account',
+ h(DropdownMenuItem, {
closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }),
- action: () => this.props.dispatch(actions.showImportPage()),
- icon: h('i.fa.fa-arrow-circle-o-up.fa-lg'),
- }),
+ onClick: () => { this.props.dispatch(actions.showImportPage()) },
+ }, 'Import Account'),
- h(DropMenuItem, {
- label: 'Lock',
+ h(DropdownMenuItem, {
closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }),
- action: () => this.props.dispatch(actions.lockMetamask()),
- icon: h('i.fa.fa-lock.fa-lg'),
- }),
+ onClick: () => { this.props.dispatch(actions.lockMetamask()) },
+ }, 'Lock'),
- h(DropMenuItem, {
- label: 'Info/Help',
+ h(DropdownMenuItem, {
closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }),
- action: () => this.props.dispatch(actions.showInfoPage()),
- icon: h('i.fa.fa-question.fa-lg'),
- }),
+ onClick: () => { this.props.dispatch(actions.showInfoPage()) },
+ }, 'Info/Help'),
])
}
@@ -433,10 +427,6 @@ App.prototype.renderPrimary = function () {
// show current view
switch (props.currentView.name) {
- case 'accounts':
- log.debug('rendering accounts screen')
- return h(AccountsScreen, {key: 'accounts'})
-
case 'accountDetail':
log.debug('rendering account detail screen')
return h(AccountDetailScreen, {key: 'account-detail'})
@@ -539,13 +529,18 @@ App.prototype.renderCustomOption = function (provider) {
return null
default:
- return h(DropMenuItem, {
- label,
- key: rpcTarget,
- closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
- icon: h('i.fa.fa-question-circle.fa-lg'),
- activeNetworkRender: 'custom',
- })
+ return h(
+ DropdownMenuItem,
+ {
+ key: rpcTarget,
+ closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
+ },
+ [
+ h('i.fa.fa-question-circle.fa-lg.menu-icon'),
+ label,
+ h('.check', '✓'),
+ ]
+ )
}
}
@@ -578,14 +573,19 @@ App.prototype.renderCommonRpc = function (rpcList, provider) {
if ((rpc === 'http://localhost:8545') || (rpc === rpcTarget)) {
return null
} else {
- return h(DropMenuItem, {
- label: rpc,
- key: rpc,
- closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
- action: () => props.dispatch(actions.setRpcTarget(rpc)),
- icon: h('i.fa.fa-question-circle.fa-lg'),
- activeNetworkRender: rpc,
- })
+ return h(
+ DropdownMenuItem,
+ {
+ key: rpc,
+ closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
+ action: () => props.dispatch(actions.setRpcTarget(rpc)),
+ },
+ [
+ h('i.fa.fa-question-circle.fa-lg.menu-icon'),
+ rpc,
+ h('.check', '✓'),
+ ]
+ )
}
})
}
diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js
new file mode 100644
index 000000000..d1d319477
--- /dev/null
+++ b/ui/app/components/account-dropdowns.js
@@ -0,0 +1,227 @@
+const Component = require('react').Component
+const PropTypes = require('react').PropTypes
+const h = require('react-hyperscript')
+const actions = require('../actions')
+const genAccountLink = require('../../lib/account-link.js')
+const connect = require('react-redux').connect
+const Dropdown = require('./dropdown').Dropdown
+const DropdownMenuItem = require('./dropdown').DropdownMenuItem
+const Identicon = require('./identicon')
+const ethUtil = require('ethereumjs-util')
+const copyToClipboard = require('copy-to-clipboard')
+
+class AccountDropdowns extends Component {
+ constructor (props) {
+ super(props)
+ this.state = {
+ accountSelectorActive: false,
+ optionsMenuActive: false,
+ }
+ }
+
+ renderAccounts () {
+ const { identities, selected } = this.props
+
+ return Object.keys(identities).map((key) => {
+ const identity = identities[key]
+ const isSelected = identity.address === selected
+
+ return h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => {},
+ onClick: () => {
+ this.props.actions.showAccountDetail(identity.address)
+ },
+ },
+ [
+ h(
+ Identicon,
+ {
+ address: identity.address,
+ diameter: 16,
+ },
+ ),
+ h('span', { style: { marginLeft: '10px' } }, identity.name || ''),
+ h('span', { style: { marginLeft: '10px' } }, isSelected ? h('.check', '✓') : null),
+ ]
+ )
+ })
+ }
+
+ renderAccountSelector () {
+ const { actions } = this.props
+ const { accountSelectorActive } = this.state
+
+ return h(
+ Dropdown,
+ {
+ style: {
+ marginLeft: '-125px',
+ minWidth: '180px',
+ },
+ isOpen: accountSelectorActive,
+ onClickOutside: () => { this.setState({ accountSelectorActive: false }) },
+ },
+ [
+ ...this.renderAccounts(),
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => {},
+ onClick: () => actions.addNewAccount(),
+ },
+ [
+ h(
+ Identicon,
+ {
+ diameter: 16,
+ },
+ ),
+ h('span', { style: { marginLeft: '10px' } }, 'Create Account'),
+ ],
+ ),
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => {},
+ onClick: () => actions.showImportPage(),
+ },
+ [
+ h(
+ Identicon,
+ {
+ diameter: 16,
+ },
+ ),
+ h('span', { style: { marginLeft: '10px' } }, 'Import Account'),
+ ]
+ ),
+ ]
+ )
+ }
+
+ renderAccountOptions () {
+ const { actions } = this.props
+ const { optionsMenuActive } = this.state
+
+ return h(
+ Dropdown,
+ {
+ style: {
+ marginLeft: '-162px',
+ minWidth: '180px',
+ },
+ isOpen: optionsMenuActive,
+ onClickOutside: () => { this.setState({ optionsMenuActive: false }) },
+ },
+ [
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => {},
+ onClick: () => actions.showConfigPage(),
+ },
+ 'Account Settings',
+ ),
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => {},
+ onClick: () => {
+ const { selected, network } = this.props
+ const url = genAccountLink(selected, network)
+ global.platform.openWindow({ url })
+ },
+ },
+ 'View account on Etherscan',
+ ),
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => {},
+ onClick: () => {
+ const { selected } = this.props
+ const checkSumAddress = selected && ethUtil.toChecksumAddress(selected)
+ copyToClipboard(checkSumAddress)
+ },
+ },
+ 'Copy Address to clipboard',
+ ),
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => {},
+ onClick: () => {
+ actions.requestAccountExport()
+ },
+ },
+ 'Export Private Key',
+ ),
+ ]
+ )
+ }
+
+ render () {
+ const { style } = this.props
+ const { optionsMenuActive, accountSelectorActive } = this.state
+
+ return h(
+ 'span',
+ {
+ style: style,
+ },
+ [
+ h(
+ 'i.fa.fa-angle-down',
+ {
+ style: {},
+ onClick: (event) => {
+ event.stopPropagation()
+ this.setState({
+ accountSelectorActive: !accountSelectorActive,
+ optionsMenuActive: false,
+ })
+ },
+ },
+ this.renderAccountSelector(),
+ ),
+ h(
+ 'i.fa.fa-ellipsis-h',
+ {
+ style: { 'marginLeft': '10px'},
+ onClick: (event) => {
+ event.stopPropagation()
+ this.setState({
+ accountSelectorActive: false,
+ optionsMenuActive: !optionsMenuActive,
+ })
+ },
+ },
+ this.renderAccountOptions()
+ ),
+ ]
+ )
+ }
+}
+
+AccountDropdowns.propTypes = {
+ identities: PropTypes.objectOf(PropTypes.object),
+ selected: PropTypes.string,
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ actions: {
+ showConfigPage: () => dispatch(actions.showConfigPage()),
+ requestAccountExport: () => dispatch(actions.requestExportAccount()),
+ showAccountDetail: (address) => dispatch(actions.showAccountDetail(address)),
+ addNewAccount: () => dispatch(actions.addNewAccount()),
+ showImportPage: () => dispatch(actions.showImportPage()),
+ },
+ }
+}
+
+module.exports = {
+ AccountDropdowns: connect(null, mapDispatchToProps)(AccountDropdowns),
+}
diff --git a/ui/app/components/account-info-link.js b/ui/app/components/account-info-link.js
deleted file mode 100644
index 6526ab502..000000000
--- a/ui/app/components/account-info-link.js
+++ /dev/null
@@ -1,41 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const Tooltip = require('./tooltip')
-const genAccountLink = require('../../lib/account-link')
-
-module.exports = AccountInfoLink
-
-inherits(AccountInfoLink, Component)
-function AccountInfoLink () {
- Component.call(this)
-}
-
-AccountInfoLink.prototype.render = function () {
- const { selected, network } = this.props
- const title = 'View account on Etherscan'
- const url = genAccountLink(selected, network)
-
- if (!url) {
- return null
- }
-
- return h('.account-info-link', {
- style: {
- display: 'flex',
- alignItems: 'center',
- },
- }, [
-
- h(Tooltip, {
- title,
- }, [
- h('i.fa.fa-info-circle.cursor-pointer.color-orange', {
- style: {
- margin: '5px',
- },
- onClick () { global.platform.openWindow({ url }) },
- }),
- ]),
- ])
-}
diff --git a/ui/app/components/drop-menu-item.js b/ui/app/components/drop-menu-item.js
deleted file mode 100644
index e42948209..000000000
--- a/ui/app/components/drop-menu-item.js
+++ /dev/null
@@ -1,59 +0,0 @@
-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 16px 6px 5px',
- fontFamily: 'Montserrat Regular',
- color: 'rgb(125, 128, 130)',
- cursor: 'pointer',
- display: 'flex',
- justifyContent: 'flex-start',
- },
- }, [
- this.props.icon,
- this.props.label,
- this.activeNetworkRender(),
- ])
-}
-
-DropMenuItem.prototype.activeNetworkRender = function () {
- const activeNetwork = this.props.activeNetworkRender
- const { provider } = this.props
- const providerType = provider ? provider.type : null
- if (activeNetwork === undefined) return
-
- switch (this.props.label) {
- case 'Main Ethereum Network':
- if (providerType === 'mainnet') return h('.check', '✓')
- break
- case 'Ropsten Test Network':
- if (providerType === 'ropsten') return h('.check', '✓')
- break
- case 'Kovan Test Network':
- if (providerType === 'kovan') return h('.check', '✓')
- break
- case 'Rinkeby Test Network':
- if (providerType === 'rinkeby') return h('.check', '✓')
- break
- case 'Localhost 8545':
- if (activeNetwork === 'http://localhost:8545') return h('.check', '✓')
- break
- default:
- if (activeNetwork === 'custom') return h('.check', '✓')
- }
-}
diff --git a/ui/app/components/dropdown.js b/ui/app/components/dropdown.js
new file mode 100644
index 000000000..e77b4c40c
--- /dev/null
+++ b/ui/app/components/dropdown.js
@@ -0,0 +1,89 @@
+const Component = require('react').Component
+const PropTypes = require('react').PropTypes
+const h = require('react-hyperscript')
+const MenuDroppo = require('menu-droppo')
+
+const noop = () => {}
+
+class Dropdown extends Component {
+ render () {
+ const { isOpen, onClickOutside, style, children } = this.props
+
+ return h(
+ MenuDroppo,
+ {
+ isOpen,
+ zIndex: 11,
+ onClickOutside,
+ style,
+ innerStyle: {
+ borderRadius: '4px',
+ padding: '8px 16px',
+ background: 'rgba(0, 0, 0, 0.8)',
+ boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px',
+ },
+ },
+ [
+ h(
+ 'style',
+ `
+ li.dropdown-menu-item:hover { color:rgb(225, 225, 225); }
+ li.dropdown-menu-item { color: rgb(185, 185, 185); }
+ `
+ ),
+ ...children,
+ ]
+ )
+ }
+}
+
+Dropdown.defaultProps = {
+ isOpen: false,
+ onClick: noop,
+}
+
+Dropdown.propTypes = {
+ isOpen: PropTypes.bool.isRequired,
+ onClick: PropTypes.func.isRequired,
+ children: PropTypes.node,
+ style: PropTypes.object.isRequired,
+}
+
+class DropdownMenuItem extends Component {
+ render () {
+ const { onClick, closeMenu, children } = this.props
+
+ return h(
+ 'li.dropdown-menu-item',
+ {
+ onClick: () => {
+ onClick()
+ closeMenu()
+ },
+ style: {
+ listStyle: 'none',
+ padding: '8px 0px 8px 0px',
+ fontSize: '12px',
+ fontStyle: 'normal',
+ fontFamily: 'Montserrat Regular',
+ cursor: 'pointer',
+ display: 'flex',
+ justifyContent: 'flex-start',
+ alignItems: 'center',
+ },
+ },
+ children
+ )
+ }
+}
+
+DropdownMenuItem.propTypes = {
+ closeMenu: PropTypes.func.isRequired,
+ onClick: PropTypes.func.isRequired,
+ children: PropTypes.node,
+}
+
+module.exports = {
+ Dropdown,
+ DropdownMenuItem,
+}
diff --git a/ui/app/components/editable-label.js b/ui/app/components/editable-label.js
index 41936f5e0..167be7eaf 100644
--- a/ui/app/components/editable-label.js
+++ b/ui/app/components/editable-label.js
@@ -30,7 +30,12 @@ EditableLabel.prototype.render = function () {
} else {
return h('div.name-label', {
onClick: (event) => {
- this.setState({ isEditingLabel: true })
+ const nameAttribute = event.target.getAttribute('name')
+ // checks for class to handle smaller CTA above the account name
+ const classAttribute = event.target.getAttribute('class')
+ if (nameAttribute === 'edit' || classAttribute === 'edit-text') {
+ this.setState({ isEditingLabel: true })
+ }
},
}, this.props.children)
}
diff --git a/ui/app/components/pending-tx.js b/ui/app/components/pending-tx.js
index 5324ccd64..d7d602f31 100644
--- a/ui/app/components/pending-tx.js
+++ b/ui/app/components/pending-tx.js
@@ -15,7 +15,7 @@ const addressSummary = util.addressSummary
const nameForAddress = require('../../lib/contract-namer')
const BNInput = require('./bn-as-decimal-input')
-const MIN_GAS_PRICE_GWEI_BN = new BN(1)
+const MIN_GAS_PRICE_GWEI_BN = new BN(2)
const GWEI_FACTOR = new BN(1e9)
const MIN_GAS_PRICE_BN = MIN_GAS_PRICE_GWEI_BN.mul(GWEI_FACTOR)
const MIN_GAS_LIMIT_BN = new BN(21000)
diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js
index 3b4ba741e..ae6aaec8c 100644
--- a/ui/app/components/transaction-list.js
+++ b/ui/app/components/transaction-list.js
@@ -24,7 +24,11 @@ TransactionList.prototype.render = function () {
return (
- h('section.transaction-list', [
+ h('section.transaction-list', {
+ style: {
+ height: '100%',
+ },
+ }, [
h('style', `
.transaction-list .transaction-list-item:not(:last-of-type) {
@@ -39,7 +43,7 @@ TransactionList.prototype.render = function () {
h('.tx-list', {
style: {
overflowY: 'auto',
- height: '300px',
+ height: '100%',
padding: '0 20px',
textAlign: 'center',
},
diff --git a/ui/app/css/index.css b/ui/app/css/index.css
index 808aafb4c..2ae92bbd6 100644
--- a/ui/app/css/index.css
+++ b/ui/app/css/index.css
@@ -19,6 +19,15 @@ html, body {
font-weight: 300;
line-height: 1.4em;
background: #F7F7F7;
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+}
+
+.css-transition-group {
+ flex: 1;
+ height: 100%;
}
input:focus, textarea:focus {
@@ -28,8 +37,7 @@ input:focus, textarea:focus {
#app-content {
overflow-x: hidden;
min-width: 357px;
- width: 360px;
- height: 500px;
+ height: 100%;
}
button, input[type="submit"] {
@@ -403,7 +411,8 @@ input.large-input {
/* account detail screen */
.account-detail-section {
-
+ display: flex;
+ flex-wrap: wrap;
}
.name-label{
diff --git a/ui/app/css/lib.css b/ui/app/css/lib.css
index 910a24ee2..b0ca958a2 100644
--- a/ui/app/css/lib.css
+++ b/ui/app/css/lib.css
@@ -232,6 +232,10 @@ hr.horizontal-line {
align-items: center;
}
+.tabSection {
+ min-width: 350px;
+}
+
.menu-icon {
display: inline-block;
height: 9px;
diff --git a/ui/app/info.js b/ui/app/info.js
index cb2e41f5b..e8470de97 100644
--- a/ui/app/info.js
+++ b/ui/app/info.js
@@ -97,17 +97,11 @@ InfoScreen.prototype.render = function () {
paddingLeft: '30px',
}},
[
- h('div.fa.fa-support', [
- h('a.info', {
- href: 'http://metamask.consensyssupport.happyfox.com',
- target: '_blank',
- }, 'Visit our Support Center'),
- ]),
h('div.fa.fa-github', [
h('a.info', {
- href: 'https://github.com/MetaMask/metamask-extension/issues/new',
+ href: 'https://github.com/MetaMask/faq',
target: '_blank',
- }, 'Found a bug? Report it!'),
+ }, 'Need Help? Read our FAQ!'),
]),
h('div', [
h('a', {
diff --git a/ui/app/keychains/hd/create-vault-complete.js b/ui/app/keychains/hd/create-vault-complete.js
index a318a9b50..c32751fff 100644
--- a/ui/app/keychains/hd/create-vault-complete.js
+++ b/ui/app/keychains/hd/create-vault-complete.js
@@ -47,8 +47,6 @@ CreateVaultCompleteScreen.prototype.render = function () {
h('div', {
style: {
- width: '360px',
- height: '78px',
fontSize: '1em',
marginTop: '10px',
textAlign: 'center',