Browse Source

Merge pull request #106 from loeck/master

Update AccountCard and Dashboard Chart, add SVG Icons
master
Loëck Vézien 7 years ago
committed by GitHub
parent
commit
4f551970b6
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      src/components/DashboardPage/AccountCard.js
  2. 68
      src/components/DashboardPage/index.js
  3. 5
      src/components/GlobalSearch.js
  4. 21
      src/components/SideBar/Item.js
  5. 21
      src/components/SideBar/index.js
  6. 8
      src/components/TopBar.js
  7. 49
      src/components/base/Chart/index.js
  8. 10
      src/icons/Activity.js
  9. 13
      src/icons/ArrowDown.js
  10. 10
      src/icons/ArrowUp.js
  11. 10
      src/icons/Devices.js
  12. 10
      src/icons/PieChart.js
  13. 10
      src/icons/Plus.js
  14. 10
      src/icons/Search.js
  15. 10
      src/icons/Settings.js
  16. 10
      src/icons/currencies/Bitcoin.js

9
src/components/DashboardPage/AccountCard.js

@ -6,10 +6,11 @@ import type { Account } from 'types/common'
import { formatBTC } from 'helpers/format'
import IconCurrencyBitcoin from 'icons/currencies/Bitcoin'
import { AreaChart } from 'components/base/Chart'
import Bar from 'components/base/Bar'
import Box, { Card } from 'components/base/Box'
import Icon from 'components/base/Icon'
const AccountCard = ({
account,
@ -22,8 +23,8 @@ const AccountCard = ({
}) => (
<Card p={4} flow={4} flex={1} style={{ cursor: 'pointer' }} onClick={onClick}>
<Box horizontal ff="Open Sans|SemiBold" flow={3} align="center">
<Box style={{ color: '#fcb653' }}>
<Icon fontSize="20px" name={{ iconName: 'btc', prefix: 'fab' }} />
<Box align="center" justify="center" style={{ color: '#fcb653' }}>
<IconCurrencyBitcoin height={20} width={20} />
</Box>
<Box>
<Box style={{ textTransform: 'uppercase' }} fontSize={0} color="warmGrey">
@ -45,7 +46,7 @@ const AccountCard = ({
height={52}
data={data}
strokeWidth={1}
linearGradient={[[5, 0.4], [100, 0]]}
linearGradient={[[5, 0.4], [80, 0]]}
/>
</Card>
)

68
src/components/DashboardPage/index.js

@ -14,6 +14,7 @@ import type { MapStateToProps } from 'react-redux'
import type { Accounts } from 'types/common'
import { formatBTC } from 'helpers/format'
import { space } from 'styles/theme'
import { getTotalBalance, getVisibleAccounts } from 'reducers/accounts'
@ -121,7 +122,7 @@ class DashboardPage extends PureComponent<Props, State> {
<Box flow={7}>
<Box horizontal align="flex-end">
<Box>
<Text color="dark" ff="Museo Sans|Regular" fontSize={7}>
<Text color="dark" ff="Museo Sans" fontSize={7}>
{'Good morning, Khalil.'}
</Text>
<Text color="grey" fontSize={5} ff="Museo Sans|Light">
@ -140,11 +141,17 @@ class DashboardPage extends PureComponent<Props, State> {
</Box>
{totalAccounts > 0 && (
<Fragment>
<Card flow={3} p={6}>
<Card flow={3} p={0} py={6}>
<Text>{formatBTC(totalBalance)}</Text>
<Box ff="Open Sans" fontSize={4} color="warmGrey">
<AreaChart
id="dashboard-chart"
margin={{
top: space[6],
bottom: 0,
left: space[6] - 10,
right: space[6],
}}
color="#5286f7"
height={250}
data={takeRight(
@ -162,32 +169,37 @@ class DashboardPage extends PureComponent<Props, State> {
/>
</Box>
</Card>
<Box flow={3}>
{this.getAccountsChunk().map((accountsByLine, i) => (
<Box
key={i} // eslint-disable-line react/no-array-index-key
horizontal
flow={3}
>
{accountsByLine.map(
(account: any, j) =>
account === null ? (
<Box
key={j} // eslint-disable-line react/no-array-index-key
p={2}
flex={1}
/>
) : (
<AccountCard
key={account.id}
account={account}
data={takeRight(fakeDatas[j], 25)}
onClick={() => push(`/account/${account.id}`)}
/>
),
)}
</Box>
))}
<Box flow={4}>
<Text color="dark" ff="Museo Sans" fontSize={6}>
{'Accounts'}
</Text>
<Box flow={5}>
{this.getAccountsChunk().map((accountsByLine, i) => (
<Box
key={i} // eslint-disable-line react/no-array-index-key
horizontal
flow={5}
>
{accountsByLine.map(
(account: any, j) =>
account === null ? (
<Box
key={j} // eslint-disable-line react/no-array-index-key
p={4}
flex={1}
/>
) : (
<AccountCard
key={account.id}
account={account}
data={takeRight(fakeDatas[j], 25)}
onClick={() => push(`/account/${account.id}`)}
/>
),
)}
</Box>
))}
</Box>
</Box>
</Fragment>
)}

5
src/components/GlobalSearch.js

@ -3,8 +3,9 @@
import React, { PureComponent } from 'react'
import styled from 'styled-components'
import IconSearch from 'icons/Search'
import Box from 'components/base/Box'
import Icon from 'components/base/Icon'
const Input = styled.input`
border: none;
@ -30,7 +31,7 @@ class GlobalSearch extends PureComponent<{}> {
return (
<Box grow horizontal ff="Open Sans|SemiBold" fontSize={4}>
<Box justify="center" onClick={this.focusInput} pr={2}>
<Icon name="search" />
<IconSearch height={16} width={16} />
</Box>
<Input placeholder="Search" innerRef={input => (this._input = input)} />
</Box>

21
src/components/SideBar/Item.js

@ -9,12 +9,12 @@ import { connect } from 'react-redux'
import { openModal } from 'reducers/modals'
import type { Node } from 'react'
import type { MapStateToProps } from 'react-redux'
import type { Location } from 'react-router'
import Box, { Tabbable } from 'components/base/Box'
import Text from 'components/base/Text'
import Icon from 'components/base/Icon'
const mapStateToProps: MapStateToProps<*, *, *> = (state: any) => ({
// connect router here only to make components re-render
@ -49,18 +49,30 @@ const Container = styled(Tabbable).attrs({
`
type Props = {
iconActiveColor?: string,
children: string,
linkTo?: string | null,
modal?: string | null,
desc?: string | null,
icon?: string | null,
icon?: Node | null,
big?: boolean,
location: Location,
push: Function,
openModal: Function,
}
function Item({ big, children, desc, icon, linkTo, push, location, modal, openModal }: Props) {
function Item({
big,
iconActiveColor,
children,
desc,
icon,
linkTo,
push,
location,
modal,
openModal,
}: Props) {
const { pathname } = location
const isActive = pathname === linkTo
return (
@ -73,7 +85,7 @@ function Item({ big, children, desc, icon, linkTo, push, location, modal, openMo
}
isActive={isActive}
>
{icon && <Icon fontSize={5} color={isActive ? 'blue' : void 0} name={icon} />}
{icon && <Box color={isActive ? iconActiveColor : void 0}>{icon}</Box>}
<Box justify="center">
<Text fontSize={4}>{children}</Text>
{desc && (
@ -87,6 +99,7 @@ function Item({ big, children, desc, icon, linkTo, push, location, modal, openMo
}
Item.defaultProps = {
iconActiveColor: 'blue',
big: false,
desc: null,
icon: null,

21
src/components/SideBar/index.js

@ -17,9 +17,15 @@ import { getVisibleAccounts } from 'reducers/accounts'
import { formatBTC } from 'helpers/format'
import IconPieChart from 'icons/PieChart'
import IconArrowDown from 'icons/ArrowDown'
import IconArrowUp from 'icons/ArrowUp'
import IconSettings from 'icons/Settings'
import IconPlus from 'icons/Plus'
import IconCurrencyBitcoin from 'icons/currencies/Bitcoin'
import Box, { Tabbable } from 'components/base/Box'
import GrowScroll from 'components/base/GrowScroll'
import Icon from 'components/base/Icon'
import Text from 'components/base/Text'
import Item from './Item'
@ -88,16 +94,16 @@ class SideBar extends PureComponent<Props> {
<Box flow={4}>
<CapsSubtitle>{t('sidebar.menu')}</CapsSubtitle>
<Box px={4} flow={2}>
<Item icon="chart-bar" linkTo="/">
<Item icon={<IconPieChart height={16} width={16} />} linkTo="/">
{t('dashboard.title')}
</Item>
<Item icon="upload" modal={MODAL_SEND}>
<Item icon={<IconArrowUp height={16} width={16} />} modal={MODAL_SEND}>
{t('send.title')}
</Item>
<Item icon="download" modal={MODAL_RECEIVE}>
<Item icon={<IconArrowDown height={16} width={16} />} modal={MODAL_RECEIVE}>
{t('receive.title')}
</Item>
<Item icon="cog" linkTo="/settings">
<Item icon={<IconSettings height={16} width={16} />} linkTo="/settings">
{t('settings.title')}
</Item>
</Box>
@ -106,7 +112,7 @@ class SideBar extends PureComponent<Props> {
<CapsSubtitle horizontal align="center">
<Box grow>{t('sidebar.accounts')}</Box>
<PlusBtn onClick={() => openModal(MODAL_ADD_ACCOUNT)}>
<Icon name="plus-circle" />
<IconPlus height={14} width={14} />
</PlusBtn>
</CapsSubtitle>
<GrowScroll pb={4} px={4} flow={2}>
@ -114,7 +120,8 @@ class SideBar extends PureComponent<Props> {
<Item
big
desc={formatBTC(account.data ? account.data.balance : 0)}
icon={{ iconName: 'btc', prefix: 'fab' }}
iconActiveColor="#fcb653"
icon={<IconCurrencyBitcoin height={16} width={16} />}
key={account.id}
linkTo={`/account/${account.id}`}
>

8
src/components/TopBar.js

@ -12,9 +12,11 @@ import { getAccounts } from 'reducers/accounts'
import { lock } from 'reducers/application'
import { hasPassword } from 'reducers/settings'
import IconDevices from 'icons/Devices'
import IconActivity from 'icons/Activity'
import Box from 'components/base/Box'
import GlobalSearch from 'components/GlobalSearch'
import Icon from 'components/base/Icon'
const Container = styled(Box).attrs({
px: 5,
@ -121,10 +123,10 @@ class TopBar extends PureComponent<Props, State> {
<Box grow horizontal flow={4}>
<GlobalSearch />
<Box justify="center">
<Icon name="tablet-alt" />
<IconDevices height={16} width={16} />
</Box>
<Box justify="center">
<Icon name="chart-line" />
<IconActivity height={16} width={16} />
</Box>
<Box justify="center">
<Bar />

49
src/components/base/Chart/index.js

@ -1,7 +1,7 @@
// @flow
import React, { PureComponent } from 'react'
import { AreaChart as ReactAreaChart, Area, XAxis, CartesianGrid, Tooltip } from 'recharts'
import { AreaChart as ReactAreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip } from 'recharts'
import Box from 'components/base/Box'
@ -89,26 +89,32 @@ export const AreaChart = ({
{linearGradient && (
<defs>
<linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
{linearGradient.map(g => (
<stop offset={`${g[0]}%`} stopColor={color} stopOpacity={g[1]} />
{linearGradient.map((g, i) => (
<stop
key={i} // eslint-disable-line react/no-array-index-key
offset={`${g[0]}%`}
stopColor={color}
stopOpacity={g[1]}
/>
))}
</linearGradient>
</defs>
)}
{!tiny && (
<XAxis
dataKey="name"
stroke="#e9eff4"
<YAxis
interval={0}
dataKey="value"
tickMargin={0}
stroke={null}
tickLine={false}
interval={2}
tick={({ x, y, index, payload, visibleTicksCount }) => {
tick={({ x, y, index, payload }) => {
const { value } = payload
if (index !== 0 && index !== visibleTicksCount - 1) {
if (index !== 0) {
return (
<g transform={`translate(${x}, ${y})`}>
<text x={0} y={0} dy={16} textAnchor="middle" fill="currentColor">
{value}
<text x={-30} y={0} dy={5} textAnchor="middle" fill="currentColor">
{value}k
</text>
</g>
)
@ -118,8 +124,27 @@ export const AreaChart = ({
}}
/>
)}
{!tiny && (
<XAxis
dataKey="name"
stroke="#e9eff4"
tickLine={false}
interval={2}
tick={({ x, y, payload }) => {
const { value } = payload
return (
<g transform={`translate(${x}, ${y})`}>
<text x={0} y={0} dy={20} textAnchor="middle" fill="currentColor">
{value}
</text>
</g>
)
}}
/>
)}
{!tiny && <CartesianGrid vertical={false} strokeDasharray="5" stroke="#e9eff4" />}
{!tiny && <Tooltip />}
{!tiny && <Tooltip isAnimationActive={false} />}
<Area
isAnimationActive={isAnimationActive}
animationDuration={ANIMATION_DURATION}

10
src/icons/Activity.js

@ -0,0 +1,10 @@
import React from 'react'
export default props => (
<svg viewBox="0 0 16 16" {...props}>
<path
fill="currentColor"
d="M11.488 8.063a.75.75 0 0 1 .712-.513H15a.75.75 0 1 1 0 1.5h-2.26l-1.928 5.787c-.228.684-1.196.684-1.424 0L5.9 4.372 4.512 8.537a.75.75 0 0 1-.712.513H1a.75.75 0 0 1 0-1.5h2.26l1.928-5.787c.228-.684 1.196-.684 1.424 0L10.1 12.228l1.388-4.165z"
/>
</svg>
)

13
src/icons/ArrowDown.js

@ -0,0 +1,13 @@
// @flow
import React from 'react'
export default (props: Object) => (
<svg viewBox="0 0 16 16" {...props}>
<path
fill="currentColor"
transform={`rotate(180, ${props.height / 2}, ${props.width / 2})`}
d="M7.25 3.81L4.53 6.53a.75.75 0 0 1-1.06-1.06l4-4a.75.75 0 0 1 1.06 0l4 4a.75.75 0 0 1-1.06 1.06L8.75 3.81V14a.75.75 0 1 1-1.5 0V3.81z"
/>
</svg>
)

10
src/icons/ArrowUp.js

@ -0,0 +1,10 @@
import React from 'react'
export default props => (
<svg viewBox="0 0 16 16" {...props}>
<path
fill="currentColor"
d="M7.25 3.81L4.53 6.53a.75.75 0 0 1-1.06-1.06l4-4a.75.75 0 0 1 1.06 0l4 4a.75.75 0 0 1-1.06 1.06L8.75 3.81V14a.75.75 0 1 1-1.5 0V3.81z"
/>
</svg>
)

10
src/icons/Devices.js

@ -0,0 +1,10 @@
import React from 'react'
export default props => (
<svg viewBox="0 0 16 16" {...props}>
<path
fill="currentColor"
d="M13 2.5h-1.5v-1h-10v13h7V16h-7C.67157287 16 0 15.3284271 0 14.5v-13C0 .67157287.67157287 0 1.5 0h10c.8284271 0 1.5.67157287 1.5 1.5v1zm0 0h-1.5v-1h-10v13h7V16h-7C.67157287 16 0 15.3284271 0 14.5v-13C0 .67157287.67157287 0 1.5 0h10c.8284271 0 1.5.67157287 1.5 1.5v1zM12 4h1.9000001C15.059798 4 16 4.94020198 16 6.0999999V15c0 .5522847-.4477153 1-1 1h-4c-.5522847 0-1-.4477153-1-1V6c0-1.1045695.8954305-2 2-2zm-.5 10.5h3V6.0999999C14.5 5.76862911 14.2313709 5.5 13.9000001 5.5H12c-.2761424 0-.5.22385763-.5.5v8.5z"
/>
</svg>
)

10
src/icons/PieChart.js

@ -0,0 +1,10 @@
import React from 'react'
export default props => (
<svg viewBox="0 0 16 16" {...props}>
<path
fill="currentColor"
d="M5.2 1.067V2.71a5.985 5.985 0 0 0 2.027 11.223A5.983 5.983 0 0 0 13.34 10.7h1.625a.759.759 0 0 1-.056.22A7.5 7.5 0 0 1 .575 9.052 7.502 7.502 0 0 1 5 1.123a.759.759 0 0 1 .2-.056zM15.5 8c0 .42-.34.759-.758.759H8A.758.758 0 0 1 7.242 8V1.26c0-.42.34-.759.758-.759a7.499 7.499 0 0 1 7.5 7.501zm-3.27-4.23a5.982 5.982 0 0 0-3.47-1.705v5.178h5.176a5.985 5.985 0 0 0-1.704-3.473z"
/>
</svg>
)

10
src/icons/Plus.js

@ -0,0 +1,10 @@
import React from 'react'
export default props => (
<svg viewBox="0 0 16 16" {...props}>
<path
fill="currentColor"
d="M12 7.5v1a.376.376 0 0 1-.375.375h-2.75v2.75A.376.376 0 0 1 8.5 12h-1a.376.376 0 0 1-.375-.375v-2.75h-2.75A.376.376 0 0 1 4 8.5v-1c0-.206.169-.375.375-.375h2.75v-2.75c0-.206.169-.375.375-.375h1c.206 0 .375.169.375.375v2.75h2.75c.206 0 .375.169.375.375zm3.75.5A7.749 7.749 0 0 1 8 15.75 7.749 7.749 0 0 1 .25 8 7.749 7.749 0 0 1 8 .25 7.749 7.749 0 0 1 15.75 8zm-1.5 0A6.248 6.248 0 0 0 8 1.75 6.248 6.248 0 0 0 1.75 8 6.248 6.248 0 0 0 8 14.25 6.248 6.248 0 0 0 14.25 8z"
/>
</svg>
)

10
src/icons/Search.js

@ -0,0 +1,10 @@
import React from 'react'
export default props => (
<svg viewBox="0 0 16 16" {...props}>
<path
fill="currentColor"
d="M12.654 11.594l2.876 2.876a.75.75 0 0 1-1.06 1.06l-2.876-2.876a6.972 6.972 0 1 1 1.06-1.06zm-1.492-.574a5.472 5.472 0 1 0-.142.142.757.757 0 0 1 .142-.142z"
/>
</svg>
)

10
src/icons/Settings.js

@ -0,0 +1,10 @@
import React from 'react'
export default props => (
<svg viewBox="0 0 16 16" {...props}>
<path
fill="currentColor"
d="M13.94 8.583H14a.583.583 0 0 0 0-1.166h-.116a1.85 1.85 0 0 1-1.693-1.122.75.75 0 0 1-.053-.189 1.854 1.854 0 0 1 .432-1.903l.04-.04a.583.583 0 1 0-.826-.826l-.046.046a1.847 1.847 0 0 1-2.033.373A1.851 1.851 0 0 1 8.583 2.06V2a.583.583 0 0 0-1.166 0v.116A1.85 1.85 0 0 1 6.295 3.81a.75.75 0 0 1-.189.053 1.854 1.854 0 0 1-1.903-.432l-.04-.04a.583.583 0 1 0-.826.826l.046.046c.529.54.675 1.349.388 1.997A1.856 1.856 0 0 1 2.06 7.47H2a.583.583 0 0 0 0 1.167h.116a1.847 1.847 0 0 1 1.69 1.114c.306.691.159 1.5-.376 2.046l-.04.04a.583.583 0 1 0 .826.826l.046-.046c.54-.529 1.349-.675 1.997-.388A1.856 1.856 0 0 1 7.47 13.94V14a.583.583 0 0 0 1.167 0v-.116a1.847 1.847 0 0 1 1.114-1.69 1.853 1.853 0 0 1 2.046.376l.04.04a.583.583 0 1 0 .826-.826l-.046-.046a1.85 1.85 0 0 1-.371-2.037 1.851 1.851 0 0 1 1.694-1.118zm-.33-2.807c.065.087.167.14.277.14H14a2.083 2.083 0 0 1 0 4.167h-.057a.35.35 0 0 0-.32.212.35.35 0 0 0 .06.388l.04.04a2.083 2.083 0 1 1-2.947 2.947c-.136-.134-.289-.162-.427-.1a.349.349 0 0 0-.212.317V14a2.083 2.083 0 0 1-4.167 0c-.003-.186-.094-.313-.273-.38a.348.348 0 0 0-.38.064l-.04.04a2.083 2.083 0 1 1-2.947-2.948c.134-.136.162-.289.1-.427a.349.349 0 0 0-.317-.212H2A2.083 2.083 0 0 1 2 5.97c.186-.003.313-.094.38-.273a.348.348 0 0 0-.064-.38l-.04-.04A2.083 2.083 0 1 1 5.225 2.33c.136.134.289.162.42.104a.75.75 0 0 1 .132-.044.348.348 0 0 0 .14-.277V2a2.083 2.083 0 1 1 4.167 0v.057c0 .14.084.265.22.324.13.057.284.03.38-.065l.04-.04a2.083 2.083 0 1 1 2.947 2.948c-.134.136-.162.289-.104.42a.75.75 0 0 1 .044.132zM8 5.25a2.75 2.75 0 1 0 0 5.5 2.75 2.75 0 0 0 0-5.5zm0 1.5a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5z"
/>
</svg>
)

10
src/icons/currencies/Bitcoin.js

@ -0,0 +1,10 @@
import React from 'react'
export default props => (
<svg viewBox="0 0 16 16" {...props}>
<path
fill="currentColor"
d="M7.61970553 0h1.70000005v3.05846154H7.61970553V0zm1.70000005 0v3.05846154H7.61970553V0h1.70000005zM7.81303887 12.9415385h1.70000004V16H7.81303887v-3.0584615zm1.70000004 0V16H7.81303887v-3.0584615h1.70000004zM4.4063722 0h1.70000005v3.05846154H4.4063722V0zm1.70000005 0v3.05846154H4.4063722V0h1.70000005zM4.59970553 12.9415385h1.70000005V16H4.59970553v-3.0584615zm1.70000005 0V16H4.59970553v-3.0584615h1.70000005zM2.6663722 8.81307695V1.94999998h.85000002l6.13827333.00156806c1.80778725.10996034 3.21199965 1.5663186 3.11839335 3.25458581l-.0017039.27851419c.110634 1.74464117-1.2981636 3.21696546-3.16829611 3.32840891H2.6663722zm.85000002 0l.85000003-.85000003v4.31926938l5.60765891.000255c.95057664-.0249932 1.67559124-.7265334 1.65900774-1.5564475l.0002249-.3703244c.0187355-.81415185-.7068616-1.51805139-1.63689158-1.54275245h-6.48zm7.55666668-3.27461541l.0012684-.37872715c.042116-.77004688-.6196246-1.45636138-1.47126841-1.50973437H4.36637225v3.46311513l5.20484808.0002342c.89861507-.06354201 1.55224847-.7529014 1.50181857-1.57488781zM4.36637225 7.11311515l5.18540306.00150901c.00432951-.00026159.15996192-.00067981.46689729-.00125468 1.859875.04881191 3.3551536 1.49937703 3.3143663 3.26201512l-.0001732.3336104c.0359164 1.7788337-1.4578252 3.2242112-3.33649348 3.2733127H2.6663722V7.1130769h.85000002l.85000003.00003825zm0 .00017966v.84978211l-.85000003-.85000002.85000003.00021791z"
/>
</svg>
)
Loading…
Cancel
Save