Add crypto currency components

This commit is contained in:
pedromcunha
2022-11-29 18:04:37 -05:00
parent 248753883d
commit 71eaa72953
16 changed files with 243 additions and 112 deletions
+3
View File
@@ -0,0 +1,3 @@
{
"typescript.tsdk": "node_modules/typescript/lib"
}
-32
View File
@@ -1,32 +0,0 @@
import { BigNumberish } from 'ethers'
import { formatBN } from 'utils/numbers'
import { FC } from 'react'
import Flex from './primitives/Flex'
import Text from './primitives/Text'
type Props = {
amount: BigNumberish | null | undefined
maximumFractionDigits?: number
css?: Parameters<typeof Text>['0']['css']
children?: React.ReactNode
}
const FormatCurrency: FC<Props> = ({
amount,
maximumFractionDigits = 4,
css,
children,
}) => {
const value = formatBN(amount, maximumFractionDigits)
return (
<Flex align="center" css={{ gap: '$1' }}>
{value !== '-' ? children : null}
<Text style="subtitle2" css={css}>
{value}
</Text>
</Flex>
)
}
export default FormatCurrency
-27
View File
@@ -1,27 +0,0 @@
import FormatCurrency from 'components/FormatCurrency'
import { FC, ComponentProps } from 'react'
type FormatEthProps = {
logoWidth?: number
}
type Props = ComponentProps<typeof FormatCurrency> & FormatEthProps
const FormatEth: FC<Props> = ({
amount,
maximumFractionDigits,
logoWidth = 8,
css,
}) => {
return (
<FormatCurrency
css={css}
amount={amount}
maximumFractionDigits={maximumFractionDigits}
>
<img src="/eth.svg" alt="ETH logo" style={{ width: `${logoWidth}px` }} />
</FormatCurrency>
)
}
export default FormatEth
-31
View File
@@ -1,31 +0,0 @@
import FormatCurrency from 'components/FormatCurrency'
import { FC, ComponentProps } from 'react'
type FormatWEthProps = {
logoWidth?: number
}
type Props = ComponentProps<typeof FormatCurrency> & FormatWEthProps
const FormatWEth: FC<Props> = ({
amount,
maximumFractionDigits,
logoWidth = 8,
css,
}) => {
return (
<FormatCurrency
css={css}
amount={amount}
maximumFractionDigits={maximumFractionDigits}
>
<img
src="/weth.svg"
alt="WETH logo"
style={{ width: `${logoWidth}px` }}
/>
</FormatCurrency>
)
}
export default FormatWEth
+8 -8
View File
@@ -1,8 +1,5 @@
import { useCollections } from '@reservoir0x/reservoir-kit-ui'
import Box from '../primitives/Box'
import Flex from '../primitives/Flex'
import Text from '../primitives/Text'
import FormatEth from '../FormatEth'
import { Text, Box, Flex, FormatCryptoCurrency } from '../primitives'
import { formatNumber } from '../../utils/numbers'
import Link from 'next/link'
@@ -29,7 +26,11 @@ const CollectionRow = ({ rank, collection }: CollectionRowProps) => {
<Text css={{ mr: '$1', color: '$gray11' }} as="p" style="body2">
Floor
</Text>
<FormatEth amount={collection?.floorAsk?.price?.amount?.native} />
<FormatCryptoCurrency
amount={collection?.floorAsk?.price?.amount?.decimal}
address={collection?.floorAsk?.price?.currency?.contract}
decimals={collection?.floorAsk?.price?.currency?.decimals}
/>
</Flex>
</Box>
@@ -37,9 +38,8 @@ const CollectionRow = ({ rank, collection }: CollectionRowProps) => {
<Text css={{ mb: 4, color: '$green10' }} style="body2" as="p">
{formatNumber(collection?.volumeChange['7day'])}%
</Text>
<FormatEth
amount={collection?.volume['7day']}
<FormatCryptoCurrency
amount={collection.volume['7day']}
maximumFractionDigits={1}
/>
</Flex>
@@ -0,0 +1,53 @@
import React, { FC } from 'react'
import { useChainCurrency } from '../../hooks'
import { constants } from 'ethers'
import { styled } from '../../stitches.config'
import { StyledComponent } from '@stitches/react/types/styled-component'
import Box from './Box'
import wrappedContracts from '../../utils/wrappedContracts'
import { useReservoirClient } from '@reservoir0x/reservoir-kit-ui'
type Props = {
address: string
} & Parameters<StyledComponent>['0']
const StyledImg = styled('img', {})
const CryptoCurrencyIcon: FC<Props> = ({
address = constants.AddressZero,
css,
}) => {
const client = useReservoirClient()
const chainCurrency = useChainCurrency()
if (chainCurrency.symbol === 'ETH') {
if (constants.AddressZero === address) {
return (
<Box css={{ display: 'flex', ...css }}>
<img src="/eth.svg" alt="ETH Logo" />
</Box>
)
}
const wrappedContractAddress = wrappedContracts[chainCurrency.chainId]
if (
wrappedContractAddress &&
wrappedContractAddress.toLowerCase() == address.toLowerCase()
) {
return (
<Box css={{ display: 'flex', ...css }}>
<img src="/weth.svg" alt="WETH Logo" />
</Box>
)
}
}
return (
<StyledImg
src={`${client?.apiBase}/redirect/currency/${address}/icon/v1`}
css={css}
/>
)
}
export default CryptoCurrencyIcon
+36
View File
@@ -0,0 +1,36 @@
import { BigNumberish } from 'ethers'
import { formatBN } from '../../utils/numbers'
import React, { FC } from 'react'
import { Flex, Text } from './index'
type Props = {
amount: BigNumberish | null | undefined
maximumFractionDigits?: number
decimals?: number
css?: Parameters<typeof Text>['0']['css']
textStyle?: Parameters<typeof Text>['0']['style']
textColor?: Parameters<typeof Text>['0']['color']
children?: React.ReactNode
}
const FormatCrypto: FC<Props> = ({
amount,
maximumFractionDigits = 4,
decimals = 18,
css,
textStyle = 'subtitle2',
textColor = 'base',
children,
}) => {
const value = formatBN(amount, maximumFractionDigits, decimals)
return (
<Flex align="center" css={{ gap: '$1' }}>
{value !== '-' ? children : null}
<Text style={textStyle} color={textColor} css={css} as="p">
{value}
</Text>
</Flex>
)
}
export default FormatCrypto
@@ -0,0 +1,37 @@
import FormatCrypto from './FormatCrypto'
import React, { FC, ComponentProps } from 'react'
import { constants } from 'ethers'
import CryptoCurrencyIcon from './CryptoCurrencyIcon'
type FormatCryptoCurrencyProps = {
logoWidth?: number
address?: string
}
type Props = ComponentProps<typeof FormatCrypto> & FormatCryptoCurrencyProps
const FormatCryptoCurrency: FC<Props> = ({
amount,
address = constants.AddressZero,
maximumFractionDigits,
logoWidth = 8,
textStyle,
css,
textColor,
decimals,
}) => {
return (
<FormatCrypto
css={css}
textColor={textColor}
textStyle={textStyle}
amount={amount}
maximumFractionDigits={maximumFractionDigits}
decimals={decimals}
>
<CryptoCurrencyIcon css={{ height: logoWidth }} address={address} />
</FormatCrypto>
)
}
export default FormatCryptoCurrency
+41
View File
@@ -0,0 +1,41 @@
import React, { ComponentPropsWithoutRef, FC, useEffect, useState } from 'react'
import { Text } from './index'
type Props = {
amount: string | number | null | undefined
currency?: Intl.NumberFormatOptions['currency']
maximumFractionDigits?: number
}
const FormatCurrency: FC<ComponentPropsWithoutRef<typeof Text> & Props> = ({
amount,
maximumFractionDigits = 2,
currency = 'USD',
...props
}) => {
const [formattedValue, setFormattedValue] = useState('')
useEffect(() => {
if (amount) {
const formatted = new Intl.NumberFormat(undefined, {
style: 'currency',
currency: currency,
}).format(+amount)
setFormattedValue(formatted)
} else {
setFormattedValue('')
}
}, [amount, maximumFractionDigits])
return (
<Text
{...props}
style={props.style || 'subtitle2'}
color={props.color || 'base'}
>
{formattedValue}
</Text>
)
}
export default FormatCurrency
+3
View File
@@ -6,3 +6,6 @@ export { default as Value } from './Value'
export { default as Button } from './Button'
export { default as Tooltip } from './Tooltip'
export { default as Switch } from './Switch'
export { default as FormatCrypto } from './FormatCrypto'
export { default as FormatCryptoCurrency } from './FormatCryptoCurrency'
export { default as FormatCurrency } from './FormatCurrency'
+1
View File
@@ -2,3 +2,4 @@ export { default as useMounted } from './useMounted'
export { default as useTimeSince } from './useTimeSince'
export { default as useUserActivity } from './useUserActivity'
export { default as useUserCollections } from './useUserCollections'
export { default as useChainCurrency } from './useChainCurrency'
+32
View File
@@ -0,0 +1,32 @@
import { constants } from 'ethers'
import { chainId, useNetwork } from 'wagmi'
export default function () {
const { chain: activeChain, chains } = useNetwork()
let chain = chains.find((chain) => activeChain?.id === chain.id)
if (!chain && chains.length > 0) {
chain = chains[0]
} else {
chain = activeChain
}
const ETHChains: number[] = [chainId.mainnet, chainId.goerli]
if (!chain || !chain.nativeCurrency || ETHChains.includes(chain.id)) {
return {
name: 'Ethereum',
symbol: 'ETH',
decimals: 18,
address: constants.AddressZero,
chainId: chain?.id || chainId.mainnet,
}
} else {
return {
...chain.nativeCurrency,
address: constants.AddressZero,
chainId: chain.id,
}
}
}
+20 -12
View File
@@ -1,5 +1,11 @@
import { NextPage } from 'next'
import { Text, Switch, Flex, Box } from '../../components/primitives'
import {
Text,
Switch,
Flex,
Box,
FormatCryptoCurrency,
} from '../../components/primitives'
import {
useCollections,
useTokens,
@@ -8,8 +14,6 @@ import {
import { formatNumber } from 'utils/numbers'
import Layout from 'components/Layout'
import { useRouter } from 'next/router'
import FormatEth from 'components/FormatEth'
import FormatWEth from 'components/FormatWEth'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import {
faCertificate,
@@ -21,7 +25,6 @@ import {
faChevronUp,
faChevronDown,
} from '@fortawesome/free-solid-svg-icons'
import { faTwitter, faDiscord } from '@fortawesome/free-brands-svg-icons'
import { useState } from 'react'
import { truncateAddress } from 'utils/truncate'
@@ -151,10 +154,11 @@ const TokenCard = ({ token }) => (
<Flex align="center" css={{ gap: '$2' }}>
<Box css={{ flex: 1 }}>
<FormatEth
<FormatCryptoCurrency
logoWidth={11}
css={{ fontSize: 16, fontWeight: 600, color: 'white' }}
amount={token.market?.floorAsk?.price?.amount.native}
amount={token.market?.floorAsk?.price?.amount?.decimal}
address={token.market?.floorAsk?.price?.currency?.contract}
/>
</Box>
<img
@@ -240,18 +244,22 @@ const IndexPage: NextPage = () => {
}}
>
<StatBox label="Floor">
<FormatEth
amount={collection?.floorAsk?.price?.amount?.native}
<FormatCryptoCurrency
amount={collection?.floorAsk?.price?.amount?.decimal}
address={collection?.floorAsk?.price?.currency.contract}
decimals={collection?.floorAsk?.price?.currency.decimals}
logoWidth={10}
css={{ fontSize: 16 }}
textStyle={'body1'}
/>
</StatBox>
<StatBox label="Top Bid">
<FormatWEth
amount={collection?.topBid?.price?.amount?.native}
<FormatCryptoCurrency
amount={collection?.topBid?.price?.amount?.decimal}
address={collection?.topBid?.price?.currency.contract}
decimals={collection?.topBid?.price?.currency.decimals}
logoWidth={10}
css={{ fontSize: 16 }}
textStyle={'body1'}
/>
</StatBox>
+1 -1
View File
@@ -1,4 +1,4 @@
<svg width="15" height="25" viewBox="0 0 15 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg width="auto" height="100%" viewBox="0 0 15 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.49721 0L0 12.4432L7.49721 9.03511V0Z" fill="#3E63DD"/>
<path d="M7.49721 9.03516L0 12.4433L7.49721 16.8768V9.03516Z" fill="#2F4EB2"/>
<path d="M14.9959 12.4432L7.49731 0V9.03511L14.9959 12.4432Z" fill="#2F4EB2"/>

Before

Width:  |  Height:  |  Size: 568 B

After

Width:  |  Height:  |  Size: 572 B

+1 -1
View File
@@ -1,4 +1,4 @@
<svg width="15" height="25" viewBox="0 0 15 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg width="auto" height="100%" viewBox="0 0 15 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.49721 0L0 12.4432L7.49721 9.03511V0Z" fill="#AE1955"/>
<path d="M7.49721 9.03506L0 12.4432L7.49721 16.8767V9.03506Z" fill="#801D45"/>
<path d="M14.9959 12.4433L7.49731 0V9.03511L14.9959 12.4433Z" fill="#801D45"/>

Before

Width:  |  Height:  |  Size: 587 B

After

Width:  |  Height:  |  Size: 591 B

+7
View File
@@ -0,0 +1,7 @@
const wrappedContracts: Record<number, string> = {
1: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
5: '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6',
137: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270',
}
export default wrappedContracts