Skip to content

Commit

Permalink
Merge pull request #1452 from blockscout/tom2drum/issue-1414
Browse files Browse the repository at this point in the history
migrate icons to SVG sprite
  • Loading branch information
tom2drum authored Dec 27, 2023
2 parents 95243dc + 1484bb3 commit 9facb82
Show file tree
Hide file tree
Showing 179 changed files with 1,029 additions and 774 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ const RESTRICTED_MODULES = {
{ 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' },
],
patterns: [
'icons/*',
],
};

module.exports = {
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
/out/
/public/assets/
/public/envs.js
/public/icons/sprite.svg
/public/icons/README.md
/analyze

# production
Expand Down
2 changes: 1 addition & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@
},
{
"type": "npm",
"script": "format-svg",
"script": "svg:format",
"problemMatcher": [],
"label": "format svg",
"detail": "format svg files with svgo",
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ RUN ./collect_envs.sh ./docs/ENVS.md

# Build app for production
RUN yarn build
RUN yarn svg:build-sprite


### FEATURE REPORTER
Expand Down
3 changes: 2 additions & 1 deletion docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:fix` | lint project files with ESLint and automatically fix problems |
| `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** |
| `yarn test:jest` | run all Jest unit tests |
| `yarn test:jest:watch` | run all Jest unit tests in watch mode |
Expand Down
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
98 changes: 43 additions & 55 deletions lib/hooks/useNavItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,6 @@ import React from 'react';
import type { NavItemInternal, NavItem, NavGroupItem } from 'types/client/navigation-items';

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 UserAvatar from 'ui/shared/UserAvatar';

Expand All @@ -50,35 +28,43 @@ export default function useNavItems(): ReturnType {
return React.useMemo(() => {
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',
nextRoute: { pathname: '/accounts' as const },
icon: topAccountsIcon,
icon: 'top-accounts',
isActive: pathname === '/accounts',
} : null;
const blocks = {
const blocks: NavItem | null = {
text: 'Blocks',
nextRoute: { pathname: '/blocks' as const },
icon: blocksIcon,
icon: 'block',
isActive: pathname === '/blocks' || pathname === '/block/[height_or_hash]',
};
const txs = {
const txs: NavItem | null = {
text: 'Transactions',
nextRoute: { pathname: '/txs' as const },
icon: transactionsIcon,
icon: 'transactions',
isActive: pathname === '/txs' || pathname === '/tx/[hash]',
};
const verifiedContracts =
// eslint-disable-next-line max-len
{ text: 'Verified contracts', nextRoute: { pathname: '/verified-contracts' as const }, icon: verifiedIcon, isActive: pathname === '/verified-contracts' };
const verifiedContracts: NavItem | null =
{
text: 'Verified contracts',
nextRoute: { pathname: '/verified-contracts' as const },
icon: 'verified',
isActive: pathname === '/verified-contracts',
};

if (config.features.zkEvmRollup.isEnabled) {
blockchainNavItems = [
[
txs,
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,
Expand All @@ -90,16 +76,16 @@ export default function useNavItems(): ReturnType {
[
txs,
// 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
{ 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,
// 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
{ 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,
Expand All @@ -115,7 +101,7 @@ export default function useNavItems(): ReturnType {
config.features.beaconChain.isEnabled && {
text: 'Withdrawals',
nextRoute: { pathname: '/withdrawals' as const },
icon: withdrawalsIcon,
icon: 'arrows/north-east',
isActive: pathname === '/withdrawals',
},
].filter(Boolean);
Expand All @@ -125,66 +111,66 @@ export default function useNavItems(): ReturnType {
config.features.restApiDocs.isEnabled ? {
text: 'REST API',
nextRoute: { pathname: '/api-docs' as const },
icon: apiDocsIcon,
icon: 'restAPI',
isActive: pathname === '/api-docs',
} : null,
config.features.graphqlApiDocs.isEnabled ? {
text: 'GraphQL',
nextRoute: { pathname: '/graphiql' as const },
icon: graphQLIcon,
icon: 'graphQL',
isActive: pathname === '/graphiql',
} : null,
!config.UI.sidebar.hiddenLinks?.rpc_api && {
text: 'RPC API',
icon: rpcIcon,
icon: 'RPC',
url: 'https://docs.blockscout.com/for-users/api/rpc-endpoints',
},
!config.UI.sidebar.hiddenLinks?.eth_rpc_api && {
text: 'Eth RPC API',
icon: rpcIcon,
icon: 'RPC',
url: ' https://docs.blockscout.com/for-users/api/eth-rpc',
},
].filter(Boolean);

const mainNavItems: ReturnType['mainNavItems'] = [
{
text: 'Blockchain',
icon: globeIcon,
icon: 'globe-b',
isActive: blockchainNavItems.flat().some(item => isInternalItem(item) && item.isActive),
subItems: blockchainNavItems,
},
{
text: 'Tokens',
nextRoute: { pathname: '/tokens' as const },
icon: tokensIcon,
icon: 'token',
isActive: pathname.startsWith('/token'),
},
config.features.marketplace.isEnabled ? {
text: 'Apps',
nextRoute: { pathname: '/apps' as const },
icon: appsIcon,
icon: 'apps',
isActive: pathname.startsWith('/app'),
} : null,
config.features.stats.isEnabled ? {
text: 'Charts & stats',
nextRoute: { pathname: '/stats' as const },
icon: statsIcon,
icon: 'stats',
isActive: pathname === '/stats',
} : null,
apiNavItems.length > 0 && {
text: 'API',
icon: apiDocsIcon,
icon: 'restAPI',
isActive: apiNavItems.some(item => isInternalItem(item) && item.isActive),
subItems: apiNavItems,
},
{
text: 'Other',
icon: gearIcon,
icon: 'gear',
subItems: [
{
text: 'Verify contract',
nextRoute: { pathname: '/contract-verification' as const },
icon: verifyContractIcon,
icon: 'verify-contract',
isActive: pathname.startsWith('/contract-verification'),
},
...config.UI.sidebar.otherLinks,
Expand All @@ -196,35 +182,37 @@ export default function useNavItems(): ReturnType {
{
text: 'Watch list',
nextRoute: { pathname: '/account/watchlist' as const },
icon: watchlistIcon,
icon: 'watchlist',
isActive: pathname === '/account/watchlist',
},
{
text: 'Private tags',
nextRoute: { pathname: '/account/tag-address' as const },
icon: privateTagIcon,
icon: 'privattags',
isActive: pathname === '/account/tag-address',
},
{
text: 'Public tags',
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',
nextRoute: { pathname: '/account/api-key' as const },
icon: apiKeysIcon, isActive: pathname === '/account/api-key',
icon: 'API',
isActive: pathname === '/account/api-key',
},
{
text: 'Custom ABI',
nextRoute: { pathname: '/account/custom-abi' as const },
icon: abiIcon,
icon: 'ABI',
isActive: pathname === '/account/custom-abi',
},
config.features.addressVerification.isEnabled && {
text: 'Verified addrs',
nextRoute: { pathname: '/account/verified-addresses' as const },
icon: verifiedIcon,
icon: 'verified',
isActive: pathname === '/account/verified-addresses',
},
].filter(Boolean);
Expand Down
10 changes: 3 additions & 7 deletions lib/web3/wallets.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
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> = {
metamask: {
name: 'MetaMask',
icon: metamaskIcon,
icon: 'wallets/metamask',
},
coinbase: {
name: 'Coinbase Wallet',
icon: coinbaseIcon,
icon: 'wallets/coinbase',
},
token_pocket: {
name: 'TokenPocket',
icon: tokenPocketIcon,
icon: 'wallets/token-pocket',
},
};
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"lint:tsc": "tsc -p ./tsconfig.json",
"lint:envs-validator:test": "cd ./deploy/tools/envs-validator && ./test.sh",
"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: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",
Expand Down Expand Up @@ -136,6 +137,7 @@
"lint-staged": ">=10",
"mockdate": "^3.0.5",
"style-loader": "^3.3.1",
"svg-icons-cli": "^0.0.5",
"svgo": "^2.8.0",
"ts-jest": "^29.0.3",
"ts-node": "^10.9.1",
Expand Down
3 changes: 3 additions & 0 deletions pages/_document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import React from 'react';
import * as serverTiming from 'nextjs/utils/serverTiming';

import theme from 'theme';
import * as svgSprite from 'ui/shared/IconSvg';

class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext) {
Expand Down Expand Up @@ -48,6 +49,8 @@ class MyDocument extends Document {
<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="mask-icon" href="/favicon/safari-pinned-tab.svg"/>

<link rel="preload" as="image" href={ svgSprite.href }/>
</Head>
<body>
<ColorModeScript initialColorMode={ theme.config.initialColorMode }/>
Expand Down
1 change: 1 addition & 0 deletions playwright/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
<div id="root"></div>
<script type="module" src="/playwright/envs.js"></script>
<script type="module" src="/playwright/index.ts"></script>
<link rel="preload" as="image" href="/public/icons/sprite.svg"/>
</body>
</html>
Loading

0 comments on commit 9facb82

Please sign in to comment.