Browse Source

Merge pull request #747 from meriadec/pixel-polish

Pixel polish
master
Gaëtan Renaudeau 7 years ago
committed by GitHub
parent
commit
d176efe551
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 53
      src/components/CurrentAddress/index.js
  2. 3
      src/components/ManagerPage/FirmwareUpdate.js
  3. 104
      src/components/base/Button/index.js
  4. 9
      src/components/modals/AccountSettingRenderBody.js
  5. 46
      src/components/modals/OperationDetails.js
  6. 7
      src/components/modals/Receive/index.js
  7. 10
      src/components/modals/Receive/steps/04-step-receive-funds.js
  8. 6
      static/i18n/en/app.yml

53
src/components/CurrentAddress/index.js

@ -16,7 +16,7 @@ import Box from 'components/base/Box'
import CopyToClipboard from 'components/base/CopyToClipboard'
import QRCode from 'components/base/QRCode'
import IconCheck from 'icons/Check'
import IconRecheck from 'icons/Recover'
import IconCopy from 'icons/Copy'
import IconInfoCircle from 'icons/InfoCircle'
import IconShield from 'icons/Shield'
@ -27,26 +27,34 @@ const Container = styled(Box).attrs({
bg: p =>
p.withQRCode ? (p.notValid ? rgba(p.theme.colors.alertRed, 0.02) : 'lightGrey') : 'transparent',
py: 4,
px: 7,
px: 5,
})`
border: ${p => (p.notValid ? `1px dashed ${rgba(p.theme.colors.alertRed, 0.5)}` : 'none')};
`
const Address = styled(Box).attrs({
bg: p => (p.notValid ? 'transparent' : p.withQRCode ? 'white' : 'lightGrey'),
bg: 'white',
borderRadius: 1,
color: 'dark',
ff: 'Open Sans|SemiBold',
fontSize: 4,
mt: 2,
px: p => (p.notValid ? 0 : 4),
py: p => (p.notValid ? 0 : 3),
px: 4,
py: 3,
relative: true,
})`
border: ${p => (p.notValid ? 'none' : `1px dashed ${p.theme.colors.fog}`)};
border: ${p => `1px dashed ${p.theme.colors.fog}`};
cursor: text;
user-select: text;
`
const CopyFeedback = styled(Box).attrs({
sticky: true,
bg: 'white',
align: 'center',
justify: 'center',
})``
const Label = styled(Box).attrs({
alignItems: 'center',
color: 'graphite',
@ -77,10 +85,11 @@ const FooterButtonWrapper = styled(Box).attrs({
alignItems: 'center',
justifyContent: 'center',
borderRadius: 1,
px: 2,
})`
line-height: 1;
cursor: pointer;
height: 55px;
width: 55px;
&:hover {
background-color: ${p => rgba(p.theme.colors.wallet, 0.1)};
@ -131,7 +140,7 @@ type Props = {
withVerify: boolean,
}
class CurrentAddress extends PureComponent<Props> {
class CurrentAddress extends PureComponent<Props, { copyFeedback: boolean }> {
static defaultProps = {
addressVerified: null,
amount: null,
@ -145,6 +154,12 @@ class CurrentAddress extends PureComponent<Props> {
withVerify: false,
}
state = {
copyFeedback: false,
}
_isUnmounted = false
render() {
const {
account: { name: accountName, currency },
@ -163,6 +178,8 @@ class CurrentAddress extends PureComponent<Props> {
...props
} = this.props
const { copyFeedback } = this.state
const notValid = addressVerified === false
return (
@ -193,6 +210,7 @@ class CurrentAddress extends PureComponent<Props> {
<IconInfoCircle size={12} />
</Label>
<Address withQRCode={withQRCode} notValid={notValid}>
{copyFeedback && <CopyFeedback>{t('app:common.addressCopied')}</CopyFeedback>}
{address}
</Address>
{withBadge && (
@ -207,11 +225,26 @@ class CurrentAddress extends PureComponent<Props> {
)}
{withFooter && (
<Footer>
<FooterButton icon={<IconCheck size={16} />} label="Verify" onClick={onVerify} />
<FooterButton
icon={<IconRecheck size={16} />}
label={notValid ? t('app:common.verify') : t('app:common.reverify')}
onClick={onVerify}
/>
<CopyToClipboard
data={address}
render={copy => (
<FooterButton icon={<IconCopy size={16} />} label="Copy" onClick={copy} />
<FooterButton
icon={<IconCopy size={16} />}
label={t('app:common.copy')}
onClick={() => {
this.setState({ copyFeedback: true })
setTimeout(() => {
if (this._isUnmounted) return
this.setState({ copyFeedback: false })
}, 1e3)
copy()
}}
/>
)}
/>
</Footer>

3
src/components/ManagerPage/FirmwareUpdate.js

@ -16,6 +16,7 @@ import getLatestFirmwareForDevice from 'commands/getLatestFirmwareForDevice'
import installOsuFirmware from 'commands/installOsuFirmware'
import type { DeviceInfo } from 'helpers/devices/getDeviceInfo'
import Tooltip from 'components/base/Tooltip'
import Box, { Card } from 'components/base/Box'
import Text from 'components/base/Text'
import Modal, { ModalBody, ModalFooter, ModalTitle, ModalContent } from 'components/base/Modal'
@ -158,7 +159,9 @@ class FirmwareUpdate extends PureComponent<Props, State> {
Ledger Nano S
</Text>
<Box color="wallet" style={{ marginLeft: 10 }}>
<Tooltip render={() => t('app:manager.yourDeviceIsGenuine')}>
<CheckFull size={13} color="wallet" />
</Tooltip>
</Box>
</Box>
<Text ff="Open Sans|SemiBold" fontSize={2}>

104
src/components/base/Button/index.js

@ -1,11 +1,12 @@
// @flow
import React from 'react'
import React, { PureComponent } from 'react'
import styled from 'styled-components'
import { space, fontSize, fontWeight, color } from 'styled-system'
import noop from 'lodash/noop'
import { track } from 'analytics/segment'
import { isGlobalTabEnabled } from 'config/global-tab'
import { darken, lighten, rgba } from 'styles/helpers'
import fontFamily from 'styles/styled/fontFamily'
import { focusedShadowStyle } from 'components/base/Box/Tabbable'
@ -16,21 +17,28 @@ type Style = any // FIXME
const buttonStyles: { [_: string]: Style } = {
default: {
default: noop,
default: p => `
box-shadow: ${p.isFocused ? focusedShadowStyle : ''}
`,
active: p => `
background: ${rgba(p.theme.colors.fog, 0.3)};
`,
hover: p => `
background: ${rgba(p.theme.colors.fog, 0.2)};
`,
focus: () => `
box-shadow: ${focusedShadowStyle};
`,
},
primary: {
default: p => `
background: ${p.disabled ? `${p.theme.colors.lightFog} !important` : p.theme.colors.wallet};
color: ${p.disabled ? p.theme.colors.grey : p.theme.colors.white};
box-shadow: ${
p.isFocused
? `
0 0 0 1px ${darken(p.theme.colors.wallet, 0.3)} inset,
0 0 0 1px ${rgba(p.theme.colors.wallet, 0.5)},
0 0 0 4px ${rgba(p.theme.colors.wallet, 0.3)};`
: ''
}
`,
hover: p => `
background: ${lighten(p.theme.colors.wallet, 0.05)};
@ -38,17 +46,20 @@ const buttonStyles: { [_: string]: Style } = {
active: p => `
background: ${darken(p.theme.colors.wallet, 0.1)};
`,
focus: p => `
box-shadow:
0 0 0 1px ${darken(p.theme.colors.wallet, 0.3)} inset,
0 0 0 1px ${rgba(p.theme.colors.wallet, 0.5)},
0 0 0 4px ${rgba(p.theme.colors.wallet, 0.3)};
`,
},
danger: {
default: p => `
background: ${p.disabled ? `${p.theme.colors.lightFog} !important` : p.theme.colors.alertRed};
color: ${p.disabled ? p.theme.colors.grey : p.theme.colors.white};
box-shadow: ${
p.isFocused
? `
0 0 0 1px ${darken(p.theme.colors.alertRed, 0.3)} inset,
0 0 0 1px ${rgba(p.theme.colors.alertRed, 0.5)},
0 0 0 4px ${rgba(p.theme.colors.alertRed, 0.3)};
`
: ''
}
`,
hover: p => `
background: ${lighten(p.theme.colors.alertRed, 0.1)};
@ -56,12 +67,6 @@ const buttonStyles: { [_: string]: Style } = {
active: p => `
background: ${darken(p.theme.colors.alertRed, 0.1)};
`,
focus: p => `
box-shadow:
0 0 0 1px ${darken(p.theme.colors.alertRed, 0.3)} inset,
0 0 0 1px ${rgba(p.theme.colors.alertRed, 0.5)},
0 0 0 4px ${rgba(p.theme.colors.alertRed, 0.3)};
`,
},
outline: {
default: p => `
@ -114,18 +119,22 @@ const buttonStyles: { [_: string]: Style } = {
function getStyles(props, state) {
let output = ``
const defaultStyle = buttonStyles.default[state]
if (defaultStyle) {
output += defaultStyle(props) || ''
}
let hasModifier = false
for (const s in buttonStyles) {
if (buttonStyles.hasOwnProperty(s) && props[s] === true) {
const style = buttonStyles[s][state]
if (style) {
hasModifier = true
output += style(props)
}
}
}
if (!hasModifier) {
const defaultStyle = buttonStyles.default[state]
if (defaultStyle) {
output += defaultStyle(props) || ''
}
}
return output
}
@ -176,9 +185,38 @@ type Props = {
eventProperties?: Object,
}
const Button = (props: Props) => {
const { disabled } = props
const { onClick, children, isLoading, event, eventProperties, ...rest } = props
class Button extends PureComponent<
Props,
{
isFocused: boolean,
},
> {
static defaultProps = {
onClick: noop,
primary: false,
small: false,
padded: false,
danger: false,
}
state = {
isFocused: false,
}
handleFocus = () => {
if (isGlobalTabEnabled()) {
this.setState({ isFocused: true })
}
}
handleBlur = () => {
this.setState({ isFocused: false })
}
render() {
const { isFocused } = this.state
const { disabled } = this.props
const { onClick, children, isLoading, event, eventProperties, ...rest } = this.props
const isClickDisabled = disabled || isLoading
const onClickHandler = e => {
if (onClick) {
@ -189,21 +227,17 @@ const Button = (props: Props) => {
}
}
return (
<Base {...rest} onClick={isClickDisabled ? undefined : onClickHandler}>
<Base
{...rest}
onClick={isClickDisabled ? undefined : onClickHandler}
isFocused={isFocused}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
>
{isLoading ? <Spinner size={16} /> : children}
</Base>
)
}
Button.defaultProps = {
children: undefined,
disabled: undefined,
icon: undefined,
onClick: noop,
primary: false,
small: false,
padded: false,
danger: false,
}
export default Button

9
src/components/modals/AccountSettingRenderBody.js

@ -206,6 +206,7 @@ class HelperComp extends PureComponent<Props, State> {
</Box>
<Box>
<Input
containerProps={{ style: { width: 230 } }}
value={account.name}
maxLength={MAX_ACCOUNT_NAME_SIZE}
onChange={this.handleChangeName}
@ -220,7 +221,7 @@ class HelperComp extends PureComponent<Props, State> {
<OptionRowTitle>{t('app:account.settings.unit.title')}</OptionRowTitle>
<OptionRowDesc>{t('app:account.settings.unit.desc')}</OptionRowDesc>
</Box>
<Box style={{ width: 180 }}>
<Box style={{ width: 230 }}>
<Select
onChange={this.handleChangeUnit}
getOptionValue={unitGetOptionValue}
@ -254,7 +255,7 @@ class HelperComp extends PureComponent<Props, State> {
</Box>
</Container>
) : null}
<Spoiler title={t('app:account.settings.advancedLogs')}>
<Spoiler textTransform title={t('app:account.settings.advancedLogs')}>
<SyncAgo date={account.lastSyncDate} />
<textarea
readOnly
@ -274,10 +275,10 @@ class HelperComp extends PureComponent<Props, State> {
</Spoiler>
</ModalContent>
<ModalFooter horizontal>
<Button small danger type="button" onClick={this.handleOpenRemoveAccountModal}>
<Button padded danger type="button" onClick={this.handleOpenRemoveAccountModal}>
{t('app:common.delete')}
</Button>
<Button small ml="auto" type="submit" primary>
<Button padded ml="auto" type="submit" primary>
{t('app:common.apply')}
</Button>
</ModalFooter>

46
src/components/modals/OperationDetails.js

@ -16,6 +16,7 @@ import { MODAL_OPERATION_DETAILS } from 'config/constants'
import { getMarketColor } from 'styles/helpers'
import Box from 'components/base/Box'
import CopyToClipboard from 'components/base/CopyToClipboard'
import GradientBox from 'components/GradientBox'
import GrowScroll from 'components/base/GrowScroll'
import Button from 'components/base/Button'
@ -28,6 +29,7 @@ import { createStructuredSelector, createSelector } from 'reselect'
import { accountSelector } from 'reducers/accounts'
import { currencySettingsForAccountSelector, marketIndicatorSelector } from 'reducers/settings'
import IconCopy from 'icons/Copy'
import IconChevronRight from 'icons/ChevronRight'
import CounterValue from 'components/CounterValue'
import ConfirmationCheck from 'components/OperationsList/ConfirmationCheck'
@ -43,11 +45,37 @@ const OpDetailsTitle = styled(Box).attrs({
letter-spacing: 2px;
`
const CopyBtn = styled(Box).attrs({
horizontal: true,
flow: 1,
align: 'center',
color: 'wallet',
cursor: 'pointer',
ff: 'Open Sans|SemiBold',
})`
background: white;
position: absolute;
top: 0;
right: 0;
bottom: 0;
padding-left: 20px;
background: linear-gradient(to right, rgba(255, 255, 255, 0), #ffffff 20%);
`
const OpDetailsData = styled(Box).attrs({
ff: 'Open Sans',
color: 'smoke',
fontSize: 4,
})``
relative: true,
})`
${CopyBtn} {
display: none;
}
&:hover ${CopyBtn} {
display: flex;
}
`
const CanSelect = styled.div`
user-select: text;
@ -166,11 +194,13 @@ const OperationDetails = connect(mapStateToProps)((props: Props) => {
<FormattedVal unit={unit} showCode val={fee} color="dark" />
</OpDetailsData>
</Fragment>
) : null}
) : (
<OpDetailsData>{t('app:operationDetails.noFees')}</OpDetailsData>
)}
</Box>
<Box flex={1}>
<OpDetailsTitle>{t('app:operationDetails.status')}</OpDetailsTitle>
<OpDetailsData color={isConfirmed ? 'positiveGreen' : null} horizontal>
<OpDetailsData color={isConfirmed ? 'positiveGreen' : null} horizontal flow={1}>
<Box>
{isConfirmed
? t('app:operationDetails.confirmed')
@ -185,6 +215,16 @@ const OperationDetails = connect(mapStateToProps)((props: Props) => {
<OpDetailsTitle>{t('app:operationDetails.identifier')}</OpDetailsTitle>
<OpDetailsData>
<Ellipsis canSelect>{hash}</Ellipsis>
<CopyToClipboard
data={hash}
render={copy => (
<CopyBtn onClick={copy}>
<IconCopy size={16} />
<span>{t('app:common.copy')}</span>
</CopyBtn>
)}
/>
</OpDetailsData>
</Box>
<B />

7
src/components/modals/Receive/index.js

@ -25,7 +25,7 @@ import Stepper from 'components/base/Stepper'
import StepAccount, { StepAccountFooter } from './steps/01-step-account'
import StepConnectDevice, { StepConnectDeviceFooter } from './steps/02-step-connect-device'
import StepConfirmAddress, { StepConfirmAddressFooter } from './steps/03-step-confirm-address'
import StepReceiveFunds, { StepReceiveFundsFooter } from './steps/04-step-receive-funds'
import StepReceiveFunds from './steps/04-step-receive-funds'
type Props = {
t: T,
@ -54,7 +54,7 @@ export type StepProps = DefaultStepProps & {
onResetSkip: void => void,
onChangeAccount: (?Account) => void,
onChangeAppOpened: boolean => void,
onChangeAddressVerified: boolean => void,
onChangeAddressVerified: (?boolean) => void,
}
const createSteps = ({ t }: { t: T }) => [
@ -83,7 +83,6 @@ const createSteps = ({ t }: { t: T }) => [
id: 'receive',
label: t('app:receive.steps.receiveFunds.title'),
component: StepReceiveFunds,
footer: StepReceiveFundsFooter,
},
]
@ -131,6 +130,8 @@ class ReceiveModal extends PureComponent<Props, State> {
handleChangeAddressVerified = (isAddressVerified: boolean) => {
if (isAddressVerified) {
this.setState({ isAddressVerified })
} else if (isAddressVerified === null) {
this.setState({ isAddressVerified: null, errorSteps: [] })
} else {
const confirmStepIndex = this.STEPS.findIndex(step => step.id === 'confirm')
if (confirmStepIndex > -1) {

10
src/components/modals/Receive/steps/04-step-receive-funds.js

@ -4,7 +4,6 @@ import invariant from 'invariant'
import React, { PureComponent } from 'react'
import TrackPage from 'analytics/TrackPage'
import Button from 'components/base/Button'
import Box from 'components/base/Box'
import Label from 'components/base/Label'
import CurrentAddressForAccount from 'components/CurrentAddressForAccount'
@ -23,6 +22,7 @@ export default class StepReceiveFunds extends PureComponent<StepProps, State> {
handleChangeAmount = (amount: number) => this.setState({ amount })
handleGoPrev = () => {
this.props.onChangeAddressVerified(null)
this.props.onChangeAppOpened(false)
this.props.onResetSkip()
this.props.transitionTo('device')
@ -58,11 +58,3 @@ export default class StepReceiveFunds extends PureComponent<StepProps, State> {
)
}
}
export function StepReceiveFundsFooter({ t, closeModal }: StepProps) {
return (
<Button primary onClick={closeModal}>
{t('app:common.close')}
</Button>
)
}

6
static/i18n/en/app.yml

@ -31,6 +31,10 @@ common:
close: Close
eastern: Eastern
western: Western
reverify: Re-verify
verify: Verify
copy: Copy
addressCopied: Address copied!
lockScreen:
title: Welcome back
subTitle:
@ -174,6 +178,7 @@ operationDetails:
confirmed: Confirmed
notConfirmed: Not confirmed
fees: Fees
noFees: No fee
from: From
to: To
identifier: Transaction ID
@ -183,6 +188,7 @@ operationDetails:
operationList:
noMoreOperations: That's all!
manager:
yourDeviceIsGenuine: Your device is genuine
tabs:
apps: Apps
device: My device

Loading…
Cancel
Save