diff --git a/assets/icons/empty-filtered-list.svg b/assets/icons/empty-filtered-list.svg new file mode 100644 index 000000000..7cd0a63c9 --- /dev/null +++ b/assets/icons/empty-filtered-list.svg @@ -0,0 +1,33 @@ +<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg"> + <circle opacity="0.8" cx="36.6667" cy="36.6667" r="36.6667" fill="var(--primary-color)" /> + <circle cx="43.3337" cy="43.3334" r="36.6667" fill="#D1DEFF" /> + <mask id="mask0_3049_19899" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="6" y="6" width="74" height="74"> + <circle cx="43.3327" cy="43.3332" r="36.6667" fill="white" /> + </mask> + <g mask="url(#mask0_3049_19899)"> + <g opacity="0.5" filter="url(#filter0_f_3049_19899)"> + <circle cx="29.1657" cy="26.6664" r="44.1667" fill="var(--primary-color)" /> + </g> + </g> + <g filter="url(#filter1_d_3049_19899)"> + <path d="M42.5005 56.6679C50.3245 56.6679 56.6671 50.325 56.6671 42.5007C56.6671 34.6764 50.3245 28.3335 42.5005 28.3335C34.6766 28.3335 28.334 34.6764 28.334 42.5007C28.334 50.325 34.6766 56.6679 42.5005 56.6679Z" stroke="white" stroke-width="3.33331" stroke-linecap="round" stroke-linejoin="round" /> + <path d="M58.3345 58.3343L52.501 52.5009" stroke="white" stroke-width="3.33331" stroke-linecap="round" stroke-linejoin="round" /> + </g> + <defs> + <filter id="filter0_f_3049_19899" x="-34.3433" y="-36.8426" width="127.018" height="127.018" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> + <feFlood flood-opacity="0" result="BackgroundImageFix" /> + <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" /> + <feGaussianBlur stdDeviation="9.67118" result="effect1_foregroundBlur_3049_19899" /> + </filter> + <filter id="filter1_d_3049_19899" x="23.3337" y="25.0001" width="40.0007" height="40.0009" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> + <feFlood flood-opacity="0" result="BackgroundImageFix" /> + <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" /> + <feOffset dy="1.66667" /> + <feGaussianBlur stdDeviation="1.66667" /> + <feComposite in2="hardAlpha" operator="out" /> + <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" /> + <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3049_19899" /> + <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3049_19899" result="shape" /> + </filter> + </defs> +</svg> diff --git a/assets/icons/no-data.svg b/assets/icons/no-data.svg new file mode 100644 index 000000000..f12532b6a --- /dev/null +++ b/assets/icons/no-data.svg @@ -0,0 +1,33 @@ +<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg"> + <circle opacity="0.8" cx="36.6667" cy="36.6667" r="36.6667" fill="currentColor" /> + <circle cx="43.3334" cy="43.3334" r="36.6667" fill="#D1DEFF" /> + <mask id="mask0_109_1784" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="6" y="6" width="74" height="74"> + <circle cx="43.3329" cy="43.3332" r="36.6667" fill="white" /> + </mask> + <g mask="url(#mask0_109_1784)"> + <g opacity="0.5" filter="url(#filter0_f_109_1784)"> + <circle cx="29.1662" cy="26.6664" r="44.1667" fill="currentColor" /> + </g> + </g> + <g filter="url(#filter1_d_109_1784)"> + <path d="M55.873 31.6612H30.8132C29.8192 31.6634 28.9087 32.2163 28.4503 33.0962L28.3283 33.3671L25.6908 40.1537H36.4295L36.4261 40.1872C36.8976 40.0539 37.3882 40.3272 37.5218 40.7975C37.5223 40.7993 37.5228 40.8012 37.5233 40.803C37.5456 40.8818 37.5569 40.9646 37.5569 41.0468C37.5569 44.2557 40.1441 46.8571 43.3347 46.8571C46.5268 46.8571 49.1135 44.2562 49.1135 41.0468V41.0468C49.1117 40.5753 49.4783 40.1839 49.95 40.1537H61.0345L58.351 33.3538V33.3538C57.9909 32.4354 57.1515 31.7906 56.1693 31.678L55.873 31.6612H55.8745H55.873H55.873ZM35.8285 41.9404H25.1125V54.4536C25.1125 55.8279 26.1446 56.9806 27.5046 57.122L27.7777 57.1353H58.8898C60.2567 57.1353 61.4029 56.0959 61.5436 54.7294L61.555 54.4536V41.9404H50.8404C50.352 46.1079 46.5965 49.0881 42.4523 48.597C38.9797 48.1857 36.2409 45.4325 35.832 41.9404H35.8286H35.8285ZM55.8715 29.8746C57.6937 29.8746 59.3298 30.9933 60.0039 32.6942L63.3333 41.1326V54.4541C63.3333 56.922 61.3441 58.9225 58.8898 58.9225H27.7777C25.3234 58.9225 23.3333 56.922 23.3333 54.4545V41.3089L26.673 32.7173C27.3392 31.0021 28.9831 29.8735 30.8142 29.874H55.871L55.8715 29.8746Z" fill="white" /> + <path d="M55.873 31.6612H30.8132C29.8192 31.6634 28.9087 32.2163 28.4503 33.0962L28.3283 33.3671L25.6908 40.1537H36.4295L36.4261 40.1872C36.8976 40.0539 37.3882 40.3272 37.5218 40.7975C37.5223 40.7993 37.5228 40.8012 37.5233 40.803C37.5456 40.8818 37.5569 40.9646 37.5569 41.0468C37.5569 44.2557 40.1441 46.8571 43.3347 46.8571C46.5268 46.8571 49.1135 44.2562 49.1135 41.0468V41.0468C49.1117 40.5753 49.4783 40.1839 49.95 40.1537H61.0345L58.351 33.3538V33.3538C57.9909 32.4354 57.1515 31.7906 56.1693 31.678L55.873 31.6612H55.8745H55.873H55.873ZM35.8285 41.9404H25.1125V54.4536C25.1125 55.8279 26.1446 56.9806 27.5046 57.122L27.7777 57.1353H58.8898C60.2567 57.1353 61.4029 56.0959 61.5436 54.7294L61.555 54.4536V41.9404H50.8404C50.352 46.1079 46.5965 49.0881 42.4523 48.597C38.9797 48.1857 36.2409 45.4325 35.832 41.9404H35.8286H35.8285ZM55.8715 29.8746C57.6937 29.8746 59.3298 30.9933 60.0039 32.6942L63.3333 41.1326V54.4541C63.3333 56.922 61.3441 58.9225 58.8898 58.9225H27.7777C25.3234 58.9225 23.3333 56.922 23.3333 54.4545V41.3089L26.673 32.7173C27.3392 31.0021 28.9831 29.8735 30.8142 29.874H55.871L55.8715 29.8746Z" stroke="white" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round" /> + </g> + <defs> + <filter id="filter0_f_109_1784" x="-34.3428" y="-36.8426" width="127.018" height="127.018" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> + <feFlood flood-opacity="0" result="BackgroundImageFix" /> + <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" /> + <feGaussianBlur stdDeviation="9.67118" result="effect1_foregroundBlur_109_1784" /> + </filter> + <filter id="filter1_d_109_1784" x="19.1667" y="27.3741" width="48.3332" height="37.3818" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> + <feFlood flood-opacity="0" result="BackgroundImageFix" /> + <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" /> + <feOffset dy="1.66667" /> + <feGaussianBlur stdDeviation="1.66667" /> + <feComposite in2="hardAlpha" operator="out" /> + <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" /> + <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_109_1784" /> + <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_109_1784" result="shape" /> + </filter> + </defs> +</svg> diff --git a/components/Alert/index.tsx b/components/Alert/index.tsx new file mode 100644 index 000000000..cb8d0e35d --- /dev/null +++ b/components/Alert/index.tsx @@ -0,0 +1,95 @@ +import { AlertProps, SnackbarProps, Snackbar, Alert as MuiAlert } from '@mui/material' +import { styled } from '@mui/material/styles' +import CheckCircleIcon from '@mui/icons-material/CheckCircle' +import CancelIcon from '@mui/icons-material/Cancel' +import ErrorIcon from '@mui/icons-material/Error' + +const StyledSnackbar = styled((props: SnackbarProps) => <Snackbar {...props} />)(({ theme }) => ({ + '&.MuiSnackbar-root': { + top: theme.spacing(20), + [theme.breakpoints.down('sm')]: { + top: theme.spacing(1), + }, + div: { + 'borderRadius': 8, + '.MuiAlert-filledSuccess': { + backgroundColor: '#F0FCF1', + color: '#2BD56F', + svg: { + color: '#2BD56F', + }, + }, + '.MuiAlert-filledError': { + backgroundColor: '#FCF0F0', + color: '#F83F3F', + svg: { + color: '#F83F3F', + }, + }, + '.MuiAlert-filledWarning': { + backgroundColor: '#FAF0E1', + color: '#F3B515', + svg: { + color: '#F3B515', + }, + }, + }, + }, +})) + +const StyledAlert = styled((props: AlertProps) => <MuiAlert {...props} />)(({ theme }) => ({ + '&.MuiAlert-filled': { + display: 'flex', + alignItems: 'center', + width: 'auto', + height: '48px', + [theme.breakpoints.down('sm')]: { + height: '40px', + }, + }, + '& .MuiAlert-icon': { + marginRight: theme.spacing(1), + svg: { + fontSize: 16, + [theme.breakpoints.down('sm')]: { + fontSize: 14, + }, + }, + }, + '& .MuiAlert-message': { + fontSize: 14, + [theme.breakpoints.down('sm')]: { + fontSize: 13, + }, + }, +})) + +// extent mui SnackBar + Alert with custom styles +const Alert: React.FC<SnackbarProps & { content: string; type: 'error' | 'success' | 'warning' }> = ({ + content, + type, + ...rest +}) => { + return ( + <StyledSnackbar + anchorOrigin={{ + horizontal: 'center', + vertical: 'top', + }} + autoHideDuration={3000} + color="secondary" + {...rest} + > + <div> + <StyledAlert + severity={type} + variant="filled" + iconMapping={{ error: <CancelIcon />, success: <CheckCircleIcon />, warning: <ErrorIcon /> }} + > + {content} + </StyledAlert> + </div> + </StyledSnackbar> + ) +} +export default Alert diff --git a/components/AssetList/index.tsx b/components/AssetList/index.tsx index 9d21c360b..b48333f91 100644 --- a/components/AssetList/index.tsx +++ b/components/AssetList/index.tsx @@ -1,11 +1,12 @@ import { useTranslation } from 'next-i18next' import NextLink from 'next/link' import { gql } from 'graphql-request' +import BigNumber from 'bignumber.js' import Table from 'components/Table' import TokenLogo from 'components/TokenLogo' -import { parseTokenName, client, formatAmount, GraphQLSchema } from 'utils' +import { parseTokenName, client, GraphQLSchema } from 'utils' +import NoDataIcon from 'assets/icons/no-data.svg' import styles from './styles.module.scss' -import BigNumber from 'bignumber.js' export type UdtList = Array<{ value: string @@ -89,8 +90,11 @@ const AssetList = ({ list = [] }: { list: UdtList }) => { }) ) : ( <tr> - <td colSpan={3} align="center" className={styles.noRecords}> - {t(`emptyAssetList`)} + <td colSpan={3} align="center"> + <div className={styles.noRecords}> + <NoDataIcon /> + <span>{t(`emptyAssetList`)}</span> + </div> </td> </tr> )} diff --git a/components/AssetList/styles.module.scss b/components/AssetList/styles.module.scss index fce77e81d..9e53c9cd9 100644 --- a/components/AssetList/styles.module.scss +++ b/components/AssetList/styles.module.scss @@ -1,3 +1,5 @@ +@import '../../styles/mixin.scss'; + .name { display: flex; align-items: center; @@ -34,5 +36,5 @@ } .noRecords { - text-align: center; + @include empty-list; } diff --git a/components/BridgedRecordList/index.tsx b/components/BridgedRecordList/index.tsx index b0ebc9b92..83352f93f 100644 --- a/components/BridgedRecordList/index.tsx +++ b/components/BridgedRecordList/index.tsx @@ -5,6 +5,7 @@ import Table from 'components/Table' import HashLink from 'components/HashLink' import Address from 'components/TruncatedAddress' import Pagination from 'components/Pagination' +import NoDataIcon from 'assets/icons/no-data.svg' import Amount from 'components/Amount' import { timeDistance, getBridgedRecordListRes, CKB_EXPLORER_URL, PCKB_UAN, PCKB_UDT_INFO } from 'utils' import styles from './styles.module.scss' @@ -84,16 +85,21 @@ const BridgedRecordList: React.FC<{ list: ParsedList; showUser?: boolean }> = ({ )) ) : ( <tr> - <td colSpan={showUser ? 7 : 6} align="center" style={{ textAlign: 'center' }}> - {t(`no_records`)} + <td colSpan={showUser ? 7 : 6}> + <div className={styles.noRecords}> + <NoDataIcon /> + <span>{t(`no_records`)}</span> + </div> </td> </tr> )} </tbody> </Table> - <div className={styles.pagination}> - <Pagination total={+list.meta.total} page={+list.meta.page} /> - </div> + {+list.meta.total ? ( + <div className={styles.pagination}> + <Pagination total={+list.meta.total} page={+list.meta.page} /> + </div> + ) : null} </> ) } diff --git a/components/BridgedRecordList/styles.module.scss b/components/BridgedRecordList/styles.module.scss index b72712c1c..ea3fa96ec 100644 --- a/components/BridgedRecordList/styles.module.scss +++ b/components/BridgedRecordList/styles.module.scss @@ -1,5 +1,10 @@ +@import '../../styles/mixin.scss'; + .pagination { display: flex; justify-content: flex-end; padding: 1.125rem 1.5rem; } +.noRecords { + @include empty-list; +} diff --git a/components/ChartComponents/styles.module.scss b/components/ChartComponents/styles.module.scss index cf967cb03..c21fbea53 100644 --- a/components/ChartComponents/styles.module.scss +++ b/components/ChartComponents/styles.module.scss @@ -20,7 +20,7 @@ } li span { font-size: 14px; - color: #333; + color: var(--primary-text-color); } li::before { position: absolute; diff --git a/components/ContractEventsList.tsx b/components/ContractEventsList.tsx index b45114d71..80320add2 100644 --- a/components/ContractEventsList.tsx +++ b/components/ContractEventsList.tsx @@ -17,8 +17,9 @@ import { InputAdornment, TextField, } from '@mui/material' -import { ParsedEventLog, IMG_URL, useDebounce } from 'utils' import ContractEventListItem from './ContractEventListItem' +import NoDataIcon from 'assets/icons/no-data.svg' +import { ParsedEventLog, IMG_URL, useDebounce } from 'utils' export const EventFilterIcon = ({ setSearchText, tooltip, value }) => ( <Tooltip title={tooltip} placement="top"> @@ -63,7 +64,7 @@ const ContractEventsList = ({ list }: { list: ParsedEventLog[] }) => { ) }, [debouncedSetListItems, list, searchText]) - return ( + return listItems?.length ? ( <Box sx={{ px: 1, py: 2 }}> <Stack direction="row" justifyContent="space-between" alignItems="center"> <Typography fontSize={14} color="#333333" sx={{ m: 1.5 }}> @@ -113,59 +114,68 @@ const ContractEventsList = ({ list }: { list: ParsedEventLog[] }) => { </TableRow> </TableHead> <TableBody> - {listItems?.length ? ( - listItems?.map((item, idx) => ( - <TableRow key={item.id + '-' + idx}> - <TableCell> - <Stack> - <NextLink href={`/tx/${item.txHash}`} passHref> + {listItems?.map((item, idx) => ( + <TableRow key={item.id + '-' + idx}> + <TableCell> + <Stack> + <NextLink href={`/tx/${item.txHash}`} passHref> + <Link + href={`/tx/${item.txHash}`} + underline="none" + color="secondary" + className="mono-font" + sx={{ fontSize: 14 }} + > + {item.txHash.slice(0, 17)}... + </Link> + </NextLink> + <Box sx={{ display: 'flex' }}> + <NextLink href={`/block/${item.blockNumber}`} passHref> <Link - href={`/tx/${item.txHash}`} + href={`/block/${item.blockNumber}`} underline="none" - color="secondary" + color="primary" className="mono-font" sx={{ fontSize: 14 }} > - {item.txHash.slice(0, 17)}... + # {item.blockNumber} </Link> </NextLink> - <Box sx={{ display: 'flex' }}> - <NextLink href={`/block/${item.blockNumber}`} passHref> - <Link - href={`/block/${item.blockNumber}`} - underline="none" - color="secondary" - sx={{ fontSize: 14 }} - > - # {item.blockNumber} - </Link> - </NextLink> - <Box sx={{ pl: 0.5 }} /> - <EventFilterIcon - setSearchText={setSearchText} - tooltip={t('filterEventBy', { filter: `BlockNo=${item.blockNumber}` })} - value={`${item.blockNumber}`} - /> - </Box> - </Stack> - </TableCell> - {/* <TableCell>{item.method}</TableCell> */} - <TableCell sx={{ pr: 1 }}> - <ContractEventListItem item={item} setSearchText={setSearchText} /> - </TableCell> - </TableRow> - )) - ) : ( - <TableRow> - <TableCell colSpan={7} align="center"> - {t('no_records')} + <Box sx={{ pl: 0.5 }} /> + <EventFilterIcon + setSearchText={setSearchText} + tooltip={t('filterEventBy', { filter: `BlockNo=${item.blockNumber}` })} + value={`${item.blockNumber}`} + /> + </Box> + </Stack> + </TableCell> + {/* <TableCell>{item.method}</TableCell> */} + <TableCell sx={{ pr: 1 }}> + <ContractEventListItem item={item} setSearchText={setSearchText} /> </TableCell> </TableRow> - )} + ))} </TableBody> </Table> </TableContainer> </Box> + ) : ( + <Box> + <div + style={{ + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + padding: '8.75rem 0', + color: 'var(--primary-color)', + }} + > + <NoDataIcon /> + <span style={{ marginTop: '2rem', color: 'var(--primary-text-color)' }}>{t(`no_records`)}</span> + </div> + </Box> ) } diff --git a/components/ContractInfo/styles.module.scss b/components/ContractInfo/styles.module.scss index 628284082..0bc4d842e 100644 --- a/components/ContractInfo/styles.module.scss +++ b/components/ContractInfo/styles.module.scss @@ -12,7 +12,7 @@ font-family: Roboto; font-weight: 400; font-size: 0.875rem; - color: #333; + color: var(--primary-text-color); border-radius: 4px; border-color: #ddd; } @@ -65,7 +65,7 @@ .params, .response { - color: #333; + color: var(--primary-text-color); font-size: 0.875rem; font-weight: 500; margin-top: 0.5rem; @@ -93,7 +93,7 @@ border: 1px solid var(--border-color); margin: 1rem auto; font-size: 0.875rem; - color: #333; + color: var(--primary-text-color); summary { display: flex; @@ -252,7 +252,7 @@ padding: 1rem 0; font-size: 0.875rem; font-weight: 400; - color: #333; + color: var(--primary-text-color); & > div { flex: 1; display: flex; @@ -284,7 +284,7 @@ h6 { font-size: 1rem; font-weight: 500; - color: #333; + color: var(--primary-text-color); margin: 0; } .title { diff --git a/components/CopyBtn/index.tsx b/components/CopyBtn/index.tsx index b4ab380cb..658b129d1 100644 --- a/components/CopyBtn/index.tsx +++ b/components/CopyBtn/index.tsx @@ -1,6 +1,6 @@ import { useState } from 'react' import { useTranslation } from 'next-i18next' -import { Alert, Snackbar } from '@mui/material' +import Alert from 'components/Alert' import CopyIcon from 'assets/icons/copy.svg' import { handleCopy } from 'utils' import styles from './styles.module.scss' @@ -18,20 +18,7 @@ const CopyBtn: React.FC<{ content: string }> = ({ content }) => { <button className={styles.copyBtn} aria-label="copy" onClick={handleHashCopy}> <CopyIcon fontSize="inherit" /> </button> - <Snackbar - open={isCopied} - onClose={() => setIsCopied(false)} - anchorOrigin={{ - horizontal: 'center', - vertical: 'top', - }} - autoHideDuration={3000} - color="secondary" - > - <Alert severity="success" variant="filled"> - {t(`blockHashCopied`)} - </Alert> - </Snackbar> + <Alert open={isCopied} onClose={() => setIsCopied(false)} content={t(`blockHashCopied`)} type="success" /> </> ) } diff --git a/components/ERC20TransferList/index.tsx b/components/ERC20TransferList/index.tsx index 4f8120419..86a40958b 100644 --- a/components/ERC20TransferList/index.tsx +++ b/components/ERC20TransferList/index.tsx @@ -11,6 +11,7 @@ import TransferDirection from 'components/TransferDirection' import RoundedAmount from 'components/RoundedAmount' import TokenLogo from 'components/TokenLogo' import ChangeIcon from 'assets/icons/change.svg' +import NoDataIcon from 'assets/icons/no-data.svg' import { client, timeDistance, getBlockStatus, GraphQLSchema } from 'utils' import styles from './styles.module.scss' @@ -234,14 +235,17 @@ const TransferList: React.FC< }) ) : ( <tr> - <td colSpan={showToken ? 8 : 7} className={styles.noRecords}> - {t(`no_records`)} + <td colSpan={showToken ? 8 : 7}> + <div className={styles.noRecords}> + <NoDataIcon /> + <span>{t(`no_records`)}</span> + </div> </td> </tr> )} </tbody> </Table> - <Pagination {...token_transfers.metadata} /> + {token_transfers.metadata.total_count ? <Pagination {...token_transfers.metadata} /> : null} </div> ) } diff --git a/components/ERC20TransferList/styles.module.scss b/components/ERC20TransferList/styles.module.scss index a8f447b7c..d06f50d71 100644 --- a/components/ERC20TransferList/styles.module.scss +++ b/components/ERC20TransferList/styles.module.scss @@ -1,3 +1,5 @@ +@import '../../styles/mixin.scss'; + .container { th, td { @@ -15,7 +17,7 @@ } } .noRecords { - text-align: center !important; + @include empty-list; } } diff --git a/components/FilterMenu/styles.module.scss b/components/FilterMenu/styles.module.scss index d78e0ca51..066031a22 100644 --- a/components/FilterMenu/styles.module.scss +++ b/components/FilterMenu/styles.module.scss @@ -53,7 +53,7 @@ input { width: 100%; - color: #333; + color: var(--primary-text-color); font-size: 0.875rem; font-weight: 500; padding: 0.75rem 0.5rem; diff --git a/components/InfoList/styles.module.scss b/components/InfoList/styles.module.scss index ea48e4b5a..6a960a637 100644 --- a/components/InfoList/styles.module.scss +++ b/components/InfoList/styles.module.scss @@ -40,7 +40,7 @@ margin: 0; font-weight: 500; font-size: 1rem; - color: #333; + color: var(--primary-text-color); border-bottom: 1px solid var(--border-color); } diff --git a/components/RawTxData/styles.module.scss b/components/RawTxData/styles.module.scss index 012a41807..b1ffad782 100644 --- a/components/RawTxData/styles.module.scss +++ b/components/RawTxData/styles.module.scss @@ -20,7 +20,7 @@ border-radius: 4px; border-color: var(--border-color); font-size: 0.875rem; - color: #333; + color: var(--primary-text-color); &:first-of-type { margin-bottom: 2rem; } diff --git a/components/SimpleERC20Transferlist/index.tsx b/components/SimpleERC20Transferlist/index.tsx index ce5e05a2c..99526887f 100644 --- a/components/SimpleERC20Transferlist/index.tsx +++ b/components/SimpleERC20Transferlist/index.tsx @@ -10,9 +10,11 @@ import Table from 'components/Table' import Pagination from 'components/SimplePagination' import TokenLogo from 'components/TokenLogo' import FilterMenu from 'components/FilterMenu' -import SortIcon from 'assets/icons/sort.svg' import RoundedAmount from 'components/RoundedAmount' +import SortIcon from 'assets/icons/sort.svg' import ChangeIcon from 'assets/icons/change.svg' +import NoDataIcon from 'assets/icons/no-data.svg' +import EmptyFilteredListIcon from 'assets/icons/empty-filtered-list.svg' import { GraphQLSchema, client } from 'utils' import styles from './styles.module.scss' @@ -104,6 +106,8 @@ export const fetchTransferList = (variables: { .then(data => data.token_transfers) .catch(() => ({ entries: [], metadata: { before: null, after: null, total_count: 0 } })) +const FILTER_KEYS = ['address_from', 'address_to'] + const TransferList: React.FC<TransferListProps> = ({ token_transfers: { entries, metadata } }) => { const [isShowLogo, setIsShowLogo] = useState(true) const [t] = useTranslation('list') @@ -113,6 +117,9 @@ const TransferList: React.FC<TransferListProps> = ({ token_transfers: { entries, asPath, } = useRouter() + const isFiltered = Object.keys(query).some(key => FILTER_KEYS.includes(key)) + const isFilterUnnecessary = !metadata.total_count && !isFiltered + const handleLogIndexSortClick = (e: React.MouseEvent<HTMLOrSVGImageElement>) => { const { dataset: { order }, @@ -128,7 +135,7 @@ const TransferList: React.FC<TransferListProps> = ({ token_transfers: { entries, const handleTokenDisplayChange = () => setIsShowLogo(show => !show) return ( - <div className={styles.container}> + <div className={styles.container} data-is-filter-unnecessary={isFilterUnnecessary}> <Table> <thead> <tr> @@ -141,13 +148,13 @@ const TransferList: React.FC<TransferListProps> = ({ token_transfers: { entries, <th> <div className={styles.from}> {t('from')} - <FilterMenu filterKeys={['address_from']} /> + <FilterMenu filterKeys={[FILTER_KEYS[0]]} /> </div> </th> <th> <div className={styles.to}> {t('to')} - <FilterMenu filterKeys={['address_to']} /> + <FilterMenu filterKeys={[FILTER_KEYS[1]]} /> </div> </th> <th className={styles.tokenLogo}> @@ -202,15 +209,24 @@ const TransferList: React.FC<TransferListProps> = ({ token_transfers: { entries, )) ) : ( <tr> - <td colSpan={5} style={{ textAlign: 'center' }}> - {t(`no_records`)} + <td colSpan={5}> + {isFiltered ? ( + <div className={styles.noRecords}> + <EmptyFilteredListIcon /> + <span>{t(`no_related_content`)}</span> + </div> + ) : ( + <div className={styles.noRecords}> + <NoDataIcon /> + <span>{t(`no_records`)}</span> + </div> + )} </td> </tr> )} </tbody> </Table> - - <Pagination {...metadata} note={t(`last-n-records`, { n: `100k` })} /> + {metadata.total_count ? <Pagination {...metadata} note={t(`last-n-records`, { n: `100k` })} /> : null} </div> ) } diff --git a/components/SimpleERC20Transferlist/styles.module.scss b/components/SimpleERC20Transferlist/styles.module.scss index 4c8b88f08..2ae9e94c5 100644 --- a/components/SimpleERC20Transferlist/styles.module.scss +++ b/components/SimpleERC20Transferlist/styles.module.scss @@ -1,3 +1,5 @@ +@import '../../styles/mixin.scss'; + .container { th { text-transform: capitalize; @@ -8,6 +10,13 @@ text-align: right; } } + &[data-is-filter-unnecessary='true'] { + th { + svg { + display: none; + } + } + } } .tokenLogo { @@ -40,3 +49,7 @@ display: flex; align-items: center; } + +.noRecords { + @include empty-list; +} diff --git a/components/Table/styles.module.scss b/components/Table/styles.module.scss index 98e5b5bf5..5c86e7cd3 100644 --- a/components/Table/styles.module.scss +++ b/components/Table/styles.module.scss @@ -2,6 +2,7 @@ font-weight: 400; font-size: 0.875rem; font-family: 'Roboto'; + overflow-x: auto; // FIXME: will make filter menu partially invisible z-index: 1; table { diff --git a/components/TokenHolderList/index.tsx b/components/TokenHolderList/index.tsx index 4484b56d7..bde9c9025 100644 --- a/components/TokenHolderList/index.tsx +++ b/components/TokenHolderList/index.tsx @@ -1,12 +1,14 @@ import { useTranslation } from 'next-i18next' import BigNumber from 'bignumber.js' +import { Stack } from '@mui/material' +import { useTheme } from '@mui/material/styles' +import useMediaQuery from '@mui/material/useMediaQuery' import Table from 'components/Table' import Address from 'components/TruncatedAddress' import Pagination from 'components/Pagination' -import { useTheme } from '@mui/material/styles' -import useMediaQuery from '@mui/material/useMediaQuery' -import { Stack } from '@mui/material' +import NoDataIcon from 'assets/icons/no-data.svg' import { getTokenHolderListRes } from 'utils' +import styles from './styles.module.scss' type ParsedTokenHolderList = ReturnType<typeof getTokenHolderListRes> @@ -45,29 +47,34 @@ const TokenHolderList: React.FC<{ )) ) : ( <tr> - <td colSpan={7} align="center" style={{ textAlign: 'center' }}> - {t(`no_records`)} + <td colSpan={7}> + <div className={styles.noRecords}> + <NoDataIcon /> + <span>{t(`no_records`)}</span> + </div> </td> </tr> )} </tbody> </Table> - <Stack - direction="row" - flexWrap="wrap" - justifyContent={isMobile ? 'center' : 'end'} - alignItems="center" - mt={{ xs: 0, md: 2 }} - pb={{ xs: 1.5, md: 2 }} - px={{ xs: 1.5, md: 3 }} - > - {/* TODO: pagesize */} - {/* <PageSize pageSize={+page_size} /> */} - {/* <Typography color="secondary.light" fontSize={{ xs: 12, md: 14 }}> + {+list.meta.total ? ( + <Stack + direction="row" + flexWrap="wrap" + justifyContent={isMobile ? 'center' : 'end'} + alignItems="center" + mt={{ xs: 0, md: 2 }} + pb={{ xs: 1.5, md: 2 }} + px={{ xs: 1.5, md: 3 }} + > + {/* TODO: pagesize */} + {/* <PageSize pageSize={+page_size} /> */} + {/* <Typography color="secondary.light" fontSize={{ xs: 12, md: 14 }}> {t('showLatestRecords', { ns: 'common', number: isMobile ? '100k' : '500k' })} </Typography> */} - <Pagination total={+list.meta.total} page={+list.meta.page} /> - </Stack> + <Pagination total={+list.meta.total} page={+list.meta.page} /> + </Stack> + ) : null} </> ) } diff --git a/components/TokenHolderList/styles.module.scss b/components/TokenHolderList/styles.module.scss new file mode 100644 index 000000000..18ebfdf04 --- /dev/null +++ b/components/TokenHolderList/styles.module.scss @@ -0,0 +1,5 @@ +@import '../../styles/mixin.scss'; + +.noRecords { + @include empty-list; +} diff --git a/components/TxList/index.tsx b/components/TxList/index.tsx index c179d5205..d90e8e4f3 100644 --- a/components/TxList/index.tsx +++ b/components/TxList/index.tsx @@ -1,4 +1,5 @@ import { useTranslation } from 'next-i18next' +import { useRouter } from 'next/router' import NextLink from 'next/link' import { gql } from 'graphql-request' import Table from 'components/Table' @@ -9,9 +10,11 @@ import Pagination from 'components/SimplePagination' import TransferDirection from 'components/TransferDirection' import Tooltip from 'components/Tooltip' import FilterMenu from 'components/FilterMenu' +import RoundedAmount from 'components/RoundedAmount' +import NoDataIcon from 'assets/icons/no-data.svg' +import EmptyFilteredListIcon from 'assets/icons/empty-filtered-list.svg' import { getBlockStatus, timeDistance, GraphQLSchema, client, PCKB_UDT_INFO } from 'utils' import styles from './styles.module.scss' -import RoundedAmount from 'components/RoundedAmount' export type TxListProps = { transactions: { @@ -108,6 +111,8 @@ export const fetchTxList = (variables: Variables) => .then(data => data.transactions) .catch(() => ({ entries: [], metadata: { before: null, after: null, total_count: 0 } })) +const FILTER_KEYS = ['block_from', 'block_to'] + const TxList: React.FC<TxListProps & { maxCount?: string; pageSize?: number }> = ({ transactions: { entries, metadata }, maxCount, @@ -115,9 +120,12 @@ const TxList: React.FC<TxListProps & { maxCount?: string; pageSize?: number }> = viewer, }) => { const [t, { language }] = useTranslation('list') + const { query } = useRouter() + const isFiltered = Object.keys(query).some(key => FILTER_KEYS.includes(key)) + const isFilterUnnecessary = !metadata.total_count && !isFiltered return ( - <div className={styles.container}> + <div className={styles.container} data-is-filter-unnecessary={isFilterUnnecessary}> <Table> <thead> <tr> @@ -125,7 +133,7 @@ const TxList: React.FC<TxListProps & { maxCount?: string; pageSize?: number }> = <th> <div style={{ display: 'flex', alignItems: 'center' }}> {t('block')} - <FilterMenu filterKeys={['block_from', 'block_to']} /> + <FilterMenu filterKeys={FILTER_KEYS} /> </div> </th> <th>{t('age')}</th> @@ -194,14 +202,25 @@ const TxList: React.FC<TxListProps & { maxCount?: string; pageSize?: number }> = }) ) : ( <tr> - <td colSpan={7} align="center" style={{ textAlign: 'center' }}> - {t(`no_records`)} + <td colSpan={7} align="center"> + {isFiltered ? ( + <div className={styles.noRecords}> + <EmptyFilteredListIcon /> + <span>{t(`no_related_content`)}</span> + </div> + ) : ( + <div className={styles.noRecords}> + <NoDataIcon /> + <span>{t(`no_records`)}</span> + </div> + )} </td> </tr> )} </tbody> </Table> - {pageSize ? ( + + {!metadata.total_count ? null : pageSize ? ( <Pagination {...metadata} note={maxCount ? t(`last-n-records`, { n: maxCount }) : ''} /> ) : ( <Pagination {...metadata} note={maxCount ? t(`last-n-records`, { n: maxCount }) : ''} /> diff --git a/components/TxList/styles.module.scss b/components/TxList/styles.module.scss index 1a844e769..b204b405b 100644 --- a/components/TxList/styles.module.scss +++ b/components/TxList/styles.module.scss @@ -1,3 +1,5 @@ +@import '../../styles/mixin.scss'; + .container { th, td { @@ -5,8 +7,19 @@ text-align: right; } } + &[data-is-filter-unnecessary='true'] { + th { + svg { + display: none; + } + } + } } .direction { padding-left: 0 !important; padding-right: 0 !important; } + +.noRecords { + @include empty-list; +} diff --git a/components/TxLogsList/index.tsx b/components/TxLogsList/index.tsx index 3d688c212..7e33f21d4 100644 --- a/components/TxLogsList/index.tsx +++ b/components/TxLogsList/index.tsx @@ -3,6 +3,7 @@ import NextLink from 'next/link' import { Link } from '@mui/material' import { ParsedEventLog } from 'utils' import LogFieldItem from 'components/LogItemField' +import NoDataIcon from 'assets/icons/no-data.svg' import styles from './styles.module.scss' const TxLogsList = ({ list }: { list: ParsedEventLog[] }) => { @@ -104,6 +105,7 @@ const TxLogsList = ({ list }: { list: ParsedEventLog[] }) => { </div> ) : ( <div className={styles.noRecords}> + <NoDataIcon /> <span>{t('noLogs')}</span> </div> ) diff --git a/components/TxLogsList/styles.module.scss b/components/TxLogsList/styles.module.scss index 59dc85cd2..e049c9bd1 100644 --- a/components/TxLogsList/styles.module.scss +++ b/components/TxLogsList/styles.module.scss @@ -1,18 +1,17 @@ +@import '../../styles/mixin.scss'; + .container { font-size: 14px; margin: 24px; overflow: auto; .title { - color: #333; + color: var(--primary-text-color); font-weight: 400; } } .noRecords { - display: flex; - justify-content: center; - align-items: center; - min-height: 50px; + @include empty-list; } .topicItem { @@ -72,7 +71,7 @@ flex-basis: 100px; flex-shrink: 0; font-size: 16px; - color: #333; + color: var(--primary-text-color); display: flex; justify-content: flex-end; padding-right: 30px; @@ -82,7 +81,7 @@ } .eventSignature { - color: #333; + color: var(--primary-text-color); display: flex; align-items: flex-start; min-height: 40px; diff --git a/pages/404.tsx b/pages/404.tsx index 636220ebf..3c00d3957 100644 --- a/pages/404.tsx +++ b/pages/404.tsx @@ -13,7 +13,7 @@ import NotFoundIcon from '../assets/icons/404.svg' const Custom404 = () => { const [t] = useTranslation('common') const [search, setSearch] = useState('') - const { back, query, push } = useRouter() + const { back, query } = useRouter() const searchRef = useRef<HTMLInputElement | null>(null) useEffect(() => { diff --git a/pages/account/styles.module.scss b/pages/account/styles.module.scss index 31b418154..88c35a86a 100644 --- a/pages/account/styles.module.scss +++ b/pages/account/styles.module.scss @@ -22,7 +22,7 @@ @include mono-font; font-size: 0.875rem; font-weight: 500; - color: #333; + color: var(--primary-text-color); word-break: break-all; user-select: none; diff --git a/pages/blocks.tsx b/pages/blocks.tsx index 52f1db05d..5c9036684 100644 --- a/pages/blocks.tsx +++ b/pages/blocks.tsx @@ -25,6 +25,7 @@ import Pagination from 'components/Pagination' import PageSize, { SIZES } from 'components/PageSize' import BlockStateIcon from 'components/BlockStateIcon' import TableCell from 'components/TableCell' +import NoDataIcon from 'assets/icons/no-data.svg' import { fetchBlockList, timeDistance } from 'utils' const BlockList = () => { @@ -223,7 +224,19 @@ const BlockList = () => { ) : ( <TableRow> <TableCell colSpan={5} align="center"> - {t(`no_records`)} + <div + style={{ + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + padding: '8.75rem 0', + color: 'var(--primary-color)', + }} + > + <NoDataIcon /> + <span style={{ marginTop: '2rem' }}>{t(`no_records`)}</span> + </div> </TableCell> </TableRow> )} diff --git a/pages/contracts.tsx b/pages/contracts.tsx index 51650201f..83584a2fa 100644 --- a/pages/contracts.tsx +++ b/pages/contracts.tsx @@ -108,7 +108,7 @@ const ContractList = () => { <td style={{ textTransform: 'capitalize' }} title={c.compiler.fileFormat}> {c.compiler.fileFormat?.split(' ')[0] ?? '-'} </td> - <td title={c.compiler.version}>{c.compiler.version.split('+')[0]}</td> + <td title={c.compiler.version}>{c.compiler.version?.split('+')[0]}</td> <td title={c.balance}> <Amount amount={c.balance ?? '0'} udt={{ symbol: PCKB_UDT_INFO.symbol, decimal: 10 }} /> </td> diff --git a/pages/token/styles.module.scss b/pages/token/styles.module.scss index f4221c8d7..37dffaa3c 100644 --- a/pages/token/styles.module.scss +++ b/pages/token/styles.module.scss @@ -32,7 +32,7 @@ @include mono-font; font-size: 0.875rem; font-weight: 500; - color: #333; + color: var(--primary-text-color); word-break: break-all; user-select: none; diff --git a/pages/tokens/[type].tsx b/pages/tokens/[type].tsx index d171cdf84..e28f858ec 100644 --- a/pages/tokens/[type].tsx +++ b/pages/tokens/[type].tsx @@ -20,6 +20,8 @@ import FilterMenu from 'components/FilterMenu' import { SIZES } from 'components/PageSize' import Amount from 'components/Amount' import AddIcon from 'assets/icons/add.svg' +import NoDataIcon from 'assets/icons/no-data.svg' +import EmptyFilteredListIcon from 'assets/icons/empty-filtered-list.svg' import { GraphQLSchema, client, parseTokenName } from 'utils' import styles from './styles.module.scss' @@ -90,6 +92,7 @@ const fetchTokenList = (variables: Variables): Promise<TokenListProps['udts']> = .then(data => data.udts) .catch(() => ({ entries: [], metadata: { before: null, after: null, total_count: 0 } })) +const FILTER_KEYS = ['name'] const TokenList = () => { const [t] = useTranslation(['tokens', 'common', 'list']) const { @@ -132,6 +135,9 @@ const TokenList = () => { }, ) + const isFiltered = !!name + const isFilterUnnecessary = !data?.metadata.total_count && !isFiltered + const handleHolderCountSortClick = (e: React.MouseEvent<HTMLOrSVGElement>) => { const { dataset: { order }, @@ -150,7 +156,11 @@ const TokenList = () => { return ( <> <SubpageHead subtitle={title} /> - <Container sx={{ px: { xs: 2, sm: 3, md: 2, lg: 0 }, pb: { xs: 5.5, md: 11 } }} className={styles.container}> + <Container + sx={{ px: { xs: 2, sm: 3, md: 2, lg: 0 }, pb: { xs: 5.5, md: 11 } }} + className={styles.container} + data-is-filter-unnecessary={isFilterUnnecessary} + > <PageTitle> <Typography variant="inherit" display="inline" pr={1}> {title} @@ -193,28 +203,6 @@ const TokenList = () => { {t(type === 'bridge' ? 'add-bridged-token' : 'add-native-erc20-token')} <AddIcon /> </a> - {/* <Button */} - {/* endIcon={<AddCircleOutlineRoundedIcon sx={{ fontSize: 13 }} />} */} - {/* component={Link} */} - {/* href={type === 'bridge' ? BRIDGED_TOKEN_TEMPLATE_URL : NATIVE_TOKEN_TEMPLATE_URL} */} - {/* target="_blank" */} - {/* rel="noreferrer noopener" */} - {/* sx={{ */} - {/* 'bgcolor': theme.palette.primary.light, */} - {/* 'borderRadius': 2, */} - {/* 'textTransform': 'none', */} - {/* 'height': 40, */} - {/* 'lineHeight': 40, */} - {/* 'px': { xs: 1, md: 2 }, */} - {/* 'fontWeight': 500, */} - {/* 'fontSize': { xs: 13, md: 14 }, */} - {/* '& .MuiButton-endIcon': { */} - {/* marginLeft: 0.5, */} - {/* }, */} - {/* }} */} - {/* > */} - {/* {t(type === 'bridge' ? 'add-bridged-token' : 'add-native-erc20-token')} */} - {/* </Button> */} </Stack> ) : ( <Stack @@ -244,7 +232,7 @@ const TokenList = () => { {t(h.label ?? h.key)} {h.key === 'token' ? ( <span> - <FilterMenu filterKeys={['name']} /> + <FilterMenu filterKeys={[FILTER_KEYS[0]]} /> </span> ) : null} {/* {h.key === 'holderCount' ? ( */} @@ -280,28 +268,59 @@ const TokenList = () => { <td title={name}> <Stack direction="row" alignItems="center"> <TokenLogo logo={token.icon} name={token.name} /> - <NextLink href={`/token/${id}`} passHref> - <Link - href={`/token/${id}`} - display="flex" - alignItems="center" - underline="none" - color="primary" - ml={1} - > - <Typography - fontSize="inherit" - fontFamily="inherit" - sx={{ - whiteSpace: 'nowrap', - textOverflow: 'ellipsis', - overflow: 'hidden', - }} + {type === 'bridge' ? ( + <Tooltip title={t(`view-mapped-native-token`)} placement="top"> + <span> + <NextLink href={`/token/${id}`} passHref> + <Link + href={`/token/${id}`} + display="flex" + alignItems="center" + underline="none" + color="primary" + ml={1} + > + <Typography + fontSize="inherit" + fontFamily="inherit" + sx={{ + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + overflow: 'hidden', + maxWidth: '16ch', + }} + > + {name || '-'} + </Typography> + </Link> + </NextLink> + </span> + </Tooltip> + ) : ( + <NextLink href={`/token/${id}`} passHref> + <Link + href={`/token/${id}`} + display="flex" + alignItems="center" + underline="none" + color="primary" + ml={1} > - {name || '-'} - </Typography> - </Link> - </NextLink> + <Typography + fontSize="inherit" + fontFamily="inherit" + sx={{ + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + overflow: 'hidden', + maxWidth: '16ch', + }} + > + {name || '-'} + </Typography> + </Link> + </NextLink> + )} </Stack> </td> <td title={addr}> @@ -340,21 +359,33 @@ const TokenList = () => { }) ) : ( <tr> - <td colSpan={headers.length} className={styles.noRecords}> - {t(`no_records`)} + <td colSpan={headers.length}> + {isFiltered ? ( + <div className={styles.noRecords}> + <EmptyFilteredListIcon /> + <span>{t(`no_related_content`, { ns: 'list' })}</span> + </div> + ) : ( + <div className={styles.noRecords}> + <NoDataIcon /> + <span>{t(`no_records`)}</span> + </div> + )} </td> </tr> )} </tbody> </Table> - <div style={{ overflow: 'hidden' }}> - {!data ? ( - <Skeleton animation="wave" width="calc(100% - 48px)" sx={{ mx: '24px', my: '20px' }} /> - ) : ( - <Pagination {...data.metadata} /> - )} - </div> + {data?.metadata.total_count ? ( + <div style={{ overflow: 'hidden' }}> + {!data ? ( + <Skeleton animation="wave" width="calc(100% - 48px)" sx={{ mx: '24px', my: '20px' }} /> + ) : ( + <Pagination {...data.metadata} /> + )} + </div> + ) : null} </Box> </Container> </> diff --git a/pages/tokens/styles.module.scss b/pages/tokens/styles.module.scss index c5ff57750..bd21383e1 100644 --- a/pages/tokens/styles.module.scss +++ b/pages/tokens/styles.module.scss @@ -1,3 +1,5 @@ +@import '../../styles/mixin.scss'; + .container { table { th { @@ -18,6 +20,13 @@ left: 0; transform: translateX(-20px); } + &[data-is-filter-unnecessary='true'] { + th { + svg { + display: none; + } + } + } } .add { @@ -51,5 +60,5 @@ } .noRecords { - text-align: center !important; + @include empty-list; } diff --git a/public/locales/en-US/list.json b/public/locales/en-US/list.json index 39ffe1b27..d4938416f 100644 --- a/public/locales/en-US/list.json +++ b/public/locales/en-US/list.json @@ -7,7 +7,7 @@ "age": "Age", "transfer": "Transfer", "token": "Token", - "no_records": "No Records", + "no_records": "There're no matching entries", "txHash": "Txn Hash", "block": "Block", "type": "Type", @@ -54,5 +54,6 @@ "address_from": "Search by address", "address_to": "Search by address" }, - "n_kinds_in_total": "{{number}} Kinds in Total" + "n_kinds_in_total": "{{number}} Kinds in Total", + "no_related_content": "No related content" } diff --git a/public/locales/en-US/tokens.json b/public/locales/en-US/tokens.json index 0cbc3e1b6..c5fb23b18 100644 --- a/public/locales/en-US/tokens.json +++ b/public/locales/en-US/tokens.json @@ -26,11 +26,12 @@ "age": "Age", "transfer": "Transfer", "transferRecords": "Transfers", - "no_records": "No Records", + "no_records": "There are no matching entries", "add-bridged-token": "Register a bridged token", "add-native-erc20-token": "Register a native token", "bridgedRecords": "Bridged Transfers", "tokenHolders": "Holders", "origin": "Origin", - "bridgeName": "Bridge" + "bridgeName": "Bridge", + "view-mapped-native-token": "View mapped native token" } diff --git a/public/locales/zh-CN/list.json b/public/locales/zh-CN/list.json index 161a321ad..1a45eec72 100644 --- a/public/locales/zh-CN/list.json +++ b/public/locales/zh-CN/list.json @@ -53,5 +53,6 @@ "address_from": "通过地址搜索", "address_to": "通过地址搜索" }, - "n_kinds_in_total": "共计 {{number}} 种" + "n_kinds_in_total": "共计 {{number}} 种", + "no_related_content": "没有相关数据" } diff --git a/public/locales/zh-CN/tokens.json b/public/locales/zh-CN/tokens.json index f1be26ed4..1c0cfc164 100644 --- a/public/locales/zh-CN/tokens.json +++ b/public/locales/zh-CN/tokens.json @@ -32,5 +32,6 @@ "bridgedRecords": "桥接交易记录", "tokenHolders": "持有人", "origin": "来源", - "bridgeName": "跨链桥" + "bridgeName": "跨链桥", + "view-mapped-native-token": "查看对应原生代币" } diff --git a/styles/mixin.scss b/styles/mixin.scss index dbf40e309..55a04784e 100644 --- a/styles/mixin.scss +++ b/styles/mixin.scss @@ -14,3 +14,21 @@ font-family: 'JetBrains Mono', monospace, 'Courier New' !important; user-select: all; } + +@mixin empty-list { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 8.25rem 0; + color: var(--primary-color); + font-size: 0.875rem; + font-weight: 400; + span { + margin-top: 2rem; + color: var(--primary-text-color); + } + @media screen and (max-width: 1024px) { + padding: 5.625rem 0; + } +}