Commit 3583f6c6 authored by tom's avatar tom

URL for featured networks config

parent abdbd513
/* eslint-disable no-restricted-properties */
import type { FeaturedNetwork, NetworkExplorer } from 'types/networks';
import type { NetworkExplorer } from 'types/networks';
import type { ChainIndicatorId } from 'ui/home/indicators/types';
const getEnvValue = (env: string | undefined) => env?.replaceAll('\'', '"');
......@@ -88,7 +88,7 @@ const config = Object.freeze({
telegram: getEnvValue(process.env.NEXT_PUBLIC_FOOTER_TELEGRAM_LINK),
staking: getEnvValue(process.env.NEXT_PUBLIC_FOOTER_STAKING_LINK),
},
featuredNetworks: parseEnvJson<Array<FeaturedNetwork>>(getEnvValue(process.env.NEXT_PUBLIC_FEATURED_NETWORKS)) || [],
featuredNetworks: getEnvValue(process.env.NEXT_PUBLIC_FEATURED_NETWORKS),
blockScoutVersion: getEnvValue(process.env.NEXT_PUBLIC_BLOCKSCOUT_VERSION),
isAccountSupported: getEnvValue(process.env.NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED) === 'true',
marketplaceConfigUrl: getEnvValue(process.env.NEXT_PUBLIC_MARKETPLACE_CONFIG_URL),
......
# ui config
NEXT_PUBLIC_FEATURED_NETWORKS=[{'title':'Ethereum','url':'https://blockscout.com/eth/mainnet','group':'mainnets','type':'eth_mainnet'},{'title':'Ethereum Classic','url':'https://blockscout.com/etx/mainnet','group':'mainnets','type':'etc_mainnet'},{'title':'Gnosis Chain','url':'https://blockscout.com/xdai/mainnet','group':'mainnets','type':'xdai_mainnet'},{'title':'Astar (EVM)','url':'https://blockscout.com/astar','group':'mainnets','type':'astar'},{'title':'Shiden (EVM)','url':'https://blockscout.com/shiden','group':'mainnets','type':'astar'},{'title':'Klaytn Mainnet (Cypress)','url':'https://klaytn-mainnet.aws-k8s.blockscout.com/','group':'mainnets','type':'klaytn'},{'title':'Goerli','url':'https://blockscout.com/eth/goerli/','group':'testnets','type':'goerli'},{'title':'Optimism Goerli','url':'https://blockscout.com/optimism/goerli/','group':'testnets','type':'optimism_goerli'},{'title':'Optimism Bedrock Alpha','url':'https://blockscout.com/optimism/bedrock-alpha','group':'testnets','type':'optimism_bedrock_alpha'},{'title':'Gnosis Chiado','url':'https://blockscout.com/gnosis/chiado/','group':'testnets','type':'gnosis_chiado'},{'title':'Shibuya (EVM)','url':'https://blockscout.com/shibuya','group':'testnets','type':'shibuya'},{'title':'Optimism Opcraft','url':'https://blockscout.com/optimism/opcraft','group':'other','type':'optimism_opcraft'},{'title':'Optimism on Gnosis Chain','url':'https://blockscout.com/xdai/optimism','group':'other','type':'optimism_gnosis'},{'title':'ARTIS-Σ1','url':'https://blockscout.com/artis/sigma1','group':'other','type':'artis_sigma1'},{'title':'LUKSO L14','url':'https://blockscout.com/lukso/l14','group':'other','type':'lukso_l14'},{'title':'POA','url':'https://blockscout.com/poa/core','group':'other','type':'poa_core'},{'title':'POA Sokol','url':'https://blockscout.com/poa/sokol','group':'other','type':'poa_sokol'}]
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/eth-goerli.json
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/ethereum/goerli/transaction','address':'/ethereum/ethereum/goerli/address'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address'}}]
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d
......
# ui config
NEXT_PUBLIC_FEATURED_NETWORKS=[{'title':'Göerli','url':'https://eth-goerli.blockscout.com/','group':'testnets','type':'goerli'},{'title':'Base Göerli','url':'https://l2-goerli.blockscout.com/','group':'testnets','type':'base_goerli'}]
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/base-goerli.json
NEXT_PUBLIC_NETWORK_EXPLORERS=
NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT=linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62
......
......@@ -11,7 +11,7 @@ NEXT_PUBLIC_FOOTER_TELEGRAM_LINK=https://t.me/poa_network
NEXT_PUBLIC_FOOTER_STAKING_LINK=https://duneanalytics.com/maxaleks/xdai-staking
NEXT_PUBLIC_FOOTER_GITHUB_LINK=https://github.com/blockscout/blockscout
NEXT_PUBLIC_FOOTER_TWITTER_LINK=https://www.twitter.com/blockscoutcom
NEXT_PUBLIC_FEATURED_NETWORKS=[{'title':'Gnosis Chain','url':'https://blockscout.com/xdai/mainnet','group':'mainnets','type':'xdai_mainnet'},{'title':'Optimism on Gnosis Chain','url':'https://blockscout.com/xdai/optimism','group':'mainnets','type':'xdai_optimism'},{'title':'Arbitrum on xDai','url':'https://blockscout.com/xdai/aox','group':'mainnets'},{'title':'Ethereum','url':'https://blockscout.com/eth/mainnet','group':'mainnets','type':'eth_mainnet'},{'title':'Ethereum Classic','url':'https://blockscout.com/etx/mainnet','group':'mainnets','type':'etc_mainnet'},{'title':'POA','url':'https://blockscout.com/poa/core','group':'mainnets','type':'poa_core'},{'title':'RSK','url':'https://blockscout.com/rsk/mainnet','group':'mainnets','type':'rsk_mainnet'},{'title':'Gnosis Chain Testnet','url':'https://blockscout.com/xdai/testnet','group':'testnets','type':'xdai_testnet'},{'title':'POA Sokol','url':'https://blockscout.com/poa/sokol','group':'testnets','type':'poa_sokol'},{'title':'ARTIS Σ1','url':'https://blockscout.com/artis/sigma1','group':'other','type':'artis_sigma1'},{'title':'LUKSO L14','url':'https://blockscout.com/lukso/l14','group':'other','type':'lukso_l14'},{'title':'Astar','url':'https://blockscout.com/astar','group':'other','type':'astar'}]
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/eth-goerli.json
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/transaction','address':'/ethereum/poa/core/address'}}]
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cup']
NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
......
# ui config
NEXT_PUBLIC_FOOTER_TELEGRAM_LINK=https://t.me/poa_network
NEXT_PUBLIC_FOOTER_STAKING_LINK=https://duneanalytics.com/maxaleks/xdai-staking
NEXT_PUBLIC_FEATURED_NETWORKS=[{'title':'Gnosis Chain','url':'https://blockscout.com/xdai/mainnet','group':'mainnets','type':'xdai_mainnet'},{'title':'Optimism on Gnosis Chain','url':'https://blockscout.com/xdai/optimism','group':'mainnets','type':'xdai_optimism'},{'title':'Arbitrum on xDai','url':'https://blockscout.com/xdai/aox','group':'mainnets'},{'title':'Ethereum','url':'https://blockscout.com/eth/mainnet','group':'mainnets','type':'eth_mainnet'},{'title':'Ethereum Classic','url':'https://blockscout.com/etx/mainnet','group':'mainnets','type':'etc_mainnet'},{'title':'POA','url':'https://blockscout.com/poa/core','group':'mainnets','type':'poa_core'},{'title':'RSK','url':'https://blockscout.com/rsk/mainnet','group':'mainnets','type':'rsk_mainnet'},{'title':'Gnosis Chain Testnet','url':'https://blockscout.com/xdai/testnet','group':'testnets','type':'xdai_testnet'},{'title':'POA Sokol','url':'https://blockscout.com/poa/sokol','group':'testnets','type':'poa_sokol'},{'title':'ARTIS Σ1','url':'https://blockscout.com/artis/sigma1','group':'other','type':'artis_sigma1'},{'title':'LUKSO L14','url':'https://blockscout.com/lukso/l14','group':'other','type':'lukso_l14'},{'title':'Astar','url':'https://blockscout.com/astar','group':'other','type':'astar'}]
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/eth-goerli.json
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/transaction','address':'/ethereum/poa/core/address'}}]
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cup']
#NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT='linear-gradient(136.9deg, #235643 1.5%, #16191E 77.77%)'
......@@ -10,8 +10,8 @@ NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-c
NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/poa.svg
# network config
NEXT_PUBLIC_NETWORK_NAME=ZetaChain
NEXT_PUBLIC_NETWORK_SHORT_NAME=ZetaChain
NEXT_PUBLIC_NETWORK_NAME=POA
NEXT_PUBLIC_NETWORK_SHORT_NAME=POA
NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME=poa
NEXT_PUBLIC_NETWORK_ID=99
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=POA
......
......@@ -366,7 +366,7 @@ frontend:
NEXT_PUBLIC_NETWORK_ICON:
_default: https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/base.svg
NEXT_PUBLIC_FEATURED_NETWORKS:
_default: "[{'title':'Göerli','url':'https://eth-goerli.blockscout.com/','group':'testnets','type':'goerli'},{'title':'Base Göerli','url':'https://l2-goerli.blockscout.com/','group':'testnets','type':'base_goerli'}]"
_default: https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/base-goerli.json
NEXT_PUBLIC_API_HOST:
_default: blockscout-optimism-goerli.test.aws-k8s.blockscout.com
NEXT_PUBLIC_APP_HOST:
......
......@@ -306,7 +306,7 @@ frontend:
environment:
# ui config
NEXT_PUBLIC_FEATURED_NETWORKS:
_default: "[{'title':'Gnosis Chain','url':'https://blockscout.com/xdai/mainnet','group':'mainnets','type':'xdai_mainnet'},{'title':'Optimism on Gnosis Chain','url':'https://blockscout.com/xdai/optimism','group':'mainnets','type':'xdai_optimism'},{'title':'Arbitrum on xDai','url':'https://blockscout.com/xdai/aox','group':'mainnets'},{'title':'Ethereum','url':'https://blockscout.com/eth/mainnet','group':'mainnets','type':'eth_mainnet'},{'title':'Ethereum Classic','url':'https://blockscout.com/etx/mainnet','group':'mainnets','type':'etc_mainnet'},{'title':'POA','url':'https://blockscout.com/poa/core','group':'mainnets','type':'poa_core'},{'title':'RSK','url':'https://blockscout.com/rsk/mainnet','group':'mainnets','type':'rsk_mainnet'},{'title':'Gnosis Chain Testnet','url':'https://blockscout.com/xdai/testnet','group':'testnets','type':'xdai_testnet'},{'title':'POA Sokol','url':'https://blockscout.com/poa/sokol','group':'testnets','type':'poa_sokol'},{'title':'ARTIS Σ1','url':'https://blockscout.com/artis/sigma1','group':'other','type':'artis_sigma1'},{'title':'LUKSO L14','url':'https://blockscout.com/lukso/l14','group':'other','type':'lukso_l14'},{'title':'Astar','url':'https://blockscout.com/astar','group':'other','type':'astar'}]"
_default: https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/eth-goerli.json
NEXT_PUBLIC_NETWORK_EXPLORERS:
_default: "[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/ethereum/goerli/transaction','address':'/ethereum/ethereum/goerli/address'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address'}}]"
# network config
......
......@@ -90,7 +90,7 @@ frontend:
NEXT_PUBLIC_NETWORK_ICON:
_default: https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/base.svg
NEXT_PUBLIC_FEATURED_NETWORKS:
_default: "[{'title':'Göerli','url':'https://eth-goerli.blockscout.com/','group':'testnets','type':'goerli'},{'title':'Base Göerli','url':'https://l2-goerli.blockscout.com/','group':'testnets','type':'base_goerli'}]"
_default: https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/base-goerli.json
NEXT_PUBLIC_API_HOST:
_default: blockscout-optimism-goerli.test.aws-k8s.blockscout.com
review: blockscout-optimism-goerli.test.aws-k8s.blockscout.com
......
......@@ -89,7 +89,7 @@ frontend:
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED:
_default: 'true'
NEXT_PUBLIC_FEATURED_NETWORKS:
_default: "[{'title':'Gnosis Chain','url':'https://blockscout.com/xdai/mainnet','group':'mainnets','type':'xdai_mainnet'},{'title':'Optimism on Gnosis Chain','url':'https://blockscout.com/xdai/optimism','group':'mainnets','type':'xdai_optimism'},{'title':'Arbitrum on xDai','url':'https://blockscout.com/xdai/aox','group':'mainnets'},{'title':'Ethereum','url':'https://blockscout.com/eth/mainnet','group':'mainnets','type':'eth_mainnet'},{'title':'Ethereum Classic','url':'https://blockscout.com/etx/mainnet','group':'mainnets','type':'etc_mainnet'},{'title':'POA','url':'https://blockscout.com/poa/core','group':'mainnets','type':'poa_core'},{'title':'RSK','url':'https://blockscout.com/rsk/mainnet','group':'mainnets','type':'rsk_mainnet'},{'title':'Gnosis Chain Testnet','url':'https://blockscout.com/xdai/testnet','group':'testnets','type':'xdai_testnet'},{'title':'POA Sokol','url':'https://blockscout.com/poa/sokol','group':'testnets','type':'poa_sokol'},{'title':'ARTIS Σ1','url':'https://blockscout.com/artis/sigma1','group':'other','type':'artis_sigma1'},{'title':'LUKSO L14','url':'https://blockscout.com/lukso/l14','group':'other','type':'lukso_l14'},{'title':'Astar','url':'https://blockscout.com/astar','group':'other','type':'astar'}]"
_default: https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth-goerli.json
NEXT_PUBLIC_API_HOST:
_default: blockscout.com
review: blockscout-main.test.aws-k8s.blockscout.com
......
......@@ -28,7 +28,7 @@ The app instance could be customized by passing following variables to NodeJS en
| Variable | Type| Description | Is required | Default value | Example value |
| --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_FEATURED_NETWORKS | `Array<FeaturedNetwork>` where `FeaturedNetwork` can have following [properties](#featured-network-configuration-properties) | Configuration of featured networks that will be shown in the network menu | - | - | `[{'title':'Gnosis Chain','url':'https://blockscout.com/xdai/mainnet','group':'mainnets'}]` |
| NEXT_PUBLIC_FEATURED_NETWORKS | `string` | URL of configuration file (`.json` format only) which contains list of featured networks that will be shown in the network menu. See [below](#featured-network-configuration-properties) list of available properties for particular network | - | - | `https://example.com/featured_networks_config.json` |
| NEXT_PUBLIC_BLOCKSCOUT_VERSION | `string` | Current running version of Blockscout (used to display link to release in the footer) | - | - | `v.5.1.0-beta`
| NEXT_PUBLIC_FOOTER_GITHUB_LINK | `string` | Link to Github in the footer | - | - | `https://github.com/blockscout/blockscout` |
| NEXT_PUBLIC_FOOTER_TWITTER_LINK | `string` | Link to Twitter in the footer | - | - | `https://www.twitter.com/blockscoutcom` |
......@@ -90,9 +90,9 @@ For each application, you need to specify the `MarketplaceCategoryId` to which i
| --- | --- | --- | --- | --- | --- |
| title | `string` | Displayed name of the network | yes | - | `Gnosis Chain` |
| url | `string` | Network explorer main page url | yes | - | `https://blockscout.com/xdai/mainnet` |
| group | `mainnets \| testnets \| other` | Indicates in which tab network appears in the menu | yes | - | `mainnets` |
| icon | `string` | Network icon; if not provided, will fallback to icon predefined in the project; if the project doesn't have icon for such network then the common placeholder will be shown; *Note* that icon size should be at least 30px by 30px | - | - | `https://placekitten.com/60/60` |
| type | `string` | Network type (used for matching pre-defined network icon, which is stored in the project). See all possible values here | - | - | `xdai_mainnet` |
| group | `Mainnets \| Testnets \| Other` | Indicates in which tab network appears in the menu | yes | - | `Mainnets` |
| icon | `string` | Network icon; if not provided, the common placeholder will be shown; *Note* that icon size should be at least 60px by 60px | - | - | `https://placekitten.com/60/60` |
| isActive | `boolean` | Pass `true` if item should be shonw as active in the menu | - | - | `true` |
### Network explorer configuration properties
......
import type { FeaturedNetwork } from 'types/networks';
import appConfig from 'configs/app/config';
// for easy .env.example update
// const FEATURED_NETWORKS = JSON.stringify([
// {
// title: 'Ethereum',
// url: 'https://blockscout.com/eth/mainnet',
// group: 'mainnets',
// type: 'eth_mainnet',
// },
// {
// title: 'Ethereum Classic',
// url: 'https://blockscout.com/etx/mainnet',
// group: 'mainnets',
// type: 'etc_mainnet',
// },
// {
// title: 'Gnosis Chain',
// url: 'https://blockscout.com/xdai/mainnet',
// group: 'mainnets',
// type: 'xdai_mainnet',
// },
// {
// title: 'Astar (EVM)',
// url: 'https://blockscout.com/astar',
// group: 'mainnets',
// type: 'astar',
// },
// {
// title: 'Shiden (EVM)',
// url: 'https://blockscout.com/shiden',
// group: 'mainnets',
// type: 'astar',
// },
// {
// title: 'Klaytn Mainnet (Cypress)',
// url: 'https://klaytn-mainnet.aws-k8s.blockscout.com/',
// group: 'mainnets',
// type: 'klaytn',
// },
// {
// title: 'Goerli',
// url: 'https://blockscout.com/eth/goerli/',
// group: 'testnets',
// type: 'goerli',
// },
// {
// title: 'Optimism Goerli',
// url: 'https://blockscout.com/optimism/goerli/',
// group: 'testnets',
// type: 'optimism_goerli',
// },
// {
// title: 'Optimism Bedrock Alpha',
// url: 'https://blockscout.com/optimism/bedrock-alpha',
// group: 'testnets',
// type: 'optimism_bedrock_alpha',
// },
// {
// title: 'Gnosis Chiado',
// url: 'https://blockscout.com/gnosis/chiado/',
// group: 'testnets',
// type: 'gnosis_chiado',
// },
// {
// title: 'Shibuya (EVM)',
// url: 'https://blockscout.com/shibuya',
// group: 'testnets',
// type: 'shibuya',
// },
// {
// title: 'Optimism Opcraft',
// url: 'https://blockscout.com/optimism/opcraft',
// group: 'other',
// type: 'optimism_opcraft',
// },
// {
// title: 'Optimism on Gnosis Chain',
// url: 'https://blockscout.com/xdai/optimism',
// group: 'other',
// type: 'optimism_gnosis',
// },
// {
// title: 'ARTIS-Σ1',
// url: 'https://blockscout.com/artis/sigma1',
// group: 'other',
// type: 'artis_sigma1',
// },
// {
// title: 'LUKSO L14',
// url: 'https://blockscout.com/lukso/l14',
// group: 'other',
// type: 'lukso_l14',
// },
// {
// title: 'POA',
// url: 'https://blockscout.com/poa/core',
// group: 'other',
// type: 'poa_core',
// },
// {
// title: 'POA Sokol',
// url: 'https://blockscout.com/poa/sokol',
// group: 'other',
// type: 'poa_sokol',
// },
// ]).replaceAll('"', '\'');
const featuredNetworks: Array<FeaturedNetwork> = (() => {
return appConfig.featuredNetworks.map((network) => ({
...network,
icon: network.icon,
}));
})();
export default featuredNetworks;
import type { FeaturedNetwork } from 'types/networks';
const FEATURED_NETWORKS: Array<FeaturedNetwork> = [
{ title: 'Gnosis Chain', url: 'https://blockscout.com/xdai/mainnet', group: 'mainnets', type: 'xdai_mainnet' },
{ title: 'Arbitrum on xDai', url: 'https://blockscout.com/xdai/aox', group: 'mainnets' },
{ title: 'Ethereum', url: 'https://blockscout.com/eth/mainnet', group: 'mainnets', type: 'eth_mainnet' },
{ title: 'Ethereum Classic', url: 'https://blockscout.com/etx/mainnet', group: 'mainnets', type: 'etc_mainnet', icon: 'https://example.com/my-logo.png' },
{ title: 'POA', url: 'https://blockscout.com/poa/core', group: 'mainnets', type: 'poa_core' },
{ title: 'RSK', url: 'https://blockscout.com/rsk/mainnet', group: 'mainnets', type: 'rsk_mainnet' },
{ title: 'Gnosis Chain Testnet', url: 'https://blockscout.com/xdai/testnet', group: 'testnets', type: 'xdai_testnet' },
{ title: 'POA Sokol', url: 'https://blockscout.com/poa/sokol', group: 'testnets', type: 'poa_sokol' },
{ title: 'ARTIS Σ1', url: 'https://blockscout.com/artis/sigma1', group: 'other', type: 'artis_sigma1' },
{ title: 'LUKSO L14', url: 'https://blockscout.com/lukso/l14', group: 'other', type: 'lukso_l14' },
{ title: 'Astar', url: 'https://blockscout.com/astar', group: 'other', type: 'astar' },
{ title: 'Gnosis Chain', url: 'https://blockscout.com/xdai/mainnet', group: 'Mainnets' },
{ title: 'Arbitrum on xDai', url: 'https://blockscout.com/xdai/aox', group: 'Mainnets' },
{ title: 'Ethereum', url: 'https://blockscout.com/eth/mainnet', group: 'Mainnets' },
{ title: 'Ethereum Classic', url: 'https://blockscout.com/etx/mainnet', group: 'Mainnets', icon: 'https://example.com/my-logo.png' },
{ title: 'POA', url: 'https://blockscout.com/poa/core', group: 'Mainnets' },
{ title: 'RSK', url: 'https://blockscout.com/rsk/mainnet', group: 'Mainnets' },
{ title: 'Gnosis Chain Testnet', url: 'https://blockscout.com/xdai/testnet', group: 'Testnets' },
{ title: 'POA Sokol', url: 'https://blockscout.com/poa/sokol', group: 'Testnets' },
{ title: 'ARTIS Σ1', url: 'https://blockscout.com/artis/sigma1', group: 'Other' },
{ title: 'LUKSO L14', url: 'https://blockscout.com/lukso/l14', group: 'Other' },
{ title: 'Astar', url: 'https://blockscout.com/astar', group: 'Other' },
];
export const FEATURED_NETWORKS_MOCK = JSON.stringify(FEATURED_NETWORKS).replaceAll('"', '\'');
import type { FunctionComponent, SVGAttributes } from 'react';
export type NetworkGroup = 'mainnets' | 'testnets' | 'other';
export type PreDefinedNetwork =
| 'xdai_mainnet'
| 'eth_mainnet'
| 'etc_mainnet'
| 'poa_core'
| 'rsk_mainnet'
| 'xdai_testnet'
| 'poa_sokol'
| 'artis_sigma1'
| 'lukso_l14'
| 'astar'
| 'shiden'
| 'shibuya'
| 'optimism'
| 'goerli'
| 'base_goerli'
| 'zetachain'
| 'li-fi'
| 'gnosis'
| 'rootstock'
| 'tombscout'
;
export type NetworkGroup = 'Mainnets' | 'Testnets' | 'Other';
export interface FeaturedNetwork {
title: string;
url: string;
group: NetworkGroup;
icon?: FunctionComponent<SVGAttributes<SVGElement>> | string;
type?: PreDefinedNetwork;
icon?: string;
isActive?: boolean;
}
......
......@@ -8,20 +8,21 @@ import NavigationMobile from 'ui/snippets/navigation/NavigationMobile';
import NetworkLogo from 'ui/snippets/networkMenu/NetworkLogo';
import NetworkMenuButton from 'ui/snippets/networkMenu/NetworkMenuButton';
import NetworkMenuContentMobile from 'ui/snippets/networkMenu/NetworkMenuContentMobile';
import useNetworkMenu from 'ui/snippets/networkMenu/useNetworkMenu';
const Burger = () => {
const iconColor = useColorModeValue('gray.600', 'white');
const { isOpen, onOpen, onClose } = useDisclosure();
const [ isNetworkMenuOpened, setNetworkMenuVisibility ] = React.useState(false);
const networkMenu = useNetworkMenu();
const handleNetworkMenuButtonClick = React.useCallback(() => {
setNetworkMenuVisibility((flag) => !flag);
}, []);
networkMenu.onToggle();
}, [ networkMenu ]);
const handleNetworkLogoClick = React.useCallback((event: React.SyntheticEvent) => {
isNetworkMenuOpened && event.preventDefault();
setNetworkMenuVisibility(false);
}, [ isNetworkMenuOpened ]);
networkMenu.isOpen && event.preventDefault();
networkMenu.onClose();
}, [ networkMenu ]);
return (
<>
......@@ -46,15 +47,15 @@ const Burger = () => {
<Icon as={ testnetIcon } h="14px" w="auto" color="red.400" alignSelf="flex-start"/>
<Flex alignItems="center" justifyContent="space-between">
<NetworkLogo onClick={ handleNetworkLogoClick }/>
{ appConfig.featuredNetworks.length > 0 ? (
{ appConfig.featuredNetworks ? (
<NetworkMenuButton
isMobile
isActive={ isNetworkMenuOpened }
isActive={ networkMenu.isOpen }
onClick={ handleNetworkMenuButtonClick }
/>
) : <Box boxSize={ 9 }/> }
</Flex>
{ isNetworkMenuOpened ? <NetworkMenuContentMobile/> : <NavigationMobile/> }
{ networkMenu.isOpen ? <NetworkMenuContentMobile tabs={ networkMenu.availableTabs } items={ networkMenu.data }/> : <NavigationMobile/> }
</DrawerBody>
</DrawerContent>
</Drawer>
......
......@@ -77,7 +77,7 @@ const NavigationDesktop = () => {
transitionTimingFunction="ease"
>
<NetworkLogo isCollapsed={ isCollapsed }/>
{ appConfig.featuredNetworks.length > 0 && <NetworkMenu isCollapsed={ isCollapsed }/> }
{ Boolean(appConfig.featuredNetworks) && <NetworkMenu isCollapsed={ isCollapsed }/> }
</Box>
<Box as="nav" mt={ 8 } w="100%">
<VStack as="ul" spacing="1" alignItems="flex-start">
......
......@@ -7,9 +7,11 @@ import TestApp from 'playwright/TestApp';
import NetworkMenu from './NetworkMenu';
const FEATURED_NETWORKS_URL = 'https://example.com/featured-networks.json';
const extendedTest = test.extend({
context: contextWithEnvs([
{ name: 'NEXT_PUBLIC_FEATURED_NETWORKS', value: FEATURED_NETWORKS_MOCK },
{ name: 'NEXT_PUBLIC_FEATURED_NETWORKS', value: FEATURED_NETWORKS_URL },
// eslint-disable-next-line @typescript-eslint/no-explicit-any
]) as any,
});
......@@ -24,6 +26,12 @@ extendedTest('base view +@dark-mode', async({ mount, page }) => {
path: './playwright/image_s.jpg',
});
});
await page.route(FEATURED_NETWORKS_URL, (route) => {
return route.fulfill({
status: 200,
body: JSON.stringify(FEATURED_NETWORKS_MOCK),
});
});
const component = await mount(
<TestApp>
......
......@@ -3,26 +3,27 @@ import React from 'react';
import NetworkMenuButton from './NetworkMenuButton';
import NetworkMenuContentDesktop from './NetworkMenuContentDesktop';
import useNetworkMenu from './useNetworkMenu';
interface Props {
isCollapsed?: boolean;
}
const NetworkMenu = ({ isCollapsed }: Props) => {
const menu = useNetworkMenu();
return (
<Popover openDelay={ 300 } placement="right-start" gutter={ 8 } isLazy>
{ ({ isOpen }) => (
<>
<PopoverTrigger>
<NetworkMenuButton
marginLeft="auto"
overflow="hidden"
width={{ base: 'auto', lg: isCollapsed === false ? 'auto' : '0px', xl: isCollapsed ? '0px' : 'auto' }}
isActive={ isOpen }
/>
</PopoverTrigger>
<NetworkMenuContentDesktop/>
</>
) }
<Popover openDelay={ 300 } placement="right-start" gutter={ 8 } isLazy isOpen={ menu.isOpen } onClose={ menu.onClose }>
<PopoverTrigger>
<NetworkMenuButton
marginLeft="auto"
overflow="hidden"
width={{ base: 'auto', lg: isCollapsed === false ? 'auto' : '0px', xl: isCollapsed ? '0px' : 'auto' }}
isActive={ menu.isOpen }
onClick={ menu.onToggle }
/>
</PopoverTrigger>
<NetworkMenuContentDesktop items={ menu.data } tabs={ menu.availableTabs }/>
</Popover>
);
};
......
import { PopoverContent, PopoverBody, Text, Tabs, TabList, TabPanels, TabPanel, Tab, VStack } from '@chakra-ui/react';
import { PopoverContent, PopoverBody, Text, Tabs, TabList, TabPanels, TabPanel, Tab, VStack, Skeleton, Flex } from '@chakra-ui/react';
import React from 'react';
import type { NetworkGroup } from 'types/networks';
import featuredNetworks from 'lib/networks/featuredNetworks';
import type { FeaturedNetwork, NetworkGroup } from 'types/networks';
import NetworkMenuLink from './NetworkMenuLink';
const TABS: Array<NetworkGroup> = [ 'mainnets', 'testnets', 'other' ];
const availableTabs = TABS.filter((tab) => featuredNetworks.some(({ group }) => group === tab));
interface Props {
tabs: Array<NetworkGroup>;
items?: Array<FeaturedNetwork>;
}
const NetworkMenuPopup = ({ items, tabs }: Props) => {
const selectedNetwork = items?.find(({ isActive }) => isActive);
const selectedTab = tabs.findIndex((tab) => selectedNetwork?.group === tab);
const NetworkMenuPopup = () => {
const selectedNetwork = featuredNetworks.find(({ isActive }) => isActive);
const selectedTab = availableTabs.findIndex((tab) => selectedNetwork?.group === tab);
const content = !items || items.length === 0 ? (
<>
<Skeleton h="30px" w="120px"/>
<Flex mt={ 4 } alignItems="center">
<Skeleton h="40px" w="105px"/>
<Skeleton h="24px" w="68px" mx={ 4 }/>
<Skeleton h="24px" w="45px" mx={ 4 }/>
</Flex>
<Flex mt={ 8 } flexDir="column" rowGap={ 2 }>
<Flex mx={ 4 } my={ 2 } alignItems="center">
<Skeleton h="30px" w="30px" borderRadius="full"/>
<Skeleton h="24px" w="120px" ml={ 3 }/>
</Flex>
<Flex mx={ 4 } my={ 2 } alignItems="center">
<Skeleton h="30px" w="30px" borderRadius="full"/>
<Skeleton h="24px" w="180px" ml={ 3 }/>
</Flex>
<Flex mx={ 4 } my={ 2 } alignItems="center">
<Skeleton h="30px" w="30px" borderRadius="full"/>
<Skeleton h="24px" w="150px" ml={ 3 }/>
</Flex>
</Flex>
</>
) : (
<>
<Text as="h4" fontSize="18px" lineHeight="30px" fontWeight="500">Networks</Text>
<Tabs variant="soft-rounded" mt={ 4 } isLazy defaultIndex={ selectedTab !== -1 ? selectedTab : undefined }>
{ tabs.length > 1 && (
<TabList>
{ tabs.map((tab) => <Tab key={ tab } textTransform="capitalize">{ tab }</Tab>) }
</TabList>
) }
<TabPanels mt={ 8 }>
{ tabs.map((tab) => (
<TabPanel key={ tab } p={ 0 }>
<VStack as="ul" spacing={ 2 } alignItems="stretch" mt={ 4 }>
{ items
.filter((network) => network.group === tab)
.map((network) => (
<NetworkMenuLink
key={ network.title }
{ ...network }
/>
)) }
</VStack>
</TabPanel>
)) }
</TabPanels>
</Tabs>
</>
);
return (
<PopoverContent w="382px">
<PopoverBody>
<Text as="h4" fontSize="18px" lineHeight="30px" fontWeight="500">Networks</Text>
<Tabs variant="soft-rounded" mt={ 4 } isLazy defaultIndex={ selectedTab !== -1 ? selectedTab : undefined }>
{ availableTabs.length > 1 && (
<TabList>
{ availableTabs.map((tab) => <Tab key={ tab } textTransform="capitalize">{ tab }</Tab>) }
</TabList>
) }
<TabPanels mt={ 8 }>
{ availableTabs.map((tab) => (
<TabPanel key={ tab } p={ 0 }>
<VStack as="ul" spacing={ 2 } alignItems="stretch" mt={ 4 }>
{ featuredNetworks
.filter((network) => network.group === tab)
.map((network) => (
<NetworkMenuLink
key={ network.title }
{ ...network }
/>
)) }
</VStack>
</TabPanel>
)) }
</TabPanels>
</Tabs>
{ content }
</PopoverBody>
</PopoverContent>
);
};
export default NetworkMenuPopup;
export default React.memo(NetworkMenuPopup);
import { Box, Select, VStack } from '@chakra-ui/react';
import { Box, Select, VStack, Skeleton, Flex } from '@chakra-ui/react';
import capitalize from 'lodash/capitalize';
import React from 'react';
import type { NetworkGroup } from 'types/networks';
import featuredNetworks from 'lib/networks/featuredNetworks';
import type { NetworkGroup, FeaturedNetwork } from 'types/networks';
import NetworkMenuLink from './NetworkMenuLink';
const TABS: Array<NetworkGroup> = [ 'mainnets', 'testnets', 'other' ];
const availableTabs = TABS.filter((tab) => featuredNetworks.some(({ group }) => group === tab));
interface Props {
tabs: Array<NetworkGroup>;
items?: Array<FeaturedNetwork>;
}
const NetworkMenuContentMobile = ({ items, tabs }: Props) => {
const selectedNetwork = items?.find(({ isActive }) => isActive);
const [ selectedTab, setSelectedTab ] = React.useState<NetworkGroup>('Mainnets');
const NetworkMenuContentMobile = () => {
const selectedNetwork = featuredNetworks.find(({ isActive }) => isActive);
const [ selectedTab, setSelectedTab ] = React.useState<NetworkGroup>(availableTabs.find((tab) => selectedNetwork?.group === tab) || 'mainnets');
React.useEffect(() => {
if (items) {
setSelectedTab(tabs.find((tab) => selectedNetwork?.group === tab) || 'Mainnets');
}
}, [ items, selectedNetwork?.group, tabs ]);
const handleSelectChange = React.useCallback((event: React.ChangeEvent<HTMLSelectElement>) => {
setSelectedTab(event.target.value as NetworkGroup);
}, []);
return (
<Box mt={ 6 }>
const content = !items || items.length === 0 ? (
<>
<Skeleton h="32px" w="100%"/>
<Flex mt={ 6 } flexDir="column" rowGap={ 2 }>
<Flex mx={ 3 } my={ 2 } alignItems="center">
<Skeleton h="30px" w="30px" borderRadius="full"/>
<Skeleton h="20px" w="60px" ml={ 3 }/>
</Flex>
<Flex mx={ 3 } my={ 2 } alignItems="center">
<Skeleton h="30px" w="30px" borderRadius="full"/>
<Skeleton h="20px" w="120px" ml={ 3 }/>
</Flex>
<Flex mx={ 3 } my={ 2 } alignItems="center">
<Skeleton h="30px" w="30px" borderRadius="full"/>
<Skeleton h="20px" w="80px" ml={ 3 }/>
</Flex>
</Flex>
</>
) : (
<>
<Select size="xs" borderRadius="base" value={ selectedTab } onChange={ handleSelectChange } focusBorderColor="none">
{ availableTabs.map((tab) => <option key={ tab } value={ tab }>{ capitalize(tab) }</option>) }
{ tabs.map((tab) => <option key={ tab } value={ tab }>{ capitalize(tab) }</option>) }
</Select>
<VStack as="ul" spacing={ 2 } alignItems="stretch" mt={ 6 }>
{ featuredNetworks
{ items
.filter(({ group }) => group === selectedTab)
.map((network) => (
<NetworkMenuLink
......@@ -36,8 +60,14 @@ const NetworkMenuContentMobile = () => {
))
}
</VStack>
</>
);
return (
<Box mt={ 6 }>
{ content }
</Box>
);
};
export default NetworkMenuContentMobile;
export default React.memo(NetworkMenuContentMobile);
import { useDisclosure } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import React from 'react';
import type { FeaturedNetwork, NetworkGroup } from 'types/networks';
import appConfig from 'configs/app/config';
import type { ResourceError } from 'lib/api/resources';
import useApiFetch from 'lib/hooks/useFetch';
const TABS: Array<NetworkGroup> = [ 'Mainnets', 'Testnets', 'Other' ];
export default function useNetworkMenu() {
const { isOpen, onClose, onOpen, onToggle } = useDisclosure();
const apiFetch = useApiFetch();
const { isLoading, data } = useQuery<unknown, ResourceError<unknown>, Array<FeaturedNetwork>>(
[ 'featured-network' ],
async() => apiFetch(appConfig.featuredNetworks || ''),
{
enabled: Boolean(appConfig.featuredNetworks) && isOpen,
staleTime: Infinity,
});
return React.useMemo(() => ({
isOpen,
onClose,
onOpen,
onToggle,
isLoading,
data,
availableTabs: TABS.filter((tab) => data?.some(({ group }) => group === tab)),
}), [ isOpen, onClose, onOpen, onToggle, data, isLoading ]);
}
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