Commit 67e7631b authored by tom's avatar tom

Merge branch 'main' of github.com:blockscout/frontend into tom2drum/issue-1446

parents 1c78a12c 9facb82d
...@@ -5,6 +5,9 @@ const RESTRICTED_MODULES = { ...@@ -5,6 +5,9 @@ const RESTRICTED_MODULES = {
{ name: '@metamask/providers', message: 'Please lazy-load @metamask/providers or use useProvider hook instead' }, { name: '@metamask/providers', message: 'Please lazy-load @metamask/providers or use useProvider hook instead' },
{ name: '@metamask/post-message-stream', message: 'Please lazy-load @metamask/post-message-stream or use useProvider hook instead' }, { name: '@metamask/post-message-stream', message: 'Please lazy-load @metamask/post-message-stream or use useProvider hook instead' },
], ],
patterns: [
'icons/*',
],
}; };
module.exports = { module.exports = {
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
/out/ /out/
/public/assets/ /public/assets/
/public/envs.js /public/envs.js
/public/icons/sprite.svg
/public/icons/README.md
/analyze /analyze
# production # production
......
...@@ -265,7 +265,7 @@ ...@@ -265,7 +265,7 @@
}, },
{ {
"type": "npm", "type": "npm",
"script": "format-svg", "script": "svg:format",
"problemMatcher": [], "problemMatcher": [],
"label": "format svg", "label": "format svg",
"detail": "format svg files with svgo", "detail": "format svg files with svgo",
......
...@@ -58,6 +58,7 @@ RUN ./collect_envs.sh ./docs/ENVS.md ...@@ -58,6 +58,7 @@ RUN ./collect_envs.sh ./docs/ENVS.md
# Build app for production # Build app for production
RUN yarn build RUN yarn build
RUN yarn svg:build-sprite
### FEATURE REPORTER ### FEATURE REPORTER
......
...@@ -182,7 +182,8 @@ We have 3 pre-configured projects. You can run your test with the desired projec ...@@ -182,7 +182,8 @@ We have 3 pre-configured projects. You can run your test with the desired projec
| `yarn lint:eslint` | lint project files with ESLint | | `yarn lint:eslint` | lint project files with ESLint |
| `yarn lint:eslint:fix` | lint project files with ESLint and automatically fix problems | | `yarn lint:eslint:fix` | lint project files with ESLint and automatically fix problems |
| `yarn lint:tsc` | compile project typescript files using TypeScript Compiler | | `yarn lint:tsc` | compile project typescript files using TypeScript Compiler |
| `yarn format-svg` | format and optimize SVG icons in the `/icons` folder using SVGO tool | | `yarn svg:format` | format and optimize SVG icons in the `/icons` folder using SVGO tool |
| `yarn svg:build-sprite` | build SVG icons sprite |
| **Testing** | | **Testing** |
| `yarn test:jest` | run all Jest unit tests | | `yarn test:jest` | run all Jest unit tests |
| `yarn test:jest:watch` | run all Jest unit tests in watch mode | | `yarn test:jest:watch` | run all Jest unit tests in watch mode |
......
...@@ -4,28 +4,6 @@ import React from 'react'; ...@@ -4,28 +4,6 @@ import React from 'react';
import type { NavItemInternal, NavItem, NavGroupItem } from 'types/client/navigation-items'; import type { NavItemInternal, NavItem, NavGroupItem } from 'types/client/navigation-items';
import config from 'configs/app'; import config from 'configs/app';
import abiIcon from 'icons/ABI.svg';
import apiKeysIcon from 'icons/API.svg';
import appsIcon from 'icons/apps.svg';
import withdrawalsIcon from 'icons/arrows/north-east.svg';
import depositsIcon from 'icons/arrows/south-east.svg';
import blocksIcon from 'icons/block.svg';
import gearIcon from 'icons/gear.svg';
import globeIcon from 'icons/globe-b.svg';
import graphQLIcon from 'icons/graphQL.svg';
import outputRootsIcon from 'icons/output_roots.svg';
import privateTagIcon from 'icons/privattags.svg';
import publicTagIcon from 'icons/publictags.svg';
import apiDocsIcon from 'icons/restAPI.svg';
import rpcIcon from 'icons/RPC.svg';
import statsIcon from 'icons/stats.svg';
import tokensIcon from 'icons/token.svg';
import topAccountsIcon from 'icons/top-accounts.svg';
import transactionsIcon from 'icons/transactions.svg';
import txnBatchIcon from 'icons/txn_batches.svg';
import verifiedIcon from 'icons/verified.svg';
import verifyContractIcon from 'icons/verify-contract.svg';
import watchlistIcon from 'icons/watchlist.svg';
import { rightLineArrow } from 'lib/html-entities'; import { rightLineArrow } from 'lib/html-entities';
import UserAvatar from 'ui/shared/UserAvatar'; import UserAvatar from 'ui/shared/UserAvatar';
...@@ -50,35 +28,43 @@ export default function useNavItems(): ReturnType { ...@@ -50,35 +28,43 @@ export default function useNavItems(): ReturnType {
return React.useMemo(() => { return React.useMemo(() => {
let blockchainNavItems: Array<NavItem> | Array<Array<NavItem>> = []; let blockchainNavItems: Array<NavItem> | Array<Array<NavItem>> = [];
const topAccounts = !config.UI.views.address.hiddenViews?.top_accounts ? { const topAccounts: NavItem | null = !config.UI.views.address.hiddenViews?.top_accounts ? {
text: 'Top accounts', text: 'Top accounts',
nextRoute: { pathname: '/accounts' as const }, nextRoute: { pathname: '/accounts' as const },
icon: topAccountsIcon, icon: 'top-accounts',
isActive: pathname === '/accounts', isActive: pathname === '/accounts',
} : null; } : null;
const blocks = { const blocks: NavItem | null = {
text: 'Blocks', text: 'Blocks',
nextRoute: { pathname: '/blocks' as const }, nextRoute: { pathname: '/blocks' as const },
icon: blocksIcon, icon: 'block',
isActive: pathname === '/blocks' || pathname === '/block/[height_or_hash]', isActive: pathname === '/blocks' || pathname === '/block/[height_or_hash]',
}; };
const txs = { const txs: NavItem | null = {
text: 'Transactions', text: 'Transactions',
nextRoute: { pathname: '/txs' as const }, nextRoute: { pathname: '/txs' as const },
icon: transactionsIcon, icon: 'transactions',
isActive: pathname === '/txs' || pathname === '/tx/[hash]', isActive: pathname === '/txs' || pathname === '/tx/[hash]',
}; };
const verifiedContracts = const verifiedContracts: NavItem | null =
// eslint-disable-next-line max-len {
{ text: 'Verified contracts', nextRoute: { pathname: '/verified-contracts' as const }, icon: verifiedIcon, isActive: pathname === '/verified-contracts' }; text: 'Verified contracts',
nextRoute: { pathname: '/verified-contracts' as const },
icon: 'verified',
isActive: pathname === '/verified-contracts',
};
if (config.features.zkEvmRollup.isEnabled) { if (config.features.zkEvmRollup.isEnabled) {
blockchainNavItems = [ blockchainNavItems = [
[ [
txs, txs,
blocks, blocks,
// eslint-disable-next-line max-len {
{ text: 'Txn batches', nextRoute: { pathname: '/zkevm-l2-txn-batches' as const }, icon: txnBatchIcon, isActive: pathname === '/zkevm-l2-txn-batches' || pathname === '/zkevm-l2-txn-batch/[number]' }, text: 'Txn batches',
nextRoute: { pathname: '/zkevm-l2-txn-batches' as const },
icon: 'txn_batches',
isActive: pathname === '/zkevm-l2-txn-batches' || pathname === '/zkevm-l2-txn-batch/[number]',
},
], ],
[ [
topAccounts, topAccounts,
...@@ -90,16 +76,16 @@ export default function useNavItems(): ReturnType { ...@@ -90,16 +76,16 @@ export default function useNavItems(): ReturnType {
[ [
txs, txs,
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
{ text: `Deposits (L1${ rightLineArrow }L2)`, nextRoute: { pathname: '/l2-deposits' as const }, icon: depositsIcon, isActive: pathname === '/l2-deposits' }, { text: `Deposits (L1${ rightLineArrow }L2)`, nextRoute: { pathname: '/l2-deposits' as const }, icon: 'arrows/south-east', isActive: pathname === '/l2-deposits' },
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
{ text: `Withdrawals (L2${ rightLineArrow }L1)`, nextRoute: { pathname: '/l2-withdrawals' as const }, icon: withdrawalsIcon, isActive: pathname === '/l2-withdrawals' }, { text: `Withdrawals (L2${ rightLineArrow }L1)`, nextRoute: { pathname: '/l2-withdrawals' as const }, icon: 'arrows/north-east', isActive: pathname === '/l2-withdrawals' },
], ],
[ [
blocks, blocks,
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
{ text: 'Txn batches', nextRoute: { pathname: '/l2-txn-batches' as const }, icon: txnBatchIcon, isActive: pathname === '/l2-txn-batches' }, { text: 'Txn batches', nextRoute: { pathname: '/l2-txn-batches' as const }, icon: 'txn_batches', isActive: pathname === '/l2-txn-batches' },
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
{ text: 'Output roots', nextRoute: { pathname: '/l2-output-roots' as const }, icon: outputRootsIcon, isActive: pathname === '/l2-output-roots' }, { text: 'Output roots', nextRoute: { pathname: '/l2-output-roots' as const }, icon: 'output_roots', isActive: pathname === '/l2-output-roots' },
], ],
[ [
topAccounts, topAccounts,
...@@ -115,7 +101,7 @@ export default function useNavItems(): ReturnType { ...@@ -115,7 +101,7 @@ export default function useNavItems(): ReturnType {
config.features.beaconChain.isEnabled && { config.features.beaconChain.isEnabled && {
text: 'Withdrawals', text: 'Withdrawals',
nextRoute: { pathname: '/withdrawals' as const }, nextRoute: { pathname: '/withdrawals' as const },
icon: withdrawalsIcon, icon: 'arrows/north-east',
isActive: pathname === '/withdrawals', isActive: pathname === '/withdrawals',
}, },
].filter(Boolean); ].filter(Boolean);
...@@ -125,23 +111,23 @@ export default function useNavItems(): ReturnType { ...@@ -125,23 +111,23 @@ export default function useNavItems(): ReturnType {
config.features.restApiDocs.isEnabled ? { config.features.restApiDocs.isEnabled ? {
text: 'REST API', text: 'REST API',
nextRoute: { pathname: '/api-docs' as const }, nextRoute: { pathname: '/api-docs' as const },
icon: apiDocsIcon, icon: 'restAPI',
isActive: pathname === '/api-docs', isActive: pathname === '/api-docs',
} : null, } : null,
config.features.graphqlApiDocs.isEnabled ? { config.features.graphqlApiDocs.isEnabled ? {
text: 'GraphQL', text: 'GraphQL',
nextRoute: { pathname: '/graphiql' as const }, nextRoute: { pathname: '/graphiql' as const },
icon: graphQLIcon, icon: 'graphQL',
isActive: pathname === '/graphiql', isActive: pathname === '/graphiql',
} : null, } : null,
!config.UI.sidebar.hiddenLinks?.rpc_api && { !config.UI.sidebar.hiddenLinks?.rpc_api && {
text: 'RPC API', text: 'RPC API',
icon: rpcIcon, icon: 'RPC',
url: 'https://docs.blockscout.com/for-users/api/rpc-endpoints', url: 'https://docs.blockscout.com/for-users/api/rpc-endpoints',
}, },
!config.UI.sidebar.hiddenLinks?.eth_rpc_api && { !config.UI.sidebar.hiddenLinks?.eth_rpc_api && {
text: 'Eth RPC API', text: 'Eth RPC API',
icon: rpcIcon, icon: 'RPC',
url: ' https://docs.blockscout.com/for-users/api/eth-rpc', url: ' https://docs.blockscout.com/for-users/api/eth-rpc',
}, },
].filter(Boolean); ].filter(Boolean);
...@@ -149,42 +135,42 @@ export default function useNavItems(): ReturnType { ...@@ -149,42 +135,42 @@ export default function useNavItems(): ReturnType {
const mainNavItems: ReturnType['mainNavItems'] = [ const mainNavItems: ReturnType['mainNavItems'] = [
{ {
text: 'Blockchain', text: 'Blockchain',
icon: globeIcon, icon: 'globe-b',
isActive: blockchainNavItems.flat().some(item => isInternalItem(item) && item.isActive), isActive: blockchainNavItems.flat().some(item => isInternalItem(item) && item.isActive),
subItems: blockchainNavItems, subItems: blockchainNavItems,
}, },
{ {
text: 'Tokens', text: 'Tokens',
nextRoute: { pathname: '/tokens' as const }, nextRoute: { pathname: '/tokens' as const },
icon: tokensIcon, icon: 'token',
isActive: pathname.startsWith('/token'), isActive: pathname.startsWith('/token'),
}, },
config.features.marketplace.isEnabled ? { config.features.marketplace.isEnabled ? {
text: 'Apps', text: 'Apps',
nextRoute: { pathname: '/apps' as const }, nextRoute: { pathname: '/apps' as const },
icon: appsIcon, icon: 'apps',
isActive: pathname.startsWith('/app'), isActive: pathname.startsWith('/app'),
} : null, } : null,
config.features.stats.isEnabled ? { config.features.stats.isEnabled ? {
text: 'Charts & stats', text: 'Charts & stats',
nextRoute: { pathname: '/stats' as const }, nextRoute: { pathname: '/stats' as const },
icon: statsIcon, icon: 'stats',
isActive: pathname === '/stats', isActive: pathname === '/stats',
} : null, } : null,
apiNavItems.length > 0 && { apiNavItems.length > 0 && {
text: 'API', text: 'API',
icon: apiDocsIcon, icon: 'restAPI',
isActive: apiNavItems.some(item => isInternalItem(item) && item.isActive), isActive: apiNavItems.some(item => isInternalItem(item) && item.isActive),
subItems: apiNavItems, subItems: apiNavItems,
}, },
{ {
text: 'Other', text: 'Other',
icon: gearIcon, icon: 'gear',
subItems: [ subItems: [
{ {
text: 'Verify contract', text: 'Verify contract',
nextRoute: { pathname: '/contract-verification' as const }, nextRoute: { pathname: '/contract-verification' as const },
icon: verifyContractIcon, icon: 'verify-contract',
isActive: pathname.startsWith('/contract-verification'), isActive: pathname.startsWith('/contract-verification'),
}, },
...config.UI.sidebar.otherLinks, ...config.UI.sidebar.otherLinks,
...@@ -196,35 +182,37 @@ export default function useNavItems(): ReturnType { ...@@ -196,35 +182,37 @@ export default function useNavItems(): ReturnType {
{ {
text: 'Watch list', text: 'Watch list',
nextRoute: { pathname: '/account/watchlist' as const }, nextRoute: { pathname: '/account/watchlist' as const },
icon: watchlistIcon, icon: 'watchlist',
isActive: pathname === '/account/watchlist', isActive: pathname === '/account/watchlist',
}, },
{ {
text: 'Private tags', text: 'Private tags',
nextRoute: { pathname: '/account/tag-address' as const }, nextRoute: { pathname: '/account/tag-address' as const },
icon: privateTagIcon, icon: 'privattags',
isActive: pathname === '/account/tag-address', isActive: pathname === '/account/tag-address',
}, },
{ {
text: 'Public tags', text: 'Public tags',
nextRoute: { pathname: '/account/public-tags-request' as const }, nextRoute: { pathname: '/account/public-tags-request' as const },
icon: publicTagIcon, isActive: pathname === '/account/public-tags-request', icon: 'publictags',
isActive: pathname === '/account/public-tags-request',
}, },
{ {
text: 'API keys', text: 'API keys',
nextRoute: { pathname: '/account/api-key' as const }, nextRoute: { pathname: '/account/api-key' as const },
icon: apiKeysIcon, isActive: pathname === '/account/api-key', icon: 'API',
isActive: pathname === '/account/api-key',
}, },
{ {
text: 'Custom ABI', text: 'Custom ABI',
nextRoute: { pathname: '/account/custom-abi' as const }, nextRoute: { pathname: '/account/custom-abi' as const },
icon: abiIcon, icon: 'ABI',
isActive: pathname === '/account/custom-abi', isActive: pathname === '/account/custom-abi',
}, },
config.features.addressVerification.isEnabled && { config.features.addressVerification.isEnabled && {
text: 'Verified addrs', text: 'Verified addrs',
nextRoute: { pathname: '/account/verified-addresses' as const }, nextRoute: { pathname: '/account/verified-addresses' as const },
icon: verifiedIcon, icon: 'verified',
isActive: pathname === '/account/verified-addresses', isActive: pathname === '/account/verified-addresses',
}, },
].filter(Boolean); ].filter(Boolean);
......
import type { WalletType, WalletInfo } from 'types/client/wallets'; import type { WalletType, WalletInfo } from 'types/client/wallets';
import coinbaseIcon from 'icons/wallets/coinbase.svg';
import metamaskIcon from 'icons/wallets/metamask.svg';
import tokenPocketIcon from 'icons/wallets/token-pocket.svg';
export const WALLETS_INFO: Record<Exclude<WalletType, 'none'>, WalletInfo> = { export const WALLETS_INFO: Record<Exclude<WalletType, 'none'>, WalletInfo> = {
metamask: { metamask: {
name: 'MetaMask', name: 'MetaMask',
icon: metamaskIcon, icon: 'wallets/metamask',
}, },
coinbase: { coinbase: {
name: 'Coinbase Wallet', name: 'Coinbase Wallet',
icon: coinbaseIcon, icon: 'wallets/coinbase',
}, },
token_pocket: { token_pocket: {
name: 'TokenPocket', name: 'TokenPocket',
icon: tokenPocketIcon, icon: 'wallets/token-pocket',
}, },
}; };
...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
"lint:tsc": "tsc -p ./tsconfig.json", "lint:tsc": "tsc -p ./tsconfig.json",
"lint:envs-validator:test": "cd ./deploy/tools/envs-validator && ./test.sh", "lint:envs-validator:test": "cd ./deploy/tools/envs-validator && ./test.sh",
"prepare": "husky install", "prepare": "husky install",
"format-svg": "svgo -r ./icons", "svg:format": "svgo -r ./icons",
"svg:build-sprite": "icons build -i ./icons -o ./public/icons --optimize",
"test:pw": "./tools/scripts/pw.sh", "test:pw": "./tools/scripts/pw.sh",
"test:pw:local": "export NODE_PATH=$(pwd)/node_modules && yarn test:pw", "test:pw:local": "export NODE_PATH=$(pwd)/node_modules && yarn test:pw",
"test:pw:docker": "docker run --rm --network host -v $(pwd):/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.35.1-focal ./tools/scripts/pw.docker.sh", "test:pw:docker": "docker run --rm --network host -v $(pwd):/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.35.1-focal ./tools/scripts/pw.docker.sh",
...@@ -136,6 +137,7 @@ ...@@ -136,6 +137,7 @@
"lint-staged": ">=10", "lint-staged": ">=10",
"mockdate": "^3.0.5", "mockdate": "^3.0.5",
"style-loader": "^3.3.1", "style-loader": "^3.3.1",
"svg-icons-cli": "^0.0.5",
"svgo": "^2.8.0", "svgo": "^2.8.0",
"ts-jest": "^29.0.3", "ts-jest": "^29.0.3",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
......
...@@ -6,6 +6,7 @@ import React from 'react'; ...@@ -6,6 +6,7 @@ import React from 'react';
import * as serverTiming from 'nextjs/utils/serverTiming'; import * as serverTiming from 'nextjs/utils/serverTiming';
import theme from 'theme'; import theme from 'theme';
import * as svgSprite from 'ui/shared/IconSvg';
class MyDocument extends Document { class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext) { static async getInitialProps(ctx: DocumentContext) {
...@@ -48,6 +49,8 @@ class MyDocument extends Document { ...@@ -48,6 +49,8 @@ class MyDocument extends Document {
<link rel="icon" sizes="16x16" type="image/png"href="/favicon/favicon-16x16.png"/> <link rel="icon" sizes="16x16" type="image/png"href="/favicon/favicon-16x16.png"/>
<link rel="apple-touch-icon" href="/favicon/apple-touch-icon-180x180.png"/> <link rel="apple-touch-icon" href="/favicon/apple-touch-icon-180x180.png"/>
<link rel="mask-icon" href="/favicon/safari-pinned-tab.svg"/> <link rel="mask-icon" href="/favicon/safari-pinned-tab.svg"/>
<link rel="preload" as="image" href={ svgSprite.href }/>
</Head> </Head>
<body> <body>
<ColorModeScript initialColorMode={ theme.config.initialColorMode }/> <ColorModeScript initialColorMode={ theme.config.initialColorMode }/>
......
...@@ -9,5 +9,6 @@ ...@@ -9,5 +9,6 @@
<div id="root"></div> <div id="root"></div>
<script type="module" src="/playwright/envs.js"></script> <script type="module" src="/playwright/envs.js"></script>
<script type="module" src="/playwright/index.ts"></script> <script type="module" src="/playwright/index.ts"></script>
<link rel="preload" as="image" href="/public/icons/sprite.svg"/>
</body> </body>
</html> </html>
// This file is generated by npm run build:icons
export type IconName =
| "ABI"
| "API"
| "apps"
| "arrows/down-right"
| "arrows/east-mini"
| "arrows/east"
| "arrows/north-east"
| "arrows/south-east"
| "arrows/up-down"
| "block_slim"
| "block"
| "brands/safe"
| "burger"
| "check"
| "clock-light"
| "clock"
| "coins/bitcoin"
| "collection"
| "contract_verified"
| "contract"
| "copy"
| "cross"
| "delete"
| "discussions"
| "docs"
| "donate"
| "edit"
| "email-sent"
| "email"
| "empty_search_result"
| "error-pages/404"
| "error-pages/422"
| "error-pages/429"
| "error-pages/500"
| "explorer"
| "files/csv"
| "files/image"
| "files/json"
| "files/placeholder"
| "files/sol"
| "files/yul"
| "filter"
| "finalized"
| "flame"
| "gas"
| "gear"
| "globe-b"
| "globe"
| "graphQL"
| "info"
| "key"
| "link"
| "lock"
| "minus"
| "monaco/file"
| "monaco/folder-open"
| "monaco/folder"
| "monaco/solidity"
| "monaco/vyper"
| "moon-with-star"
| "moon"
| "networks"
| "networks/icon-placeholder"
| "networks/logo-placeholder"
| "nft_shield"
| "output_roots"
| "plus"
| "privattags"
| "profile"
| "publictags_slim"
| "publictags"
| "qr_code"
| "repeat_arrow"
| "restAPI"
| "rocket"
| "RPC"
| "scope"
| "score/score-not-ok"
| "score/score-ok"
| "search"
| "social/canny"
| "social/coingecko"
| "social/coinmarketcap"
| "social/defi_llama"
| "social/discord_filled"
| "social/discord"
| "social/facebook_filled"
| "social/git"
| "social/github_filled"
| "social/linkedin_filled"
| "social/medium_filled"
| "social/opensea_filled"
| "social/reddit_filled"
| "social/slack_filled"
| "social/stats"
| "social/telega"
| "social/telegram_filled"
| "social/tweet"
| "social/twitter_filled"
| "star_filled"
| "star_outline"
| "stats"
| "status/error"
| "status/pending"
| "status/success"
| "status/warning"
| "sun"
| "testnet"
| "token-placeholder"
| "token"
| "tokens"
| "tokens/xdai"
| "top-accounts"
| "transactions_slim"
| "transactions"
| "txn_batches_slim"
| "txn_batches"
| "unfinalized"
| "uniswap"
| "verified_token"
| "verified"
| "verify-contract"
| "vertical_dots"
| "wallet"
| "wallets/coinbase"
| "wallets/metamask"
| "wallets/token-pocket"
| "watchlist";
\ No newline at end of file
...@@ -5,11 +5,11 @@ module.exports = { ...@@ -5,11 +5,11 @@ module.exports = {
params: { params: {
overrides: { overrides: {
removeViewBox: false, removeViewBox: false,
removeHiddenElems: false,
}, },
}, },
}, },
'removeDimensions', 'removeDimensions',
'prefixIds',
], ],
js2svg: { js2svg: {
indent: 2, indent: 2,
......
...@@ -19,6 +19,9 @@ dotenv \ ...@@ -19,6 +19,9 @@ dotenv \
-e $config_file \ -e $config_file \
-- bash -c './deploy/scripts/download_assets.sh ./public/assets' -- bash -c './deploy/scripts/download_assets.sh ./public/assets'
yarn svg:build-sprite
echo ""
# generate envs.js file and run the app # generate envs.js file and run the app
dotenv \ dotenv \
-v NEXT_PUBLIC_GIT_COMMIT_SHA=$(git rev-parse --short HEAD) \ -v NEXT_PUBLIC_GIT_COMMIT_SHA=$(git rev-parse --short HEAD) \
......
...@@ -8,6 +8,9 @@ dotenv \ ...@@ -8,6 +8,9 @@ dotenv \
-e .env \ -e .env \
-- bash -c './deploy/scripts/download_assets.sh ./public/assets' -- bash -c './deploy/scripts/download_assets.sh ./public/assets'
yarn svg:build-sprite
echo ""
# generate envs.js file and run the app # generate envs.js file and run the app
dotenv \ dotenv \
-v NEXT_PUBLIC_GIT_COMMIT_SHA=$(git rev-parse --short HEAD) \ -v NEXT_PUBLIC_GIT_COMMIT_SHA=$(git rev-parse --short HEAD) \
......
...@@ -8,6 +8,8 @@ dotenv \ ...@@ -8,6 +8,8 @@ dotenv \
-e $config_file \ -e $config_file \
-- bash -c './deploy/scripts/make_envs_script.sh ./playwright/envs.js' -- bash -c './deploy/scripts/make_envs_script.sh ./playwright/envs.js'
yarn svg:build-sprite
dotenv \ dotenv \
-v NODE_OPTIONS=\"--max-old-space-size=4096\" \ -v NODE_OPTIONS=\"--max-old-space-size=4096\" \
-e $config_file \ -e $config_file \
......
...@@ -2,8 +2,10 @@ import type React from 'react'; ...@@ -2,8 +2,10 @@ import type React from 'react';
import type { Route } from 'nextjs-routes'; import type { Route } from 'nextjs-routes';
import type { IconName } from 'ui/shared/IconSvg';
type NavIconOrComponent = { type NavIconOrComponent = {
icon?: React.FunctionComponent<React.SVGAttributes<SVGElement>>; icon?: IconName;
} | { } | {
iconComponent?: React.FC<{size?: number}>; iconComponent?: React.FC<{size?: number}>;
}; };
......
import type { ArrayElement } from 'types/utils'; import type { ArrayElement } from 'types/utils';
import type { IconName } from 'ui/shared/IconSvg';
export const SUPPORTED_WALLETS = [ export const SUPPORTED_WALLETS = [
'metamask', 'metamask',
'coinbase', 'coinbase',
...@@ -10,5 +12,5 @@ export type WalletType = ArrayElement<typeof SUPPORTED_WALLETS>; ...@@ -10,5 +12,5 @@ export type WalletType = ArrayElement<typeof SUPPORTED_WALLETS>;
export interface WalletInfo { export interface WalletInfo {
name: string; name: string;
icon: React.ElementType; icon: IconName;
} }
import { chakra, Icon, Tooltip, Hide, Skeleton, Flex } from '@chakra-ui/react'; import { chakra, Tooltip, Hide, Skeleton, Flex } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { CsvExportParams } from 'types/client/address'; import type { CsvExportParams } from 'types/client/address';
...@@ -6,9 +6,9 @@ import type { CsvExportParams } from 'types/client/address'; ...@@ -6,9 +6,9 @@ import type { CsvExportParams } from 'types/client/address';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import svgFileIcon from 'icons/files/csv.svg';
import useIsInitialLoading from 'lib/hooks/useIsInitialLoading'; import useIsInitialLoading from 'lib/hooks/useIsInitialLoading';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
interface Props { interface Props {
...@@ -47,7 +47,7 @@ const AddressCsvExportLink = ({ className, address, params, isLoading }: Props) ...@@ -47,7 +47,7 @@ const AddressCsvExportLink = ({ className, address, params, isLoading }: Props)
href={ route({ pathname: '/csv-export', query: { ...params, address } }) } href={ route({ pathname: '/csv-export', query: { ...params, address } }) }
flexShrink={ 0 } flexShrink={ 0 }
> >
<Icon as={ svgFileIcon } boxSize={{ base: '30px', lg: 6 }}/> <IconSvg name="files/csv" boxSize={{ base: '30px', lg: 6 }}/>
<Hide ssr={ false } below="lg"><chakra.span ml={ 1 }>Download CSV</chakra.span></Hide> <Hide ssr={ false } below="lg"><chakra.span ml={ 1 }>Download CSV</chakra.span></Hide>
</LinkInternal> </LinkInternal>
</Tooltip> </Tooltip>
......
...@@ -5,8 +5,6 @@ import React from 'react'; ...@@ -5,8 +5,6 @@ import React from 'react';
import type { NFTTokenType } from 'types/api/token'; import type { NFTTokenType } from 'types/api/token';
import type { PaginationParams } from 'ui/shared/pagination/types'; import type { PaginationParams } from 'ui/shared/pagination/types';
import listIcon from 'icons/apps.svg';
import collectionIcon from 'icons/collection.svg';
import { useAppContext } from 'lib/contexts/app'; import { useAppContext } from 'lib/contexts/app';
import * as cookies from 'lib/cookies'; import * as cookies from 'lib/cookies';
import getFilterValuesFromQuery from 'lib/getFilterValuesFromQuery'; import getFilterValuesFromQuery from 'lib/getFilterValuesFromQuery';
...@@ -125,8 +123,8 @@ const AddressTokens = () => { ...@@ -125,8 +123,8 @@ const AddressTokens = () => {
defaultValue={ nftDisplayType } defaultValue={ nftDisplayType }
name="type" name="type"
options={ [ options={ [
{ title: 'By collection', value: 'collection', icon: collectionIcon, onlyIcon: isMobile }, { title: 'By collection', value: 'collection', icon: 'collection', onlyIcon: isMobile },
{ title: 'List', value: 'list', icon: listIcon, onlyIcon: isMobile }, { title: 'List', value: 'list', icon: 'apps', onlyIcon: isMobile },
] } ] }
/> />
); );
......
...@@ -4,7 +4,6 @@ import { ...@@ -4,7 +4,6 @@ import {
Text, Text,
Grid, Grid,
Button, Button,
Icon,
chakra, chakra,
Popover, Popover,
PopoverTrigger, PopoverTrigger,
...@@ -19,10 +18,9 @@ import React from 'react'; ...@@ -19,10 +18,9 @@ import React from 'react';
import { SolidityscanReport } from 'types/api/contract'; import { SolidityscanReport } from 'types/api/contract';
import scoreNotOkIcon from 'icons/score/score-not-ok.svg';
import scoreOkIcon from 'icons/score/score-ok.svg';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import { SOLIDITYSCAN_REPORT } from 'stubs/contract'; import { SOLIDITYSCAN_REPORT } from 'stubs/contract';
import IconSvg from 'ui/shared/IconSvg';
import LinkExternal from 'ui/shared/LinkExternal'; import LinkExternal from 'ui/shared/LinkExternal';
type DistributionItem = { type DistributionItem = {
...@@ -125,7 +123,7 @@ const SolidityscanReport = ({ className, hash }: Props) => { ...@@ -125,7 +123,7 @@ const SolidityscanReport = ({ className, hash }: Props) => {
h="32px" h="32px"
flexShrink={ 0 } flexShrink={ 0 }
> >
<Icon as={ score < 80 ? scoreNotOkIcon : scoreOkIcon } boxSize={ 5 } mr={ 1 }/> <IconSvg name={ score < 80 ? 'score/score-not-ok' : 'score/score-ok' } boxSize={ 5 } mr={ 1 }/>
{ score } { score }
</Button> </Button>
</Skeleton> </Skeleton>
...@@ -143,7 +141,7 @@ const SolidityscanReport = ({ className, hash }: Props) => { ...@@ -143,7 +141,7 @@ const SolidityscanReport = ({ className, hash }: Props) => {
mr={ 3 } mr={ 3 }
> >
<Center position="absolute" w="38px" h="38px" top="5px" right="5px" bg={ popoverBgColor } borderRadius="20px"> <Center position="absolute" w="38px" h="38px" top="5px" right="5px" bg={ popoverBgColor } borderRadius="20px">
<Icon as={ score < 80 ? scoreNotOkIcon : scoreOkIcon } boxSize={ 5 } color={ scoreColor }/> <IconSvg name={ score < 80 ? 'score/score-not-ok' : 'score/score-ok' } boxSize={ 5 } color={ scoreColor }/>
</Center> </Center>
</Box> </Box>
<Box> <Box>
......
...@@ -78,6 +78,31 @@ test('verified with changed byte code socket', async({ mount, page, createSocket ...@@ -78,6 +78,31 @@ test('verified with changed byte code socket', async({ mount, page, createSocket
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
test('verified via lookup in eth_bytecode_db', async({ mount, page, createSocket }) => {
await page.route(CONTRACT_API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify(contractMock.nonVerified),
}));
await page.route('https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/**', (route) => route.abort());
await mount(
<TestApp withSocket>
<ContractCode addressHash={ addressHash }/>
</TestApp>,
{ hooksConfig },
);
const socket = await createSocket();
const channel = await socketServer.joinChannel(socket, 'addresses:' + addressHash.toLowerCase());
await page.waitForResponse(CONTRACT_API_URL);
socketServer.sendMessage(socket, channel, 'smart_contract_was_verified', {});
const request = await page.waitForRequest(CONTRACT_API_URL);
expect(request).toBeTruthy();
});
test('verified with multiple sources', async({ mount, page }) => { test('verified with multiple sources', async({ mount, page }) => {
await page.route(CONTRACT_API_URL, (route) => route.fulfill({ await page.route(CONTRACT_API_URL, (route) => route.fulfill({
status: 200, status: 200,
......
...@@ -38,7 +38,6 @@ const ContractCode = ({ addressHash, noSocket }: Props) => { ...@@ -38,7 +38,6 @@ const ContractCode = ({ addressHash, noSocket }: Props) => {
const [ isChangedBytecodeSocket, setIsChangedBytecodeSocket ] = React.useState<boolean>(); const [ isChangedBytecodeSocket, setIsChangedBytecodeSocket ] = React.useState<boolean>();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const refetchQueries = queryClient.refetchQueries;
const addressInfo = queryClient.getQueryData<AddressInfo>(getResourceKey('address', { pathParams: { hash: addressHash } })); const addressInfo = queryClient.getQueryData<AddressInfo>(getResourceKey('address', { pathParams: { hash: addressHash } }));
const { data, isPlaceholderData, isError } = useApiQuery('contract', { const { data, isPlaceholderData, isError } = useApiQuery('contract', {
...@@ -55,13 +54,13 @@ const ContractCode = ({ addressHash, noSocket }: Props) => { ...@@ -55,13 +54,13 @@ const ContractCode = ({ addressHash, noSocket }: Props) => {
}, [ ]); }, [ ]);
const handleContractWasVerifiedMessage: SocketMessage.SmartContractWasVerified['handler'] = React.useCallback(() => { const handleContractWasVerifiedMessage: SocketMessage.SmartContractWasVerified['handler'] = React.useCallback(() => {
refetchQueries({ queryClient.refetchQueries({
queryKey: getResourceKey('address', { pathParams: { hash: addressHash } }), queryKey: getResourceKey('address', { pathParams: { hash: addressHash } }),
}); });
refetchQueries({ queryClient.refetchQueries({
queryKey: getResourceKey('contract', { pathParams: { hash: addressHash } }), queryKey: getResourceKey('contract', { pathParams: { hash: addressHash } }),
}); });
}, [ addressHash, refetchQueries ]); }, [ addressHash, queryClient ]);
const enableQuery = React.useCallback(() => setIsQueryEnabled(true), []); const enableQuery = React.useCallback(() => setIsQueryEnabled(true), []);
......
...@@ -4,7 +4,6 @@ import { ...@@ -4,7 +4,6 @@ import {
Button, Button,
Flex, Flex,
Heading, Heading,
Icon,
Modal, Modal,
ModalCloseButton, ModalCloseButton,
ModalContent, ModalContent,
...@@ -20,11 +19,10 @@ import React from 'react'; ...@@ -20,11 +19,10 @@ import React from 'react';
import type { SmartContractExternalLibrary } from 'types/api/contract'; import type { SmartContractExternalLibrary } from 'types/api/contract';
import arrowIcon from 'icons/arrows/east-mini.svg';
import iconWarning from 'icons/status/warning.svg';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import { apos } from 'lib/html-entities'; import { apos } from 'lib/html-entities';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import IconSvg from 'ui/shared/IconSvg';
interface Props { interface Props {
className?: string; className?: string;
...@@ -66,8 +64,8 @@ const ContractExternalLibraries = ({ className, data }: Props) => { ...@@ -66,8 +64,8 @@ const ContractExternalLibraries = ({ className, data }: Props) => {
aria-label="View external libraries" aria-label="View external libraries"
> >
<span>{ data.length } { data.length > 1 ? 'Libraries' : 'Library' } </span> <span>{ data.length } { data.length > 1 ? 'Libraries' : 'Library' } </span>
<Icon as={ iconWarning } boxSize={ 5 } color="orange.400" ml="2px"/> <IconSvg name="status/warning" boxSize={ 5 } color="orange.400" ml="2px"/>
<Icon as={ arrowIcon } transform={ isOpen ? 'rotate(90deg)' : 'rotate(-90deg)' } transitionDuration="faster" boxSize={ 5 } ml={ 2 }/> <IconSvg name="arrows/east-mini" transform={ isOpen ? 'rotate(90deg)' : 'rotate(-90deg)' } transitionDuration="faster" boxSize={ 5 } ml={ 2 }/>
</Button> </Button>
); );
......
import { Box, Button, chakra, Flex, Icon, Text } from '@chakra-ui/react'; import { Box, Button, chakra, Flex, Text } from '@chakra-ui/react';
import _fromPairs from 'lodash/fromPairs'; import _fromPairs from 'lodash/fromPairs';
import React from 'react'; import React from 'react';
import type { SubmitHandler } from 'react-hook-form'; import type { SubmitHandler } from 'react-hook-form';
...@@ -7,8 +7,8 @@ import { useForm } from 'react-hook-form'; ...@@ -7,8 +7,8 @@ import { useForm } from 'react-hook-form';
import type { MethodFormFields, ContractMethodCallResult } from './types'; import type { MethodFormFields, ContractMethodCallResult } from './types';
import type { SmartContractMethodInput, SmartContractMethod } from 'types/api/contract'; import type { SmartContractMethodInput, SmartContractMethod } from 'types/api/contract';
import arrowIcon from 'icons/arrows/down-right.svg';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import IconSvg from 'ui/shared/IconSvg';
import ContractMethodField from './ContractMethodField'; import ContractMethodField from './ContractMethodField';
...@@ -157,7 +157,7 @@ const ContractMethodCallable = <T extends SmartContractMethod>({ data, onSubmit, ...@@ -157,7 +157,7 @@ const ContractMethodCallable = <T extends SmartContractMethod>({ data, onSubmit,
</chakra.form> </chakra.form>
{ 'outputs' in data && !isWrite && data.outputs.length > 0 && ( { 'outputs' in data && !isWrite && data.outputs.length > 0 && (
<Flex mt={ 3 }> <Flex mt={ 3 }>
<Icon as={ arrowIcon } boxSize={ 5 } mr={ 1 }/> <IconSvg name="arrows/down-right" boxSize={ 5 } mr={ 1 }/>
<Text>{ data.outputs.map(({ type }) => type).join(', ') }</Text> <Text>{ data.outputs.map(({ type }) => type).join(', ') }</Text>
</Flex> </Flex>
) } ) }
......
...@@ -8,15 +8,13 @@ import { ...@@ -8,15 +8,13 @@ import {
Button, Button,
List, List,
ListItem, ListItem,
Icon,
useDisclosure, useDisclosure,
Input, Input,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import iconEastMini from 'icons/arrows/east-mini.svg';
import iconCheck from 'icons/check.svg';
import { times } from 'lib/html-entities'; import { times } from 'lib/html-entities';
import IconSvg from 'ui/shared/IconSvg';
interface Props { interface Props {
onClick: (power: number) => void; onClick: (power: number) => void;
...@@ -80,7 +78,7 @@ const ContractMethodFieldZeroes = ({ onClick, isDisabled }: Props) => { ...@@ -80,7 +78,7 @@ const ContractMethodFieldZeroes = ({ onClick, isDisabled }: Props) => {
onClick={ onToggle } onClick={ onToggle }
isDisabled={ isDisabled } isDisabled={ isDisabled }
> >
<Icon as={ iconEastMini } transform={ isOpen ? 'rotate(90deg)' : 'rotate(-90deg)' } boxSize={ 6 }/> <IconSvg name="arrows/east-mini" transform={ isOpen ? 'rotate(90deg)' : 'rotate(-90deg)' } boxSize={ 6 }/>
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
<Portal> <Portal>
...@@ -99,7 +97,7 @@ const ContractMethodFieldZeroes = ({ onClick, isDisabled }: Props) => { ...@@ -99,7 +97,7 @@ const ContractMethodFieldZeroes = ({ onClick, isDisabled }: Props) => {
cursor="pointer" cursor="pointer"
> >
<span>10*{ id }</span> <span>10*{ id }</span>
{ selectedOption === id && <Icon as={ iconCheck } boxSize={ 6 } color="blue.600"/> } { selectedOption === id && <IconSvg name="check" boxSize={ 6 } color="blue.600"/> }
</ListItem> </ListItem>
)) } )) }
<ListItem <ListItem
......
import { AccordionButton, AccordionIcon, AccordionItem, AccordionPanel, Box, Icon, Tooltip, useClipboard, useDisclosure } from '@chakra-ui/react'; import { AccordionButton, AccordionIcon, AccordionItem, AccordionPanel, Box, Tooltip, useClipboard, useDisclosure } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { Element } from 'react-scroll'; import { Element } from 'react-scroll';
...@@ -7,8 +7,8 @@ import type { SmartContractMethod } from 'types/api/contract'; ...@@ -7,8 +7,8 @@ import type { SmartContractMethod } from 'types/api/contract';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import iconLink from 'icons/link.svg';
import Hint from 'ui/shared/Hint'; import Hint from 'ui/shared/Hint';
import IconSvg from 'ui/shared/IconSvg';
interface Props<T extends SmartContractMethod> { interface Props<T extends SmartContractMethod> {
data: T; data: T;
...@@ -57,7 +57,7 @@ const ContractMethodsAccordionItem = <T extends SmartContractMethod>({ data, ind ...@@ -57,7 +57,7 @@ const ContractMethodsAccordionItem = <T extends SmartContractMethod>({ data, ind
onMouseEnter={ onOpen } onMouseEnter={ onOpen }
onMouseLeave={ onClose } onMouseLeave={ onClose }
> >
<Icon as={ iconLink } boxSize={ 5 }/> <IconSvg name="link" boxSize={ 5 }/>
</Box> </Box>
</Tooltip> </Tooltip>
) } ) }
......
import { Icon, chakra, Tooltip, IconButton, useDisclosure } from '@chakra-ui/react'; import { chakra, Tooltip, IconButton, useDisclosure } from '@chakra-ui/react';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import config from 'configs/app'; import config from 'configs/app';
import starFilledIcon from 'icons/star_filled.svg';
import starOutlineIcon from 'icons/star_outline.svg';
import { getResourceKey } from 'lib/api/useApiQuery'; import { getResourceKey } from 'lib/api/useApiQuery';
import useIsAccountActionAllowed from 'lib/hooks/useIsAccountActionAllowed'; import useIsAccountActionAllowed from 'lib/hooks/useIsAccountActionAllowed';
import usePreventFocusAfterModalClosing from 'lib/hooks/usePreventFocusAfterModalClosing'; import usePreventFocusAfterModalClosing from 'lib/hooks/usePreventFocusAfterModalClosing';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import IconSvg from 'ui/shared/IconSvg';
import WatchlistAddModal from 'ui/watchlist/AddressModal/AddressModal'; import WatchlistAddModal from 'ui/watchlist/AddressModal/AddressModal';
import DeleteAddressModal from 'ui/watchlist/DeleteAddressModal'; import DeleteAddressModal from 'ui/watchlist/DeleteAddressModal';
...@@ -73,7 +72,7 @@ const AddressFavoriteButton = ({ className, hash, watchListId }: Props) => { ...@@ -73,7 +72,7 @@ const AddressFavoriteButton = ({ className, hash, watchListId }: Props) => {
pr="6px" pr="6px"
flexShrink={ 0 } flexShrink={ 0 }
onClick={ handleClick } onClick={ handleClick }
icon={ <Icon as={ watchListId ? starFilledIcon : starOutlineIcon } boxSize={ 5 }/> } icon={ <IconSvg name={ watchListId ? 'star_filled' : 'star_outline' } boxSize={ 5 }/> }
onFocusCapture={ onFocusCapture } onFocusCapture={ onFocusCapture }
/> />
</Tooltip> </Tooltip>
......
import { import {
chakra, chakra,
Alert, Alert,
Icon,
Modal, Modal,
ModalBody, ModalBody,
ModalContent, ModalContent,
...@@ -22,10 +21,10 @@ import React from 'react'; ...@@ -22,10 +21,10 @@ import React from 'react';
import type { Address as AddressType } from 'types/api/address'; import type { Address as AddressType } from 'types/api/address';
import qrCodeIcon from 'icons/qr_code.svg';
import getPageType from 'lib/mixpanel/getPageType'; import getPageType from 'lib/mixpanel/getPageType';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import IconSvg from 'ui/shared/IconSvg';
const SVG_OPTIONS = { const SVG_OPTIONS = {
margin: 0, margin: 0,
...@@ -78,7 +77,7 @@ const AddressQrCode = ({ address, className, isLoading }: Props) => { ...@@ -78,7 +77,7 @@ const AddressQrCode = ({ address, className, isLoading }: Props) => {
pl="6px" pl="6px"
pr="6px" pr="6px"
onClick={ onOpen } onClick={ onOpen }
icon={ <Icon as={ qrCodeIcon } boxSize={ 5 }/> } icon={ <IconSvg name="qr_code" boxSize={ 5 }/> }
flexShrink={ 0 } flexShrink={ 0 }
/> />
</Tooltip> </Tooltip>
......
...@@ -5,13 +5,12 @@ import React from 'react'; ...@@ -5,13 +5,12 @@ import React from 'react';
import type { InternalTransaction } from 'types/api/internalTransaction'; import type { InternalTransaction } from 'types/api/internalTransaction';
import config from 'configs/app'; import config from 'configs/app';
import eastArrowIcon from 'icons/arrows/east.svg';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import Icon from 'ui/shared/chakra/Icon';
import Tag from 'ui/shared/chakra/Tag'; import Tag from 'ui/shared/chakra/Tag';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import BlockEntity from 'ui/shared/entities/block/BlockEntity'; import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
import IconSvg from 'ui/shared/IconSvg';
import InOutTag from 'ui/shared/InOutTag'; import InOutTag from 'ui/shared/InOutTag';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile'; import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TxStatus from 'ui/shared/statusTag/TxStatus'; import TxStatus from 'ui/shared/statusTag/TxStatus';
...@@ -76,7 +75,7 @@ const TxInternalsListItem = ({ ...@@ -76,7 +75,7 @@ const TxInternalsListItem = ({
/> />
{ (isIn || isOut) ? { (isIn || isOut) ?
<InOutTag isIn={ isIn } isOut={ isOut } isLoading={ isLoading }/> : <InOutTag isIn={ isIn } isOut={ isOut } isLoading={ isLoading }/> :
<Icon as={ eastArrowIcon } boxSize={ 6 } color="gray.500" isLoading={ isLoading }/> <IconSvg name="arrows/east" boxSize={ 6 } color="gray.500" isLoading={ isLoading }/>
} }
{ toData && ( { toData && (
<AddressEntity <AddressEntity
......
...@@ -5,13 +5,12 @@ import React from 'react'; ...@@ -5,13 +5,12 @@ import React from 'react';
import type { InternalTransaction } from 'types/api/internalTransaction'; import type { InternalTransaction } from 'types/api/internalTransaction';
import config from 'configs/app'; import config from 'configs/app';
import rightArrowIcon from 'icons/arrows/east.svg';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Icon from 'ui/shared/chakra/Icon';
import Tag from 'ui/shared/chakra/Tag'; import Tag from 'ui/shared/chakra/Tag';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import BlockEntity from 'ui/shared/entities/block/BlockEntity'; import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
import IconSvg from 'ui/shared/IconSvg';
import InOutTag from 'ui/shared/InOutTag'; import InOutTag from 'ui/shared/InOutTag';
import TxStatus from 'ui/shared/statusTag/TxStatus'; import TxStatus from 'ui/shared/statusTag/TxStatus';
import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils'; import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
...@@ -89,7 +88,7 @@ const AddressIntTxsTableItem = ({ ...@@ -89,7 +88,7 @@ const AddressIntTxsTableItem = ({
<Td px={ 0 } verticalAlign="middle"> <Td px={ 0 } verticalAlign="middle">
{ (isIn || isOut) ? { (isIn || isOut) ?
<InOutTag isIn={ isIn } isOut={ isOut } isLoading={ isLoading } w="100%"/> : <InOutTag isIn={ isIn } isOut={ isOut } isLoading={ isLoading } w="100%"/> :
<Icon as={ rightArrowIcon } boxSize={ 6 } color="gray.500" isLoading={ isLoading }/> <IconSvg name="arrows/east" boxSize={ 6 } color="gray.500" isLoading={ isLoading }/>
} }
</Td> </Td>
<Td verticalAlign="middle"> <Td verticalAlign="middle">
......
import { Box, Flex, Icon, IconButton, Skeleton, Tooltip } from '@chakra-ui/react'; import { Box, Flex, IconButton, Skeleton, Tooltip } from '@chakra-ui/react';
import { useQueryClient, useIsFetching } from '@tanstack/react-query'; import { useQueryClient, useIsFetching } from '@tanstack/react-query';
import _sumBy from 'lodash/sumBy'; import _sumBy from 'lodash/sumBy';
import NextLink from 'next/link'; import NextLink from 'next/link';
...@@ -7,11 +7,11 @@ import React from 'react'; ...@@ -7,11 +7,11 @@ import React from 'react';
import type { Address } from 'types/api/address'; import type { Address } from 'types/api/address';
import walletIcon from 'icons/wallet.svg';
import { getResourceKey } from 'lib/api/useApiQuery'; import { getResourceKey } from 'lib/api/useApiQuery';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import IconSvg from 'ui/shared/IconSvg';
import useFetchTokens from '../utils/useFetchTokens'; import useFetchTokens from '../utils/useFetchTokens';
import TokenSelectDesktop from './TokenSelectDesktop'; import TokenSelectDesktop from './TokenSelectDesktop';
...@@ -69,7 +69,7 @@ const TokenSelect = ({ onClick }: Props) => { ...@@ -69,7 +69,7 @@ const TokenSelect = ({ onClick }: Props) => {
size="sm" size="sm"
pl="6px" pl="6px"
pr="6px" pr="6px"
icon={ <Icon as={ walletIcon } boxSize={ 5 }/> } icon={ <IconSvg name="wallet" boxSize={ 5 }/> }
as="a" as="a"
onClick={ handleIconButtonClick } onClick={ handleIconButtonClick }
/> />
......
import { Box, Button, Icon, Skeleton, Text, useColorModeValue } from '@chakra-ui/react'; import { Box, Button, Skeleton, Text, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { FormattedData } from './types'; import type { FormattedData } from './types';
import arrowIcon from 'icons/arrows/east-mini.svg';
import tokensIcon from 'icons/tokens.svg';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import IconSvg from 'ui/shared/IconSvg';
import { getTokensTotalInfo } from '../utils/tokenUtils'; import { getTokensTotalInfo } from '../utils/tokenUtils';
...@@ -41,10 +40,10 @@ const TokenSelectButton = ({ isOpen, isLoading, onClick, data }: Props, ref: Rea ...@@ -41,10 +40,10 @@ const TokenSelectButton = ({ isOpen, isLoading, onClick, data }: Props, ref: Rea
onClick={ handleClick } onClick={ handleClick }
aria-label="Token select" aria-label="Token select"
> >
<Icon as={ tokensIcon } boxSize={ 4 } mr={ 2 }/> <IconSvg name="tokens" boxSize={ 4 } mr={ 2 }/>
<Text fontWeight={ 600 }>{ prefix }{ num }</Text> <Text fontWeight={ 600 }>{ prefix }{ num }</Text>
<Text whiteSpace="pre" variant="secondary" fontWeight={ 400 }> ({ prefix }${ usd.toFormat(2) })</Text> <Text whiteSpace="pre" variant="secondary" fontWeight={ 400 }> ({ prefix }${ usd.toFormat(2) })</Text>
<Icon as={ arrowIcon } transform={ isOpen ? 'rotate(90deg)' : 'rotate(-90deg)' } transitionDuration="faster" boxSize={ 5 } ml={ 3 }/> <IconSvg name="arrows/east-mini" transform={ isOpen ? 'rotate(90deg)' : 'rotate(-90deg)' } transitionDuration="faster" boxSize={ 5 } ml={ 3 }/>
</Button> </Button>
{ isLoading && !isOpen && <Skeleton h="100%" w="100%" position="absolute" top={ 0 } left={ 0 } bgColor={ skeletonBgColor }/> } { isLoading && !isOpen && <Skeleton h="100%" w="100%" position="absolute" top={ 0 } left={ 0 } bgColor={ skeletonBgColor }/> }
</Box> </Box>
......
import { Icon, Text, Box, Input, InputGroup, InputLeftElement, useColorModeValue, Flex, Link } from '@chakra-ui/react'; import { Text, Box, Input, InputGroup, InputLeftElement, useColorModeValue, Flex, Link } from '@chakra-ui/react';
import _sumBy from 'lodash/sumBy'; import _sumBy from 'lodash/sumBy';
import type { ChangeEvent } from 'react'; import type { ChangeEvent } from 'react';
import React from 'react'; import React from 'react';
...@@ -6,8 +6,7 @@ import React from 'react'; ...@@ -6,8 +6,7 @@ import React from 'react';
import type { FormattedData } from './types'; import type { FormattedData } from './types';
import type { TokenType } from 'types/api/token'; import type { TokenType } from 'types/api/token';
import arrowIcon from 'icons/arrows/east.svg'; import IconSvg from 'ui/shared/IconSvg';
import searchIcon from 'icons/search.svg';
import type { Sort } from '../utils/tokenUtils'; import type { Sort } from '../utils/tokenUtils';
import { sortTokenGroups, sortingFns } from '../utils/tokenUtils'; import { sortTokenGroups, sortingFns } from '../utils/tokenUtils';
...@@ -32,7 +31,7 @@ const TokenSelectMenu = ({ erc20sort, erc1155sort, filteredData, onInputChange, ...@@ -32,7 +31,7 @@ const TokenSelectMenu = ({ erc20sort, erc1155sort, filteredData, onInputChange,
<> <>
<InputGroup size="xs" mb={ 5 }> <InputGroup size="xs" mb={ 5 }>
<InputLeftElement > <InputLeftElement >
<Icon as={ searchIcon } boxSize={ 4 } color={ searchIconColor }/> <IconSvg name="search" boxSize={ 4 } color={ searchIconColor }/>
</InputLeftElement> </InputLeftElement>
<Input <Input
paddingInlineStart="38px" paddingInlineStart="38px"
...@@ -72,7 +71,7 @@ const TokenSelectMenu = ({ erc20sort, erc1155sort, filteredData, onInputChange, ...@@ -72,7 +71,7 @@ const TokenSelectMenu = ({ erc20sort, erc1155sort, filteredData, onInputChange,
<Text mb={ 3 } color="gray.500" fontWeight={ 600 } fontSize="sm">{ type } tokens ({ numPrefix }{ tokenInfo.items.length })</Text> <Text mb={ 3 } color="gray.500" fontWeight={ 600 } fontSize="sm">{ type } tokens ({ numPrefix }{ tokenInfo.items.length })</Text>
{ hasSort && ( { hasSort && (
<Link data-type={ type } onClick={ onSortClick } aria-label={ `Sort ${ type } tokens` }> <Link data-type={ type } onClick={ onSortClick } aria-label={ `Sort ${ type } tokens` }>
<Icon as={ arrowIcon } boxSize={ 5 } transform={ arrowTransform } transitionDuration="faster"/> <IconSvg name="arrows/east" boxSize={ 5 } transform={ arrowTransform } transitionDuration="faster"/>
</Link> </Link>
) } ) }
</Flex> </Flex>
......
...@@ -22,7 +22,13 @@ const ERC20TokensTableItem = ({ ...@@ -22,7 +22,13 @@ const ERC20TokensTableItem = ({
} = getCurrencyValue({ value: value, exchangeRate: token.exchange_rate, decimals: token.decimals, accuracy: 8, accuracyUsd: 2 }); } = getCurrencyValue({ value: value, exchangeRate: token.exchange_rate, decimals: token.decimals, accuracy: 8, accuracyUsd: 2 });
return ( return (
<Tr> <Tr
sx={{
'&:hover [aria-label="Add token to wallet"]': {
opacity: 1,
},
}}
>
<Td verticalAlign="middle"> <Td verticalAlign="middle">
<TokenEntity <TokenEntity
token={ token } token={ token }
...@@ -39,7 +45,7 @@ const ERC20TokensTableItem = ({ ...@@ -39,7 +45,7 @@ const ERC20TokensTableItem = ({
isLoading={ isLoading } isLoading={ isLoading }
noIcon noIcon
/> />
<AddressAddToWallet token={ token } ml={ 4 } isLoading={ isLoading }/> <AddressAddToWallet token={ token } ml={ 4 } isLoading={ isLoading } opacity="0"/>
</Flex> </Flex>
</Td> </Td>
<Td isNumeric verticalAlign="middle"> <Td isNumeric verticalAlign="middle">
......
import { Box, Flex, Icon, Skeleton, Text, useColorModeValue } from '@chakra-ui/react'; import { Box, Flex, Skeleton, Text, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import walletIcon from 'icons/wallet.svg'; import IconSvg from 'ui/shared/IconSvg';
const TokenBalancesItem = ({ name, value, isLoading }: {name: string; value: string; isLoading: boolean }) => { const TokenBalancesItem = ({ name, value, isLoading }: {name: string; value: string; isLoading: boolean }) => {
...@@ -9,7 +9,7 @@ const TokenBalancesItem = ({ name, value, isLoading }: {name: string; value: str ...@@ -9,7 +9,7 @@ const TokenBalancesItem = ({ name, value, isLoading }: {name: string; value: str
return ( return (
<Flex p={ 5 } bgColor={ bgColor } borderRadius="16px" alignItems="center"> <Flex p={ 5 } bgColor={ bgColor } borderRadius="16px" alignItems="center">
<Icon as={ walletIcon } boxSize="30px" mr={ 3 }/> <IconSvg name="wallet" boxSize="30px" mr={ 3 }/>
<Box> <Box>
<Text variant="secondary" fontSize="xs">{ name }</Text> <Text variant="secondary" fontSize="xs">{ name }</Text>
<Skeleton isLoaded={ !isLoading } fontWeight="500">{ value }</Skeleton> <Skeleton isLoaded={ !isLoading } fontWeight="500">{ value }</Skeleton>
......
import { Icon, Modal, ModalBody, ModalCloseButton, ModalContent, ModalHeader, ModalOverlay, Link } from '@chakra-ui/react'; import { Modal, ModalBody, ModalCloseButton, ModalContent, ModalHeader, ModalOverlay, Link } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { AddressVerificationFormFirstStepFields, AddressCheckStatusSuccess } from './types'; import type { AddressVerificationFormFirstStepFields, AddressCheckStatusSuccess } from './types';
import type { VerifiedAddress } from 'types/api/account'; import type { VerifiedAddress } from 'types/api/account';
import eastArrowIcon from 'icons/arrows/east.svg';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import IconSvg from 'ui/shared/IconSvg';
import Web3ModalProvider from 'ui/shared/Web3ModalProvider'; import Web3ModalProvider from 'ui/shared/Web3ModalProvider';
import AddressVerificationStepAddress from './steps/AddressVerificationStepAddress'; import AddressVerificationStepAddress from './steps/AddressVerificationStepAddress';
...@@ -100,7 +100,7 @@ const AddressVerificationModal = ({ defaultAddress, isOpen, onClose, onSubmit, o ...@@ -100,7 +100,7 @@ const AddressVerificationModal = ({ defaultAddress, isOpen, onClose, onSubmit, o
<ModalHeader fontWeight="500" textStyle="h3" mb={ 6 }> <ModalHeader fontWeight="500" textStyle="h3" mb={ 6 }>
{ stepIndex !== 0 && ( { stepIndex !== 0 && (
<Link mr={ 3 } onClick={ handleGoToPrevStep }> <Link mr={ 3 } onClick={ handleGoToPrevStep }>
<Icon as={ eastArrowIcon } boxSize={ 6 } transform="rotate(180deg)" verticalAlign="middle"/> <IconSvg name="arrows/east" boxSize={ 6 } transform="rotate(180deg)" verticalAlign="middle"/>
</Link> </Link>
) } ) }
<span>{ step.title }</span> <span>{ step.title }</span>
......
...@@ -11,8 +11,6 @@ import type { Block } from 'types/api/block'; ...@@ -11,8 +11,6 @@ import type { Block } from 'types/api/block';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import clockIcon from 'icons/clock.svg';
import flameIcon from 'icons/flame.svg';
import type { ResourceError } from 'lib/api/resources'; import type { ResourceError } from 'lib/api/resources';
import getBlockReward from 'lib/block/getBlockReward'; import getBlockReward from 'lib/block/getBlockReward';
import { GWEI, WEI, WEI_IN_GWEI, ZERO } from 'lib/consts'; import { GWEI, WEI, WEI_IN_GWEI, ZERO } from 'lib/consts';
...@@ -20,7 +18,6 @@ import dayjs from 'lib/date/dayjs'; ...@@ -20,7 +18,6 @@ import dayjs from 'lib/date/dayjs';
import { space } from 'lib/html-entities'; import { space } from 'lib/html-entities';
import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle'; import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import Icon from 'ui/shared/chakra/Icon';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
...@@ -28,6 +25,7 @@ import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider'; ...@@ -28,6 +25,7 @@ import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import GasUsedToTargetRatio from 'ui/shared/GasUsedToTargetRatio'; import GasUsedToTargetRatio from 'ui/shared/GasUsedToTargetRatio';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
import PrevNext from 'ui/shared/PrevNext'; import PrevNext from 'ui/shared/PrevNext';
import RawDataSnippet from 'ui/shared/RawDataSnippet'; import RawDataSnippet from 'ui/shared/RawDataSnippet';
...@@ -169,7 +167,7 @@ const BlockDetails = ({ query }: Props) => { ...@@ -169,7 +167,7 @@ const BlockDetails = ({ query }: Props) => {
hint="Date & time at which block was produced." hint="Date & time at which block was produced."
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
> >
<Icon as={ clockIcon } boxSize={ 5 } color="gray.500" isLoading={ isPlaceholderData }/> <IconSvg name="clock" boxSize={ 5 } color="gray.500" isLoading={ isPlaceholderData }/>
<Skeleton isLoaded={ !isPlaceholderData } ml={ 1 }> <Skeleton isLoaded={ !isPlaceholderData } ml={ 1 }>
{ dayjs(data.timestamp).fromNow() } { dayjs(data.timestamp).fromNow() }
</Skeleton> </Skeleton>
...@@ -318,7 +316,7 @@ const BlockDetails = ({ query }: Props) => { ...@@ -318,7 +316,7 @@ const BlockDetails = ({ query }: Props) => {
} }
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
> >
<Icon as={ flameIcon } boxSize={ 5 } color="gray.500" isLoading={ isPlaceholderData }/> <IconSvg name="flame" boxSize={ 5 } color="gray.500" isLoading={ isPlaceholderData }/>
<Skeleton isLoaded={ !isPlaceholderData } ml={ 2 }> <Skeleton isLoaded={ !isPlaceholderData } ml={ 2 }>
{ burntFees.dividedBy(WEI).toFixed() } { config.chain.currency.symbol } { burntFees.dividedBy(WEI).toFixed() } { config.chain.currency.symbol }
</Skeleton> </Skeleton>
......
...@@ -8,15 +8,14 @@ import type { Block } from 'types/api/block'; ...@@ -8,15 +8,14 @@ import type { Block } from 'types/api/block';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import flameIcon from 'icons/flame.svg';
import getBlockTotalReward from 'lib/block/getBlockTotalReward'; import getBlockTotalReward from 'lib/block/getBlockTotalReward';
import { WEI } from 'lib/consts'; import { WEI } from 'lib/consts';
import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle'; import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle';
import BlockTimestamp from 'ui/blocks/BlockTimestamp'; import BlockTimestamp from 'ui/blocks/BlockTimestamp';
import Icon from 'ui/shared/chakra/Icon';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import BlockEntity from 'ui/shared/entities/block/BlockEntity'; import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import GasUsedToTargetRatio from 'ui/shared/GasUsedToTargetRatio'; import GasUsedToTargetRatio from 'ui/shared/GasUsedToTargetRatio';
import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile'; import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TextSeparator from 'ui/shared/TextSeparator'; import TextSeparator from 'ui/shared/TextSeparator';
...@@ -106,7 +105,7 @@ const BlocksListItem = ({ data, isLoading, enableTimeIncrement }: Props) => { ...@@ -106,7 +105,7 @@ const BlocksListItem = ({ data, isLoading, enableTimeIncrement }: Props) => {
<Text fontWeight={ 500 }>Burnt fees</Text> <Text fontWeight={ 500 }>Burnt fees</Text>
<Flex columnGap={ 4 } mt={ 2 }> <Flex columnGap={ 4 } mt={ 2 }>
<Flex> <Flex>
<Icon as={ flameIcon } boxSize={ 5 } color="gray.500" isLoading={ isLoading }/> <IconSvg name="flame" boxSize={ 5 } color="gray.500" isLoading={ isLoading }/>
<Skeleton isLoaded={ !isLoading } display="inline-block" color="text_secondary" ml={ 2 }> <Skeleton isLoaded={ !isLoading } display="inline-block" color="text_secondary" ml={ 2 }>
<span>{ burntFees.div(WEI).toFixed() }</span> <span>{ burntFees.div(WEI).toFixed() }</span>
</Skeleton> </Skeleton>
......
...@@ -8,14 +8,13 @@ import type { Block } from 'types/api/block'; ...@@ -8,14 +8,13 @@ import type { Block } from 'types/api/block';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import flameIcon from 'icons/flame.svg';
import getBlockTotalReward from 'lib/block/getBlockTotalReward'; import getBlockTotalReward from 'lib/block/getBlockTotalReward';
import { WEI } from 'lib/consts'; import { WEI } from 'lib/consts';
import BlockTimestamp from 'ui/blocks/BlockTimestamp'; import BlockTimestamp from 'ui/blocks/BlockTimestamp';
import Icon from 'ui/shared/chakra/Icon';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import BlockEntity from 'ui/shared/entities/block/BlockEntity'; import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import GasUsedToTargetRatio from 'ui/shared/GasUsedToTargetRatio'; import GasUsedToTargetRatio from 'ui/shared/GasUsedToTargetRatio';
import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
import TextSeparator from 'ui/shared/TextSeparator'; import TextSeparator from 'ui/shared/TextSeparator';
import Utilization from 'ui/shared/Utilization/Utilization'; import Utilization from 'ui/shared/Utilization/Utilization';
...@@ -116,7 +115,7 @@ const BlocksTableItem = ({ data, isLoading, enableTimeIncrement }: Props) => { ...@@ -116,7 +115,7 @@ const BlocksTableItem = ({ data, isLoading, enableTimeIncrement }: Props) => {
{ !isRollup && !config.UI.views.block.hiddenFields?.burnt_fees && ( { !isRollup && !config.UI.views.block.hiddenFields?.burnt_fees && (
<Td fontSize="sm"> <Td fontSize="sm">
<Flex alignItems="center" columnGap={ 2 }> <Flex alignItems="center" columnGap={ 2 }>
<Icon as={ flameIcon } boxSize={ 5 } color={ burntFeesIconColor } isLoading={ isLoading }/> <IconSvg name="flame" boxSize={ 5 } color={ burntFeesIconColor } isLoading={ isLoading }/>
<Skeleton isLoaded={ !isLoading } display="inline-block"> <Skeleton isLoaded={ !isLoading } display="inline-block">
{ burntFees.dividedBy(WEI).toFixed(8) } { burntFees.dividedBy(WEI).toFixed(8) }
</Skeleton> </Skeleton>
......
import { chakra, Checkbox, Code, Icon } from '@chakra-ui/react'; import { chakra, Checkbox, Code } from '@chakra-ui/react';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
import type { ControllerRenderProps } from 'react-hook-form'; import type { ControllerRenderProps } from 'react-hook-form';
...@@ -7,10 +7,10 @@ import { useFormContext, Controller } from 'react-hook-form'; ...@@ -7,10 +7,10 @@ import { useFormContext, Controller } from 'react-hook-form';
import type { FormFields } from '../types'; import type { FormFields } from '../types';
import type { SmartContractVerificationConfig } from 'types/api/contract'; import type { SmartContractVerificationConfig } from 'types/api/contract';
import iconSearch from 'icons/search.svg';
import { getResourceKey } from 'lib/api/useApiQuery'; import { getResourceKey } from 'lib/api/useApiQuery';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import FancySelect from 'ui/shared/FancySelect/FancySelect'; import FancySelect from 'ui/shared/FancySelect/FancySelect';
import IconSvg from 'ui/shared/IconSvg';
import ContractVerificationFormRow from '../ContractVerificationFormRow'; import ContractVerificationFormRow from '../ContractVerificationFormRow';
...@@ -56,7 +56,7 @@ const ContractVerificationFieldCompiler = ({ isVyper }: Props) => { ...@@ -56,7 +56,7 @@ const ContractVerificationFieldCompiler = ({ isVyper }: Props) => {
defaultOptions defaultOptions
size={ isMobile ? 'md' : 'lg' } size={ isMobile ? 'md' : 'lg' }
placeholder="Compiler (enter version or use the dropdown)" placeholder="Compiler (enter version or use the dropdown)"
placeholderIcon={ <Icon as={ iconSearch }/> } placeholderIcon={ <IconSvg name="search"/> }
isDisabled={ formState.isSubmitting } isDisabled={ formState.isSubmitting }
error={ error } error={ error }
isRequired isRequired
......
import { Flex, FormControl, Icon, IconButton, Input, Text } from '@chakra-ui/react'; import { Flex, FormControl, IconButton, Input, Text } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { Control, ControllerRenderProps, FieldError } from 'react-hook-form'; import type { Control, ControllerRenderProps, FieldError } from 'react-hook-form';
import { Controller } from 'react-hook-form'; import { Controller } from 'react-hook-form';
import type { FormFields } from '../types'; import type { FormFields } from '../types';
import minusIcon from 'icons/minus.svg';
import plusIcon from 'icons/plus.svg';
import { ADDRESS_REGEXP } from 'lib/validations/address'; import { ADDRESS_REGEXP } from 'lib/validations/address';
import IconSvg from 'ui/shared/IconSvg';
import InputPlaceholder from 'ui/shared/InputPlaceholder'; import InputPlaceholder from 'ui/shared/InputPlaceholder';
import ContractVerificationFormRow from '../ContractVerificationFormRow'; import ContractVerificationFormRow from '../ContractVerificationFormRow';
...@@ -86,7 +85,7 @@ const ContractVerificationFieldLibraryItem = ({ control, index, fieldsLength, on ...@@ -86,7 +85,7 @@ const ContractVerificationFieldLibraryItem = ({ control, index, fieldsLength, on
w="30px" w="30px"
h="30px" h="30px"
onClick={ handleRemoveButtonClick } onClick={ handleRemoveButtonClick }
icon={ <Icon as={ minusIcon } w="20px" h="20px"/> } icon={ <IconSvg name="minus" w="20px" h="20px"/> }
isDisabled={ isDisabled } isDisabled={ isDisabled }
/> />
) } ) }
...@@ -97,7 +96,7 @@ const ContractVerificationFieldLibraryItem = ({ control, index, fieldsLength, on ...@@ -97,7 +96,7 @@ const ContractVerificationFieldLibraryItem = ({ control, index, fieldsLength, on
w="30px" w="30px"
h="30px" h="30px"
onClick={ handleAddButtonClick } onClick={ handleAddButtonClick }
icon={ <Icon as={ plusIcon } w="20px" h="20px"/> } icon={ <IconSvg name="plus" w="20px" h="20px"/> }
isDisabled={ isDisabled } isDisabled={ isDisabled }
/> />
) } ) }
......
import { import {
Link, Link,
Icon,
chakra, chakra,
Popover, Popover,
PopoverTrigger, PopoverTrigger,
...@@ -20,9 +19,9 @@ import { Controller } from 'react-hook-form'; ...@@ -20,9 +19,9 @@ import { Controller } from 'react-hook-form';
import type { FormFields } from '../types'; import type { FormFields } from '../types';
import type { SmartContractVerificationConfig, SmartContractVerificationMethod } from 'types/api/contract'; import type { SmartContractVerificationConfig, SmartContractVerificationMethod } from 'types/api/contract';
import infoIcon from 'icons/info.svg';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import FancySelect from 'ui/shared/FancySelect/FancySelect'; import FancySelect from 'ui/shared/FancySelect/FancySelect';
import IconSvg from 'ui/shared/IconSvg';
import { METHOD_LABELS } from '../utils'; import { METHOD_LABELS } from '../utils';
...@@ -105,7 +104,7 @@ const ContractVerificationFieldMethod = ({ control, isDisabled, methods }: Props ...@@ -105,7 +104,7 @@ const ContractVerificationFieldMethod = ({ control, isDisabled, methods }: Props
<Popover trigger="hover" isLazy placement={ isMobile ? 'bottom-end' : 'right-start' } offset={ [ -8, 8 ] }> <Popover trigger="hover" isLazy placement={ isMobile ? 'bottom-end' : 'right-start' } offset={ [ -8, 8 ] }>
<PopoverTrigger> <PopoverTrigger>
<chakra.span display="inline-block" ml={ 1 } cursor="pointer" verticalAlign="middle" h="22px"> <chakra.span display="inline-block" ml={ 1 } cursor="pointer" verticalAlign="middle" h="22px">
<Icon as={ infoIcon } boxSize={ 5 } color="link" _hover={{ color: 'link_hovered' }}/> <IconSvg name="info" boxSize={ 5 } color="link" _hover={{ color: 'link_hovered' }}/>
</chakra.span> </chakra.span>
</PopoverTrigger> </PopoverTrigger>
<Portal> <Portal>
......
...@@ -11,12 +11,11 @@ import React from 'react'; ...@@ -11,12 +11,11 @@ import React from 'react';
import type { Transaction } from 'types/api/transaction'; import type { Transaction } from 'types/api/transaction';
import config from 'configs/app'; import config from 'configs/app';
import rightArrowIcon from 'icons/arrows/east.svg';
import getValueWithUnit from 'lib/getValueWithUnit'; import getValueWithUnit from 'lib/getValueWithUnit';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Icon from 'ui/shared/chakra/Icon';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
import IconSvg from 'ui/shared/IconSvg';
import TxStatus from 'ui/shared/statusTag/TxStatus'; import TxStatus from 'ui/shared/statusTag/TxStatus';
import TxFeeStability from 'ui/shared/tx/TxFeeStability'; import TxFeeStability from 'ui/shared/tx/TxFeeStability';
import TxWatchListTags from 'ui/shared/tx/TxWatchListTags'; import TxWatchListTags from 'ui/shared/tx/TxWatchListTags';
...@@ -81,8 +80,8 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => { ...@@ -81,8 +80,8 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
</Box> </Box>
</Flex> </Flex>
<Flex alignItems="center" alignSelf="flex-start"> <Flex alignItems="center" alignSelf="flex-start">
<Icon <IconSvg
as={ rightArrowIcon } name="arrows/east"
boxSize={ 6 } boxSize={ 6 }
color="gray.500" color="gray.500"
transform="rotate(90deg)" transform="rotate(90deg)"
......
...@@ -10,12 +10,11 @@ import React from 'react'; ...@@ -10,12 +10,11 @@ import React from 'react';
import type { Transaction } from 'types/api/transaction'; import type { Transaction } from 'types/api/transaction';
import config from 'configs/app'; import config from 'configs/app';
import rightArrowIcon from 'icons/arrows/east.svg';
import getValueWithUnit from 'lib/getValueWithUnit'; import getValueWithUnit from 'lib/getValueWithUnit';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Icon from 'ui/shared/chakra/Icon';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
import IconSvg from 'ui/shared/IconSvg';
import TxStatus from 'ui/shared/statusTag/TxStatus'; import TxStatus from 'ui/shared/statusTag/TxStatus';
import TxFeeStability from 'ui/shared/tx/TxFeeStability'; import TxFeeStability from 'ui/shared/tx/TxFeeStability';
import TxWatchListTags from 'ui/shared/tx/TxWatchListTags'; import TxWatchListTags from 'ui/shared/tx/TxWatchListTags';
...@@ -76,8 +75,8 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => { ...@@ -76,8 +75,8 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
fontWeight="500" fontWeight="500"
mr={ 2 } mr={ 2 }
/> />
<Icon <IconSvg
as={ rightArrowIcon } name="arrows/east"
boxSize={ 6 } boxSize={ 6 }
color="gray.500" color="gray.500"
isLoading={ isLoading } isLoading={ isLoading }
......
...@@ -5,13 +5,6 @@ import React from 'react'; ...@@ -5,13 +5,6 @@ import React from 'react';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import blockIcon from 'icons/block.svg';
import clockIcon from 'icons/clock-light.svg';
import bitcoinIcon from 'icons/coins/bitcoin.svg';
import gasIcon from 'icons/gas.svg';
import txIcon from 'icons/transactions.svg';
import batchesIcon from 'icons/txn_batches.svg';
import walletIcon from 'icons/wallet.svg';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import { WEI } from 'lib/consts'; import { WEI } from 'lib/consts';
import { HOMEPAGE_STATS } from 'stubs/stats'; import { HOMEPAGE_STATS } from 'stubs/stats';
...@@ -58,7 +51,7 @@ const Stats = () => { ...@@ -58,7 +51,7 @@ const Stats = () => {
<> <>
{ config.features.zkEvmRollup.isEnabled ? ( { config.features.zkEvmRollup.isEnabled ? (
<StatsItem <StatsItem
icon={ batchesIcon } icon="txn_batches"
title="Latest batch" title="Latest batch"
value={ (zkEvmLatestBatchQuery.data || 0).toLocaleString() } value={ (zkEvmLatestBatchQuery.data || 0).toLocaleString() }
url={ route({ pathname: '/zkevm-l2-txn-batches' }) } url={ route({ pathname: '/zkevm-l2-txn-batches' }) }
...@@ -66,7 +59,7 @@ const Stats = () => { ...@@ -66,7 +59,7 @@ const Stats = () => {
/> />
) : ( ) : (
<StatsItem <StatsItem
icon={ blockIcon } icon="block"
title="Total blocks" title="Total blocks"
value={ Number(data.total_blocks).toLocaleString() } value={ Number(data.total_blocks).toLocaleString() }
url={ route({ pathname: '/blocks' }) } url={ route({ pathname: '/blocks' }) }
...@@ -75,21 +68,21 @@ const Stats = () => { ...@@ -75,21 +68,21 @@ const Stats = () => {
) } ) }
{ hasAvgBlockTime && ( { hasAvgBlockTime && (
<StatsItem <StatsItem
icon={ clockIcon } icon="clock-light"
title="Average block time" title="Average block time"
value={ `${ (data.average_block_time / 1000).toFixed(1) }s` } value={ `${ (data.average_block_time / 1000).toFixed(1) }s` }
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
/> />
) } ) }
<StatsItem <StatsItem
icon={ txIcon } icon="transactions"
title="Total transactions" title="Total transactions"
value={ Number(data.total_transactions).toLocaleString() } value={ Number(data.total_transactions).toLocaleString() }
url={ route({ pathname: '/txs' }) } url={ route({ pathname: '/txs' }) }
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
/> />
<StatsItem <StatsItem
icon={ walletIcon } icon="wallet"
title="Wallet addresses" title="Wallet addresses"
value={ Number(data.total_addresses).toLocaleString() } value={ Number(data.total_addresses).toLocaleString() }
_last={ isOdd ? lastItemTouchStyle : undefined } _last={ isOdd ? lastItemTouchStyle : undefined }
...@@ -97,7 +90,7 @@ const Stats = () => { ...@@ -97,7 +90,7 @@ const Stats = () => {
/> />
{ hasGasTracker && data.gas_prices && ( { hasGasTracker && data.gas_prices && (
<StatsItem <StatsItem
icon={ gasIcon } icon="gas"
title="Gas tracker" title="Gas tracker"
value={ `${ Number(data.gas_prices.average).toLocaleString() } Gwei` } value={ `${ Number(data.gas_prices.average).toLocaleString() } Gwei` }
_last={ isOdd ? lastItemTouchStyle : undefined } _last={ isOdd ? lastItemTouchStyle : undefined }
...@@ -107,7 +100,7 @@ const Stats = () => { ...@@ -107,7 +100,7 @@ const Stats = () => {
) } ) }
{ data.rootstock_locked_btc && ( { data.rootstock_locked_btc && (
<StatsItem <StatsItem
icon={ bitcoinIcon } icon="coins/bitcoin"
title="BTC Locked in 2WP" title="BTC Locked in 2WP"
value={ `${ BigNumber(data.rootstock_locked_btc).div(WEI).dp(0).toFormat() } RBTC` } value={ `${ BigNumber(data.rootstock_locked_btc).div(WEI).dp(0).toFormat() } RBTC` }
_last={ isOdd ? lastItemTouchStyle : undefined } _last={ isOdd ? lastItemTouchStyle : undefined }
......
...@@ -3,11 +3,12 @@ import { Skeleton, Flex, useColorModeValue, chakra, LightMode } from '@chakra-ui ...@@ -3,11 +3,12 @@ import { Skeleton, Flex, useColorModeValue, chakra, LightMode } from '@chakra-ui
import React from 'react'; import React from 'react';
import breakpoints from 'theme/foundations/breakpoints'; import breakpoints from 'theme/foundations/breakpoints';
import Icon from 'ui/shared/chakra/Icon';
import Hint from 'ui/shared/Hint'; import Hint from 'ui/shared/Hint';
import type { IconName } from 'ui/shared/IconSvg';
import IconSvg from 'ui/shared/IconSvg';
type Props = { type Props = {
icon: React.FC<React.SVGAttributes<SVGElement>>; icon: IconName;
title: string; title: string;
value: string; value: string;
className?: string; className?: string;
...@@ -57,7 +58,7 @@ const StatsItem = ({ icon, title, value, className, tooltipLabel, url, isLoading ...@@ -57,7 +58,7 @@ const StatsItem = ({ icon, title, value, className, tooltipLabel, url, isLoading
href: url, href: url,
} : {}) } } : {}) }
> >
<Icon as={ icon } boxSize={ 7 } isLoading={ isLoading } borderRadius="base"/> <IconSvg name={ icon } boxSize={ 7 } isLoading={ isLoading } borderRadius="base"/>
<Flex <Flex
flexDirection="column" flexDirection="column"
alignItems="start" alignItems="start"
......
import { Icon } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { TChainIndicator } from '../types'; import type { TChainIndicator } from '../types';
import config from 'configs/app'; import config from 'configs/app';
import globeIcon from 'icons/globe.svg';
import lockIcon from 'icons/lock.svg';
import txIcon from 'icons/transactions.svg';
import { sortByDateDesc } from 'ui/shared/chart/utils/sorts'; import { sortByDateDesc } from 'ui/shared/chart/utils/sorts';
import * as TokenEntity from 'ui/shared/entities/token/TokenEntity'; import * as TokenEntity from 'ui/shared/entities/token/TokenEntity';
import IconSvg from 'ui/shared/IconSvg';
const dailyTxsIndicator: TChainIndicator<'homepage_chart_txs'> = { const dailyTxsIndicator: TChainIndicator<'homepage_chart_txs'> = {
id: 'daily_txs', id: 'daily_txs',
title: 'Daily transactions', title: 'Daily transactions',
value: (stats) => Number(stats.transactions_today).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }), value: (stats) => Number(stats.transactions_today).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }),
icon: <Icon as={ txIcon } boxSize={ 6 } bgColor="#56ACD1" borderRadius="base" color="white"/>, icon: <IconSvg name="transactions" boxSize={ 6 } bgColor="#56ACD1" borderRadius="base" color="white"/>,
hint: `Number of transactions yesterday (0:00 - 23:59 UTC). The chart displays daily transactions for the past 30 days.`, hint: `Number of transactions yesterday (0:00 - 23:59 UTC). The chart displays daily transactions for the past 30 days.`,
api: { api: {
resourceName: 'homepage_chart_txs', resourceName: 'homepage_chart_txs',
...@@ -58,7 +55,7 @@ const marketPriceIndicator: TChainIndicator<'homepage_chart_market'> = { ...@@ -58,7 +55,7 @@ const marketPriceIndicator: TChainIndicator<'homepage_chart_market'> = {
id: 'market_cap', id: 'market_cap',
title: 'Market cap', title: 'Market cap',
value: (stats) => '$' + Number(stats.market_cap).toLocaleString(undefined, { maximumFractionDigits: 0, notation: 'compact' }), value: (stats) => '$' + Number(stats.market_cap).toLocaleString(undefined, { maximumFractionDigits: 0, notation: 'compact' }),
icon: <Icon as={ globeIcon } boxSize={ 6 } bgColor="#6A5DCC" borderRadius="base" color="white"/>, icon: <IconSvg name="globe" boxSize={ 6 } bgColor="#6A5DCC" borderRadius="base" color="white"/>,
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
hint: 'The total market value of a cryptocurrency\'s circulating supply. It is analogous to the free-float capitalization in the stock market. Market Cap = Current Price x Circulating Supply.', hint: 'The total market value of a cryptocurrency\'s circulating supply. It is analogous to the free-float capitalization in the stock market. Market Cap = Current Price x Circulating Supply.',
api: { api: {
...@@ -81,7 +78,7 @@ const tvlIndicator: TChainIndicator<'homepage_chart_market'> = { ...@@ -81,7 +78,7 @@ const tvlIndicator: TChainIndicator<'homepage_chart_market'> = {
id: 'tvl', id: 'tvl',
title: 'Total value locked', title: 'Total value locked',
value: (stats) => '$' + Number(stats.tvl).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }), value: (stats) => '$' + Number(stats.tvl).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }),
icon: <Icon as={ lockIcon } boxSize={ 6 } bgColor="#517FDB" borderRadius="base" color="white"/>, icon: <IconSvg name="lock" boxSize={ 6 } bgColor="#517FDB" borderRadius="base" color="white"/>,
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
hint: 'Total value of digital assets locked or staked in a chain', hint: 'Total value of digital assets locked or staked in a chain',
api: { api: {
......
import { Box, Icon, IconButton, Image, Link, LinkBox, Skeleton, useColorModeValue } from '@chakra-ui/react'; import { Box, IconButton, Image, Link, LinkBox, Skeleton, useColorModeValue } from '@chakra-ui/react';
import type { MouseEvent } from 'react'; import type { MouseEvent } from 'react';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { MarketplaceAppPreview } from 'types/client/marketplace'; import type { MarketplaceAppPreview } from 'types/client/marketplace';
import northEastIcon from 'icons/arrows/north-east.svg'; import IconSvg from 'ui/shared/IconSvg';
import starFilledIcon from 'icons/star_filled.svg';
import starOutlineIcon from 'icons/star_outline.svg';
import MarketplaceAppCardLink from './MarketplaceAppCardLink'; import MarketplaceAppCardLink from './MarketplaceAppCardLink';
...@@ -152,8 +150,8 @@ const MarketplaceAppCard = ({ ...@@ -152,8 +150,8 @@ const MarketplaceAppCard = ({
> >
More More
<Icon <IconSvg
as={ northEastIcon } name="arrows/north-east"
marginLeft={ 1 } marginLeft={ 1 }
/> />
</Link> </Link>
...@@ -175,8 +173,8 @@ const MarketplaceAppCard = ({ ...@@ -175,8 +173,8 @@ const MarketplaceAppCard = ({
h={ 8 } h={ 8 }
onClick={ handleFavoriteClick } onClick={ handleFavoriteClick }
icon={ isFavorite ? icon={ isFavorite ?
<Icon as={ starFilledIcon } w={ 4 } h={ 4 } color="yellow.400"/> : <IconSvg name="star_filled" w={ 4 } h={ 4 } color="yellow.400"/> :
<Icon as={ starOutlineIcon } w={ 4 } h={ 4 } color="gray.300"/> <IconSvg name="star_outline" w={ 4 } h={ 4 } color="gray.300"/>
} }
/> />
) } ) }
......
import { import {
Box, Flex, Heading, Icon, IconButton, Image, Link, List, Modal, ModalBody, Box, Flex, Heading, IconButton, Image, Link, List, Modal, ModalBody,
ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, Tag, Text, useColorModeValue, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, Tag, Text, useColorModeValue,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { MarketplaceAppOverview } from 'types/client/marketplace'; import type { MarketplaceAppOverview } from 'types/client/marketplace';
import linkIcon from 'icons/link.svg';
import ghIcon from 'icons/social/git.svg';
import tgIcon from 'icons/social/telega.svg';
import twIcon from 'icons/social/tweet.svg';
import starFilledIcon from 'icons/star_filled.svg';
import starOutlineIcon from 'icons/star_outline.svg';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import { nbsp } from 'lib/html-entities'; import { nbsp } from 'lib/html-entities';
import type { IconName } from 'ui/shared/IconSvg';
import IconSvg from 'ui/shared/IconSvg';
import MarketplaceAppModalLink from './MarketplaceAppModalLink'; import MarketplaceAppModalLink from './MarketplaceAppModalLink';
...@@ -47,15 +43,15 @@ const MarketplaceAppModal = ({ ...@@ -47,15 +43,15 @@ const MarketplaceAppModal = ({
const socialLinks = [ const socialLinks = [
telegram ? { telegram ? {
icon: tgIcon, icon: 'social/telega' as IconName,
url: telegram, url: telegram,
} : null, } : null,
twitter ? { twitter ? {
icon: twIcon, icon: 'social/tweet' as IconName,
url: twitter, url: twitter,
} : null, } : null,
github ? { github ? {
icon: ghIcon, icon: 'social/git' as IconName,
url: github, url: github,
} : null, } : null,
].filter(Boolean); ].filter(Boolean);
...@@ -138,8 +134,8 @@ const MarketplaceAppModal = ({ ...@@ -138,8 +134,8 @@ const MarketplaceAppModal = ({
h={ 8 } h={ 8 }
onClick={ handleFavoriteClick } onClick={ handleFavoriteClick }
icon={ isFavorite ? icon={ isFavorite ?
<Icon as={ starFilledIcon } w={ 4 } h={ 4 } color="yellow.400"/> : <IconSvg name="star_filled" w={ 4 } h={ 4 } color="yellow.400"/> :
<Icon as={ starOutlineIcon } w={ 4 } h={ 4 } color="gray.300"/> } <IconSvg name="star_outline" w={ 4 } h={ 4 } color="gray.300"/> }
/> />
</Box> </Box>
</Box> </Box>
...@@ -188,8 +184,8 @@ const MarketplaceAppModal = ({ ...@@ -188,8 +184,8 @@ const MarketplaceAppModal = ({
maxW="100%" maxW="100%"
overflow="hidden" overflow="hidden"
> >
<Icon <IconSvg
as={ linkIcon } name="link"
display="inline" display="inline"
verticalAlign="baseline" verticalAlign="baseline"
boxSize="18px" boxSize="18px"
...@@ -227,8 +223,8 @@ const MarketplaceAppModal = ({ ...@@ -227,8 +223,8 @@ const MarketplaceAppModal = ({
w={ 10 } w={ 10 }
h={ 10 } h={ 10 }
> >
<Icon <IconSvg
as={ icon } name={ icon }
w="20px" w="20px"
h="20px" h="20px"
display="block" display="block"
......
import { Box, Button, Icon, Menu, MenuButton, MenuList, Skeleton } from '@chakra-ui/react'; import { Box, Button, Menu, MenuButton, MenuList, Skeleton } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { MarketplaceCategory } from 'types/client/marketplace'; import { MarketplaceCategory } from 'types/client/marketplace';
import eastMiniArrowIcon from 'icons/arrows/east-mini.svg'; import IconSvg from 'ui/shared/IconSvg';
import MarketplaceCategoriesMenuItem from './MarketplaceCategoriesMenuItem'; import MarketplaceCategoriesMenuItem from './MarketplaceCategoriesMenuItem';
...@@ -50,7 +50,7 @@ const MarketplaceCategoriesMenu = ({ selectedCategoryId, onSelect, categories, i ...@@ -50,7 +50,7 @@ const MarketplaceCategoriesMenu = ({ selectedCategoryId, onSelect, categories, i
alignItems="center" alignItems="center"
> >
{ selectedCategoryId } { selectedCategoryId }
<Icon transform="rotate(-90deg)" ml={{ base: 'auto', sm: 1 }} as={ eastMiniArrowIcon } w={ 5 } h={ 5 }/> <IconSvg transform="rotate(-90deg)" ml={{ base: 'auto', sm: 1 }} name="arrows/east-mini" w={ 5 } h={ 5 }/>
</Box> </Box>
</MenuButton> </MenuButton>
......
import { Icon, MenuItem } from '@chakra-ui/react'; import { MenuItem } from '@chakra-ui/react';
import type { FunctionComponent, SVGAttributes } from 'react';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { MarketplaceCategory } from 'types/client/marketplace'; import { MarketplaceCategory } from 'types/client/marketplace';
import starFilledIcon from 'icons/star_filled.svg'; import type { IconName } from 'ui/shared/IconSvg';
import IconSvg from 'ui/shared/IconSvg';
type Props = { type Props = {
id: string; id: string;
onClick: (category: string) => void; onClick: (category: string) => void;
} }
const ICONS: Record<string, FunctionComponent<SVGAttributes<SVGElement>>> = { const ICONS: Record<string, IconName> = {
[MarketplaceCategory.FAVORITES]: starFilledIcon, [MarketplaceCategory.FAVORITES]: 'star_filled',
}; };
const MarketplaceCategoriesMenuItem = ({ id, onClick }: Props) => { const MarketplaceCategoriesMenuItem = ({ id, onClick }: Props) => {
...@@ -27,7 +27,7 @@ const MarketplaceCategoriesMenuItem = ({ id, onClick }: Props) => { ...@@ -27,7 +27,7 @@ const MarketplaceCategoriesMenuItem = ({ id, onClick }: Props) => {
display="flex" display="flex"
alignItems="center" alignItems="center"
> >
{ id in ICONS && <Icon mr={ 3 } as={ ICONS[id] } w={ 4 } h={ 4 } color="blackAlpha.800"/> } { id in ICONS && <IconSvg mr={ 3 } name={ ICONS[id] } w={ 4 } h={ 4 } color="blackAlpha.800"/> }
{ id } { id }
</MenuItem> </MenuItem>
); );
......
import { Box, Flex, HStack, Icon } from '@chakra-ui/react'; import { Box, Flex, HStack } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import type { RoutedTab } from 'ui/shared/Tabs/types'; import type { RoutedTab } from 'ui/shared/Tabs/types';
import config from 'configs/app'; import config from 'configs/app';
import iconSuccess from 'icons/status/success.svg';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import { useAppContext } from 'lib/contexts/app'; import { useAppContext } from 'lib/contexts/app';
import useContractTabs from 'lib/hooks/useContractTabs'; import useContractTabs from 'lib/hooks/useContractTabs';
...@@ -30,6 +29,7 @@ import TextAd from 'ui/shared/ad/TextAd'; ...@@ -30,6 +29,7 @@ import TextAd from 'ui/shared/ad/TextAd';
import AddressAddToWallet from 'ui/shared/address/AddressAddToWallet'; import AddressAddToWallet from 'ui/shared/address/AddressAddToWallet';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import EntityTags from 'ui/shared/EntityTags'; import EntityTags from 'ui/shared/EntityTags';
import IconSvg from 'ui/shared/IconSvg';
import NetworkExplorers from 'ui/shared/NetworkExplorers'; import NetworkExplorers from 'ui/shared/NetworkExplorers';
import PageTitle from 'ui/shared/Page/PageTitle'; import PageTitle from 'ui/shared/Page/PageTitle';
import RoutedTabs from 'ui/shared/Tabs/RoutedTabs'; import RoutedTabs from 'ui/shared/Tabs/RoutedTabs';
...@@ -127,7 +127,7 @@ const AddressPageContent = () => { ...@@ -127,7 +127,7 @@ const AddressPageContent = () => {
return ( return (
<> <>
<span>Contract</span> <span>Contract</span>
<Icon as={ iconSuccess } boxSize="14px" color="green.500" ml={ 1 }/> <IconSvg name="status/success" boxSize="14px" color="green.500" ml={ 1 }/>
</> </>
); );
} }
......
import { Box, Flex, Icon, Tooltip } from '@chakra-ui/react'; import { Box, Flex, Tooltip } from '@chakra-ui/react';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
...@@ -9,8 +9,6 @@ import type { PaginationParams } from 'ui/shared/pagination/types'; ...@@ -9,8 +9,6 @@ import type { PaginationParams } from 'ui/shared/pagination/types';
import type { RoutedTab } from 'ui/shared/Tabs/types'; import type { RoutedTab } from 'ui/shared/Tabs/types';
import config from 'configs/app'; import config from 'configs/app';
import iconSuccess from 'icons/status/success.svg';
import iconVerifiedToken from 'icons/verified_token.svg';
import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery'; import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery';
import { useAppContext } from 'lib/contexts/app'; import { useAppContext } from 'lib/contexts/app';
import useContractTabs from 'lib/hooks/useContractTabs'; import useContractTabs from 'lib/hooks/useContractTabs';
...@@ -30,6 +28,7 @@ import AddressAddToWallet from 'ui/shared/address/AddressAddToWallet'; ...@@ -30,6 +28,7 @@ import AddressAddToWallet from 'ui/shared/address/AddressAddToWallet';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import * as TokenEntity from 'ui/shared/entities/token/TokenEntity'; import * as TokenEntity from 'ui/shared/entities/token/TokenEntity';
import EntityTags from 'ui/shared/EntityTags'; import EntityTags from 'ui/shared/EntityTags';
import IconSvg from 'ui/shared/IconSvg';
import NetworkExplorers from 'ui/shared/NetworkExplorers'; import NetworkExplorers from 'ui/shared/NetworkExplorers';
import PageTitle from 'ui/shared/Page/PageTitle'; import PageTitle from 'ui/shared/Page/PageTitle';
import Pagination from 'ui/shared/pagination/Pagination'; import Pagination from 'ui/shared/pagination/Pagination';
...@@ -189,7 +188,7 @@ const TokenPageContent = () => { ...@@ -189,7 +188,7 @@ const TokenPageContent = () => {
return ( return (
<> <>
<span>Contract</span> <span>Contract</span>
<Icon as={ iconSuccess } boxSize="14px" color="green.500" ml={ 1 }/> <IconSvg name="status/success" boxSize="14px" color="green.500" ml={ 1 }/>
</> </>
); );
} }
...@@ -250,7 +249,7 @@ const TokenPageContent = () => { ...@@ -250,7 +249,7 @@ const TokenPageContent = () => {
{ verifiedInfoQuery.data?.tokenAddress && ( { verifiedInfoQuery.data?.tokenAddress && (
<Tooltip label={ `Information on this token has been verified by ${ config.chain.name }` }> <Tooltip label={ `Information on this token has been verified by ${ config.chain.name }` }>
<Box boxSize={ 6 }> <Box boxSize={ 6 }>
<Icon as={ iconVerifiedToken } color="green.500" boxSize={ 6 } cursor="pointer"/> <IconSvg name="verified_token" color="green.500" boxSize={ 6 } cursor="pointer"/>
</Box> </Box>
</Tooltip> </Tooltip>
) } ) }
......
import { Box, Text, Button, Heading, Icon, chakra } from '@chakra-ui/react'; import { Box, Text, Button, Heading, chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import iconEmailSent from 'icons/email-sent.svg';
import useApiFetch from 'lib/api/useApiFetch'; import useApiFetch from 'lib/api/useApiFetch';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import getErrorObjPayload from 'lib/errors/getErrorObjPayload'; import getErrorObjPayload from 'lib/errors/getErrorObjPayload';
import getErrorObjStatusCode from 'lib/errors/getErrorObjStatusCode'; import getErrorObjStatusCode from 'lib/errors/getErrorObjStatusCode';
import useToast from 'lib/hooks/useToast'; import useToast from 'lib/hooks/useToast';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import IconSvg from 'ui/shared/IconSvg';
interface Props { interface Props {
email?: string; // TODO: obtain email from API email?: string; // TODO: obtain email from API
...@@ -77,7 +77,7 @@ const UnverifiedEmail = ({ email }: Props) => { ...@@ -77,7 +77,7 @@ const UnverifiedEmail = ({ email }: Props) => {
return ( return (
<Box> <Box>
<Icon as={ iconEmailSent } width="180px" height="auto" mt="52px"/> <IconSvg name="email-sent" width="180px" height="auto" mt="52px"/>
<Heading mt={ 6 } size="2xl">Verify your email address</Heading> <Heading mt={ 6 } size="2xl">Verify your email address</Heading>
<Text variant="secondary" mt={ 3 }> <Text variant="secondary" mt={ 3 }>
<span>Please confirm your email address to use the My Account feature. A confirmation email was sent to </span> <span>Please confirm your email address to use the My Account feature. A confirmation email was sent to </span>
......
import type { InputProps } from '@chakra-ui/react'; import type { InputProps } from '@chakra-ui/react';
import { IconButton, Icon, Flex } from '@chakra-ui/react'; import { IconButton, Flex } from '@chakra-ui/react';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { ControllerRenderProps, Control, FieldError } from 'react-hook-form'; import type { ControllerRenderProps, Control, FieldError } from 'react-hook-form';
import { Controller } from 'react-hook-form'; import { Controller } from 'react-hook-form';
import MinusIcon from 'icons/minus.svg';
import PlusIcon from 'icons/plus.svg';
import { ADDRESS_REGEXP } from 'lib/validations/address'; import { ADDRESS_REGEXP } from 'lib/validations/address';
import AddressInput from 'ui/shared/AddressInput'; import AddressInput from 'ui/shared/AddressInput';
import IconSvg from 'ui/shared/IconSvg';
import type { Inputs } from './PublicTagsForm'; import type { Inputs } from './PublicTagsForm';
...@@ -60,7 +59,7 @@ export default function PublicTagFormAction({ control, index, fieldsLength, erro ...@@ -60,7 +59,7 @@ export default function PublicTagFormAction({ control, index, fieldsLength, erro
w="30px" w="30px"
h="30px" h="30px"
onClick={ onRemoveFieldClick(index) } onClick={ onRemoveFieldClick(index) }
icon={ <Icon as={ MinusIcon } w="20px" h="20px"/> } icon={ <IconSvg name="minus" w="20px" h="20px"/> }
/> />
) } ) }
{ index === fieldsLength - 1 && fieldsLength < MAX_INPUTS_NUM && ( { index === fieldsLength - 1 && fieldsLength < MAX_INPUTS_NUM && (
...@@ -70,7 +69,7 @@ export default function PublicTagFormAction({ control, index, fieldsLength, erro ...@@ -70,7 +69,7 @@ export default function PublicTagFormAction({ control, index, fieldsLength, erro
w="30px" w="30px"
h="30px" h="30px"
onClick={ onAddFieldClick } onClick={ onAddFieldClick }
icon={ <Icon as={ PlusIcon } w="20px" h="20px"/> } icon={ <IconSvg name="plus" w="20px" h="20px"/> }
/> />
) } ) }
</Flex> </Flex>
......
import { Flex, Grid, Icon, Image, Box, Text, Skeleton, useColorMode, Tag } from '@chakra-ui/react'; import { Flex, Grid, Image, Box, Text, Skeleton, useColorMode, Tag } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import xss from 'xss'; import xss from 'xss';
...@@ -6,9 +6,6 @@ import type { SearchResultItem } from 'types/api/search'; ...@@ -6,9 +6,6 @@ import type { SearchResultItem } from 'types/api/search';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import labelIcon from 'icons/publictags_slim.svg';
import iconSuccess from 'icons/status/success.svg';
import verifiedToken from 'icons/verified_token.svg';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import highlightText from 'lib/highlightText'; import highlightText from 'lib/highlightText';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
...@@ -18,6 +15,7 @@ import * as BlockEntity from 'ui/shared/entities/block/BlockEntity'; ...@@ -18,6 +15,7 @@ import * as BlockEntity from 'ui/shared/entities/block/BlockEntity';
import * as TokenEntity from 'ui/shared/entities/token/TokenEntity'; import * as TokenEntity from 'ui/shared/entities/token/TokenEntity';
import * as TxEntity from 'ui/shared/entities/tx/TxEntity'; import * as TxEntity from 'ui/shared/entities/tx/TxEntity';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import IconSvg from 'ui/shared/IconSvg';
import LinkExternal from 'ui/shared/LinkExternal'; import LinkExternal from 'ui/shared/LinkExternal';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile'; import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
...@@ -68,7 +66,7 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => { ...@@ -68,7 +66,7 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
textOverflow="ellipsis" textOverflow="ellipsis"
/> />
</LinkInternal> </LinkInternal>
{ data.is_verified_via_admin_panel && <Icon as={ verifiedToken } boxSize={ 4 } ml={ 1 } color="green.500"/> } { data.is_verified_via_admin_panel && <IconSvg name="verified_token" boxSize={ 4 } ml={ 1 } color="green.500"/> }
</Flex> </Flex>
); );
} }
...@@ -107,7 +105,7 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => { ...@@ -107,7 +105,7 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
case 'label': { case 'label': {
return ( return (
<Flex alignItems="center"> <Flex alignItems="center">
<Icon as={ labelIcon } boxSize={ 6 } mr={ 2 } color="gray.500"/> <IconSvg name="publictags_slim" boxSize={ 6 } mr={ 2 } color="gray.500"/>
<LinkInternal <LinkInternal
href={ route({ pathname: '/address/[hash]', query: { hash: data.address } }) } href={ route({ pathname: '/address/[hash]', query: { hash: data.address } }) }
fontWeight={ 700 } fontWeight={ 700 }
...@@ -214,12 +212,12 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => { ...@@ -214,12 +212,12 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
<Text whiteSpace="nowrap" overflow="hidden"> <Text whiteSpace="nowrap" overflow="hidden">
<HashStringShortenDynamic hash={ data.address } isTooltipDisabled/> <HashStringShortenDynamic hash={ data.address } isTooltipDisabled/>
</Text> </Text>
{ data.is_smart_contract_verified && <Icon as={ iconSuccess } color="green.500" ml={ 1 }/> } { data.is_smart_contract_verified && <IconSvg name="status/success" boxSize="14px" color="green.500" ml={ 1 } flexShrink={ 0 }/> }
</Skeleton> </Skeleton>
<Text overflow="hidden" whiteSpace="nowrap" textOverflow="ellipsis" fontWeight={ 700 }> <Skeleton isLoaded={ !isLoading } overflow="hidden" whiteSpace="nowrap" textOverflow="ellipsis" fontWeight={ 700 }>
{ data.token_type === 'ERC-20' && data.exchange_rate && `$${ Number(data.exchange_rate).toLocaleString() }` } { data.token_type === 'ERC-20' && data.exchange_rate && `$${ Number(data.exchange_rate).toLocaleString() }` }
{ data.token_type !== 'ERC-20' && data.total_supply && `Items ${ Number(data.total_supply).toLocaleString() }` } { data.token_type !== 'ERC-20' && data.total_supply && `Items ${ Number(data.total_supply).toLocaleString() }` }
</Text> </Skeleton>
</Grid> </Grid>
); );
} }
...@@ -245,7 +243,7 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => { ...@@ -245,7 +243,7 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
<Box overflow="hidden"> <Box overflow="hidden">
<HashStringShortenDynamic hash={ data.address }/> <HashStringShortenDynamic hash={ data.address }/>
</Box> </Box>
{ data.is_smart_contract_verified && <Icon as={ iconSuccess } color="green.500" ml={ 1 }/> } { data.is_smart_contract_verified && <IconSvg name="status/success" boxSize="14px" color="green.500" ml={ 1 } flexShrink={ 0 }/> }
</Flex> </Flex>
); );
} }
......
import { Tr, Td, Text, Flex, Icon, Image, Box, Skeleton, useColorMode, Tag } from '@chakra-ui/react'; import { Tr, Td, Text, Flex, Image, Box, Skeleton, useColorMode, Tag } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import xss from 'xss'; import xss from 'xss';
...@@ -6,9 +6,6 @@ import type { SearchResultItem } from 'types/api/search'; ...@@ -6,9 +6,6 @@ import type { SearchResultItem } from 'types/api/search';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import labelIcon from 'icons/publictags_slim.svg';
import iconSuccess from 'icons/status/success.svg';
import verifiedToken from 'icons/verified_token.svg';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import highlightText from 'lib/highlightText'; import highlightText from 'lib/highlightText';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
...@@ -18,6 +15,7 @@ import * as BlockEntity from 'ui/shared/entities/block/BlockEntity'; ...@@ -18,6 +15,7 @@ import * as BlockEntity from 'ui/shared/entities/block/BlockEntity';
import * as TokenEntity from 'ui/shared/entities/token/TokenEntity'; import * as TokenEntity from 'ui/shared/entities/token/TokenEntity';
import * as TxEntity from 'ui/shared/entities/tx/TxEntity'; import * as TxEntity from 'ui/shared/entities/tx/TxEntity';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import IconSvg from 'ui/shared/IconSvg';
import LinkExternal from 'ui/shared/LinkExternal'; import LinkExternal from 'ui/shared/LinkExternal';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
import type { SearchResultAppItem } from 'ui/shared/search/utils'; import type { SearchResultAppItem } from 'ui/shared/search/utils';
...@@ -68,7 +66,7 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading }: Props) => { ...@@ -68,7 +66,7 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading }: Props) => {
dangerouslySetInnerHTML={{ __html: highlightText(name, searchTerm) }} dangerouslySetInnerHTML={{ __html: highlightText(name, searchTerm) }}
/> />
</LinkInternal> </LinkInternal>
{ data.is_verified_via_admin_panel && <Icon as={ verifiedToken } boxSize={ 4 } ml={ 1 } color="green.500"/> } { data.is_verified_via_admin_panel && <IconSvg name="verified_token" boxSize={ 4 } ml={ 1 } color="green.500"/> }
</Flex> </Flex>
</Td> </Td>
<Td fontSize="sm" verticalAlign="middle"> <Td fontSize="sm" verticalAlign="middle">
...@@ -76,7 +74,7 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading }: Props) => { ...@@ -76,7 +74,7 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading }: Props) => {
<Box overflow="hidden" whiteSpace="nowrap" w={ data.is_smart_contract_verified ? 'calc(100%-28px)' : 'unset' }> <Box overflow="hidden" whiteSpace="nowrap" w={ data.is_smart_contract_verified ? 'calc(100%-28px)' : 'unset' }>
<HashStringShortenDynamic hash={ data.address }/> <HashStringShortenDynamic hash={ data.address }/>
</Box> </Box>
{ data.is_smart_contract_verified && <Icon as={ iconSuccess } color="green.500" ml={ 1 }/> } { data.is_smart_contract_verified && <IconSvg name="status/success" boxSize="14px" color="green.500" ml={ 1 } flexShrink={ 0 }/> }
</Skeleton> </Skeleton>
</Td> </Td>
<Td fontSize="sm" verticalAlign="middle" isNumeric> <Td fontSize="sm" verticalAlign="middle" isNumeric>
...@@ -165,7 +163,7 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading }: Props) => { ...@@ -165,7 +163,7 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading }: Props) => {
<> <>
<Td fontSize="sm"> <Td fontSize="sm">
<Flex alignItems="center"> <Flex alignItems="center">
<Icon as={ labelIcon } boxSize={ 6 } mr={ 2 } color="gray.500"/> <IconSvg name="publictags_slim" boxSize={ 6 } mr={ 2 } color="gray.500"/>
<LinkInternal <LinkInternal
href={ route({ pathname: '/address/[hash]', query: { hash: data.address } }) } href={ route({ pathname: '/address/[hash]', query: { hash: data.address } }) }
fontWeight={ 700 } fontWeight={ 700 }
...@@ -182,7 +180,7 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading }: Props) => { ...@@ -182,7 +180,7 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading }: Props) => {
<Box overflow="hidden" whiteSpace="nowrap" w={ data.is_smart_contract_verified ? 'calc(100%-28px)' : 'unset' }> <Box overflow="hidden" whiteSpace="nowrap" w={ data.is_smart_contract_verified ? 'calc(100%-28px)' : 'unset' }>
<HashStringShortenDynamic hash={ data.address }/> <HashStringShortenDynamic hash={ data.address }/>
</Box> </Box>
{ data.is_smart_contract_verified && <Icon as={ iconSuccess } color="green.500" ml={ 1 }/> } { data.is_smart_contract_verified && <IconSvg name="status/success" boxSize="14px" color="green.500" ml={ 1 } flexShrink={ 0 }/> }
</Flex> </Flex>
</Td> </Td>
<Td></Td> <Td></Td>
......
import { Button, Menu, MenuButton, MenuList, Icon, Flex, Skeleton, chakra } from '@chakra-ui/react'; import { Button, Menu, MenuButton, MenuList, Flex, Skeleton, chakra } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import config from 'configs/app'; import config from 'configs/app';
import iconArrow from 'icons/arrows/east-mini.svg';
import useIsAccountActionAllowed from 'lib/hooks/useIsAccountActionAllowed'; import useIsAccountActionAllowed from 'lib/hooks/useIsAccountActionAllowed';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import IconSvg from 'ui/shared/IconSvg';
import PrivateTagMenuItem from './items/PrivateTagMenuItem'; import PrivateTagMenuItem from './items/PrivateTagMenuItem';
import PublicTagMenuItem from './items/PublicTagMenuItem'; import PublicTagMenuItem from './items/PublicTagMenuItem';
...@@ -44,7 +44,7 @@ const AccountActionsMenu = ({ isLoading, className }: Props) => { ...@@ -44,7 +44,7 @@ const AccountActionsMenu = ({ isLoading, className }: Props) => {
> >
<Flex alignItems="center"> <Flex alignItems="center">
<span>More</span> <span>More</span>
<Icon as={ iconArrow } transform="rotate(-90deg)" boxSize={ 5 } ml={ 1 }/> <IconSvg name="arrows/east-mini" transform="rotate(-90deg)" boxSize={ 5 } ml={ 1 }/>
</Flex> </Flex>
</MenuButton> </MenuButton>
</Skeleton> </Skeleton>
......
import { MenuItem, Icon, chakra, useDisclosure } from '@chakra-ui/react'; import { MenuItem, chakra, useDisclosure } from '@chakra-ui/react';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
...@@ -6,11 +6,11 @@ import React from 'react'; ...@@ -6,11 +6,11 @@ import React from 'react';
import type { Address } from 'types/api/address'; import type { Address } from 'types/api/address';
import type { Transaction } from 'types/api/transaction'; import type { Transaction } from 'types/api/transaction';
import iconPrivateTags from 'icons/privattags.svg';
import { getResourceKey } from 'lib/api/useApiQuery'; import { getResourceKey } from 'lib/api/useApiQuery';
import getPageType from 'lib/mixpanel/getPageType'; import getPageType from 'lib/mixpanel/getPageType';
import AddressModal from 'ui/privateTags/AddressModal/AddressModal'; import AddressModal from 'ui/privateTags/AddressModal/AddressModal';
import TransactionModal from 'ui/privateTags/TransactionModal/TransactionModal'; import TransactionModal from 'ui/privateTags/TransactionModal/TransactionModal';
import IconSvg from 'ui/shared/IconSvg';
interface Props { interface Props {
className?: string; className?: string;
...@@ -61,7 +61,7 @@ const PrivateTagMenuItem = ({ className, hash, onBeforeClick, type = 'address' } ...@@ -61,7 +61,7 @@ const PrivateTagMenuItem = ({ className, hash, onBeforeClick, type = 'address' }
return ( return (
<> <>
<MenuItem className={ className } onClick={ handleClick }> <MenuItem className={ className } onClick={ handleClick }>
<Icon as={ iconPrivateTags } boxSize={ 6 } mr={ 2 }/> <IconSvg name="privattags" boxSize={ 6 } mr={ 2 }/>
<span>Add private tag</span> <span>Add private tag</span>
</MenuItem> </MenuItem>
{ type === 'tx' ? { type === 'tx' ?
......
import { MenuItem, Icon, chakra } from '@chakra-ui/react'; import { MenuItem, chakra } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import iconPublicTags from 'icons/publictags.svg'; import IconSvg from 'ui/shared/IconSvg';
interface Props { interface Props {
className?: string; className?: string;
...@@ -23,7 +23,7 @@ const PublicTagMenuItem = ({ className, hash, onBeforeClick }: Props) => { ...@@ -23,7 +23,7 @@ const PublicTagMenuItem = ({ className, hash, onBeforeClick }: Props) => {
return ( return (
<MenuItem className={ className }onClick={ handleClick }> <MenuItem className={ className }onClick={ handleClick }>
<Icon as={ iconPublicTags } boxSize={ 6 } mr={ 2 }/> <IconSvg name="publictags" boxSize={ 6 } mr={ 2 }/>
<span>Add public tag</span> <span>Add public tag</span>
</MenuItem> </MenuItem>
); );
......
import { MenuItem, Icon, chakra, useDisclosure } from '@chakra-ui/react'; import { MenuItem, chakra, useDisclosure } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import type { Route } from 'nextjs-routes'; import type { Route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import iconEdit from 'icons/edit.svg';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import useHasAccount from 'lib/hooks/useHasAccount'; import useHasAccount from 'lib/hooks/useHasAccount';
import { PAGE_TYPE_DICT } from 'lib/mixpanel/getPageType'; import { PAGE_TYPE_DICT } from 'lib/mixpanel/getPageType';
import AddressVerificationModal from 'ui/addressVerification/AddressVerificationModal'; import AddressVerificationModal from 'ui/addressVerification/AddressVerificationModal';
import IconSvg from 'ui/shared/IconSvg';
interface Props { interface Props {
className?: string; className?: string;
...@@ -61,7 +61,7 @@ const TokenInfoMenuItem = ({ className, hash, onBeforeClick }: Props) => { ...@@ -61,7 +61,7 @@ const TokenInfoMenuItem = ({ className, hash, onBeforeClick }: Props) => {
router.push({ pathname: '/account/verified-addresses' }); router.push({ pathname: '/account/verified-addresses' });
}, [ router ]); }, [ router ]);
const icon = <Icon as={ iconEdit } boxSize={ 6 } mr={ 2 } p={ 1 }/>; const icon = <IconSvg name="edit" boxSize={ 6 } mr={ 2 } p={ 1 }/>;
const content = (() => { const content = (() => {
if (!verifiedAddressesQuery.data?.verifiedAddresses.find(({ contractAddress }) => contractAddress.toLowerCase() === hash.toLowerCase())) { if (!verifiedAddressesQuery.data?.verifiedAddresses.find(({ contractAddress }) => contractAddress.toLowerCase() === hash.toLowerCase())) {
......
import { import {
Icon,
useColorModeValue, useColorModeValue,
chakra, chakra,
Button, Button,
...@@ -7,7 +6,7 @@ import { ...@@ -7,7 +6,7 @@ import {
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import infoIcon from 'icons/info.svg'; import IconSvg from 'ui/shared/IconSvg';
interface Props { interface Props {
isOpen?: boolean; isOpen?: boolean;
...@@ -39,8 +38,8 @@ const AdditionalInfoButton = ({ isOpen, onClick, className, isLoading }: Props, ...@@ -39,8 +38,8 @@ const AdditionalInfoButton = ({ isOpen, onClick, className, isLoading }: Props,
cursor="pointer" cursor="pointer"
flexShrink={ 0 } flexShrink={ 0 }
> >
<Icon <IconSvg
as={ infoIcon } name="info"
boxSize={ 5 } boxSize={ 5 }
color="link" color="link"
_hover={{ color: 'link_hovered' }} _hover={{ color: 'link_hovered' }}
......
import { Box, HStack, Flex, Skeleton, useColorModeValue } from '@chakra-ui/react'; import { Box, HStack, Flex, Skeleton, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import keyIcon from 'icons/key.svg';
import Icon from 'ui/shared/chakra/Icon';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import IconSvg from 'ui/shared/IconSvg';
interface Props { interface Props {
apiKey: string; apiKey: string;
...@@ -14,7 +13,7 @@ interface Props { ...@@ -14,7 +13,7 @@ interface Props {
const ApiKeySnippet = ({ apiKey, name, isLoading }: Props) => { const ApiKeySnippet = ({ apiKey, name, isLoading }: Props) => {
return ( return (
<HStack spacing={ 2 } alignItems="start"> <HStack spacing={ 2 } alignItems="start">
<Icon as={ keyIcon } boxSize={ 6 } color={ useColorModeValue('gray.500', 'gray.400') } isLoading={ isLoading }/> <IconSvg name="key" boxSize={ 6 } color={ useColorModeValue('gray.500', 'gray.400') } isLoading={ isLoading }/>
<Box> <Box>
<Flex alignItems={{ base: 'flex-start', lg: 'center' }}> <Flex alignItems={{ base: 'flex-start', lg: 'center' }}>
<Skeleton isLoaded={ !isLoading } display="inline-block" fontWeight={ 600 } mr={ 1 }> <Skeleton isLoaded={ !isLoading } display="inline-block" fontWeight={ 600 } mr={ 1 }>
......
import { Icon } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import icon404 from 'icons/error-pages/404.svg'; import type { IconName } from 'ui/shared/IconSvg';
import icon422 from 'icons/error-pages/422.svg'; import IconSvg from 'ui/shared/IconSvg';
import icon429 from 'icons/error-pages/429.svg';
import icon500 from 'icons/error-pages/500.svg';
const ICONS: Record<string, React.FunctionComponent<React.SVGAttributes<SVGElement>> > = { const ICONS: Record<string, IconName> = {
'404': icon404, '404': 'error-pages/404',
'422': icon422, '422': 'error-pages/422',
'429': icon429, '429': 'error-pages/429',
'500': icon500, '500': 'error-pages/500',
}; };
interface Props { interface Props {
...@@ -18,7 +15,7 @@ interface Props { ...@@ -18,7 +15,7 @@ interface Props {
} }
const AppErrorIcon = ({ statusCode }: Props) => { const AppErrorIcon = ({ statusCode }: Props) => {
return <Icon as={ ICONS[String(statusCode)] || ICONS['500'] } width="200px" height="auto" color="text"/>; return <IconSvg name={ ICONS[String(statusCode)] || ICONS['500'] } width="200px" height="100px" color="text"/>;
}; };
export default AppErrorIcon; export default AppErrorIcon;
/* eslint-disable max-len */ /* eslint-disable max-len */
import { Box, OrderedList, ListItem, Icon, useColorModeValue, Flex } from '@chakra-ui/react'; import { Box, OrderedList, ListItem, useColorModeValue, Flex } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import txIcon from 'icons/transactions.svg'; import IconSvg from 'ui/shared/IconSvg';
import AppErrorTitle from '../AppErrorTitle'; import AppErrorTitle from '../AppErrorTitle';
...@@ -18,7 +18,7 @@ const AppErrorInvalidTxHash = () => { ...@@ -18,7 +18,7 @@ const AppErrorInvalidTxHash = () => {
<> <>
<Box p={ 4 } borderColor={ snippet.borderColor } borderRadius="md" w="230px" borderWidth="1px"> <Box p={ 4 } borderColor={ snippet.borderColor } borderRadius="md" w="230px" borderWidth="1px">
<Flex alignItems="center" pb={ 4 } borderBottomWidth="1px" borderColor={ snippet.borderColor }> <Flex alignItems="center" pb={ 4 } borderBottomWidth="1px" borderColor={ snippet.borderColor }>
<Icon as={ txIcon } boxSize={ 8 } color={ snippet.iconColor } bgColor={ snippet.iconBg } p={ 1 } borderRadius="md"/> <IconSvg name="transactions" boxSize={ 8 } color={ snippet.iconColor } bgColor={ snippet.iconBg } p={ 1 } borderRadius="md"/>
<Box ml={ 2 }> <Box ml={ 2 }>
<Box w="125px" h="8px" borderRadius="full" bgColor={ snippet.iconBg }/> <Box w="125px" h="8px" borderRadius="full" bgColor={ snippet.iconBg }/>
<Box w="30px" h="8px" borderRadius="full" bgColor={ snippet.borderColor } mt={ 1.5 }/> <Box w="30px" h="8px" borderRadius="full" bgColor={ snippet.borderColor } mt={ 1.5 }/>
......
import { chakra, Icon, IconButton, useColorModeValue } from '@chakra-ui/react'; import { chakra, IconButton, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import errorIcon from 'icons/status/error.svg'; import IconSvg from 'ui/shared/IconSvg';
interface Props { interface Props {
onClick: (e: React.SyntheticEvent) => void; onClick: (e: React.SyntheticEvent) => void;
...@@ -21,7 +21,7 @@ const ClearButton = ({ onClick, isDisabled, className }: Props) => { ...@@ -21,7 +21,7 @@ const ClearButton = ({ onClick, isDisabled, className }: Props) => {
aria-label="Clear input" aria-label="Clear input"
title="Clear input" title="Clear input"
boxSize={ 6 } boxSize={ 6 }
icon={ <Icon as={ errorIcon } boxSize={ 3 } color={ iconColor } focusable={ false } _hover={{ color: iconColorHover }}/> } icon={ <IconSvg name="status/error" boxSize={ 3 } color={ iconColor } _hover={{ color: iconColorHover }}/> }
size="sm" size="sm"
onClick={ onClick } onClick={ onClick }
/> />
......
import { IconButton, Tooltip, useClipboard, chakra, useDisclosure, Skeleton } from '@chakra-ui/react'; import { IconButton, Tooltip, useClipboard, chakra, useDisclosure, Skeleton } from '@chakra-ui/react';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import CopyIcon from 'icons/copy.svg'; import IconSvg from 'ui/shared/IconSvg';
export interface Props { export interface Props {
text: string; text: string;
...@@ -31,7 +31,7 @@ const CopyToClipboard = ({ text, className, isLoading }: Props) => { ...@@ -31,7 +31,7 @@ const CopyToClipboard = ({ text, className, isLoading }: Props) => {
<Tooltip label={ copied ? 'Copied' : 'Copy to clipboard' } isOpen={ isOpen || copied }> <Tooltip label={ copied ? 'Copied' : 'Copy to clipboard' } isOpen={ isOpen || copied }>
<IconButton <IconButton
aria-label="copy" aria-label="copy"
icon={ <CopyIcon/> } icon={ <IconSvg name="copy" boxSize={ 5 }/> }
w="20px" w="20px"
h="20px" h="20px"
color="gray.400" color="gray.400"
......
import { Box, Heading, Icon, Text } from '@chakra-ui/react'; import { Box, Heading, Text } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import emptyIcon from 'icons/empty_search_result.svg'; import IconSvg from 'ui/shared/IconSvg';
interface Props { interface Props {
text: string; text: string;
...@@ -14,8 +14,8 @@ const EmptySearchResult = ({ text }: Props) => { ...@@ -14,8 +14,8 @@ const EmptySearchResult = ({ text }: Props) => {
flexDirection="column" flexDirection="column"
alignItems="center" alignItems="center"
> >
<Icon <IconSvg
as={ emptyIcon } name="empty_search_result"
boxSize={ 60 } boxSize={ 60 }
display="block" display="block"
/> />
......
...@@ -2,7 +2,7 @@ import type { TooltipProps } from '@chakra-ui/react'; ...@@ -2,7 +2,7 @@ import type { TooltipProps } from '@chakra-ui/react';
import { chakra, IconButton, Tooltip, useDisclosure, Skeleton } from '@chakra-ui/react'; import { chakra, IconButton, Tooltip, useDisclosure, Skeleton } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import InfoIcon from 'icons/info.svg'; import IconSvg from 'ui/shared/IconSvg';
interface Props { interface Props {
label: string | React.ReactNode; label: string | React.ReactNode;
...@@ -21,7 +21,7 @@ const Hint = ({ label, className, tooltipProps, isLoading }: Props) => { ...@@ -21,7 +21,7 @@ const Hint = ({ label, className, tooltipProps, isLoading }: Props) => {
}, [ onToggle ]); }, [ onToggle ]);
if (isLoading) { if (isLoading) {
return <Skeleton boxSize={ 5 } borderRadius="sm"/>; return <Skeleton className={ className } boxSize={ 5 } borderRadius="sm"/>;
} }
return ( return (
...@@ -35,7 +35,7 @@ const Hint = ({ label, className, tooltipProps, isLoading }: Props) => { ...@@ -35,7 +35,7 @@ const Hint = ({ label, className, tooltipProps, isLoading }: Props) => {
<IconButton <IconButton
colorScheme="none" colorScheme="none"
aria-label="hint" aria-label="hint"
icon={ <InfoIcon/> } icon={ <IconSvg name="info" w="100%" h="100%"/> }
boxSize={ 5 } boxSize={ 5 }
variant="simple" variant="simple"
display="inline-block" display="inline-block"
......
import type { HTMLChakraProps } from '@chakra-ui/react';
import { Skeleton, chakra } from '@chakra-ui/react';
import { type IconName } from 'public/icons/name';
import React from 'react';
export const href = '/icons/sprite.svg';
export { IconName };
interface Props extends HTMLChakraProps<'div'> {
name: IconName;
isLoading?: boolean;
}
const IconSvg = ({ name, isLoading, ...props }: Props) => {
return (
<Skeleton isLoaded={ !isLoading } display="inline-block" { ...props }>
<chakra.svg w="100%" h="100%">
<use href={ `${ href }#${ name }` }/>
</chakra.svg>
</Skeleton>
);
};
export default IconSvg;
import type { ChakraProps } from '@chakra-ui/react'; import type { ChakraProps } from '@chakra-ui/react';
import { Link, Icon, chakra, Box, Skeleton, useColorModeValue } from '@chakra-ui/react'; import { Link, chakra, Box, Skeleton, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import arrowIcon from 'icons/arrows/north-east.svg'; import IconSvg from 'ui/shared/IconSvg';
interface Props { interface Props {
href: string; href: string;
...@@ -59,7 +59,7 @@ const LinkExternal = ({ href, children, className, isLoading, variant }: Props) ...@@ -59,7 +59,7 @@ const LinkExternal = ({ href, children, className, isLoading, variant }: Props)
return ( return (
<Link className={ className } { ...styleProps } target="_blank" href={ href }> <Link className={ className } { ...styleProps } target="_blank" href={ href }>
{ children } { children }
<Icon as={ arrowIcon } boxSize={ 4 } verticalAlign="middle" color="gray.400"/> <IconSvg name="arrows/north-east" boxSize={ 4 } verticalAlign="middle" color="gray.400" flexShrink={ 0 }/>
</Link> </Link>
); );
}; };
......
import { Button, Icon } from '@chakra-ui/react'; import { Button } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import config from 'configs/app'; import config from 'configs/app';
...@@ -7,6 +7,7 @@ import * as mixpanel from 'lib/mixpanel/index'; ...@@ -7,6 +7,7 @@ import * as mixpanel from 'lib/mixpanel/index';
import useAddOrSwitchChain from 'lib/web3/useAddOrSwitchChain'; import useAddOrSwitchChain from 'lib/web3/useAddOrSwitchChain';
import useProvider from 'lib/web3/useProvider'; import useProvider from 'lib/web3/useProvider';
import { WALLETS_INFO } from 'lib/web3/wallets'; import { WALLETS_INFO } from 'lib/web3/wallets';
import IconSvg from 'ui/shared/IconSvg';
const feature = config.features.web3Wallet; const feature = config.features.web3Wallet;
...@@ -55,7 +56,7 @@ const NetworkAddToWallet = () => { ...@@ -55,7 +56,7 @@ const NetworkAddToWallet = () => {
return ( return (
<Button variant="outline" size="sm" onClick={ handleClick }> <Button variant="outline" size="sm" onClick={ handleClick }>
<Icon as={ WALLETS_INFO[wallet].icon } boxSize={ 5 } mr={ 2 }/> <IconSvg name={ WALLETS_INFO[wallet].icon } boxSize={ 5 } mr={ 2 }/>
Add { config.chain.name } Add { config.chain.name }
</Button> </Button>
); );
......
import { Flex, Button, Icon, chakra, Popover, PopoverTrigger, PopoverBody, PopoverContent, useDisclosure } from '@chakra-ui/react'; import { Flex, Button, chakra, Popover, PopoverTrigger, PopoverBody, PopoverContent, useDisclosure } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { NetworkExplorer as TNetworkExplorer } from 'types/networks'; import type { NetworkExplorer as TNetworkExplorer } from 'types/networks';
import config from 'configs/app'; import config from 'configs/app';
import arrowIcon from 'icons/arrows/east-mini.svg';
import explorerIcon from 'icons/explorer.svg';
import stripTrailingSlash from 'lib/stripTrailingSlash'; import stripTrailingSlash from 'lib/stripTrailingSlash';
import IconSvg from 'ui/shared/IconSvg';
import LinkExternal from 'ui/shared/LinkExternal'; import LinkExternal from 'ui/shared/LinkExternal';
interface Props { interface Props {
...@@ -46,8 +45,8 @@ const NetworkExplorers = ({ className, type, pathParam }: Props) => { ...@@ -46,8 +45,8 @@ const NetworkExplorers = ({ className, type, pathParam }: Props) => {
h="32px" h="32px"
flexShrink={ 0 } flexShrink={ 0 }
> >
<Icon as={ explorerIcon } boxSize={ 5 }/> <IconSvg name="explorer" boxSize={ 5 }/>
<Icon as={ arrowIcon } transform={ isOpen ? 'rotate(90deg)' : 'rotate(-90deg)' } transitionDuration="faster" boxSize={ 5 }/> <IconSvg name="arrows/east-mini" transform={ isOpen ? 'rotate(90deg)' : 'rotate(-90deg)' } transitionDuration="faster" boxSize={ 5 }/>
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent w="240px"> <PopoverContent w="240px">
......
import { Heading, Flex, Tooltip, Icon, Link, chakra, Skeleton, useDisclosure } from '@chakra-ui/react'; import { Heading, Flex, Tooltip, Link, chakra, Skeleton, useDisclosure } from '@chakra-ui/react';
import _debounce from 'lodash/debounce'; import _debounce from 'lodash/debounce';
import React from 'react'; import React from 'react';
import eastArrowIcon from 'icons/arrows/east.svg';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import TextAd from 'ui/shared/ad/TextAd'; import TextAd from 'ui/shared/ad/TextAd';
import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
type BackLinkProp = { label: string; url: string } | { label: string; onClick: () => void }; type BackLinkProp = { label: string; url: string } | { label: string; onClick: () => void };
...@@ -32,7 +32,7 @@ const BackLink = (props: BackLinkProp & { isLoading?: boolean }) => { ...@@ -32,7 +32,7 @@ const BackLink = (props: BackLinkProp & { isLoading?: boolean }) => {
return <Skeleton boxSize={ 6 } display="inline-block" borderRadius="base" mr={ 3 } my={ 2 } verticalAlign="text-bottom" isLoaded={ !props.isLoading }/>; return <Skeleton boxSize={ 6 } display="inline-block" borderRadius="base" mr={ 3 } my={ 2 } verticalAlign="text-bottom" isLoaded={ !props.isLoading }/>;
} }
const icon = <Icon as={ eastArrowIcon } boxSize={ 6 } transform="rotate(180deg)" margin="auto" color="gray.400"/>; const icon = <IconSvg name="arrows/east" boxSize={ 6 } transform="rotate(180deg)" margin="auto" color="gray.400"/>;
if ('url' in props) { if ('url' in props) {
return ( return (
......
import { Icon } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { TokenInfo } from 'types/api/token'; import type { TokenInfo } from 'types/api/token';
import iconVerifiedToken from 'icons/verified_token.svg';
import * as addressMock from 'mocks/address/address'; import * as addressMock from 'mocks/address/address';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import * as TokenEntity from 'ui/shared/entities/token/TokenEntity'; import * as TokenEntity from 'ui/shared/entities/token/TokenEntity';
import EntityTags from 'ui/shared/EntityTags'; import EntityTags from 'ui/shared/EntityTags';
import IconSvg from 'ui/shared/IconSvg';
import NetworkExplorers from 'ui/shared/NetworkExplorers'; import NetworkExplorers from 'ui/shared/NetworkExplorers';
import PageTitle from '../PageTitle'; import PageTitle from '../PageTitle';
...@@ -33,7 +32,7 @@ const DefaultView = () => { ...@@ -33,7 +32,7 @@ const DefaultView = () => {
const contentAfter = ( const contentAfter = (
<> <>
<Icon as={ iconVerifiedToken } color="green.500" boxSize={ 6 } cursor="pointer"/> <IconSvg name="verified_token" color="green.500" boxSize={ 6 } cursor="pointer"/>
<EntityTags <EntityTags
tagsBefore={ [ tagsBefore={ [
{ label: 'example', display_name: 'Example label' }, { label: 'example', display_name: 'Example label' },
......
/* eslint-disable max-len */ /* eslint-disable max-len */
import { Icon } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { TokenInfo } from 'types/api/token'; import type { TokenInfo } from 'types/api/token';
import iconVerifiedToken from 'icons/verified_token.svg';
import { publicTag, privateTag, watchlistName } from 'mocks/address/tag'; import { publicTag, privateTag, watchlistName } from 'mocks/address/tag';
import * as TokenEntity from 'ui/shared/entities/token/TokenEntity'; import * as TokenEntity from 'ui/shared/entities/token/TokenEntity';
import EntityTags from 'ui/shared/EntityTags'; import EntityTags from 'ui/shared/EntityTags';
import IconSvg from 'ui/shared/IconSvg';
import NetworkExplorers from 'ui/shared/NetworkExplorers'; import NetworkExplorers from 'ui/shared/NetworkExplorers';
import PageTitle from '../PageTitle'; import PageTitle from '../PageTitle';
...@@ -28,7 +27,7 @@ const LongNameAndManyTags = () => { ...@@ -28,7 +27,7 @@ const LongNameAndManyTags = () => {
const contentAfter = ( const contentAfter = (
<> <>
<Icon as={ iconVerifiedToken } color="green.500" boxSize={ 6 } cursor="pointer"/> <IconSvg name="verified_token" color="green.500" boxSize={ 6 } cursor="pointer" flexShrink={ 0 }/>
<EntityTags <EntityTags
data={{ data={{
private_tags: [ privateTag ], private_tags: [ privateTag ],
......
import { Box, Icon, IconButton, chakra, Tooltip, Flex, Skeleton } from '@chakra-ui/react'; import { Box, IconButton, chakra, Tooltip, Flex, Skeleton } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import eastArrow from 'icons/arrows/east-mini.svg'; import IconSvg from 'ui/shared/IconSvg';
interface Props { interface Props {
className?: string; className?: string;
...@@ -36,7 +36,7 @@ const PrevNext = ({ className, onClick, prevLabel, nextLabel, isPrevDisabled, is ...@@ -36,7 +36,7 @@ const PrevNext = ({ className, onClick, prevLabel, nextLabel, isPrevDisabled, is
<Tooltip label={ prevLabel }> <Tooltip label={ prevLabel }>
<IconButton <IconButton
aria-label="prev" aria-label="prev"
icon={ <Icon as={ eastArrow } boxSize={ 6 }/> } icon={ <IconSvg name="arrows/east-mini" boxSize={ 6 }/> }
h={ 6 } h={ 6 }
borderRadius="sm" borderRadius="sm"
variant="subtle" variant="subtle"
...@@ -48,7 +48,7 @@ const PrevNext = ({ className, onClick, prevLabel, nextLabel, isPrevDisabled, is ...@@ -48,7 +48,7 @@ const PrevNext = ({ className, onClick, prevLabel, nextLabel, isPrevDisabled, is
<Tooltip label={ nextLabel }> <Tooltip label={ nextLabel }>
<IconButton <IconButton
aria-label="next" aria-label="next"
icon={ <Icon as={ eastArrow }boxSize={ 6 } transform="rotate(180deg)"/> } icon={ <IconSvg name="arrows/east-mini" boxSize={ 6 } transform="rotate(180deg)"/> }
h={ 6 } h={ 6 }
borderRadius="sm" borderRadius="sm"
variant="subtle" variant="subtle"
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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