Commit 4fb75da4 authored by tom goriunov's avatar tom goriunov Committed by GitHub

Merge pull request #26 from blockscout/redesign-w

watchlist redesign
parents c457a938 50b93e4a
...@@ -19,7 +19,8 @@ ...@@ -19,7 +19,8 @@
"next": "12.1.6", "next": "12.1.6",
"next-react-svg": "1.1.3", "next-react-svg": "1.1.3",
"react": "18.1.0", "react": "18.1.0",
"react-dom": "18.1.0" "react-dom": "18.1.0",
"react-jazzicon": "^1.0.4"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "17.0.36", "@types/node": "17.0.36",
......
...@@ -21,7 +21,7 @@ const variantOutline: PartsStyleFunction<typeof parts> = (props) => { ...@@ -21,7 +21,7 @@ const variantOutline: PartsStyleFunction<typeof parts> = (props) => {
return { return {
field: { field: {
border: '1px solid', border: '2px solid',
borderColor: 'inherit', borderColor: 'inherit',
bg: 'inherit', bg: 'inherit',
_hover: { _hover: {
...@@ -46,7 +46,7 @@ const variantOutline: PartsStyleFunction<typeof parts> = (props) => { ...@@ -46,7 +46,7 @@ const variantOutline: PartsStyleFunction<typeof parts> = (props) => {
}, },
}, },
addon: { addon: {
border: '1px solid', border: '2px solid',
borderColor: mode('inherit', 'whiteAlpha.50')(props), borderColor: mode('inherit', 'whiteAlpha.50')(props),
bg: mode('gray.100', 'whiteAlpha.300')(props), bg: mode('gray.100', 'whiteAlpha.300')(props),
}, },
......
...@@ -11,17 +11,17 @@ const Modal: ComponentMultiStyleConfig = { ...@@ -11,17 +11,17 @@ const Modal: ComponentMultiStyleConfig = {
}, },
baseStyle: { baseStyle: {
dialog: { dialog: {
padding: '40px', padding: 8,
borderRadius: '30px', borderRadius: 'lg',
}, },
header: { header: {
padding: 0, padding: 0,
marginBottom: '20px', marginBottom: 8,
fontSize: '2xl', fontSize: '2xl',
}, },
body: { body: {
padding: 0, padding: 0,
marginBottom: '40px', marginBottom: 8,
}, },
footer: { footer: {
padding: 0, padding: 0,
......
import type { ComponentMultiStyleConfig } from '@chakra-ui/theme';
import { cssVar } from '@chakra-ui/theme-tools';
const $width = cssVar('switch-track-width');
const $height = cssVar('switch-track-height');
const Switch: ComponentMultiStyleConfig = {
parts: [ ],
sizes: {
md: {
container: {
[$width.variable]: '38px',
[$height.variable]: '18px',
},
},
},
baseStyle: {
track: {
p: '1px',
},
},
}
export default Switch;
import type { ComponentMultiStyleConfig } from '@chakra-ui/theme'; import type { ComponentMultiStyleConfig } from '@chakra-ui/theme';
const firstLastStyle = {
_first: { paddingLeft: 0 },
_last: { paddingRight: 0 },
}
const Table: ComponentMultiStyleConfig = { const Table: ComponentMultiStyleConfig = {
parts: [ 'th', 'td', 'table' ], parts: [ 'th', 'td', 'table' ],
baseStyle: { baseStyle: {
thead: {
backgroundColor: 'gray.50',
},
th: { th: {
...firstLastStyle,
textTransform: 'none', textTransform: 'none',
fontWeight: 'normal', fontWeight: 'normal',
overflow: 'hidden',
color: 'gray.500',
}, },
td: { td: {
...firstLastStyle,
fontSize: 'md', fontSize: 'md',
verticalAlign: 'top', verticalAlign: 'top',
}, },
table: { table: {
tableLayout: 'fixed', tableLayout: 'fixed',
borderTopLeftRadius: 'md',
borderTopRightRadius: 'md',
overflow: 'hidden',
},
},
sizes: {
md: {
th: {
px: 4,
fontSize: 'sm',
},
td: {
px: 4,
py: 6,
},
},
},
variants: {
simple: {
th: {
border: 0,
},
}, },
}, },
} }
......
...@@ -6,6 +6,15 @@ const Tag: ComponentStyleConfig = { ...@@ -6,6 +6,15 @@ const Tag: ComponentStyleConfig = {
display: 'inline-block', display: 'inline-block',
overflow: 'hidden', overflow: 'hidden',
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
borderRadius: 'md',
},
},
variants: {
gray: {
container: {
bg: 'gray.200',
color: 'gray.600',
},
}, },
}, },
} }
......
import Switch from './Switch';
import Button from './Button'; import Button from './Button';
import Modal from './Modal'; import Modal from './Modal';
import Table from './Table'; import Table from './Table';
...@@ -7,7 +6,6 @@ import Input from './Input'; ...@@ -7,7 +6,6 @@ import Input from './Input';
import Tag from './Tag'; import Tag from './Tag';
const components = { const components = {
Switch,
Button, Button,
Modal, Modal,
Table, Table,
......
...@@ -2,8 +2,9 @@ const borders = { ...@@ -2,8 +2,9 @@ const borders = {
radii: { radii: {
none: '0', none: '0',
sm: '4px', sm: '4px',
base: '10px', md: '8px',
lg: '30px', base: '12px',
lg: '24px',
full: '9999px', full: '9999px',
}, },
} }
......
...@@ -8,8 +8,15 @@ const typography = { ...@@ -8,8 +8,15 @@ const typography = {
textStyles: { textStyles: {
h2: { h2: {
fontSize: [ '32px' ], fontSize: [ '32px' ],
fontWeight: 'semibold', fontWeight: '500',
lineHeight: '40px', lineHeight: '40px',
fontFamily: 'heading',
},
h3: {
fontSize: '24px',
fontWeight: '500',
lineHeight: '32px',
fontFamily: 'heading',
}, },
}, },
} }
......
...@@ -79,15 +79,15 @@ const AddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => { ...@@ -79,15 +79,15 @@ const AddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
<Modal isOpen={ isOpen } onClose={ onClose } size="md"> <Modal isOpen={ isOpen } onClose={ onClose } size="md">
<ModalOverlay/> <ModalOverlay/>
<ModalContent> <ModalContent>
<ModalHeader fontWeight="500">{ title }</ModalHeader> <ModalHeader fontWeight="500" textStyle="h3">{ title }</ModalHeader>
<ModalCloseButton/> <ModalCloseButton/>
<ModalBody> <ModalBody>
{ !data && ( { !data && (
<Text lineHeight="30px" marginBottom="40px"> <Text lineHeight="30px" marginBottom={ 12 }>
An Email notification can be sent to you when an address on your watch list sends or receives any transactions. An Email notification can be sent to you when an address on your watch list sends or receives any transactions.
</Text> </Text>
) } ) }
<FormControl variant="floating" id="address" marginBottom="20px" isRequired> <FormControl variant="floating" id="address" marginBottom={ 5 } isRequired>
<Input <Input
placeholder=" " placeholder=" "
onChange={ onAddressChange } onChange={ onAddressChange }
...@@ -98,31 +98,32 @@ const AddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => { ...@@ -98,31 +98,32 @@ const AddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
/> />
<FormLabel>Address (0x...)</FormLabel> <FormLabel>Address (0x...)</FormLabel>
</FormControl> </FormControl>
<FormControl variant="floating" id="tag" marginBottom="30px" isRequired> <FormControl variant="floating" id="tag" marginBottom={ 8 } isRequired>
<Input placeholder=" " onChange={ onTagChange } value={ tag || '' } maxLength={ 35 }/> <Input placeholder=" " onChange={ onTagChange } value={ tag || '' } maxLength={ 35 }/>
<FormLabel>Private tag (max 35 characters)</FormLabel> <FormLabel>Private tag (max 35 characters)</FormLabel>
</FormControl> </FormControl>
<Text color="gray.600" fontSize="sm" marginBottom="32px"> <Text color="gray.500" fontSize="sm" marginBottom={ 8 }>
Please select what types of notifications you will receive: Please select what types of notifications you will receive:
</Text> </Text>
<Box marginBottom="32px"> <Box marginBottom={ 8 }>
<Grid templateColumns="repeat(3, max-content)" gap="20px 24px"> <Grid templateColumns="repeat(3, max-content)" gap="20px 24px">
{ NOTIFICATIONS.map((notification: string) => { { NOTIFICATIONS.map((notification: string) => {
return ( return (
<> <>
<GridItem>{ notification }</GridItem> <GridItem>{ notification }</GridItem>
<GridItem><Checkbox colorScheme="green">Incoming</Checkbox></GridItem> <GridItem><Checkbox colorScheme="blue" size="lg">Incoming</Checkbox></GridItem>
<GridItem><Checkbox colorScheme="green">Outgoing</Checkbox></GridItem> <GridItem><Checkbox colorScheme="blue" size="lg">Outgoing</Checkbox></GridItem>
</> </>
) )
}) } }) }
</Grid> </Grid>
</Box> </Box>
<Text color="gray.600" fontSize="sm" marginBottom="20px">Notification methods:</Text> <Text color="gray.500" fontSize="sm" marginBottom={ 5 }>Notification methods:</Text>
<Checkbox <Checkbox
isChecked={ notification } isChecked={ notification }
colorScheme="green" colorScheme="blue"
onChange={ onNotificationChange } onChange={ onNotificationChange }
size="lg"
> >
Email notifications Email notifications
</Checkbox> </Checkbox>
......
import React from 'react'; import React from 'react';
import Jazzicon, { jsNumberForAddress } from 'react-jazzicon';
import { Link, HStack, VStack, Image, Text, Icon } from '@chakra-ui/react'; import { Box, Link, HStack, VStack, Image, Text, Icon } from '@chakra-ui/react';
import CopyToClipboard from '../CopyToClipboard/CopyToClipboard'; import CopyToClipboard from '../CopyToClipboard/CopyToClipboard';
import type { TWatchlistItem } from '../../data/watchlist'; import type { TWatchlistItem } from '../../data/watchlist';
...@@ -9,32 +10,42 @@ import TokensIcon from '../../icons/tokens.svg'; ...@@ -9,32 +10,42 @@ import TokensIcon from '../../icons/tokens.svg';
import WalletIcon from '../../icons/wallet.svg'; import WalletIcon from '../../icons/wallet.svg';
const WatchListAddressItem = ({ item }: {item: TWatchlistItem}) => { const WatchListAddressItem = ({ item }: {item: TWatchlistItem}) => {
const image = <Jazzicon diameter={ 50 } seed={ jsNumberForAddress(item.address) }/>
return ( return (
<HStack spacing={ 3 } align="top"> <HStack spacing={ 3 } align="top">
<Image src="/acc.png" alt="Account Image" w="50px" h="50px"/> <Box width="50px">{ image }</Box>
<VStack align="stretch" overflow="hidden"> <VStack spacing={ 2 } align="stretch" overflow="hidden">
<HStack spacing={ 2 } alignContent="center"> <HStack spacing={ 2 } alignContent="center">
<Link href="#" color="blue.500" title={ item.address } overflow="hidden" textOverflow="ellipsis"> <Link
href="#"
color="blue.500"
title={ item.address }
overflow="hidden"
textOverflow="ellipsis"
fontWeight={ 600 }
lineHeight="24px"
>
{ item.address } { item.address }
</Link> </Link>
<CopyToClipboard text={ item.address }/> <CopyToClipboard text={ item.address }/>
</HStack> </HStack>
{ item.tokenBalance && ( { item.tokenBalance && (
<HStack spacing={ 0 } fontSize="xs"> <HStack spacing={ 0 } fontSize="sm" h={ 6 }>
<Image src="./xdai.png" alt="chain-logo" marginRight="10px" w="16px" h="16px"/> <Image src="./xdai.png" alt="chain-logo" marginRight="10px" w="16px" h="16px"/>
<Text>{ item.tokenBalance + ' xDAI' }</Text> <Text>{ item.tokenBalance + ' xDAI' }</Text>
<Text color="gray.500">{ `${ nbsp }($${ item.tokenBalanceUSD } USD)` }</Text> <Text color="gray.500">{ `${ nbsp }($${ item.tokenBalanceUSD } USD)` }</Text>
</HStack> </HStack>
) } ) }
{ item.tokensAmount && ( { item.tokensAmount && (
<HStack spacing={ 0 } fontSize="xs"> <HStack spacing={ 0 } fontSize="sm">
<Icon as={ TokensIcon } marginRight="10px" w="17px" h="16px"/> <Icon as={ TokensIcon } marginRight="10px" w="17px" h="16px"/>
<Text>{ item.tokensAmount + ' tokens' }</Text> <Text>{ item.tokensAmount + ' tokens' }</Text>
<Text color="gray.500">{ `${ nbsp }($${ item.tokensUSD } USD)` }</Text> <Text color="gray.500">{ `${ nbsp }($${ item.tokensUSD } USD)` }</Text>
</HStack> </HStack>
) } ) }
{ item.totalUSD && ( { item.totalUSD && (
<HStack spacing={ 0 } fontSize="xs"> <HStack spacing={ 0 } fontSize="sm">
<Icon as={ WalletIcon } marginRight="10px" w="16px" h="16px"/> <Icon as={ WalletIcon } marginRight="10px" w="16px" h="16px"/>
<Text>{ `Total balance:${ nbsp }` }</Text> <Text>{ `Total balance:${ nbsp }` }</Text>
<Link href="#" color="blue.500">{ `$${ item.totalUSD } USD` }</Link> <Link href="#" color="blue.500">{ `$${ item.totalUSD } USD` }</Link>
......
...@@ -35,15 +35,15 @@ const WatchlistTableItem = ({ item, onEditClick, onDeleteClick }: Props) => { ...@@ -35,15 +35,15 @@ const WatchlistTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
<Tr alignItems="top" key={ item.address }> <Tr alignItems="top" key={ item.address }>
<Td><WatchListAddressItem item={ item }/></Td> <Td><WatchListAddressItem item={ item }/></Td>
<Td> <Td>
<Tag lineHeight="24px" title={ item.tag }> <Tag variant="gray" lineHeight="24px" title={ item.tag }>
{ item.tag } { item.tag }
</Tag> </Tag>
</Td> </Td>
<Td><Switch colorScheme="green" size="md" isChecked={ item.notification }/></Td> <Td><Switch colorScheme="blue" size="md" isChecked={ item.notification }/></Td>
<Td> <Td>
<HStack spacing="30px"> <HStack spacing={ 6 }>
<Icon as={ EditIcon } w="20px" h="20px" cursor="pointer" color="blue.500" onClick={ onItemEditClick }/> <Icon as={ EditIcon } w="20px" h="20px" cursor="pointer" color="blue.600" onClick={ onItemEditClick }/>
<Icon as={ DeleteIcon } w="20px" h="20px" cursor="pointer" color="red.200" onClick={ onItemDeleteClick }/> <Icon as={ DeleteIcon } w="20px" h="20px" cursor="pointer" color="blue.600" onClick={ onItemDeleteClick }/>
</HStack> </HStack>
</Td> </Td>
</Tr> </Tr>
......
...@@ -25,10 +25,10 @@ const WatchlistTable = ({ data, onDeleteClick, onEditClick }: Props) => { ...@@ -25,10 +25,10 @@ const WatchlistTable = ({ data, onDeleteClick, onEditClick }: Props) => {
<Table variant="simple" minWidth="600px"> <Table variant="simple" minWidth="600px">
<Thead> <Thead>
<Tr> <Tr>
<Th width="70%" overflow="hidden">Address</Th> <Th width="70%">Address</Th>
<Th width="30%" overflow="hidden">Private tag</Th> <Th width="30%">Private tag</Th>
<Th width="108px" overflow="hidden">Notification</Th> <Th width="108px">Notification</Th>
<Th width="108px" overflow="hidden"></Th> <Th width="108px"></Th>
</Tr> </Tr>
</Thead> </Thead>
<Tbody> <Tbody>
......
...@@ -42,7 +42,7 @@ const WatchList: React.FC = () => { ...@@ -42,7 +42,7 @@ const WatchList: React.FC = () => {
<Page> <Page>
<Box h="100%"> <Box h="100%">
<Box as="h1" textStyle="h2" marginBottom={ 8 }>Watch list</Box> <Box as="h1" textStyle="h2" marginBottom={ 8 }>Watch list</Box>
<Text marginBottom="40px">An Email notification can be sent to you when an address on your watch list sends or receives any transactions.</Text> <Text marginBottom={ 12 }>An Email notification can be sent to you when an address on your watch list sends or receives any transactions.</Text>
{ Boolean(watchlist.length) && ( { Boolean(watchlist.length) && (
<WatchlistTable <WatchlistTable
data={ watchlist } data={ watchlist }
...@@ -50,7 +50,7 @@ const WatchList: React.FC = () => { ...@@ -50,7 +50,7 @@ const WatchList: React.FC = () => {
onEditClick={ onEditClick } onEditClick={ onEditClick }
/> />
) } ) }
<Box marginTop="32px"> <Box marginTop={ 8 }>
<Button <Button
variant="primary" variant="primary"
onClick={ addressModalProps.onOpen } onClick={ addressModalProps.onOpen }
......
...@@ -2446,6 +2446,11 @@ merge2@^1.3.0, merge2@^1.4.1: ...@@ -2446,6 +2446,11 @@ merge2@^1.3.0, merge2@^1.4.1:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
mersenne-twister@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/mersenne-twister/-/mersenne-twister-1.1.0.tgz#f916618ee43d7179efcf641bec4531eb9670978a"
integrity sha512-mUYWsMKNrm4lfygPkL3OfGzOPTR2DBlTkBNHM//F6hGp8cLThY897crAlk3/Jo17LEOOjQUrNAx6DvgO77QJkA==
micromatch@^4.0.4, micromatch@^4.0.5: micromatch@^4.0.4, micromatch@^4.0.5:
version "4.0.5" version "4.0.5"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
...@@ -2792,6 +2797,13 @@ react-is@^16.13.1, react-is@^16.7.0: ...@@ -2792,6 +2797,13 @@ react-is@^16.13.1, react-is@^16.7.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-jazzicon@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/react-jazzicon/-/react-jazzicon-1.0.4.tgz#31e5f6908e042786ba93a9093b852dea1870e7a0"
integrity sha512-/3kWv5vtAhI18GBFoqjpxRTtL+EImuB73PAC02r/zJQ6E+PAUmoBx8edYvTCIYHwS01uFf6N3elTDqSrVPwg4w==
dependencies:
mersenne-twister "^1.1.0"
react-remove-scroll-bar@^2.3.1: react-remove-scroll-bar@^2.3.1:
version "2.3.1" version "2.3.1"
resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.1.tgz#9f13b05b249eaa57c8d646c1ebb83006b3581f5f" resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.1.tgz#9f13b05b249eaa57c8d646c1ebb83006b3581f5f"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment