Merge pull request #5241 from MetaMask/refactor-settings
Refactor settings page to use JSX and follow component file folder st…feature/default_network_editable
commit
04988eca5e
@ -1,64 +1 @@ |
||||
const { Component } = require('react') |
||||
const { Switch, Route, matchPath } = require('react-router-dom') |
||||
const PropTypes = require('prop-types') |
||||
const h = require('react-hyperscript') |
||||
const TabBar = require('../../tab-bar') |
||||
const Settings = require('./settings') |
||||
const Info = require('./info') |
||||
const { DEFAULT_ROUTE, SETTINGS_ROUTE, INFO_ROUTE } = require('../../../routes') |
||||
|
||||
class Config extends Component { |
||||
renderTabs () { |
||||
const { history, location } = this.props |
||||
|
||||
return h('div.settings__tabs', [ |
||||
h(TabBar, { |
||||
tabs: [ |
||||
{ content: this.context.t('settings'), key: SETTINGS_ROUTE }, |
||||
{ content: this.context.t('info'), key: INFO_ROUTE }, |
||||
], |
||||
isActive: key => matchPath(location.pathname, { path: key, exact: true }), |
||||
onSelect: key => history.push(key), |
||||
}), |
||||
]) |
||||
} |
||||
|
||||
render () { |
||||
const { history } = this.props |
||||
|
||||
return ( |
||||
h('.main-container.settings', {}, [ |
||||
h('.settings__header', [ |
||||
h('div.settings__close-button', { |
||||
onClick: () => history.push(DEFAULT_ROUTE), |
||||
}), |
||||
this.renderTabs(), |
||||
]), |
||||
h(Switch, [ |
||||
h(Route, { |
||||
exact: true, |
||||
path: INFO_ROUTE, |
||||
component: Info, |
||||
}), |
||||
h(Route, { |
||||
exact: true, |
||||
path: SETTINGS_ROUTE, |
||||
component: Settings, |
||||
}), |
||||
]), |
||||
]) |
||||
) |
||||
} |
||||
} |
||||
|
||||
Config.propTypes = { |
||||
location: PropTypes.object, |
||||
history: PropTypes.object, |
||||
t: PropTypes.func, |
||||
} |
||||
|
||||
Config.contextTypes = { |
||||
t: PropTypes.func, |
||||
} |
||||
|
||||
module.exports = Config |
||||
export { default } from './settings.component' |
||||
|
@ -0,0 +1,80 @@ |
||||
@import './info-tab/index'; |
||||
|
||||
@import './settings-tab/index'; |
||||
|
||||
.settings-page { |
||||
position: relative; |
||||
background: $white; |
||||
display: flex; |
||||
flex-flow: column nowrap; |
||||
|
||||
&__header { |
||||
padding: 25px 25px 0; |
||||
} |
||||
|
||||
&__close-button::after { |
||||
content: '\00D7'; |
||||
font-size: 40px; |
||||
color: $dusty-gray; |
||||
position: absolute; |
||||
top: 25px; |
||||
right: 30px; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
&__content { |
||||
padding: 25px; |
||||
height: auto; |
||||
overflow: auto; |
||||
} |
||||
|
||||
&__content-row { |
||||
display: flex; |
||||
flex-direction: row; |
||||
padding: 10px 0 20px; |
||||
|
||||
@media screen and (max-width: 575px) { |
||||
flex-direction: column; |
||||
padding: 10px 0; |
||||
} |
||||
} |
||||
|
||||
&__content-item { |
||||
flex: 1; |
||||
min-width: 0; |
||||
display: flex; |
||||
flex-direction: column; |
||||
padding: 0 5px; |
||||
min-height: 71px; |
||||
|
||||
@media screen and (max-width: 575px) { |
||||
height: initial; |
||||
padding: 5px 0; |
||||
} |
||||
|
||||
&--without-height { |
||||
height: initial; |
||||
} |
||||
} |
||||
|
||||
&__content-label { |
||||
text-transform: capitalize; |
||||
} |
||||
|
||||
&__content-description { |
||||
font-size: 14px; |
||||
color: $dusty-gray; |
||||
padding-top: 5px; |
||||
} |
||||
|
||||
&__content-item-col { |
||||
max-width: 300px; |
||||
display: flex; |
||||
flex-direction: column; |
||||
|
||||
@media screen and (max-width: 575px) { |
||||
max-width: 100%; |
||||
width: 100%; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1 @@ |
||||
export { default } from './info-tab.component' |
@ -0,0 +1,56 @@ |
||||
.info-tab { |
||||
&__logo-wrapper { |
||||
height: 80px; |
||||
margin-bottom: 20px; |
||||
} |
||||
|
||||
&__logo { |
||||
max-height: 100%; |
||||
max-width: 100%; |
||||
} |
||||
|
||||
&__item { |
||||
padding: 10px 0; |
||||
} |
||||
|
||||
&__link-header { |
||||
padding-bottom: 15px; |
||||
|
||||
@media screen and (max-width: 575px) { |
||||
padding-bottom: 5px; |
||||
} |
||||
} |
||||
|
||||
&__link-item { |
||||
padding: 15px 0; |
||||
|
||||
@media screen and (max-width: 575px) { |
||||
padding: 5px 0; |
||||
} |
||||
} |
||||
|
||||
&__link-text { |
||||
color: $curious-blue; |
||||
} |
||||
|
||||
&__version-number { |
||||
padding-top: 5px; |
||||
font-size: 13px; |
||||
color: $dusty-gray; |
||||
} |
||||
|
||||
&__separator { |
||||
margin: 15px 0; |
||||
width: 80px; |
||||
border-color: $alto; |
||||
border: none; |
||||
height: 1px; |
||||
background-color: $alto; |
||||
color: $alto; |
||||
} |
||||
|
||||
&__about { |
||||
color: $dusty-gray; |
||||
margin-bottom: 15px; |
||||
} |
||||
} |
@ -0,0 +1,136 @@ |
||||
import React, { PureComponent } from 'react' |
||||
import PropTypes from 'prop-types' |
||||
|
||||
export default class InfoTab extends PureComponent { |
||||
state = { |
||||
version: global.platform.getVersion(), |
||||
} |
||||
|
||||
static propTypes = { |
||||
tab: PropTypes.string, |
||||
metamask: PropTypes.object, |
||||
setCurrentCurrency: PropTypes.func, |
||||
setRpcTarget: PropTypes.func, |
||||
displayWarning: PropTypes.func, |
||||
revealSeedConfirmation: PropTypes.func, |
||||
warning: PropTypes.string, |
||||
location: PropTypes.object, |
||||
history: PropTypes.object, |
||||
} |
||||
|
||||
static contextTypes = { |
||||
t: PropTypes.func, |
||||
} |
||||
|
||||
renderInfoLinks () { |
||||
const { t } = this.context |
||||
|
||||
return ( |
||||
<div className="settings-page__content-item settings-page__content-item--without-height"> |
||||
<div className="info-tab__link-header"> |
||||
{ t('links') } |
||||
</div> |
||||
<div className="info-tab__link-item"> |
||||
<a |
||||
href="https://metamask.io/privacy.html" |
||||
target="_blank" |
||||
rel="noopener noreferrer" |
||||
> |
||||
<span className="info-tab__link-text"> |
||||
{ t('privacyMsg') } |
||||
</span> |
||||
</a> |
||||
</div> |
||||
<div className="info-tab__link-item"> |
||||
<a |
||||
href="https://metamask.io/terms.html" |
||||
target="_blank" |
||||
rel="noopener noreferrer" |
||||
> |
||||
<span className="info-tab__link-text"> |
||||
{ t('terms') } |
||||
</span> |
||||
</a> |
||||
</div> |
||||
<div className="info-tab__link-item"> |
||||
<a |
||||
href="https://metamask.io/attributions.html" |
||||
target="_blank" |
||||
rel="noopener noreferrer" |
||||
> |
||||
<span className="info-tab__link-text"> |
||||
{ t('attributions') } |
||||
</span> |
||||
</a> |
||||
</div> |
||||
<hr className="info-tab__separator" /> |
||||
<div className="info-tab__link-item"> |
||||
<a |
||||
href="https://support.metamask.io" |
||||
target="_blank" |
||||
rel="noopener noreferrer" |
||||
> |
||||
<span className="info-tab__link-text"> |
||||
{ t('supportCenter') } |
||||
</span> |
||||
</a> |
||||
</div> |
||||
<div className="info-tab__link-item"> |
||||
<a |
||||
href="https://metamask.io/" |
||||
target="_blank" |
||||
rel="noopener noreferrer" |
||||
> |
||||
<span className="info-tab__link-text"> |
||||
{ t('visitWebSite') } |
||||
</span> |
||||
</a> |
||||
</div> |
||||
<div className="info-tab__link-item"> |
||||
<a |
||||
href="mailto:help@metamask.io?subject=Feedback" |
||||
target="_blank" |
||||
rel="noopener noreferrer" |
||||
> |
||||
<span className="info-tab__link-text"> |
||||
{ t('emailUs') } |
||||
</span> |
||||
</a> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
render () { |
||||
const { t } = this.context |
||||
|
||||
return ( |
||||
<div className="settings-page__content"> |
||||
<div className="settings-page__content-row"> |
||||
<div className="settings-page__content-item settings-page__content-item--without-height"> |
||||
<div className="info-tab__logo-wrapper"> |
||||
<img |
||||
src="images/info-logo.png" |
||||
className="info-tab__logo" |
||||
/> |
||||
</div> |
||||
<div className="info-tab__item"> |
||||
<div className="info-tab__version-header"> |
||||
{ t('metamaskVersion') } |
||||
</div> |
||||
<div className="info-tab__version-number"> |
||||
{ this.state.version } |
||||
</div> |
||||
</div> |
||||
<div className="info-tab__item"> |
||||
<div className="info-tab__about"> |
||||
{ t('builtInCalifornia') } |
||||
</div> |
||||
</div> |
||||
</div> |
||||
{ this.renderInfoLinks() } |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
} |
@ -1,120 +0,0 @@ |
||||
const { Component } = require('react') |
||||
const PropTypes = require('prop-types') |
||||
const h = require('react-hyperscript') |
||||
|
||||
class Info extends Component { |
||||
constructor (props) { |
||||
super(props) |
||||
|
||||
this.state = { |
||||
version: global.platform.getVersion(), |
||||
} |
||||
} |
||||
|
||||
renderLogo () { |
||||
return ( |
||||
h('div.settings__info-logo-wrapper', [ |
||||
h('img.settings__info-logo', { src: 'images/info-logo.png' }), |
||||
]) |
||||
) |
||||
} |
||||
|
||||
renderInfoLinks () { |
||||
return ( |
||||
h('div.settings__content-item.settings__content-item--without-height', [ |
||||
h('div.settings__info-link-header', this.context.t('links')), |
||||
h('div.settings__info-link-item', [ |
||||
h('a', { |
||||
href: 'https://metamask.io/privacy.html', |
||||
target: '_blank', |
||||
}, [ |
||||
h('span.settings__info-link', this.context.t('privacyMsg')), |
||||
]), |
||||
]), |
||||
h('div.settings__info-link-item', [ |
||||
h('a', { |
||||
href: 'https://metamask.io/terms.html', |
||||
target: '_blank', |
||||
}, [ |
||||
h('span.settings__info-link', this.context.t('terms')), |
||||
]), |
||||
]), |
||||
h('div.settings__info-link-item', [ |
||||
h('a', { |
||||
href: 'https://metamask.io/attributions.html', |
||||
target: '_blank', |
||||
}, [ |
||||
h('span.settings__info-link', this.context.t('attributions')), |
||||
]), |
||||
]), |
||||
h('hr.settings__info-separator'), |
||||
h('div.settings__info-link-item', [ |
||||
h('a', { |
||||
href: 'https://support.metamask.io', |
||||
target: '_blank', |
||||
}, [ |
||||
h('span.settings__info-link', this.context.t('supportCenter')), |
||||
]), |
||||
]), |
||||
h('div.settings__info-link-item', [ |
||||
h('a', { |
||||
href: 'https://metamask.io/', |
||||
target: '_blank', |
||||
}, [ |
||||
h('span.settings__info-link', this.context.t('visitWebSite')), |
||||
]), |
||||
]), |
||||
h('div.settings__info-link-item', [ |
||||
h('a', { |
||||
target: '_blank', |
||||
href: 'mailto:help@metamask.io?subject=Feedback', |
||||
}, [ |
||||
h('span.settings__info-link', this.context.t('emailUs')), |
||||
]), |
||||
]), |
||||
]) |
||||
) |
||||
} |
||||
|
||||
render () { |
||||
return ( |
||||
h('div.settings__content', [ |
||||
h('div.settings__content-row', [ |
||||
h('div.settings__content-item.settings__content-item--without-height', [ |
||||
this.renderLogo(), |
||||
h('div.settings__info-item', [ |
||||
h('div.settings__info-version-header', 'MetaMask Version'), |
||||
h('div.settings__info-version-number', this.state.version), |
||||
]), |
||||
h('div.settings__info-item', [ |
||||
h( |
||||
'div.settings__info-about', |
||||
this.context.t('builtInCalifornia') |
||||
), |
||||
]), |
||||
]), |
||||
this.renderInfoLinks(), |
||||
]), |
||||
]) |
||||
) |
||||
} |
||||
} |
||||
|
||||
Info.propTypes = { |
||||
tab: PropTypes.string, |
||||
metamask: PropTypes.object, |
||||
setCurrentCurrency: PropTypes.func, |
||||
setRpcTarget: PropTypes.func, |
||||
displayWarning: PropTypes.func, |
||||
revealSeedConfirmation: PropTypes.func, |
||||
warning: PropTypes.string, |
||||
location: PropTypes.object, |
||||
history: PropTypes.object, |
||||
t: PropTypes.func, |
||||
} |
||||
|
||||
Info.contextTypes = { |
||||
t: PropTypes.func, |
||||
} |
||||
|
||||
module.exports = Info |
@ -0,0 +1 @@ |
||||
export { default } from './settings-tab.container' |
@ -0,0 +1,51 @@ |
||||
.settings-tab { |
||||
&__error { |
||||
padding-bottom: 20px; |
||||
text-align: center; |
||||
color: $crimson; |
||||
} |
||||
|
||||
&__rpc-save-button { |
||||
align-self: flex-end; |
||||
padding: 5px; |
||||
text-transform: uppercase; |
||||
color: $dusty-gray; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
&__rpc-save-button { |
||||
align-self: flex-end; |
||||
padding: 5px; |
||||
text-transform: uppercase; |
||||
color: $dusty-gray; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
&__button--red { |
||||
border-color: lighten($monzo, 10%); |
||||
color: $monzo; |
||||
|
||||
&:active { |
||||
background: lighten($monzo, 55%); |
||||
border-color: $monzo; |
||||
} |
||||
|
||||
&:hover { |
||||
border-color: $monzo; |
||||
} |
||||
} |
||||
|
||||
&__button--orange { |
||||
border-color: lighten($ecstasy, 20%); |
||||
color: $ecstasy; |
||||
|
||||
&:active { |
||||
background: lighten($ecstasy, 40%); |
||||
border-color: $ecstasy; |
||||
} |
||||
|
||||
&:hover { |
||||
border-color: $ecstasy; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,359 @@ |
||||
import React, { PureComponent } from 'react' |
||||
import PropTypes from 'prop-types' |
||||
import infuraCurrencies from '../../../../infura-conversion.json' |
||||
import validUrl from 'valid-url' |
||||
import { exportAsFile } from '../../../../util' |
||||
import SimpleDropdown from '../../../dropdowns/simple-dropdown' |
||||
import ToggleButton from 'react-toggle-button' |
||||
import { REVEAL_SEED_ROUTE } from '../../../../routes' |
||||
import locales from '../../../../../../app/_locales/index.json' |
||||
import TextField from '../../../text-field' |
||||
import Button from '../../../button' |
||||
|
||||
const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => { |
||||
return a.quote.name.toLocaleLowerCase().localeCompare(b.quote.name.toLocaleLowerCase()) |
||||
}) |
||||
|
||||
const infuraCurrencyOptions = sortedCurrencies.map(({ quote: { code, name } }) => { |
||||
return { |
||||
displayValue: `${code.toUpperCase()} - ${name}`, |
||||
key: code, |
||||
value: code, |
||||
} |
||||
}) |
||||
|
||||
const localeOptions = locales.map(locale => { |
||||
return { |
||||
displayValue: `${locale.name}`, |
||||
key: locale.code, |
||||
value: locale.code, |
||||
} |
||||
}) |
||||
|
||||
export default class SettingsTab extends PureComponent { |
||||
static contextTypes = { |
||||
t: PropTypes.func, |
||||
} |
||||
|
||||
static propTypes = { |
||||
metamask: PropTypes.object, |
||||
setUseBlockie: PropTypes.func, |
||||
setHexDataFeatureFlag: PropTypes.func, |
||||
setCurrentCurrency: PropTypes.func, |
||||
setRpcTarget: PropTypes.func, |
||||
displayWarning: PropTypes.func, |
||||
revealSeedConfirmation: PropTypes.func, |
||||
setFeatureFlagToBeta: PropTypes.func, |
||||
showResetAccountConfirmationModal: PropTypes.func, |
||||
warning: PropTypes.string, |
||||
history: PropTypes.object, |
||||
isMascara: PropTypes.bool, |
||||
updateCurrentLocale: PropTypes.func, |
||||
currentLocale: PropTypes.string, |
||||
useBlockie: PropTypes.bool, |
||||
sendHexData: PropTypes.bool, |
||||
currentCurrency: PropTypes.string, |
||||
conversionDate: PropTypes.number, |
||||
} |
||||
|
||||
state = { |
||||
newRpc: '', |
||||
} |
||||
|
||||
renderCurrentConversion () { |
||||
const { t } = this.context |
||||
const { currentCurrency, conversionDate, setCurrentCurrency } = this.props |
||||
|
||||
return ( |
||||
<div className="settings-page__content-row"> |
||||
<div className="settings-page__content-item"> |
||||
<span>{ t('currentConversion') }</span> |
||||
<span className="settings-page__content-description"> |
||||
{ t('updatedWithDate', [Date(conversionDate)]) } |
||||
</span> |
||||
</div> |
||||
<div className="settings-page__content-item"> |
||||
<div className="settings-page__content-item-col"> |
||||
<SimpleDropdown |
||||
placeholder={t('selectCurrency')} |
||||
options={infuraCurrencyOptions} |
||||
selectedOption={currentCurrency} |
||||
onSelect={newCurrency => setCurrentCurrency(newCurrency)} |
||||
/> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
renderCurrentLocale () { |
||||
const { t } = this.context |
||||
const { updateCurrentLocale, currentLocale } = this.props |
||||
const currentLocaleMeta = locales.find(locale => locale.code === currentLocale) |
||||
const currentLocaleName = currentLocaleMeta ? currentLocaleMeta.name : '' |
||||
|
||||
return ( |
||||
<div className="settings-page__content-row"> |
||||
<div className="settings-page__content-item"> |
||||
<span className="settings-page__content-label"> |
||||
{ t('currentLanguage') } |
||||
</span> |
||||
<span className="settings-page__content-description"> |
||||
{ currentLocaleName } |
||||
</span> |
||||
</div> |
||||
<div className="settings-page__content-item"> |
||||
<div className="settings-page__content-item-col"> |
||||
<SimpleDropdown |
||||
placeholder={t('selectLocale')} |
||||
options={localeOptions} |
||||
selectedOption={currentLocale} |
||||
onSelect={async newLocale => updateCurrentLocale(newLocale)} |
||||
/> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
renderNewRpcUrl () { |
||||
const { t } = this.context |
||||
const { newRpc } = this.state |
||||
|
||||
return ( |
||||
<div className="settings-page__content-row"> |
||||
<div className="settings-page__content-item"> |
||||
<span>{ t('newRPC') }</span> |
||||
</div> |
||||
<div className="settings-page__content-item"> |
||||
<div className="settings-page__content-item-col"> |
||||
<TextField |
||||
type="text" |
||||
id="new-rpc" |
||||
placeholder={t('newRPC')} |
||||
value={newRpc} |
||||
onChange={e => this.setState({ newRpc: e.target.value })} |
||||
onKeyPress={e => { |
||||
if (e.key === 'Enter') { |
||||
this.validateRpc(newRpc) |
||||
} |
||||
}} |
||||
fullWidth |
||||
margin="none" |
||||
/> |
||||
<div |
||||
className="settings-tab__rpc-save-button" |
||||
onClick={e => { |
||||
e.preventDefault() |
||||
this.validateRpc(newRpc) |
||||
}} |
||||
> |
||||
{ t('save') } |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
validateRpc (newRpc) { |
||||
const { setRpcTarget, displayWarning } = this.props |
||||
|
||||
if (validUrl.isWebUri(newRpc)) { |
||||
setRpcTarget(newRpc) |
||||
} else { |
||||
const appendedRpc = `http://${newRpc}` |
||||
|
||||
if (validUrl.isWebUri(appendedRpc)) { |
||||
displayWarning(this.context.t('uriErrorMsg')) |
||||
} else { |
||||
displayWarning(this.context.t('invalidRPC')) |
||||
} |
||||
} |
||||
} |
||||
|
||||
renderStateLogs () { |
||||
const { t } = this.context |
||||
const { displayWarning } = this.props |
||||
|
||||
return ( |
||||
<div className="settings-page__content-row"> |
||||
<div className="settings-page__content-item"> |
||||
<span>{ t('stateLogs') }</span> |
||||
<span className="settings-page__content-description"> |
||||
{ t('stateLogsDescription') } |
||||
</span> |
||||
</div> |
||||
<div className="settings-page__content-item"> |
||||
<div className="settings-page__content-item-col"> |
||||
<Button |
||||
type="primary" |
||||
large |
||||
onClick={() => { |
||||
window.logStateString((err, result) => { |
||||
if (err) { |
||||
displayWarning(t('stateLogError')) |
||||
} else { |
||||
exportAsFile('MetaMask State Logs.json', result) |
||||
} |
||||
}) |
||||
}} |
||||
> |
||||
{ t('downloadStateLogs') } |
||||
</Button> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
renderSeedWords () { |
||||
const { t } = this.context |
||||
const { history } = this.props |
||||
|
||||
return ( |
||||
<div className="settings-page__content-row"> |
||||
<div className="settings-page__content-item"> |
||||
<span>{ t('revealSeedWords') }</span> |
||||
</div> |
||||
<div className="settings-page__content-item"> |
||||
<div className="settings-page__content-item-col"> |
||||
<Button |
||||
type="secondary" |
||||
large |
||||
onClick={event => { |
||||
event.preventDefault() |
||||
history.push(REVEAL_SEED_ROUTE) |
||||
}} |
||||
> |
||||
{ t('revealSeedWords') } |
||||
</Button> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
renderOldUI () { |
||||
const { t } = this.context |
||||
const { setFeatureFlagToBeta } = this.props |
||||
|
||||
return ( |
||||
<div className="settings-page__content-row"> |
||||
<div className="settings-page__content-item"> |
||||
<span>{ t('useOldUI') }</span> |
||||
</div> |
||||
<div className="settings-page__content-item"> |
||||
<div className="settings-page__content-item-col"> |
||||
<Button |
||||
type="secondary" |
||||
large |
||||
className="settings-tab__button--orange" |
||||
onClick={event => { |
||||
event.preventDefault() |
||||
setFeatureFlagToBeta() |
||||
}} |
||||
> |
||||
{ t('useOldUI') } |
||||
</Button> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
renderResetAccount () { |
||||
const { t } = this.context |
||||
const { showResetAccountConfirmationModal } = this.props |
||||
|
||||
return ( |
||||
<div className="settings-page__content-row"> |
||||
<div className="settings-page__content-item"> |
||||
<span>{ t('resetAccount') }</span> |
||||
</div> |
||||
<div className="settings-page__content-item"> |
||||
<div className="settings-page__content-item-col"> |
||||
<Button |
||||
type="secondary" |
||||
large |
||||
className="settings-tab__button--orange" |
||||
onClick={event => { |
||||
event.preventDefault() |
||||
showResetAccountConfirmationModal() |
||||
}} |
||||
> |
||||
{ t('resetAccount') } |
||||
</Button> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
renderBlockieOptIn () { |
||||
const { useBlockie, setUseBlockie } = this.props |
||||
|
||||
return ( |
||||
<div className="settings-page__content-row"> |
||||
<div className="settings-page__content-item"> |
||||
<span>{ this.context.t('blockiesIdenticon') }</span> |
||||
</div> |
||||
<div className="settings-page__content-item"> |
||||
<div className="settings-page__content-item-col"> |
||||
<ToggleButton |
||||
value={useBlockie} |
||||
onToggle={value => setUseBlockie(!value)} |
||||
activeLabel="" |
||||
inactiveLabel="" |
||||
/> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
renderHexDataOptIn () { |
||||
const { t } = this.context |
||||
const { sendHexData, setHexDataFeatureFlag } = this.props |
||||
|
||||
return ( |
||||
<div className="settings-page__content-row"> |
||||
<div className="settings-page__content-item"> |
||||
<span>{ t('showHexData') }</span> |
||||
<div className="settings-page__content-description"> |
||||
{ t('showHexDataDescription') } |
||||
</div> |
||||
</div> |
||||
<div className="settings-page__content-item"> |
||||
<div className="settings-page__content-item-col"> |
||||
<ToggleButton |
||||
value={sendHexData} |
||||
onToggle={value => setHexDataFeatureFlag(!value)} |
||||
activeLabel="" |
||||
inactiveLabel="" |
||||
/> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
render () { |
||||
const { warning, isMascara } = this.props |
||||
|
||||
return ( |
||||
<div className="settings-page__content"> |
||||
{ warning && <div className="settings-tab__error">{ warning }</div> } |
||||
{ this.renderCurrentConversion() } |
||||
{ this.renderCurrentLocale() } |
||||
{ this.renderNewRpcUrl() } |
||||
{ this.renderStateLogs() } |
||||
{ this.renderSeedWords() } |
||||
{ !isMascara && this.renderOldUI() } |
||||
{ this.renderResetAccount() } |
||||
{ this.renderBlockieOptIn() } |
||||
{ this.renderHexDataOptIn() } |
||||
</div> |
||||
) |
||||
} |
||||
} |
@ -0,0 +1,59 @@ |
||||
import SettingsTab from './settings-tab.component' |
||||
import { compose } from 'recompose' |
||||
import { connect } from 'react-redux' |
||||
import { withRouter } from 'react-router-dom' |
||||
import { |
||||
setCurrentCurrency, |
||||
setRpcTarget, |
||||
displayWarning, |
||||
revealSeedConfirmation, |
||||
setUseBlockie, |
||||
updateCurrentLocale, |
||||
setFeatureFlag, |
||||
showModal, |
||||
} from '../../../../actions' |
||||
|
||||
const mapStateToProps = state => { |
||||
const { appState: { warning }, metamask } = state |
||||
const { |
||||
currentCurrency, |
||||
conversionDate, |
||||
useBlockie, |
||||
featureFlags: { sendHexData } = {}, |
||||
provider = {}, |
||||
isMascara, |
||||
currentLocale, |
||||
} = metamask |
||||
|
||||
return { |
||||
warning, |
||||
isMascara, |
||||
currentLocale, |
||||
currentCurrency, |
||||
conversionDate, |
||||
useBlockie, |
||||
sendHexData, |
||||
provider, |
||||
} |
||||
} |
||||
|
||||
const mapDispatchToProps = dispatch => { |
||||
return { |
||||
setCurrentCurrency: currency => dispatch(setCurrentCurrency(currency)), |
||||
setRpcTarget: newRpc => dispatch(setRpcTarget(newRpc)), |
||||
displayWarning: warning => dispatch(displayWarning(warning)), |
||||
revealSeedConfirmation: () => dispatch(revealSeedConfirmation()), |
||||
setUseBlockie: value => dispatch(setUseBlockie(value)), |
||||
updateCurrentLocale: key => dispatch(updateCurrentLocale(key)), |
||||
setFeatureFlagToBeta: () => { |
||||
return dispatch(setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')) |
||||
}, |
||||
setHexDataFeatureFlag: shouldShow => dispatch(setFeatureFlag('sendHexData', shouldShow)), |
||||
showResetAccountConfirmationModal: () => dispatch(showModal({ name: 'CONFIRM_RESET_ACCOUNT' })), |
||||
} |
||||
} |
||||
|
||||
export default compose( |
||||
withRouter, |
||||
connect(mapStateToProps, mapDispatchToProps) |
||||
)(SettingsTab) |
@ -0,0 +1,54 @@ |
||||
import React, { PureComponent } from 'react' |
||||
import PropTypes from 'prop-types' |
||||
import { Switch, Route, matchPath } from 'react-router-dom' |
||||
import TabBar from '../../tab-bar' |
||||
import SettingsTab from './settings-tab' |
||||
import InfoTab from './info-tab' |
||||
import { DEFAULT_ROUTE, SETTINGS_ROUTE, INFO_ROUTE } from '../../../routes' |
||||
|
||||
export default class SettingsPage extends PureComponent { |
||||
static propTypes = { |
||||
location: PropTypes.object, |
||||
history: PropTypes.object, |
||||
t: PropTypes.func, |
||||
} |
||||
|
||||
static contextTypes = { |
||||
t: PropTypes.func, |
||||
} |
||||
|
||||
render () { |
||||
const { history, location } = this.props |
||||
|
||||
return ( |
||||
<div className="main-container settings-page"> |
||||
<div className="settings-page__header"> |
||||
<div |
||||
className="settings-page__close-button" |
||||
onClick={() => history.push(DEFAULT_ROUTE)} |
||||
/> |
||||
<TabBar |
||||
tabs={[ |
||||
{ content: this.context.t('settings'), key: SETTINGS_ROUTE }, |
||||
{ content: this.context.t('info'), key: INFO_ROUTE }, |
||||
]} |
||||
isActive={key => matchPath(location.pathname, { path: key, exact: true })} |
||||
onSelect={key => history.push(key)} |
||||
/> |
||||
</div> |
||||
<Switch> |
||||
<Route |
||||
exact |
||||
path={INFO_ROUTE} |
||||
component={InfoTab} |
||||
/> |
||||
<Route |
||||
exact |
||||
path={SETTINGS_ROUTE} |
||||
component={SettingsTab} |
||||
/> |
||||
</Switch> |
||||
</div> |
||||
) |
||||
} |
||||
} |
@ -1,408 +0,0 @@ |
||||
const { Component } = require('react') |
||||
const { withRouter } = require('react-router-dom') |
||||
const { compose } = require('recompose') |
||||
const PropTypes = require('prop-types') |
||||
const h = require('react-hyperscript') |
||||
const connect = require('react-redux').connect |
||||
const actions = require('../../../actions') |
||||
const infuraCurrencies = require('../../../infura-conversion.json') |
||||
const validUrl = require('valid-url') |
||||
const { exportAsFile } = require('../../../util') |
||||
const SimpleDropdown = require('../../dropdowns/simple-dropdown') |
||||
const ToggleButton = require('react-toggle-button') |
||||
const { REVEAL_SEED_ROUTE } = require('../../../routes') |
||||
const locales = require('../../../../../app/_locales/index.json') |
||||
|
||||
import Button from '../../button' |
||||
|
||||
const getInfuraCurrencyOptions = () => { |
||||
const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => { |
||||
return a.quote.name.toLocaleLowerCase().localeCompare(b.quote.name.toLocaleLowerCase()) |
||||
}) |
||||
|
||||
return sortedCurrencies.map(({ quote: { code, name } }) => { |
||||
return { |
||||
displayValue: `${code.toUpperCase()} - ${name}`, |
||||
key: code, |
||||
value: code, |
||||
} |
||||
}) |
||||
} |
||||
|
||||
const getLocaleOptions = () => { |
||||
return locales.map((locale) => { |
||||
return { |
||||
displayValue: `${locale.name}`, |
||||
key: locale.code, |
||||
value: locale.code, |
||||
} |
||||
}) |
||||
} |
||||
|
||||
class Settings extends Component { |
||||
constructor (props) { |
||||
super(props) |
||||
|
||||
this.state = { |
||||
newRpc: '', |
||||
} |
||||
} |
||||
|
||||
renderBlockieOptIn () { |
||||
const { metamask: { useBlockie }, setUseBlockie } = this.props |
||||
|
||||
return h('div.settings__content-row', [ |
||||
h('div.settings__content-item', [ |
||||
h('span', this.context.t('blockiesIdenticon')), |
||||
]), |
||||
h('div.settings__content-item', [ |
||||
h('div.settings__content-item-col', [ |
||||
h(ToggleButton, { |
||||
value: useBlockie, |
||||
onToggle: (value) => setUseBlockie(!value), |
||||
activeLabel: '', |
||||
inactiveLabel: '', |
||||
}), |
||||
]), |
||||
]), |
||||
]) |
||||
} |
||||
|
||||
renderHexDataOptIn () { |
||||
const { metamask: { featureFlags: { sendHexData } }, setHexDataFeatureFlag } = this.props |
||||
|
||||
return h('div.settings__content-row', [ |
||||
h('div.settings__content-item', [ |
||||
h('span', this.context.t('showHexData')), |
||||
h( |
||||
'div.settings__content-description', |
||||
this.context.t('showHexDataDescription') |
||||
), |
||||
]), |
||||
h('div.settings__content-item', [ |
||||
h('div.settings__content-item-col', [ |
||||
h(ToggleButton, { |
||||
value: sendHexData, |
||||
onToggle: (value) => setHexDataFeatureFlag(!value), |
||||
activeLabel: '', |
||||
inactiveLabel: '', |
||||
}), |
||||
]), |
||||
]), |
||||
]) |
||||
} |
||||
|
||||
renderCurrentConversion () { |
||||
const { metamask: { currentCurrency, conversionDate }, setCurrentCurrency } = this.props |
||||
|
||||
return h('div.settings__content-row', [ |
||||
h('div.settings__content-item', [ |
||||
h('span', this.context.t('currentConversion')), |
||||
h('span.settings__content-description', `Updated ${Date(conversionDate)}`), |
||||
]), |
||||
h('div.settings__content-item', [ |
||||
h('div.settings__content-item-col', [ |
||||
h(SimpleDropdown, { |
||||
placeholder: this.context.t('selectCurrency'), |
||||
options: getInfuraCurrencyOptions(), |
||||
selectedOption: currentCurrency, |
||||
onSelect: newCurrency => setCurrentCurrency(newCurrency), |
||||
}), |
||||
]), |
||||
]), |
||||
]) |
||||
} |
||||
|
||||
renderCurrentLocale () { |
||||
const { updateCurrentLocale, currentLocale } = this.props |
||||
const currentLocaleMeta = locales.find(locale => locale.code === currentLocale) |
||||
const currentLocaleName = currentLocaleMeta ? currentLocaleMeta.name : '' |
||||
|
||||
return h('div.settings__content-row', [ |
||||
h('div.settings__content-item', [ |
||||
h('span', 'Current Language'), |
||||
h('span.settings__content-description', `${currentLocaleName}`), |
||||
]), |
||||
h('div.settings__content-item', [ |
||||
h('div.settings__content-item-col', [ |
||||
h(SimpleDropdown, { |
||||
placeholder: 'Select Locale', |
||||
options: getLocaleOptions(), |
||||
selectedOption: currentLocale, |
||||
onSelect: async (newLocale) => { |
||||
updateCurrentLocale(newLocale) |
||||
}, |
||||
}), |
||||
]), |
||||
]), |
||||
]) |
||||
} |
||||
|
||||
renderCurrentProvider () { |
||||
const { metamask: { provider = {} } } = this.props |
||||
let title, value, color |
||||
|
||||
switch (provider.type) { |
||||
|
||||
case 'mainnet': |
||||
title = this.context.t('currentNetwork') |
||||
value = this.context.t('mainnet') |
||||
color = '#038789' |
||||
break |
||||
|
||||
case 'ropsten': |
||||
title = this.context.t('currentNetwork') |
||||
value = this.context.t('ropsten') |
||||
color = '#e91550' |
||||
break |
||||
|
||||
case 'kovan': |
||||
title = this.context.t('currentNetwork') |
||||
value = this.context.t('kovan') |
||||
color = '#690496' |
||||
break |
||||
|
||||
case 'rinkeby': |
||||
title = this.context.t('currentNetwork') |
||||
value = this.context.t('rinkeby') |
||||
color = '#ebb33f' |
||||
break |
||||
|
||||
default: |
||||
title = this.context.t('currentRpc') |
||||
value = provider.rpcTarget |
||||
} |
||||
|
||||
return h('div.settings__content-row', [ |
||||
h('div.settings__content-item', title), |
||||
h('div.settings__content-item', [ |
||||
h('div.settings__content-item-col', [ |
||||
h('div.settings__provider-wrapper', [ |
||||
h('div.settings__provider-icon', { style: { background: color } }), |
||||
h('div', value), |
||||
]), |
||||
]), |
||||
]), |
||||
]) |
||||
} |
||||
|
||||
renderNewRpcUrl () { |
||||
return ( |
||||
h('div.settings__content-row', [ |
||||
h('div.settings__content-item', [ |
||||
h('span', this.context.t('newRPC')), |
||||
]), |
||||
h('div.settings__content-item', [ |
||||
h('div.settings__content-item-col', [ |
||||
h('input.settings__input', { |
||||
placeholder: this.context.t('newRPC'), |
||||
onChange: event => this.setState({ newRpc: event.target.value }), |
||||
onKeyPress: event => { |
||||
if (event.key === 'Enter') { |
||||
this.validateRpc(this.state.newRpc) |
||||
} |
||||
}, |
||||
}), |
||||
h('div.settings__rpc-save-button', { |
||||
onClick: event => { |
||||
event.preventDefault() |
||||
this.validateRpc(this.state.newRpc) |
||||
}, |
||||
}, this.context.t('save')), |
||||
]), |
||||
]), |
||||
]) |
||||
) |
||||
} |
||||
|
||||
validateRpc (newRpc) { |
||||
const { setRpcTarget, displayWarning } = this.props |
||||
|
||||
if (validUrl.isWebUri(newRpc)) { |
||||
setRpcTarget(newRpc) |
||||
} else { |
||||
const appendedRpc = `http://${newRpc}` |
||||
|
||||
if (validUrl.isWebUri(appendedRpc)) { |
||||
displayWarning(this.context.t('uriErrorMsg')) |
||||
} else { |
||||
displayWarning(this.context.t('invalidRPC')) |
||||
} |
||||
} |
||||
} |
||||
|
||||
renderStateLogs () { |
||||
return ( |
||||
h('div.settings__content-row', [ |
||||
h('div.settings__content-item', [ |
||||
h('div', this.context.t('stateLogs')), |
||||
h( |
||||
'div.settings__content-description', |
||||
this.context.t('stateLogsDescription') |
||||
), |
||||
]), |
||||
h('div.settings__content-item', [ |
||||
h('div.settings__content-item-col', [ |
||||
h(Button, { |
||||
type: 'primary', |
||||
large: true, |
||||
className: 'settings__button', |
||||
onClick (event) { |
||||
window.logStateString((err, result) => { |
||||
if (err) { |
||||
this.state.dispatch(actions.displayWarning(this.context.t('stateLogError'))) |
||||
} else { |
||||
exportAsFile('MetaMask State Logs.json', result) |
||||
} |
||||
}) |
||||
}, |
||||
}, this.context.t('downloadStateLogs')), |
||||
]), |
||||
]), |
||||
]) |
||||
) |
||||
} |
||||
|
||||
renderSeedWords () { |
||||
const { history } = this.props |
||||
|
||||
return ( |
||||
h('div.settings__content-row', [ |
||||
h('div.settings__content-item', this.context.t('revealSeedWords')), |
||||
h('div.settings__content-item', [ |
||||
h('div.settings__content-item-col', [ |
||||
h(Button, { |
||||
type: 'primary', |
||||
large: true, |
||||
className: 'settings__button--red', |
||||
onClick: event => { |
||||
event.preventDefault() |
||||
history.push(REVEAL_SEED_ROUTE) |
||||
}, |
||||
}, this.context.t('revealSeedWords')), |
||||
]), |
||||
]), |
||||
]) |
||||
) |
||||
} |
||||
|
||||
renderOldUI () { |
||||
const { setFeatureFlagToBeta } = this.props |
||||
|
||||
return ( |
||||
h('div.settings__content-row', [ |
||||
h('div.settings__content-item', this.context.t('useOldUI')), |
||||
h('div.settings__content-item', [ |
||||
h('div.settings__content-item-col', [ |
||||
h(Button, { |
||||
type: 'primary', |
||||
large: true, |
||||
className: 'settings__button--orange', |
||||
onClick (event) { |
||||
event.preventDefault() |
||||
setFeatureFlagToBeta() |
||||
}, |
||||
}, this.context.t('useOldUI')), |
||||
]), |
||||
]), |
||||
]) |
||||
) |
||||
} |
||||
|
||||
renderResetAccount () { |
||||
const { showResetAccountConfirmationModal } = this.props |
||||
|
||||
return h('div.settings__content-row', [ |
||||
h('div.settings__content-item', this.context.t('resetAccount')), |
||||
h('div.settings__content-item', [ |
||||
h('div.settings__content-item-col', [ |
||||
h(Button, { |
||||
type: 'primary', |
||||
large: true, |
||||
className: 'settings__button--orange', |
||||
onClick (event) { |
||||
event.preventDefault() |
||||
showResetAccountConfirmationModal() |
||||
}, |
||||
}, this.context.t('resetAccount')), |
||||
]), |
||||
]), |
||||
]) |
||||
} |
||||
|
||||
render () { |
||||
const { warning, isMascara } = this.props |
||||
|
||||
return ( |
||||
h('div.settings__content', [ |
||||
warning && h('div.settings__error', warning), |
||||
this.renderCurrentConversion(), |
||||
this.renderCurrentLocale(), |
||||
// this.renderCurrentProvider(),
|
||||
this.renderNewRpcUrl(), |
||||
this.renderStateLogs(), |
||||
this.renderSeedWords(), |
||||
!isMascara && this.renderOldUI(), |
||||
this.renderResetAccount(), |
||||
this.renderBlockieOptIn(), |
||||
this.renderHexDataOptIn(), |
||||
]) |
||||
) |
||||
} |
||||
} |
||||
|
||||
Settings.propTypes = { |
||||
metamask: PropTypes.object, |
||||
setUseBlockie: PropTypes.func, |
||||
setHexDataFeatureFlag: PropTypes.func, |
||||
setCurrentCurrency: PropTypes.func, |
||||
setRpcTarget: PropTypes.func, |
||||
displayWarning: PropTypes.func, |
||||
revealSeedConfirmation: PropTypes.func, |
||||
setFeatureFlagToBeta: PropTypes.func, |
||||
showResetAccountConfirmationModal: PropTypes.func, |
||||
warning: PropTypes.string, |
||||
history: PropTypes.object, |
||||
isMascara: PropTypes.bool, |
||||
updateCurrentLocale: PropTypes.func, |
||||
currentLocale: PropTypes.string, |
||||
t: PropTypes.func, |
||||
} |
||||
|
||||
const mapStateToProps = state => { |
||||
return { |
||||
metamask: state.metamask, |
||||
warning: state.appState.warning, |
||||
isMascara: state.metamask.isMascara, |
||||
currentLocale: state.metamask.currentLocale, |
||||
} |
||||
} |
||||
|
||||
const mapDispatchToProps = dispatch => { |
||||
return { |
||||
setCurrentCurrency: currency => dispatch(actions.setCurrentCurrency(currency)), |
||||
setRpcTarget: newRpc => dispatch(actions.setRpcTarget(newRpc)), |
||||
displayWarning: warning => dispatch(actions.displayWarning(warning)), |
||||
revealSeedConfirmation: () => dispatch(actions.revealSeedConfirmation()), |
||||
setUseBlockie: value => dispatch(actions.setUseBlockie(value)), |
||||
updateCurrentLocale: key => dispatch(actions.updateCurrentLocale(key)), |
||||
setFeatureFlagToBeta: () => { |
||||
return dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')) |
||||
}, |
||||
setHexDataFeatureFlag: (featureFlagShowState) => { |
||||
return dispatch(actions.setFeatureFlag('sendHexData', featureFlagShowState)) |
||||
}, |
||||
showResetAccountConfirmationModal: () => { |
||||
return dispatch(actions.showModal({ name: 'CONFIRM_RESET_ACCOUNT' })) |
||||
}, |
||||
} |
||||
} |
||||
|
||||
Settings.contextTypes = { |
||||
t: PropTypes.func, |
||||
} |
||||
|
||||
module.exports = compose( |
||||
withRouter, |
||||
connect(mapStateToProps, mapDispatchToProps) |
||||
)(Settings) |
@ -1,214 +0,0 @@ |
||||
.settings { |
||||
position: relative; |
||||
background: $white; |
||||
display: flex; |
||||
flex-flow: column nowrap; |
||||
} |
||||
|
||||
.settings__header { |
||||
padding: 25px; |
||||
} |
||||
|
||||
.settings__close-button::after { |
||||
content: '\00D7'; |
||||
font-size: 40px; |
||||
color: $dusty-gray; |
||||
position: absolute; |
||||
top: 25px; |
||||
right: 30px; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
.settings__error { |
||||
padding-bottom: 20px; |
||||
text-align: center; |
||||
color: $crimson; |
||||
} |
||||
|
||||
.settings__content { |
||||
padding: 0 25px; |
||||
height: auto; |
||||
overflow: auto; |
||||
} |
||||
|
||||
.settings__content-row { |
||||
display: flex; |
||||
flex-direction: row; |
||||
padding: 10px 0 20px; |
||||
|
||||
@media screen and (max-width: 575px) { |
||||
flex-direction: column; |
||||
padding: 10px 0; |
||||
} |
||||
} |
||||
|
||||
.settings__content-item { |
||||
flex: 1; |
||||
min-width: 0; |
||||
display: flex; |
||||
flex-direction: column; |
||||
padding: 0 5px; |
||||
height: 71px; |
||||
|
||||
@media screen and (max-width: 575px) { |
||||
height: initial; |
||||
padding: 5px 0; |
||||
} |
||||
|
||||
&--without-height { |
||||
height: initial; |
||||
} |
||||
} |
||||
|
||||
.settings__content-item-col { |
||||
max-width: 300px; |
||||
display: flex; |
||||
flex-direction: column; |
||||
|
||||
@media screen and (max-width: 575px) { |
||||
max-width: 100%; |
||||
width: 100%; |
||||
} |
||||
} |
||||
|
||||
.settings__content-description { |
||||
font-size: 14px; |
||||
color: $dusty-gray; |
||||
padding-top: 5px; |
||||
} |
||||
|
||||
.settings__input { |
||||
padding-left: 10px; |
||||
font-size: 14px; |
||||
height: 40px; |
||||
border: 1px solid $alto; |
||||
} |
||||
|
||||
.settings__input::-webkit-input-placeholder { |
||||
font-weight: 100; |
||||
color: $dusty-gray; |
||||
} |
||||
|
||||
.settings__input::-moz-placeholder { |
||||
font-weight: 100; |
||||
color: $dusty-gray; |
||||
} |
||||
|
||||
.settings__input:-ms-input-placeholder { |
||||
font-weight: 100; |
||||
color: $dusty-gray; |
||||
} |
||||
|
||||
.settings__input:-moz-placeholder { |
||||
font-weight: 100; |
||||
color: $dusty-gray; |
||||
} |
||||
|
||||
.settings__provider-wrapper { |
||||
font-size: 16px; |
||||
border: 1px solid $alto; |
||||
border-radius: 2px; |
||||
padding: 15px; |
||||
background-color: $white; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: flex-start; |
||||
} |
||||
|
||||
.settings__provider-icon { |
||||
height: 10px; |
||||
width: 10px; |
||||
margin-right: 10px; |
||||
border-radius: 10px; |
||||
} |
||||
|
||||
.settings__rpc-save-button { |
||||
align-self: flex-end; |
||||
padding: 5px; |
||||
text-transform: uppercase; |
||||
color: $dusty-gray; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
.settings__button--red { |
||||
border-color: lighten($monzo, 10%); |
||||
color: $monzo; |
||||
|
||||
&:active { |
||||
background: lighten($monzo, 55%); |
||||
border-color: $monzo; |
||||
} |
||||
|
||||
&:hover { |
||||
border-color: $monzo; |
||||
} |
||||
} |
||||
|
||||
.settings__button--orange { |
||||
border-color: lighten($ecstasy, 20%); |
||||
color: $ecstasy; |
||||
|
||||
&:active { |
||||
background: lighten($ecstasy, 40%); |
||||
border-color: $ecstasy; |
||||
} |
||||
|
||||
&:hover { |
||||
border-color: $ecstasy; |
||||
} |
||||
} |
||||
|
||||
.settings__info-logo-wrapper { |
||||
height: 80px; |
||||
margin-bottom: 20px; |
||||
} |
||||
|
||||
.settings__info-logo { |
||||
max-height: 100%; |
||||
max-width: 100%; |
||||
} |
||||
|
||||
.settings__info-item { |
||||
padding: 10px 0; |
||||
} |
||||
|
||||
.settings__info-link-header { |
||||
padding-bottom: 15px; |
||||
|
||||
@media screen and (max-width: 575px) { |
||||
padding-bottom: 5px; |
||||
} |
||||
} |
||||
|
||||
.settings__info-link-item { |
||||
padding: 15px 0; |
||||
|
||||
@media screen and (max-width: 575px) { |
||||
padding: 5px 0; |
||||
} |
||||
} |
||||
|
||||
.settings__info-version-number { |
||||
padding-top: 5px; |
||||
font-size: 13px; |
||||
color: $dusty-gray; |
||||
} |
||||
|
||||
.settings__info-about { |
||||
color: $dusty-gray; |
||||
margin-bottom: 15px; |
||||
} |
||||
|
||||
.settings__info-link { |
||||
color: $curious-blue; |
||||
} |
||||
|
||||
.settings__info-separator { |
||||
margin: 15px 0; |
||||
width: 80px; |
||||
border-color: $alto; |
||||
border: none; |
||||
height: 1px; |
||||
background-color: $alto; |
||||
color: $alto; |
||||
} |
Loading…
Reference in new issue