Meriadec Pillet
7 years ago
committed by
GitHub
9 changed files with 409 additions and 325 deletions
@ -0,0 +1,173 @@ |
|||||
|
// @flow
|
||||
|
|
||||
|
import React, { PureComponent } from 'react' |
||||
|
import styled from 'styled-components' |
||||
|
import { translate } from 'react-i18next' |
||||
|
import { connect } from 'react-redux' |
||||
|
import { compose } from 'redux' |
||||
|
import { withRouter } from 'react-router' |
||||
|
import { push } from 'react-router-redux' |
||||
|
import { getCryptoCurrencyIcon } from '@ledgerhq/live-common/lib/react' |
||||
|
|
||||
|
import type { Location } from 'react-router' |
||||
|
import type { Account } from '@ledgerhq/live-common/lib/types' |
||||
|
|
||||
|
import type { T } from 'types/common' |
||||
|
import type { UpdateStatus } from 'reducers/update' |
||||
|
|
||||
|
import { MODAL_RECEIVE, MODAL_SEND } from 'config/constants' |
||||
|
|
||||
|
import { accountsSelector } from 'reducers/accounts' |
||||
|
import { openModal } from 'reducers/modals' |
||||
|
import { getUpdateStatus } from 'reducers/update' |
||||
|
|
||||
|
import { SideBarList } from 'components/base/SideBar' |
||||
|
import Box, { Tabbable } from 'components/base/Box' |
||||
|
import Space from 'components/base/Space' |
||||
|
import FormattedVal from 'components/base/FormattedVal' |
||||
|
|
||||
|
import IconManager from 'icons/Manager' |
||||
|
import IconPieChart from 'icons/PieChart' |
||||
|
import IconPlus from 'icons/Plus' |
||||
|
import IconReceive from 'icons/Receive' |
||||
|
import IconSend from 'icons/Send' |
||||
|
import IconExchange from 'icons/Exchange' |
||||
|
|
||||
|
const mapStateToProps = state => ({ |
||||
|
accounts: accountsSelector(state), |
||||
|
updateStatus: getUpdateStatus(state), |
||||
|
}) |
||||
|
|
||||
|
const mapDispatchToProps = { |
||||
|
push, |
||||
|
openModal, |
||||
|
} |
||||
|
|
||||
|
type Props = { |
||||
|
t: T, |
||||
|
accounts: Account[], |
||||
|
location: Location, |
||||
|
push: string => void, |
||||
|
openModal: string => void, |
||||
|
updateStatus: UpdateStatus, |
||||
|
} |
||||
|
|
||||
|
class MainSideBar extends PureComponent<Props> { |
||||
|
push(to: string) { |
||||
|
const { push } = this.props |
||||
|
const { |
||||
|
location: { pathname }, |
||||
|
} = this.props |
||||
|
if (pathname === to) { |
||||
|
return |
||||
|
} |
||||
|
push(to) |
||||
|
} |
||||
|
|
||||
|
render() { |
||||
|
const { t, accounts, openModal, location, updateStatus } = this.props |
||||
|
const { pathname } = location |
||||
|
|
||||
|
const navigationItems = [ |
||||
|
{ |
||||
|
value: 'dashboard', |
||||
|
label: t('dashboard:title'), |
||||
|
icon: IconPieChart, |
||||
|
iconActiveColor: 'wallet', |
||||
|
onClick: () => this.push('/'), |
||||
|
isActive: pathname === '/', |
||||
|
hasNotif: updateStatus === 'downloaded', |
||||
|
}, |
||||
|
{ |
||||
|
value: 'send', |
||||
|
label: t('send:title'), |
||||
|
icon: IconSend, |
||||
|
iconActiveColor: 'wallet', |
||||
|
onClick: () => openModal(MODAL_SEND), |
||||
|
}, |
||||
|
{ |
||||
|
value: 'receive', |
||||
|
label: t('receive:title'), |
||||
|
icon: IconReceive, |
||||
|
iconActiveColor: 'wallet', |
||||
|
onClick: () => openModal(MODAL_RECEIVE), |
||||
|
}, |
||||
|
{ |
||||
|
value: 'manager', |
||||
|
label: t('sidebar:manager'), |
||||
|
icon: IconManager, |
||||
|
iconActiveColor: 'wallet', |
||||
|
onClick: () => this.push('/manager'), |
||||
|
isActive: pathname === '/manager', |
||||
|
}, |
||||
|
{ |
||||
|
value: 'exchange', |
||||
|
label: t('sidebar:exchange'), |
||||
|
icon: IconExchange, |
||||
|
iconActiveColor: 'wallet', |
||||
|
onClick: () => this.push('/exchange'), |
||||
|
isActive: pathname === '/exchange', |
||||
|
}, |
||||
|
] |
||||
|
|
||||
|
const accountsItems = accounts.map(account => { |
||||
|
const accountURL = `/account/${account.id}` |
||||
|
return { |
||||
|
value: account.id, |
||||
|
label: account.name, |
||||
|
desc: () => ( |
||||
|
<FormattedVal |
||||
|
alwaysShowSign={false} |
||||
|
color="graphite" |
||||
|
unit={account.unit} |
||||
|
showCode |
||||
|
val={account.balance || 0} |
||||
|
/> |
||||
|
), |
||||
|
iconActiveColor: account.currency.color, |
||||
|
icon: getCryptoCurrencyIcon(account.currency), |
||||
|
onClick: () => this.push(accountURL), |
||||
|
isActive: pathname === accountURL, |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
return ( |
||||
|
<Box bg="white" style={{ width: 230 }}> |
||||
|
<Space of={70} /> |
||||
|
<SideBarList title={t('sidebar:menu')} items={navigationItems} /> |
||||
|
<Space of={40} /> |
||||
|
<SideBarList |
||||
|
scroll |
||||
|
title={t('sidebar:accounts')} |
||||
|
titleRight={ |
||||
|
<PlusWrapper onClick={() => openModal('importAccounts')}> |
||||
|
<IconPlus size={16} /> |
||||
|
</PlusWrapper> |
||||
|
} |
||||
|
items={accountsItems} |
||||
|
emptyText={t('emptyState:sidebar.text')} |
||||
|
/> |
||||
|
</Box> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const PlusWrapper = styled(Tabbable).attrs({ |
||||
|
p: 1, |
||||
|
cursor: 'pointer', |
||||
|
borderRadius: 1, |
||||
|
})` |
||||
|
opacity: 0.4; |
||||
|
&:hover { |
||||
|
opacity: 1; |
||||
|
} |
||||
|
|
||||
|
border: 1px dashed rgba(0, 0, 0, 0); |
||||
|
&:focus { |
||||
|
border: 1px dashed rgba(0, 0, 0, 0.2); |
||||
|
outline: none; |
||||
|
} |
||||
|
` |
||||
|
|
||||
|
const decorate = compose(withRouter, translate(), connect(mapStateToProps, mapDispatchToProps)) |
||||
|
export default decorate(MainSideBar) |
@ -1,146 +0,0 @@ |
|||||
// @flow
|
|
||||
|
|
||||
import React from 'react' |
|
||||
import styled from 'styled-components' |
|
||||
import { compose } from 'redux' |
|
||||
import { withRouter } from 'react-router' |
|
||||
import { push } from 'react-router-redux' |
|
||||
import { connect } from 'react-redux' |
|
||||
|
|
||||
import { openModal } from 'reducers/modals' |
|
||||
|
|
||||
import type { Node } from 'react' |
|
||||
import type { Location } from 'react-router' |
|
||||
|
|
||||
import Box, { Tabbable } from 'components/base/Box' |
|
||||
import Text from 'components/base/Text' |
|
||||
|
|
||||
const mapStateToProps = (state: any) => ({ |
|
||||
// connect router here only to make components re-render
|
|
||||
// see https://github.com/ReactTraining/react-router/issues/4671
|
|
||||
router: state.router, |
|
||||
}) |
|
||||
|
|
||||
const mapDispatchToProps: Object = { |
|
||||
push, |
|
||||
openModal, |
|
||||
} |
|
||||
|
|
||||
const Container = styled(Tabbable).attrs({ |
|
||||
alignItems: 'center', |
|
||||
borderRadius: 1, |
|
||||
ff: 'Open Sans|SemiBold', |
|
||||
flow: 3, |
|
||||
horizontal: true, |
|
||||
pl: 3, |
|
||||
})` |
|
||||
cursor: ${p => (p.isActive ? 'default' : 'pointer')}; |
|
||||
color: ${p => p.theme.colors.dark}; |
|
||||
background: ${p => (p.isActive ? p.theme.colors.lightGrey : '')}; |
|
||||
height: ${p => (p.big ? 50 : 36)}px; |
|
||||
outline: none; |
|
||||
|
|
||||
.desaturate { |
|
||||
opacity: ${p => (p.isActive ? 1 : 0.4)}; |
|
||||
} |
|
||||
|
|
||||
&:hover, |
|
||||
&:focus { |
|
||||
.desaturate { |
|
||||
opacity: 1; |
|
||||
} |
|
||||
|
|
||||
svg { |
|
||||
color: ${p => p.theme.colors[p.iconActiveColor] || p.iconActiveColor}; |
|
||||
} |
|
||||
} |
|
||||
` |
|
||||
|
|
||||
const Bullet = styled.div` |
|
||||
background: ${p => p.theme.colors.wallet}; |
|
||||
width: 8px; |
|
||||
height: 8px; |
|
||||
border-radius: 100%; |
|
||||
` |
|
||||
|
|
||||
type Props = { |
|
||||
iconActiveColor?: string, |
|
||||
children: string, |
|
||||
linkTo?: string | null, |
|
||||
modal?: string | null, |
|
||||
desc?: string | null, |
|
||||
icon?: Node | null, |
|
||||
big?: boolean, |
|
||||
highlight?: boolean, |
|
||||
location: Location, |
|
||||
push: Function, |
|
||||
openModal: Function, |
|
||||
} |
|
||||
|
|
||||
function Item({ |
|
||||
big, |
|
||||
iconActiveColor, |
|
||||
children, |
|
||||
desc, |
|
||||
icon, |
|
||||
linkTo, |
|
||||
push, |
|
||||
location, |
|
||||
modal, |
|
||||
openModal, |
|
||||
highlight, |
|
||||
}: Props) { |
|
||||
const { pathname } = location |
|
||||
const isActive = linkTo === pathname |
|
||||
return ( |
|
||||
<Container |
|
||||
big={big} |
|
||||
iconActiveColor={iconActiveColor} |
|
||||
isActive={isActive} |
|
||||
onClick={ |
|
||||
linkTo |
|
||||
? isActive |
|
||||
? undefined |
|
||||
: () => push(linkTo) |
|
||||
: modal |
|
||||
? () => openModal(modal) |
|
||||
: void 0 |
|
||||
} |
|
||||
> |
|
||||
{icon && ( |
|
||||
<Box color={isActive ? iconActiveColor : void 0} className="desaturate"> |
|
||||
{icon} |
|
||||
</Box> |
|
||||
)} |
|
||||
<Box justifyContent="center" className="desaturate"> |
|
||||
<Text fontSize={4}>{children}</Text> |
|
||||
{desc && ( |
|
||||
<Box color="graphite" fontSize={3}> |
|
||||
{desc} |
|
||||
</Box> |
|
||||
)} |
|
||||
</Box> |
|
||||
{highlight && ( |
|
||||
<Box flex="1" align="flex-end" pr={2}> |
|
||||
<Bullet /> |
|
||||
</Box> |
|
||||
)} |
|
||||
</Container> |
|
||||
) |
|
||||
} |
|
||||
|
|
||||
Item.defaultProps = { |
|
||||
iconActiveColor: 'wallet', |
|
||||
big: false, |
|
||||
desc: null, |
|
||||
icon: null, |
|
||||
linkTo: null, |
|
||||
modal: null, |
|
||||
} |
|
||||
|
|
||||
export default compose( |
|
||||
withRouter, |
|
||||
connect(mapStateToProps, mapDispatchToProps, null, { |
|
||||
pure: false, |
|
||||
}), |
|
||||
)(Item) |
|
@ -1,178 +0,0 @@ |
|||||
// @flow
|
|
||||
|
|
||||
import React, { PureComponent, Fragment } from 'react' |
|
||||
import { compose } from 'redux' |
|
||||
import { translate } from 'react-i18next' |
|
||||
import styled from 'styled-components' |
|
||||
import { withRouter } from 'react-router' |
|
||||
import { connect } from 'react-redux' |
|
||||
import { getCryptoCurrencyIcon } from '@ledgerhq/live-common/lib/react' |
|
||||
import type { Account } from '@ledgerhq/live-common/lib/types' |
|
||||
|
|
||||
import { MODAL_SEND, MODAL_RECEIVE } from 'config/constants' |
|
||||
|
|
||||
import type { T } from 'types/common' |
|
||||
|
|
||||
import { openModal } from 'reducers/modals' |
|
||||
import { accountsSelector } from 'reducers/accounts' |
|
||||
import { getUpdateStatus } from 'reducers/update' |
|
||||
import type { UpdateStatus } from 'reducers/update' |
|
||||
|
|
||||
import IconManager from 'icons/Manager' |
|
||||
import IconPieChart from 'icons/PieChart' |
|
||||
import IconPlus from 'icons/Plus' |
|
||||
import IconReceive from 'icons/Receive' |
|
||||
import IconSend from 'icons/Send' |
|
||||
import IconExchange from 'icons/Exchange' |
|
||||
|
|
||||
import Box, { Tabbable } from 'components/base/Box' |
|
||||
import FormattedVal from 'components/base/FormattedVal' |
|
||||
import GrowScroll from 'components/base/GrowScroll' |
|
||||
import Tooltip from 'components/base/Tooltip' |
|
||||
|
|
||||
import Item from './Item' |
|
||||
|
|
||||
const CapsSubtitle = styled(Box).attrs({ |
|
||||
color: 'dark', |
|
||||
ff: 'Museo Sans|ExtraBold', |
|
||||
fontSize: 1, |
|
||||
px: 4, |
|
||||
})` |
|
||||
cursor: default; |
|
||||
letter-spacing: 2px; |
|
||||
text-transform: uppercase; |
|
||||
` |
|
||||
|
|
||||
const Container = styled(Box)` |
|
||||
width: ${p => p.theme.sizes.sideBarWidth}px; |
|
||||
` |
|
||||
|
|
||||
const PlusBtn = styled(Tabbable).attrs({ |
|
||||
p: 1, |
|
||||
m: -1, |
|
||||
})` |
|
||||
cursor: pointer; |
|
||||
outline: none; |
|
||||
` |
|
||||
|
|
||||
type Props = { |
|
||||
t: T, |
|
||||
openModal: Function, |
|
||||
updateStatus: UpdateStatus, |
|
||||
accounts: Account[], |
|
||||
} |
|
||||
|
|
||||
const mapStateToProps = state => ({ |
|
||||
accounts: accountsSelector(state), |
|
||||
updateStatus: getUpdateStatus(state), |
|
||||
}) |
|
||||
|
|
||||
const mapDispatchToProps: Object = { |
|
||||
openModal, |
|
||||
} |
|
||||
|
|
||||
class SideBar extends PureComponent<Props> { |
|
||||
render() { |
|
||||
const { t, openModal, updateStatus, accounts } = this.props |
|
||||
|
|
||||
return ( |
|
||||
<Container bg="white"> |
|
||||
<Box flow={7} pt={8} grow> |
|
||||
<Box flow={4}> |
|
||||
<CapsSubtitle>{t('sidebar:menu')}</CapsSubtitle> |
|
||||
<Box px={4} flow={2}> |
|
||||
<Item |
|
||||
icon={<IconPieChart size={16} />} |
|
||||
linkTo="/" |
|
||||
highlight={updateStatus === 'downloaded'} |
|
||||
> |
|
||||
{t('dashboard:title')} |
|
||||
</Item> |
|
||||
<Item icon={<IconSend size={16} />} modal={MODAL_SEND}> |
|
||||
{t('send:title')} |
|
||||
</Item> |
|
||||
<Item icon={<IconReceive size={16} />} modal={MODAL_RECEIVE}> |
|
||||
{t('receive:title')} |
|
||||
</Item> |
|
||||
<Item icon={<IconManager size={16} />} linkTo="/manager"> |
|
||||
{t('sidebar:manager')} |
|
||||
</Item> |
|
||||
<Item icon={<IconExchange size={16} />} linkTo="/exchange"> |
|
||||
{t('sidebar:exchange')} |
|
||||
</Item> |
|
||||
</Box> |
|
||||
</Box> |
|
||||
<Box flow={4} grow pt={1}> |
|
||||
<CapsSubtitle horizontal alignItems="center"> |
|
||||
<Box grow>{t('sidebar:accounts')}</Box> |
|
||||
<Tooltip render={() => t('addAccount:title')}> |
|
||||
<PlusBtn onClick={() => openModal('importAccounts')}> |
|
||||
<IconPlus size={16} /> |
|
||||
</PlusBtn> |
|
||||
</Tooltip> |
|
||||
</CapsSubtitle> |
|
||||
<GrowScroll pb={4} px={4} flow={2}> |
|
||||
{accounts.length > 0 ? ( |
|
||||
<AccountsList /> |
|
||||
) : ( |
|
||||
<NoAccountsText>{t('emptyState:sidebar.text')}</NoAccountsText> |
|
||||
)} |
|
||||
</GrowScroll> |
|
||||
</Box> |
|
||||
</Box> |
|
||||
</Container> |
|
||||
) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
const AccountsList = compose( |
|
||||
withRouter, |
|
||||
connect( |
|
||||
state => ({ |
|
||||
accounts: accountsSelector(state), |
|
||||
}), |
|
||||
null, |
|
||||
null, |
|
||||
{ pure: false }, |
|
||||
), |
|
||||
)(({ accounts }: { accounts: Account[] }) => ( |
|
||||
<Fragment> |
|
||||
{accounts.map(account => { |
|
||||
const Icon = getCryptoCurrencyIcon(account.currency) |
|
||||
return ( |
|
||||
<Item |
|
||||
big |
|
||||
desc={ |
|
||||
<FormattedVal |
|
||||
alwaysShowSign={false} |
|
||||
color="graphite" |
|
||||
unit={account.unit} |
|
||||
showCode |
|
||||
val={account.balance || 0} |
|
||||
/> |
|
||||
} |
|
||||
iconActiveColor={account.currency.color} |
|
||||
icon={Icon ? <Icon size={16} /> : null} |
|
||||
key={account.id} |
|
||||
linkTo={`/account/${account.id}`} |
|
||||
> |
|
||||
{account.name} |
|
||||
</Item> |
|
||||
) |
|
||||
})} |
|
||||
</Fragment> |
|
||||
)) |
|
||||
|
|
||||
export default compose( |
|
||||
withRouter, |
|
||||
connect(mapStateToProps, mapDispatchToProps, null, { pure: false }), |
|
||||
translate(), |
|
||||
)(SideBar) |
|
||||
|
|
||||
export const NoAccountsText = styled(Box).attrs({ |
|
||||
ff: 'Open Sans|Regular', |
|
||||
fontSize: 3, |
|
||||
color: p => p.theme.colors.grey, |
|
||||
shrink: true, |
|
||||
mt: 3, |
|
||||
})`` |
|
@ -0,0 +1,71 @@ |
|||||
|
// @flow
|
||||
|
|
||||
|
import React, { PureComponent, Fragment } from 'react' |
||||
|
import styled from 'styled-components' |
||||
|
|
||||
|
import GrowScroll from 'components/base/GrowScroll' |
||||
|
import Box from 'components/base/Box' |
||||
|
import Space from 'components/base/Space' |
||||
|
|
||||
|
import SideBarListItem from './SideBarListItem' |
||||
|
|
||||
|
import type { Item } from './SideBarListItem' |
||||
|
|
||||
|
type Props = { |
||||
|
items: Item[], |
||||
|
title?: Node | string, |
||||
|
activeValue?: string, |
||||
|
scroll?: boolean, |
||||
|
titleRight?: any, // TODO: type should be more precise, but, eh ¯\_(ツ)_/¯
|
||||
|
emptyText?: string, |
||||
|
} |
||||
|
|
||||
|
class SideBarList extends PureComponent<Props> { |
||||
|
render() { |
||||
|
const { items, title, activeValue, scroll, titleRight, emptyText, ...props } = this.props |
||||
|
const ListWrapper = scroll ? GrowScroll : Box |
||||
|
return ( |
||||
|
<Fragment> |
||||
|
{!!title && ( |
||||
|
<Fragment> |
||||
|
<SideBarListTitle> |
||||
|
{title} |
||||
|
{!!titleRight && <Box ml="auto">{titleRight}</Box>} |
||||
|
</SideBarListTitle> |
||||
|
<Space of={20} /> |
||||
|
</Fragment> |
||||
|
)} |
||||
|
{items.length > 0 ? ( |
||||
|
<ListWrapper flow={2} px={3} fontSize={3} {...props}> |
||||
|
{items.map(item => { |
||||
|
const itemProps = { |
||||
|
item, |
||||
|
isActive: item.isActive || (!!activeValue && activeValue === item.value), |
||||
|
} |
||||
|
return <SideBarListItem key={item.value} {...itemProps} /> |
||||
|
})} |
||||
|
</ListWrapper> |
||||
|
) : emptyText ? ( |
||||
|
<Box px={4} ff="Open Sans|Regular" fontSize={3} color="grey"> |
||||
|
{emptyText} |
||||
|
</Box> |
||||
|
) : null} |
||||
|
</Fragment> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const SideBarListTitle = styled(Box).attrs({ |
||||
|
horizontal: true, |
||||
|
align: 'center', |
||||
|
color: 'dark', |
||||
|
ff: 'Museo Sans|ExtraBold', |
||||
|
fontSize: 1, |
||||
|
px: 4, |
||||
|
})` |
||||
|
cursor: default; |
||||
|
letter-spacing: 2px; |
||||
|
text-transform: uppercase; |
||||
|
` |
||||
|
|
||||
|
export default SideBarList |
@ -0,0 +1,94 @@ |
|||||
|
// @flow
|
||||
|
|
||||
|
import React, { PureComponent } from 'react' |
||||
|
import styled from 'styled-components' |
||||
|
|
||||
|
import Box, { Tabbable } from 'components/base/Box' |
||||
|
|
||||
|
export type Item = { |
||||
|
value: string, |
||||
|
label: string | (Props => React$Element<any>), |
||||
|
desc?: Props => any, // TODO: type should be more precise, but, eh ¯\_(ツ)_/¯
|
||||
|
icon?: any, // TODO: type should be more precise, but, eh ¯\_(ツ)_/¯
|
||||
|
iconActiveColor: ?string, |
||||
|
hasNotif?: boolean, |
||||
|
isActive?: boolean, |
||||
|
onClick?: void => void, |
||||
|
} |
||||
|
|
||||
|
export type Props = { |
||||
|
item: Item, |
||||
|
isActive: boolean, |
||||
|
} |
||||
|
|
||||
|
class SideBarListItem extends PureComponent<Props> { |
||||
|
render() { |
||||
|
const { |
||||
|
item: { icon: Icon, label, desc, iconActiveColor, hasNotif, onClick }, |
||||
|
isActive, |
||||
|
} = this.props |
||||
|
return ( |
||||
|
<Container isActive={isActive} iconActiveColor={iconActiveColor} onClick={onClick}> |
||||
|
{!!Icon && <Icon size={16} />} |
||||
|
<Box grow shrink> |
||||
|
{typeof label === 'function' ? ( |
||||
|
label(this.props) |
||||
|
) : ( |
||||
|
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}> |
||||
|
{label} |
||||
|
</span> |
||||
|
)} |
||||
|
{!!desc && desc(this.props)} |
||||
|
</Box> |
||||
|
{!!hasNotif && <Bullet />} |
||||
|
</Container> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const Container = styled(Tabbable).attrs({ |
||||
|
align: 'center', |
||||
|
borderRadius: 1, |
||||
|
ff: 'Open Sans|SemiBold', |
||||
|
flow: 3, |
||||
|
horizontal: true, |
||||
|
px: 3, |
||||
|
py: 2, |
||||
|
})` |
||||
|
cursor: ${p => (p.isActive ? 'default' : 'pointer')}; |
||||
|
color: ${p => p.theme.colors.dark}; |
||||
|
background: ${p => (p.isActive ? p.theme.colors.lightGrey : '')}; |
||||
|
|
||||
|
opacity: ${p => (p.isActive ? 1 : 0.4)}; |
||||
|
|
||||
|
&:active { |
||||
|
background: ${p => p.theme.colors.lightGrey}; |
||||
|
} |
||||
|
|
||||
|
&:hover { |
||||
|
opacity: ${p => (p.isActive ? 1 : 0.7)}; |
||||
|
} |
||||
|
|
||||
|
border: 1px dashed rgba(0, 0, 0, 0); |
||||
|
&:focus { |
||||
|
border: 1px dashed rgba(0, 0, 0, 0.2); |
||||
|
outline: none; |
||||
|
} |
||||
|
|
||||
|
${p => { |
||||
|
const iconActiveColor = p.theme.colors[p.iconActiveColor] || p.iconActiveColor |
||||
|
return ` |
||||
|
svg { color: ${p.isActive ? iconActiveColor : ''}; } |
||||
|
&:hover svg { color: ${iconActiveColor}; } |
||||
|
` |
||||
|
}}; |
||||
|
` |
||||
|
|
||||
|
const Bullet = styled.div` |
||||
|
background: ${p => p.theme.colors.wallet}; |
||||
|
width: 8px; |
||||
|
height: 8px; |
||||
|
border-radius: 100%; |
||||
|
` |
||||
|
|
||||
|
export default SideBarListItem |
@ -0,0 +1,3 @@ |
|||||
|
// @flow
|
||||
|
|
||||
|
export { default as SideBarList } from './SideBarList' |
@ -0,0 +1,62 @@ |
|||||
|
// @flow
|
||||
|
|
||||
|
import React from 'react' |
||||
|
import { storiesOf } from '@storybook/react' |
||||
|
import { select } from '@storybook/addon-knobs' |
||||
|
|
||||
|
import { SideBarList } from 'components/base/SideBar' |
||||
|
import Box from 'components/base/Box' |
||||
|
|
||||
|
import IconAccountSettings from 'icons/AccountSettings' |
||||
|
import IconPrint from 'icons/Print' |
||||
|
import IconControls from 'icons/Controls' |
||||
|
import IconCurrencies from 'icons/Currencies' |
||||
|
import IconExclamationCircle from 'icons/ExclamationCircle' |
||||
|
|
||||
|
const stories = storiesOf('Components/base/SideBar', module) |
||||
|
|
||||
|
const SIDEBAR_ITEMS = [ |
||||
|
{ |
||||
|
value: 'first', |
||||
|
label: 'First', |
||||
|
icon: IconAccountSettings, |
||||
|
iconActiveColor: '#ffae35', |
||||
|
}, |
||||
|
{ |
||||
|
value: 'second', |
||||
|
label: 'Second', |
||||
|
icon: IconPrint, |
||||
|
iconActiveColor: '#0ebdcd', |
||||
|
}, |
||||
|
{ |
||||
|
value: 'third', |
||||
|
label: 'Third very very very very long text very long text very long', |
||||
|
icon: IconControls, |
||||
|
iconActiveColor: '#27a2db', |
||||
|
hasNotif: true, |
||||
|
}, |
||||
|
{ |
||||
|
value: 'fourth', |
||||
|
label: () => ( |
||||
|
<Box> |
||||
|
{'custom'} |
||||
|
<Box>{'render'}</Box> |
||||
|
</Box> |
||||
|
), |
||||
|
icon: IconCurrencies, |
||||
|
iconActiveColor: '#3ca569', |
||||
|
}, |
||||
|
{ |
||||
|
value: 'fifth', |
||||
|
label: 'Fifth', |
||||
|
icon: IconExclamationCircle, |
||||
|
iconActiveColor: '#0e76aa', |
||||
|
}, |
||||
|
] |
||||
|
|
||||
|
stories.add('SideBarList', () => ( |
||||
|
<SideBarList |
||||
|
items={SIDEBAR_ITEMS} |
||||
|
activeValue={select('activeValue', [...SIDEBAR_ITEMS.map(i => i.value), null], 'third')} |
||||
|
/> |
||||
|
)) |
@ -0,0 +1,5 @@ |
|||||
|
import styled from 'styled-components' |
||||
|
|
||||
|
export default styled.div` |
||||
|
height: ${p => p.of}px; |
||||
|
` |
Loading…
Reference in new issue