Commit 6e4b3187 authored by tom's avatar tom

token page

parent 359ce166
......@@ -10,37 +10,41 @@ NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws
# Instance ENVs
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP={ "id": "728301", "width": "728", "height": "90" }
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE={ "id": "728302", "width": "320", "height": "100" }
NEXT_PUBLIC_AD_BANNER_ADDITIONAL_PROVIDER=adbutler
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com
NEXT_PUBLIC_API_BASE_PATH=/
NEXT_PUBLIC_API_HOST=base.blockscout.com
NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
NEXT_PUBLIC_CONTRACT_CODE_IDES=[{'title':'Remix IDE','url':'https://remix.ethereum.org/?address={hash}&blockscout={domain}','icon_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/ide-icons/remix.png'}]
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swap','icon':'swap','dappId':'aerodrome'},{'text':'Payment link','icon':'payment_link','dappId':'peanut-protocol'},{'text':'Get gas','icon':'gas','dappId':'smol-refuel'}]
NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swap','icon':'swap','dappId':'rubic'},{'text':'Disperse','icon':'txn_batches_slim','dappId':'smol'},{'text':'Payment link','icon':'payment_link','dappId':'peanut-protocol'},{'text':'Get gas','icon':'gas','dappId':'smol-refuel'}]
NEXT_PUBLIC_DEX_POOLS_ENABLED=true
NEXT_PUBLIC_FAULT_PROOF_ENABLED=true
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/base-mainnet.json
NEXT_PUBLIC_FOOTER_LINKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/footer-links/base-mainnet.json
NEXT_PUBLIC_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/sherblockHolmesBadge
NEXT_PUBLIC_GAS_REFUEL_PROVIDER_CONFIG={'name': 'Need gas?', 'url_template': 'https://smolrefuel.com/?outboundChain={chainId}&partner=blockscout&utm_source=blockscout&disableBridges=true', 'dapp_id': 'smol-refuel', 'logo': 'https://blockscout-content.s3.amazonaws.com/smolrefuel-logo-action-button.png'}
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xfd5c5dae7b69fe29e61d19b9943e688aa0f1be1e983c4fba8fe985f90ff69d5f
NEXT_PUBLIC_HAS_CONTRACT_AUDIT_REPORTS=true
NEXT_PUBLIC_HAS_USER_OPS=true
NEXT_PUBLIC_HIDE_INDEXING_ALERT_INT_TXS=true
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND=linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)
NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)']}
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_LOGOUT_URL=https://basechain.us.auth0.com/v2/logout
NEXT_PUBLIC_MARKETPLACE_BANNER_CONTENT_URL=https://gist.githubusercontent.com/maxaleks/0d18fc309ff499075127b364cc69306d/raw/2a51f961a8c1b9f884f2ab7eed79d4b69330e1ae/peanut_protocol_banner.html
NEXT_PUBLIC_MARKETPLACE_BANNER_LINK_URL=https://base.blockscout.com/apps/peanut-protocol
NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE=<p>Joined recent campaigns? Mint your Merit Badge <a href="https://badges.blockscout.com?utm_source=instance&utm_medium=base">here</a></p>
NEXT_PUBLIC_MARKETPLACE_BANNER_CONTENT_URL=https://gist.githubusercontent.com/maikReal/974c47f86a3158c1a86b092ae2f044b3/raw/abcc7e02150cd85d4974503a0357162c0a2c35a9/merits-banner.html
NEXT_PUBLIC_MARKETPLACE_BANNER_LINK_URL=https://swap.blockscout.com?utm_source=blockscout&utm_medium=base
NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-categories/default.json
NEXT_PUBLIC_MARKETPLACE_ENABLED=true
NEXT_PUBLIC_MARKETPLACE_RATING_AIRTABLE_BASE_ID=appGkvtmKI7fXE4Vs
NEXT_PUBLIC_MARKETPLACE_SECURITY_REPORTS_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-security-reports/default.json
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6uMGPKjj1DK7NL
NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form
NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com
NEXT_PUBLIC_METASUITES_ENABLED=true
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}]
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'},{'name': 'zapper', 'url_template': 'https://zapper.xyz/account/{address}', 'logo': 'https://blockscout-content.s3.amazonaws.com/zapper-icon.png'}]
NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps']
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/pools']
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
......@@ -59,8 +63,10 @@ NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth.blockscout.com/
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://bridge.base.org/withdraw
NEXT_PUBLIC_ROLLUP_TYPE=optimistic
NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-base.safe.global
NEXT_PUBLIC_STATS_API_HOST=https://stats-l2-base-mainnet.k8s-prod-1.blockscout.com
NEXT_PUBLIC_STATS_API_HOST=https://stats-l2-base-mainnet.k8s-prod-2.blockscout.com
NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout
NEXT_PUBLIC_VIEWS_ADDRESS_IDENTICON_TYPE=gradient_avatar
NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
\ No newline at end of file
NEXT_PUBLIC_VIEWS_NFT_MARKETPLACES=[{'name':'OpenSea','collection_url':'https://opensea.io/assets/base/{hash}','instance_url':'https://opensea.io/assets/base/{hash}/{id}','logo_url':'https://opensea.io/static/images/logos/opensea-logo.svg'}]
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
NEXT_PUBLIC_XSTAR_SCORE_URL=https://docs.xname.app/the-solution-adaptive-proof-of-humanity-on-blockchain/xhs-scoring-algorithm?utm_source=blockscout&utm_medium=address
\ No newline at end of file
......@@ -10,14 +10,14 @@ import fetchApi from 'nextjs/utils/fetchApi';
import config from 'configs/app';
import getQueryParamString from 'lib/router/getQueryParamString';
// import Token from 'ui/pages/Token';
import Token from 'ui/pages/Token';
const pathname: Route['pathname'] = '/token/[hash]';
const Page: NextPage<Props<typeof pathname>> = (props: Props<typeof pathname>) => {
return (
<PageNextJs pathname={ pathname } query={ props.query } apiData={ props.apiData }>
{ /* <Token/> */ }
<Token/>
</PageNextJs>
);
};
......
......@@ -4,9 +4,9 @@ import { useRouter } from 'next/router';
import React, { useEffect } from 'react';
import type { SocketMessage } from 'lib/socket/types';
import type { TabItemRegular } from 'toolkit/components/AdaptiveTabs/types';
import type { TokenInfo } from 'types/api/token';
import type { PaginationParams } from 'ui/shared/pagination/types';
import type { RoutedTab } from 'ui/shared/Tabs/types';
import config from 'configs/app';
import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery';
......@@ -20,6 +20,7 @@ import * as addressStubs from 'stubs/address';
import * as tokenStubs from 'stubs/token';
import { getTokenHoldersStub } from 'stubs/token';
import { generateListStub } from 'stubs/utils';
import RoutedTabs from 'toolkit/components/RoutedTabs/RoutedTabs';
import AddressContract from 'ui/address/AddressContract';
import AddressCsvExportLink from 'ui/address/AddressCsvExportLink';
import useContractTabs from 'ui/address/contract/useContractTabs';
......@@ -28,7 +29,6 @@ import TextAd from 'ui/shared/ad/TextAd';
import IconSvg from 'ui/shared/IconSvg';
import Pagination from 'ui/shared/pagination/Pagination';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import RoutedTabs from 'ui/shared/Tabs/RoutedTabs';
import TokenDetails from 'ui/token/TokenDetails';
import TokenHolders from 'ui/token/TokenHolders/TokenHolders';
import TokenInventory from 'ui/token/TokenInventory';
......@@ -161,7 +161,7 @@ const TokenPageContent = () => {
const isLoading = tokenQuery.isPlaceholderData || addressQuery.isPlaceholderData;
const contractTabs = useContractTabs(addressQuery.data, addressQuery.isPlaceholderData);
const tabs: Array<RoutedTab> = [
const tabs: Array<TabItemRegular> = [
hasInventoryTab ? {
id: 'inventory',
title: 'Inventory',
......@@ -212,7 +212,7 @@ const TokenPageContent = () => {
pagination = inventoryQuery.pagination;
}
const tabListProps = React.useCallback(({ isSticky, activeTabIndex }: { isSticky: boolean; activeTabIndex: number }) => {
const tabListProps = React.useCallback(() => {
if (isMobile) {
return { mt: 8 };
}
......@@ -221,7 +221,6 @@ const TokenPageContent = () => {
pt: 6,
pb: 6,
marginBottom: 0,
boxShadow: activeTabIndex === 2 && isSticky ? 'action_bar' : 'none',
};
}, [ isMobile ]);
......@@ -257,7 +256,7 @@ const TokenPageContent = () => {
<RoutedTabs
tabs={ tabs }
tabListProps={ tabListProps }
listProps={ tabListProps }
rightSlot={ tabsRightSlot }
rightSlotProps={ TABS_RIGHT_SLOT_PROPS }
stickyEnabled={ !isMobile }
......
......@@ -82,6 +82,7 @@ const EntityTag = ({ data, isLoading, noLink, ...rest }: Props) => {
onClick={ handleLinkClick }
noIcon
cursor={ hasLink ? 'pointer' : 'default' }
{ ...rest }
>
<Tag
bg={ data.meta?.bgColor }
......@@ -92,7 +93,6 @@ const EntityTag = ({ data, isLoading, noLink, ...rest }: Props) => {
endElementProps={ linkParams?.type === 'external' ? { ml: -1 } : undefined }
_hover={ hasLink ? { opacity: 0.76 } : undefined }
variant={ hasLink ? 'clickable' : 'subtle' }
{ ...rest }
>
{ prefix }{ name }
</Tag>
......
......@@ -45,7 +45,7 @@ const EntityTags = ({ tags, className, isLoading }: Props) => {
+{ tags.length - visibleNum }
</Badge>
</PopoverTrigger>
<PopoverContent maxW="300px">
<PopoverContent maxW="300px" w="fit-content">
<PopoverBody>
<Flex columnGap={ 2 } rowGap={ 2 } flexWrap="wrap">
{ tags.slice(visibleNum).map((tag) => <EntityTag key={ tag.slug } data={ tag }/>) }
......
import {
PopoverTrigger, PopoverContent, PopoverBody,
Modal, ModalContent, ModalCloseButton,
useDisclosure,
Button,
} from '@chakra-ui/react';
import React from 'react';
import useIsMobile from 'lib/hooks/useIsMobile';
import Popover from 'ui/shared/chakra/Popover';
import IconSvg from './IconSvg';
import { Button } from 'toolkit/chakra/button';
import { DialogRoot, DialogContent, DialogTrigger, DialogHeader } from 'toolkit/chakra/dialog';
import { PopoverBody, PopoverContent, PopoverRoot, PopoverTrigger } from 'toolkit/chakra/popover';
import IconSvg from 'ui/shared/IconSvg';
interface Props {
children: React.ReactNode;
......@@ -17,21 +12,16 @@ interface Props {
const InfoButton = ({ children }: Props) => {
const isMobile = useIsMobile();
const { isOpen, onToggle, onClose } = useDisclosure();
const triggerButton = (
<Button
size="sm"
variant="outline"
colorScheme="gray"
onClick={ onToggle }
isActive={ isOpen }
variant="dropdown"
gap={ 0 }
aria-label="Show info"
fontWeight={ 500 }
lineHeight={ 6 }
pl={ 1 }
pr={ isMobile ? 1 : 2 }
h="32px"
>
<IconSvg name="info" boxSize={ 6 } mr={ isMobile ? 0 : 1 }/>
{ !isMobile && <span>Info</span> }
......@@ -40,29 +30,29 @@ const InfoButton = ({ children }: Props) => {
if (isMobile) {
return (
<>
{ triggerButton }
<Modal isOpen={ isOpen } onClose={ onClose } size="full">
<ModalContent>
<ModalCloseButton/>
{ children }
</ModalContent>
</Modal>
</>
<DialogRoot size="full">
<DialogTrigger>
{ triggerButton }
</DialogTrigger>
<DialogContent>
<DialogHeader/>
{ children }
</DialogContent>
</DialogRoot>
);
}
return (
<Popover isOpen={ isOpen } onClose={ onClose } placement="bottom-start" isLazy>
<PopoverRoot>
<PopoverTrigger>
{ triggerButton }
</PopoverTrigger>
<PopoverContent w="500px">
<PopoverBody px={ 6 } py={ 5 }>
<PopoverBody>
{ children }
</PopoverBody>
</PopoverContent>
</Popover>
</PopoverRoot>
);
};
......
import { Tooltip, Flex, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import { IconButton } from 'toolkit/chakra/icon-button';
import { Tooltip } from 'toolkit/chakra/tooltip';
import IconSvg from 'ui/shared/IconSvg';
type Props = {
......@@ -8,22 +9,14 @@ type Props = {
};
const ResetIconButton = ({ onClick }: Props) => {
const resetTokenIconColor = useColorModeValue('blue.600', 'blue.300');
const resetTokenIconHoverColor = useColorModeValue('blue.400', 'blue.200');
return (
<Tooltip label="Reset filter">
<Flex>
<Tooltip content="Reset filter">
<IconButton ml={ 1 } variant="link" onClick={ onClick }>
<IconSvg
name="cross"
boxSize={ 5 }
ml={ 1 }
color={ resetTokenIconColor }
cursor="pointer"
_hover={{ color: resetTokenIconHoverColor }}
onClick={ onClick }
/>
</Flex>
</IconButton>
</Tooltip>
);
};
......
import { Box, Grid, Link } from '@chakra-ui/react';
import { Box, Grid } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query';
import BigNumber from 'bignumber.js';
import { useRouter } from 'next/router';
......@@ -14,10 +14,11 @@ import throwOnResourceLoadError from 'lib/errors/throwOnResourceLoadError';
import getCurrencyValue from 'lib/getCurrencyValue';
import useIsMounted from 'lib/hooks/useIsMounted';
import { TOKEN_COUNTERS } from 'stubs/token';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import type { TokenTabs } from 'ui/pages/Token';
import AppActionButton from 'ui/shared/AppActionButton/AppActionButton';
import useAppActionData from 'ui/shared/AppActionButton/useAppActionData';
import Skeleton from 'ui/shared/chakra/Skeleton';
import * as DetailedInfo from 'ui/shared/DetailedInfo/DetailedInfo';
import DetailedInfoSponsoredItem from 'ui/shared/DetailedInfo/DetailedInfoSponsoredItem';
import TruncatedValue from 'ui/shared/TruncatedValue';
......@@ -65,11 +66,9 @@ const TokenDetails = ({ tokenQuery }: Props) => {
const tab: TokenTabs = item === 'token_holders_count' ? 'holders' : 'token_transfers';
return (
<Skeleton isLoaded={ !tokenCountersQuery.isPlaceholderData }>
<Link onClick={ changeUrlAndScroll(tab) }>
{ Number(itemValue).toLocaleString() }
</Link>
</Skeleton>
<Link onClick={ changeUrlAndScroll(tab) } loading={ tokenCountersQuery.isPlaceholderData }>
{ Number(itemValue).toLocaleString() }
</Link>
);
}, [ tokenCountersQuery.data, tokenCountersQuery.isPlaceholderData, changeUrlAndScroll ]);
......@@ -112,7 +111,7 @@ const TokenDetails = ({ tokenQuery }: Props) => {
Price
</DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue>
<Skeleton isLoaded={ !tokenQuery.isPlaceholderData } display="inline-block">
<Skeleton loading={ tokenQuery.isPlaceholderData } display="inline-block">
<span>{ `$${ Number(exchangeRate).toLocaleString(undefined, { minimumSignificantDigits: 4 }) }` }</span>
</Skeleton>
</DetailedInfo.ItemValue>
......@@ -128,7 +127,7 @@ const TokenDetails = ({ tokenQuery }: Props) => {
Fully diluted market cap
</DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue>
<Skeleton isLoaded={ !tokenQuery.isPlaceholderData } display="inline-block">
<Skeleton loading={ tokenQuery.isPlaceholderData } display="inline-block">
<span>{ `$${ BigNumber(marketCap).toFormat() }` }</span>
</Skeleton>
</DetailedInfo.ItemValue>
......@@ -146,7 +145,7 @@ const TokenDetails = ({ tokenQuery }: Props) => {
wordBreak="break-word"
whiteSpace="pre-wrap"
>
<Skeleton isLoaded={ !tokenQuery.isPlaceholderData } w="100%" display="flex">
<Skeleton loading={ tokenQuery.isPlaceholderData } w="100%" display="flex">
<TruncatedValue value={ totalSupplyValue || '0' } maxW="80%" flexShrink={ 0 }/>
<Box flexShrink={ 0 }> </Box>
<TruncatedValue value={ symbol || '' }/>
......@@ -160,7 +159,7 @@ const TokenDetails = ({ tokenQuery }: Props) => {
Holders
</DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue>
<Skeleton isLoaded={ !tokenCountersQuery.isPlaceholderData }>
<Skeleton loading={ tokenCountersQuery.isPlaceholderData }>
{ countersItem('token_holders_count') }
</Skeleton>
</DetailedInfo.ItemValue>
......@@ -172,7 +171,7 @@ const TokenDetails = ({ tokenQuery }: Props) => {
Transfers
</DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue>
<Skeleton isLoaded={ !tokenCountersQuery.isPlaceholderData }>
<Skeleton loading={ tokenCountersQuery.isPlaceholderData }>
{ countersItem('transfers_count') }
</Skeleton>
</DetailedInfo.ItemValue>
......@@ -186,7 +185,7 @@ const TokenDetails = ({ tokenQuery }: Props) => {
Decimals
</DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue>
<Skeleton isLoaded={ !tokenQuery.isPlaceholderData } minW={ 6 }>
<Skeleton loading={ tokenQuery.isPlaceholderData } minW={ 6 }>
{ decimals }
</Skeleton>
</DetailedInfo.ItemValue>
......
......@@ -37,11 +37,13 @@ const TokenHoldersContent = ({ holdersQuery, token, shouldRender = true }: Props
const actionBar = isMobile && holdersQuery.pagination.isVisible && (
<ActionBar mt={ -6 }>
<AddressCsvExportLink
address={ token?.address }
params={{ type: 'holders' }}
isLoading={ holdersQuery.pagination.isLoading }
/>
{ token && (
<AddressCsvExportLink
address={ token.address }
params={{ type: 'holders' }}
isLoading={ holdersQuery.pagination.isLoading }
/>
) }
<Pagination ml="auto" { ...holdersQuery.pagination }/>
</ActionBar>
);
......@@ -54,7 +56,7 @@ const TokenHoldersContent = ({ holdersQuery, token, shouldRender = true }: Props
<TokenHoldersTable
data={ items }
token={ token }
top={ holdersQuery.pagination.isVisible ? TABS_HEIGHT : 0 }
top={ TABS_HEIGHT }
isLoading={ holdersQuery.isPlaceholderData }
/>
</Box>
......@@ -71,11 +73,12 @@ const TokenHoldersContent = ({ holdersQuery, token, shouldRender = true }: Props
return (
<DataListDisplay
isError={ holdersQuery.isError }
items={ holdersQuery.data?.items }
itemsNum={ holdersQuery.data?.items.length }
emptyText="There are no holders for this token."
content={ content }
actionBar={ actionBar }
/>
>
{ content }
</DataListDisplay>
);
};
......
......@@ -3,7 +3,7 @@ import React from 'react';
import type { TokenHolder, TokenInfo } from 'types/api/token';
import Skeleton from 'ui/shared/chakra/Skeleton';
import { Skeleton } from 'toolkit/chakra/skeleton';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import ListItemMobileGrid from 'ui/shared/ListItemMobile/ListItemMobileGrid';
import Utilization from 'ui/shared/Utilization/Utilization';
......@@ -33,7 +33,7 @@ const TokenHoldersListItem = ({ holder, token, isLoading }: Props) => {
<>
<ListItemMobileGrid.Label isLoading={ isLoading }>ID#</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value>
<Skeleton isLoaded={ !isLoading } display="inline-block">
<Skeleton loading={ isLoading } display="inline-block">
{ holder.token_id }
</Skeleton>
</ListItemMobileGrid.Value>
......@@ -42,7 +42,7 @@ const TokenHoldersListItem = ({ holder, token, isLoading }: Props) => {
<ListItemMobileGrid.Label isLoading={ isLoading }>Quantity</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value>
<Skeleton isLoaded={ !isLoading } display="inline-block">
<Skeleton loading={ isLoading } display="inline-block">
{ quantity }
</Skeleton>
</ListItemMobileGrid.Value>
......
import { Table, Tbody, Tr, Th } from '@chakra-ui/react';
import React from 'react';
import type { TokenHolder, TokenInfo } from 'types/api/token';
import { default as Thead } from 'ui/shared/TheadSticky';
import { TableBody, TableColumnHeader, TableHeaderSticky, TableRoot, TableRow } from 'toolkit/chakra/table';
import TokenHoldersTableItem from 'ui/token/TokenHolders/TokenHoldersTableItem';
interface Props {
......@@ -15,21 +14,21 @@ interface Props {
const TokenHoldersTable = ({ data, token, top, isLoading }: Props) => {
return (
<Table layout="auto">
<Thead top={ top }>
<Tr>
<Th>Holder</Th>
{ (token.type === 'ERC-1155' || token.type === 'ERC-404') && <Th>ID#</Th> }
<Th isNumeric>Quantity</Th>
{ token.total_supply && token.type !== 'ERC-404' && <Th isNumeric width="175px">Percentage</Th> }
</Tr>
</Thead>
<Tbody>
<TableRoot tableLayout="auto">
<TableHeaderSticky top={ top }>
<TableRow>
<TableColumnHeader>Holder</TableColumnHeader>
{ (token.type === 'ERC-1155' || token.type === 'ERC-404') && <TableColumnHeader>ID#</TableColumnHeader> }
<TableColumnHeader isNumeric>Quantity</TableColumnHeader>
{ token.total_supply && token.type !== 'ERC-404' && <TableColumnHeader isNumeric width="175px">Percentage</TableColumnHeader> }
</TableRow>
</TableHeaderSticky>
<TableBody>
{ data.map((item, index) => (
<TokenHoldersTableItem key={ item.address.hash + (isLoading ? index : '') } holder={ item } token={ token } isLoading={ isLoading }/>
)) }
</Tbody>
</Table>
</TableBody>
</TableRoot>
);
};
......
import { Tr, Td } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
import type { TokenHolder, TokenInfo } from 'types/api/token';
import Skeleton from 'ui/shared/chakra/Skeleton';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { TableCell, TableRow } from 'toolkit/chakra/table';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import Utilization from 'ui/shared/Utilization/Utilization';
......@@ -18,38 +18,38 @@ const TokenTransferTableItem = ({ holder, token, isLoading }: Props) => {
const quantity = BigNumber(holder.value).div(BigNumber(10 ** Number(token.decimals))).toFormat();
return (
<Tr>
<Td verticalAlign="middle">
<TableRow>
<TableCell verticalAlign="middle">
<AddressEntity
address={ holder.address }
isLoading={ isLoading }
flexGrow={ 1 }
fontWeight="700"
/>
</Td>
</TableCell>
{ (token.type === 'ERC-1155' || token.type === 'ERC-404') && 'token_id' in holder && (
<Td verticalAlign="middle">
<Skeleton isLoaded={ !isLoading } display="inline-block">
<TableCell verticalAlign="middle">
<Skeleton loading={ isLoading } display="inline-block">
{ 'token_id' in holder && holder.token_id }
</Skeleton>
</Td>
</TableCell>
) }
<Td verticalAlign="middle" isNumeric>
<Skeleton isLoaded={ !isLoading } display="inline-block" wordBreak="break-word">
<TableCell verticalAlign="middle" isNumeric>
<Skeleton loading={ isLoading } display="inline-block" wordBreak="break-word">
{ quantity }
</Skeleton>
</Td>
</TableCell>
{ token.total_supply && token.type !== 'ERC-404' && (
<Td verticalAlign="middle" isNumeric>
<TableCell verticalAlign="middle" isNumeric>
<Utilization
value={ BigNumber(holder.value).div(BigNumber(token.total_supply)).dp(4).toNumber() }
colorScheme="green"
display="inline-flex"
isLoading={ isLoading }
/>
</Td>
</TableCell>
) }
</Tr>
</TableRow>
);
};
......
......@@ -88,15 +88,16 @@ const TokenInventory = ({ inventoryQuery, tokenQuery, ownerFilter, shouldRender
return (
<DataListDisplay
isError={ inventoryQuery.isError }
items={ items }
itemsNum={ items?.length }
emptyText="There are no tokens."
filterProps={{
hasActiveFilters: Boolean(ownerFilter),
emptyFilteredText: 'No tokens found for the selected owner.',
}}
content={ content }
actionBar={ actionBar }
/>
>
{ content }
</DataListDisplay>
);
};
......
import { Box, Flex, Text, Link, useColorModeValue } from '@chakra-ui/react';
import { Box, Flex, Text } from '@chakra-ui/react';
import React from 'react';
import type { TokenInfo, TokenInstance } from 'types/api/token';
......@@ -6,9 +6,9 @@ import type { TokenInfo, TokenInstance } from 'types/api/token';
import { route } from 'nextjs-routes';
import useIsMobile from 'lib/hooks/useIsMobile';
import Skeleton from 'ui/shared/chakra/Skeleton';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import LinkInternal from 'ui/shared/links/LinkInternal';
import NftMedia from 'ui/shared/nft/NftMedia';
import TruncatedTextTooltip from 'ui/shared/TruncatedTextTooltip';
......@@ -33,38 +33,37 @@ const TokenInventoryItem = ({ item, token, isLoading }: Props) => {
<Box
w={{ base: '100%', lg: '210px' }}
border="1px solid"
borderColor={ useColorModeValue('blackAlpha.100', 'whiteAlpha.200') }
borderColor={{ _light: 'blackAlpha.100', _dark: 'whiteAlpha.200' }}
borderRadius="12px"
p="10px"
fontSize="sm"
textStyle="sm"
fontWeight={ 500 }
lineHeight="20px"
>
<Link href={ isLoading ? undefined : url }>
<Link href={ isLoading ? undefined : url } display="inline">
{ mediaElement }
</Link>
{ item.id && (
<Flex mb={ 2 } ml={ 1 }>
<Text whiteSpace="pre" variant="secondary">ID# </Text>
<Text whiteSpace="pre" color="text.secondary">ID# </Text>
<TruncatedTextTooltip label={ item.id }>
<Skeleton isLoaded={ !isLoading } overflow="hidden">
<LinkInternal
<Skeleton loading={ isLoading } overflow="hidden">
<Link
overflow="hidden"
textOverflow="ellipsis"
whiteSpace="nowrap"
display="block"
isLoading={ isLoading }
loading={ isLoading }
href={ url }
>
{ item.id }
</LinkInternal>
</Link>
</Skeleton>
</TruncatedTextTooltip>
</Flex>
) }
{ item.owner && (
<Flex mb={ 2 } ml={ 1 }>
<Text whiteSpace="pre" variant="secondary" mr={ 2 } lineHeight="24px">Owner</Text>
<Text whiteSpace="pre" color="text.secondary" mr={ 2 } lineHeight="24px">Owner</Text>
<AddressEntity
address={ item.owner }
isLoading={ isLoading }
......
import { Image, Link, Tooltip } from '@chakra-ui/react';
import React from 'react';
import type { AddressMetadataTagFormatted } from 'types/client/addressMetadata';
import config from 'configs/app';
import { Image } from 'toolkit/chakra/image';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { Tooltip } from 'toolkit/chakra/tooltip';
import AppActionButton from 'ui/shared/AppActionButton/AppActionButton';
import Skeleton from 'ui/shared/chakra/Skeleton';
import * as DetailedInfo from 'ui/shared/DetailedInfo/DetailedInfo';
import TextSeparator from 'ui/shared/TextSeparator';
......@@ -33,14 +35,14 @@ const TokenNftMarketplaces = ({ hash, id, isLoading, appActionData, source }: Pr
<DetailedInfo.ItemValue
py={ appActionData ? '1px' : '6px' }
>
<Skeleton isLoaded={ !isLoading } display="flex" columnGap={ 3 } flexWrap="wrap" alignItems="center">
<Skeleton loading={ isLoading } display="flex" columnGap={ 3 } flexWrap="wrap" alignItems="center">
{ config.UI.views.nft.marketplaces.map((item) => {
const hrefTemplate = id ? item.instance_url : item.collection_url;
const href = hrefTemplate.replace('{id}', id || '').replace('{hash}', hash || '');
return (
<Tooltip label={ `View on ${ item.name }` } key={ item.name }>
<Tooltip content={ `View on ${ item.name }` } key={ item.name }>
<Link href={ href } target="_blank">
<Image
src={ item.logo_url }
......
import { Box, Flex, Tooltip, useToken } from '@chakra-ui/react';
import { Flex, useToken } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query';
import React from 'react';
......@@ -12,6 +12,7 @@ import type { ResourceError } from 'lib/api/resources';
import useApiQuery from 'lib/api/useApiQuery';
import { useAppContext } from 'lib/contexts/app';
import { getTokenTypeName } from 'lib/token/tokenTypes';
import { Tooltip } from 'toolkit/chakra/tooltip';
import AddressMetadataAlert from 'ui/address/details/AddressMetadataAlert';
import AddressQrCode from 'ui/address/details/AddressQrCode';
import AccountActionsMenu from 'ui/shared/AccountActionsMenu/AccountActionsMenu';
......@@ -66,8 +67,8 @@ const TokenPageTitle = ({ tokenQuery, addressQuery, hash }: Props) => {
};
}, [ appProps.referrer ]);
const bridgedTokenTagBgColor = useToken('colors', 'blue.500');
const bridgedTokenTagTextColor = useToken('colors', 'white');
const [ bridgedTokenTagBgColor ] = useToken('colors', 'blue.500');
const [ bridgedTokenTagTextColor ] = useToken('colors', 'white');
const tags: Array<EntityTag> = React.useMemo(() => {
return [
......@@ -105,10 +106,8 @@ const TokenPageTitle = ({ tokenQuery, addressQuery, hash }: Props) => {
const contentAfter = (
<>
{ verifiedInfoQuery.data?.tokenAddress && (
<Tooltip label={ `Information on this token has been verified by ${ config.chain.name }` }>
<Box boxSize={ 6 }>
<IconSvg name="certified" color="green.500" boxSize={ 6 } cursor="pointer"/>
</Box>
<Tooltip content={ `Information on this token has been verified by ${ config.chain.name }` }>
<IconSvg name="certified" color="green.500" boxSize={ 6 } cursor="pointer"/>
</Tooltip>
) }
<EntityTags
......@@ -131,7 +130,7 @@ const TokenPageTitle = ({ tokenQuery, addressQuery, hash }: Props) => {
/>
) }
{ !isLoading && tokenQuery.data && <AddressAddToWallet token={ tokenQuery.data } variant="button"/> }
<AddressQrCode address={ addressQuery.data } isLoading={ isLoading }/>
{ addressQuery.data && <AddressQrCode hash={ addressQuery.data.hash } isLoading={ isLoading }/> }
<AccountActionsMenu isLoading={ isLoading }/>
<Flex ml={{ base: 0, lg: 'auto' }} columnGap={ 2 } flexGrow={{ base: 1, lg: 0 }}>
<TokenVerifiedInfo verifiedInfoQuery={ verifiedInfoQuery }/>
......
......@@ -59,7 +59,7 @@ const Content = ({ data }: Props) => {
<Flex fontSize="sm" flexDir="column" rowGap={ 5 }>
{ (description || docs || support) && (
<div>
<Text variant="secondary" fontSize="xs">Description and support info</Text>
<Text color="text.secondary" fontSize="xs">Description and support info</Text>
{ description }
{ (docs || support) && (
<Flex alignItems="center" flexWrap="wrap" columnGap={ 6 } mt={ 3 }>
......@@ -71,7 +71,7 @@ const Content = ({ data }: Props) => {
) }
{ socialLinks.length > 0 && (
<div>
<Text variant="secondary" fontSize="xs">Links</Text>
<Text color="text.secondary" fontSize="xs">Links</Text>
<Grid templateColumns={{ base: 'repeat(2, 1fr)', lg: 'repeat(3, 1fr)' }} columnGap={ 4 } rowGap={ 3 } mt={ 3 }>
{ socialLinks.map((link) => <ServiceLink key={ link.field } { ...link }/>) }
</Grid>
......@@ -79,7 +79,7 @@ const Content = ({ data }: Props) => {
) }
{ priceTickersLinks.length > 0 && (
<div>
<Text variant="secondary" fontSize="xs">Crypto markets</Text>
<Text color="text.secondary" fontSize="xs">Crypto markets</Text>
<Grid templateColumns={{ base: 'repeat(2, 1fr)', lg: 'repeat(3, 1fr)' }} columnGap={ 4 } rowGap={ 3 } mt={ 3 }>
{ priceTickersLinks.map((link) => <ServiceLink key={ link.field } { ...link }/>) }
</Grid>
......
import { Link } from '@chakra-ui/react';
import React from 'react';
import { Link } from 'toolkit/chakra/link';
import IconSvg from 'ui/shared/IconSvg';
interface Props {
......@@ -16,7 +16,7 @@ const DocsLink = ({ href }: Props) => {
alignItems="center"
columnGap={ 1 }
>
<IconSvg name="docs" boxSize={ 6 } color="text_secondary"/>
<IconSvg name="docs" boxSize={ 6 } color="text.secondary"/>
<span>Documentation</span>
</Link>
);
......
import { Link } from '@chakra-ui/react';
import React from 'react';
import type { TokenVerifiedInfo } from 'types/api/token';
import { Link } from 'toolkit/chakra/link';
import type { IconName } from 'ui/shared/IconSvg';
import IconSvg from 'ui/shared/IconSvg';
......@@ -23,7 +23,7 @@ const ServiceLink = ({ href, title, icon }: Props) => {
display="inline-flex"
alignItems="center"
>
<IconSvg name={ icon } boxSize={ 5 } mr={ 2 } color="text_secondary"/>
<IconSvg name={ icon } boxSize={ 5 } mr={ 2 } color="text.secondary"/>
<span>{ title }</span>
</Link>
);
......
import { Link } from '@chakra-ui/react';
import React from 'react';
import { Link } from 'toolkit/chakra/link';
import IconSvg from 'ui/shared/IconSvg';
interface Props {
......@@ -19,7 +19,7 @@ const SupportLink = ({ url }: Props) => {
alignItems="center"
columnGap={ 1 }
>
<IconSvg name={ isEmail ? 'email' : 'link' } boxSize={ 6 } color="text_secondary"/>
<IconSvg name={ isEmail ? 'email' : 'link' } boxSize={ 6 } color="text.secondary"/>
<span>{ url }</span>
</Link>
);
......
......@@ -74,7 +74,7 @@ const TokenTransfer = ({ transfersQuery, tokenId, tokenQuery, shouldRender = tru
<Box display={{ base: 'none', lg: 'block' }}>
<TokenTransferTable
data={ data?.items }
top={ pagination.isVisible ? TABS_HEIGHT : 0 }
top={ TABS_HEIGHT }
showSocketInfo={ pagination.page === 1 }
socketInfoAlert={ socketAlert }
socketInfoNum={ newItemsCount }
......@@ -107,11 +107,12 @@ const TokenTransfer = ({ transfersQuery, tokenId, tokenQuery, shouldRender = tru
return (
<DataListDisplay
isError={ isError || isTokenError }
items={ data?.items }
itemsNum={ data?.items.length }
emptyText="There are no token transfers."
content={ content }
actionBar={ actionBar }
/>
>
{ content }
</DataListDisplay>
);
};
......
......@@ -5,9 +5,9 @@ import type { TokenTransfer } from 'types/api/tokenTransfer';
import getCurrencyValue from 'lib/getCurrencyValue';
import { NFT_TOKEN_TYPE_IDS } from 'lib/token/tokenTypes';
import { Badge } from 'toolkit/chakra/badge';
import { Skeleton } from 'toolkit/chakra/skeleton';
import AddressFromTo from 'ui/shared/address/AddressFromTo';
import Skeleton from 'ui/shared/chakra/Skeleton';
import Tag from 'ui/shared/chakra/Tag';
import NftEntity from 'ui/shared/entities/nft/NftEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
......@@ -36,7 +36,7 @@ const TokenTransferListItem = ({
}) : { usd: null, valueStr: null };
return (
<ListItemMobile rowGap={ 3 } isAnimated>
<ListItemMobile rowGap={ 3 }>
<Flex justifyContent="space-between" alignItems="center" lineHeight="24px" width="100%">
<TxEntity
isLoading={ isLoading }
......@@ -48,13 +48,13 @@ const TokenTransferListItem = ({
timestamp={ timestamp }
enableIncrement
isLoading={ isLoading }
color="text_secondary"
color="text.secondary"
fontWeight="400"
fontSize="sm"
display="inline-block"
/>
</Flex>
{ method && <Tag isLoading={ isLoading }>{ method }</Tag> }
{ method && <Badge loading={ isLoading }>{ method }</Badge> }
<AddressFromTo
from={ from }
to={ to }
......@@ -65,12 +65,12 @@ const TokenTransferListItem = ({
/>
{ valueStr && token && (token.type === 'ERC-20' || token.type === 'ERC-1155') && (
<Grid gap={ 2 } templateColumns={ `1fr auto auto${ usd ? ' auto' : '' }` }>
<Skeleton isLoaded={ !isLoading } flexShrink={ 0 } fontWeight={ 500 }>
<Skeleton loading={ isLoading } flexShrink={ 0 } fontWeight={ 500 }>
Value
</Skeleton>
<Skeleton
isLoaded={ !isLoading }
color="text_secondary"
loading={ isLoading }
color="text.secondary"
wordBreak="break-all"
overflow="hidden"
flexGrow={ 1 }
......@@ -80,8 +80,8 @@ const TokenTransferListItem = ({
{ token.symbol && <TruncatedValue isLoading={ isLoading } value={ token.symbol }/> }
{ usd && (
<Skeleton
isLoaded={ !isLoading }
color="text_secondary"
loading={ isLoading }
color="text.secondary"
wordBreak="break-all"
overflow="hidden"
>
......
import { Table, Tbody, Tr, Th } from '@chakra-ui/react';
import React from 'react';
import type { TokenInfo } from 'types/api/token';
......@@ -6,8 +5,8 @@ import type { TokenTransfer } from 'types/api/tokenTransfer';
import { AddressHighlightProvider } from 'lib/contexts/addressHighlight';
import { NFT_TOKEN_TYPE_IDS } from 'lib/token/tokenTypes';
import { TableBody, TableColumnHeader, TableHeaderSticky, TableRoot, TableRow } from 'toolkit/chakra/table';
import * as SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
import { default as Thead } from 'ui/shared/TheadSticky';
import TruncatedValue from 'ui/shared/TruncatedValue';
import TokenTransferTableItem from 'ui/token/TokenTransfer/TokenTransferTableItem';
......@@ -28,23 +27,23 @@ const TokenTransferTable = ({ data, top, showSocketInfo, socketInfoAlert, socket
return (
<AddressHighlightProvider>
<Table minW="950px">
<Thead top={ top }>
<Tr>
<Th width="280px">Txn hash</Th>
<Th width="200px">Method</Th>
<Th width={{ lg: '224px', xl: '380px' }}>From/To</Th>
<TableRoot minW="950px">
<TableHeaderSticky top={ top }>
<TableRow>
<TableColumnHeader width="280px">Txn hash</TableColumnHeader>
<TableColumnHeader width="200px">Method</TableColumnHeader>
<TableColumnHeader width={{ lg: '224px', xl: '380px' }}>From/To</TableColumnHeader>
{ (NFT_TOKEN_TYPE_IDS.includes(tokenType)) &&
<Th width={ tokenType === 'ERC-1155' || tokenType === 'ERC-404' ? '50%' : '100%' }>Token ID</Th>
<TableColumnHeader width={ tokenType === 'ERC-1155' || tokenType === 'ERC-404' ? '50%' : '100%' }>Token ID</TableColumnHeader>
}
{ (tokenType === 'ERC-20' || tokenType === 'ERC-1155' || tokenType === 'ERC-404') && (
<Th width={ tokenType === 'ERC-20' ? '100%' : '50%' } isNumeric>
<TableColumnHeader width={ tokenType === 'ERC-20' ? '100%' : '50%' } isNumeric>
<TruncatedValue value={ `Value ${ token?.symbol || '' }` } w="100%" verticalAlign="middle"/>
</Th>
</TableColumnHeader>
) }
</Tr>
</Thead>
<Tbody>
</TableRow>
</TableHeaderSticky>
<TableBody>
{ showSocketInfo && (
<SocketNewItemsNotice.Desktop
url={ window.location.href }
......@@ -62,8 +61,8 @@ const TokenTransferTable = ({ data, top, showSocketInfo, socketInfoAlert, socket
isLoading={ isLoading }
/>
)) }
</Tbody>
</Table>
</TableBody>
</TableRoot>
</AddressHighlightProvider>
);
};
......
import { Tr, Td, Flex, Box } from '@chakra-ui/react';
import { Flex, Box } from '@chakra-ui/react';
import React from 'react';
import type { TokenTransfer } from 'types/api/tokenTransfer';
import getCurrencyValue from 'lib/getCurrencyValue';
import { NFT_TOKEN_TYPE_IDS } from 'lib/token/tokenTypes';
import { Badge } from 'toolkit/chakra/badge';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { TableCell, TableRow } from 'toolkit/chakra/table';
import AddressFromTo from 'ui/shared/address/AddressFromTo';
import Skeleton from 'ui/shared/chakra/Skeleton';
import Tag from 'ui/shared/chakra/Tag';
import NftEntity from 'ui/shared/entities/nft/NftEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip';
......@@ -34,8 +35,8 @@ const TokenTransferTableItem = ({
}) : { usd: null, valueStr: null };
return (
<Tr alignItems="top">
<Td>
<TableRow alignItems="top">
<TableCell>
<Flex alignItems="center" py="7px">
<TxEntity
hash={ txHash }
......@@ -54,15 +55,15 @@ const TokenTransferTableItem = ({
ml="10px"
/>
</Flex>
</Td>
<Td>
</TableCell>
<TableCell>
{ method ? (
<Box my="3px">
<Tag isLoading={ isLoading } isTruncated>{ method }</Tag>
<Badge loading={ isLoading } truncated>{ method }</Badge>
</Box>
) : null }
</Td>
<Td>
</TableCell>
<TableCell>
<AddressFromTo
from={ from }
to={ to }
......@@ -71,9 +72,9 @@ const TokenTransferTableItem = ({
mode={{ lg: 'compact', xl: 'long' }}
tokenHash={ token?.address }
/>
</Td>
</TableCell>
{ (token && NFT_TOKEN_TYPE_IDS.includes(token.type)) && (
<Td>
<TableCell>
{ total && 'token_id' in total && token && total.token_id !== null ? (
<NftEntity
hash={ token.address }
......@@ -83,23 +84,23 @@ const TokenTransferTableItem = ({
/>
) : ''
}
</Td>
</TableCell>
) }
{ token && (token.type === 'ERC-20' || token.type === 'ERC-1155' || token.type === 'ERC-404') && (
<Td isNumeric verticalAlign="top">
<TableCell isNumeric verticalAlign="top">
{ valueStr && (
<Skeleton isLoaded={ !isLoading } display="inline-block" mt="7px" wordBreak="break-all">
<Skeleton loading={ isLoading } display="inline-block" mt="7px" wordBreak="break-all">
{ valueStr }
</Skeleton>
) }
{ usd && (
<Skeleton isLoaded={ !isLoading } color="text_secondary" mt="10px" wordBreak="break-all">
<Skeleton loading={ isLoading } color="text.secondary" mt="10px" wordBreak="break-all">
<span>${ usd }</span>
</Skeleton>
) }
</Td>
</TableCell>
) }
</Tr>
</TableRow>
);
};
......
......@@ -5,8 +5,8 @@ import type { TokenVerifiedInfo as TTokenVerifiedInfo } from 'types/api/token';
import config from 'configs/app';
import type { ResourceError } from 'lib/api/resources';
import Skeleton from 'ui/shared/chakra/Skeleton';
import LinkExternal from 'ui/shared/links/LinkExternal';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import TokenProjectInfo from './TokenProjectInfo';
......@@ -26,9 +26,9 @@ const TokenVerifiedInfo = ({ verifiedInfoQuery }: Props) => {
if (isPending) {
return (
<>
<Skeleton w="100px" h="30px" borderRadius="base"/>
<Skeleton w="100px" h="30px" borderRadius="base"/>
<Skeleton w="70px" h="30px" borderRadius="base"/>
<Skeleton loading w="100px" h="30px" borderRadius="base"/>
<Skeleton loading w="100px" h="30px" borderRadius="base"/>
<Skeleton loading w="70px" h="30px" borderRadius="base"/>
</>
);
}
......@@ -41,9 +41,9 @@ const TokenVerifiedInfo = ({ verifiedInfoQuery }: Props) => {
try {
const url = new URL(data.projectWebsite);
return (
<LinkExternal href={ data.projectWebsite } variant="subtle" flexShrink={ 0 } fontSize="sm" lineHeight={ 5 }>
<Link external href={ data.projectWebsite } variant="underlaid" flexShrink={ 0 } textStyle="sm">
{ url.host }
</LinkExternal>
</Link>
);
} catch (error) {
return null;
......
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