From 71fd48cd82ebc31cf5f0b894183cbceee99eb053 Mon Sep 17 00:00:00 2001 From: tom goriunov Date: Wed, 11 Sep 2024 18:10:56 +0400 Subject: [PATCH] Home page stats config (#2221) Fixes #2143 --- configs/app/ui.ts | 22 +++- configs/envs/.env.celo_alfajores | 3 +- configs/envs/.env.jest | 1 - configs/envs/.env.pw | 1 - configs/envs/.env.rootstock_testnet | 3 +- deploy/tools/envs-validator/schema.ts | 10 +- deploy/tools/envs-validator/test/.env.alt | 3 +- deploy/tools/envs-validator/test/.env.base | 2 +- docs/DEPRECATED_ENVS.md | 1 + docs/ENVS.md | 2 +- types/homepage.ts | 13 +++ ui/home/Stats.pw.tsx | 10 +- ui/home/Stats.tsx | 108 ++++++++++++------ ...-items-default-view-mobile---default-1.png | Bin 7703 -> 8546 bytes ...-items-default-view-mobile---default-1.png | Bin 9511 -> 10439 bytes 15 files changed, 125 insertions(+), 54 deletions(-) diff --git a/configs/app/ui.ts b/configs/app/ui.ts index f4ae2ff6e2..366ef2d5ee 100644 --- a/configs/app/ui.ts +++ b/configs/app/ui.ts @@ -1,12 +1,13 @@ import type { ContractCodeIde } from 'types/client/contract'; import { NAVIGATION_LINK_IDS, type NavItemExternal, type NavigationLinkId, type NavigationLayout } from 'types/client/navigation'; -import type { ChainIndicatorId, HeroBannerConfig } from 'types/homepage'; +import { HOME_STATS_WIDGET_IDS, type ChainIndicatorId, type HeroBannerConfig, type HomeStatsWidgetId } from 'types/homepage'; import type { NetworkExplorer } from 'types/networks'; import type { ColorThemeId } from 'types/settings'; import type { FontFamily } from 'types/ui'; import { COLOR_THEMES } from 'lib/settings/colorTheme'; +import * as features from './features'; import * as views from './ui/views'; import { getEnvValue, getExternalAssetFilePath, parseEnvJson } from './utils'; @@ -25,6 +26,22 @@ const hiddenLinks = (() => { return result; })(); +const homePageStats: Array = (() => { + const parsedValue = parseEnvJson>(getEnvValue('NEXT_PUBLIC_HOMEPAGE_STATS')); + + if (!Array.isArray(parsedValue)) { + const rollupFeature = features.rollup; + + if (rollupFeature.isEnabled && [ 'zkEvm', 'zkSync', 'arbitrum' ].includes(rollupFeature.type)) { + return [ 'latest_batch', 'average_block_time', 'total_txs', 'wallet_addresses', 'gas_tracker' ]; + } + + return [ 'total_blocks', 'average_block_time', 'total_txs', 'wallet_addresses', 'gas_tracker' ]; + } + + return parsedValue.filter((item) => HOME_STATS_WIDGET_IDS.includes(item)); +})(); + const highlightedRoutes = (() => { const parsedValue = parseEnvJson>(getEnvValue('NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES')); return Array.isArray(parsedValue) ? parsedValue : []; @@ -58,12 +75,13 @@ const UI = Object.freeze({ }, homepage: { charts: parseEnvJson>(getEnvValue('NEXT_PUBLIC_HOMEPAGE_CHARTS')) || [], + stats: homePageStats, heroBanner: parseEnvJson(getEnvValue('NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG')), + // !!! DEPRECATED !!! plate: { background: getEnvValue('NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND'), textColor: getEnvValue('NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR'), }, - showAvgBlockTime: getEnvValue('NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME') === 'false' ? false : true, }, views, indexingAlert: { diff --git a/configs/envs/.env.celo_alfajores b/configs/envs/.env.celo_alfajores index 2cbb790629..2934345c90 100644 --- a/configs/envs/.env.celo_alfajores +++ b/configs/envs/.env.celo_alfajores @@ -36,4 +36,5 @@ NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/celo.png NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true -NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com \ No newline at end of file +NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com +NEXT_PUBLIC_HOMEPAGE_STATS=['total_blocks','average_block_time','total_txs','wallet_addresses','gas_tracker','current_epoch'] \ No newline at end of file diff --git a/configs/envs/.env.jest b/configs/envs/.env.jest index e1f80c7e75..abe2107a80 100644 --- a/configs/envs/.env.jest +++ b/configs/envs/.env.jest @@ -24,7 +24,6 @@ NEXT_PUBLIC_API_BASE_PATH=/ # ui config ## homepage NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cap'] -NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME=true NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND= ## sidebar NEXT_PUBLIC_NETWORK_LOGO= diff --git a/configs/envs/.env.pw b/configs/envs/.env.pw index 1794de039d..dec30c09fe 100644 --- a/configs/envs/.env.pw +++ b/configs/envs/.env.pw @@ -25,7 +25,6 @@ NEXT_PUBLIC_API_BASE_PATH=/ # ui config ## homepage NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cap'] -NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME=true ## sidebar ## footer NEXT_PUBLIC_GIT_TAG=v1.0.11 diff --git a/configs/envs/.env.rootstock_testnet b/configs/envs/.env.rootstock_testnet index 2c3f426912..a4218a2fac 100644 --- a/configs/envs/.env.rootstock_testnet +++ b/configs/envs/.env.rootstock_testnet @@ -42,4 +42,5 @@ NEXT_PUBLIC_STATS_API_HOST=https://stats-rsk-testnet.k8s.blockscout.com NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout NEXT_PUBLIC_VIEWS_BLOCK_HIDDEN_FIELDS=['burnt_fees','total_reward','nonce'] NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true -NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com \ No newline at end of file +NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com +NEXT_PUBLIC_HOMEPAGE_STATS=['total_blocks','average_block_time','total_txs','wallet_addresses','gas_tracker','btc_locked'] \ No newline at end of file diff --git a/deploy/tools/envs-validator/schema.ts b/deploy/tools/envs-validator/schema.ts index fa1e1d72b4..7f31fb219d 100644 --- a/deploy/tools/envs-validator/schema.ts +++ b/deploy/tools/envs-validator/schema.ts @@ -29,8 +29,8 @@ import type { ValidatorsChainType } from '../../../types/client/validators'; import type { WalletType } from '../../../types/client/wallets'; import { SUPPORTED_WALLETS } from '../../../types/client/wallets'; import type { CustomLink, CustomLinksGroup } from '../../../types/footerLinks'; -import { CHAIN_INDICATOR_IDS } from '../../../types/homepage'; -import type { ChainIndicatorId, HeroBannerButtonState, HeroBannerConfig } from '../../../types/homepage'; +import { CHAIN_INDICATOR_IDS, HOME_STATS_WIDGET_IDS } from '../../../types/homepage'; +import type { ChainIndicatorId, HeroBannerButtonState, HeroBannerConfig, HomeStatsWidgetId } from '../../../types/homepage'; import { type NetworkVerificationTypeEnvs, type NetworkExplorer, type FeaturedNetwork, NETWORK_GROUPS } from '../../../types/networks'; import { COLOR_THEME_IDS } from '../../../types/settings'; import type { FontFamily } from '../../../types/ui'; @@ -567,6 +567,11 @@ const schema = yup .transform(replaceQuotes) .json() .of(yup.string().oneOf(CHAIN_INDICATOR_IDS)), + NEXT_PUBLIC_HOMEPAGE_STATS: yup + .array() + .transform(replaceQuotes) + .json() + .of(yup.string().oneOf(HOME_STATS_WIDGET_IDS)), NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR: yup.string(), NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND: yup.string(), NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG: yup @@ -586,7 +591,6 @@ const schema = yup const isUndefined = data === undefined; return isUndefined || heroBannerSchema.isValidSync(data); }), - NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME: yup.boolean(), // b. sidebar NEXT_PUBLIC_FEATURED_NETWORKS: yup diff --git a/deploy/tools/envs-validator/test/.env.alt b/deploy/tools/envs-validator/test/.env.alt index 62183782bf..6482ea4197 100644 --- a/deploy/tools/envs-validator/test/.env.alt +++ b/deploy/tools/envs-validator/test/.env.alt @@ -1,3 +1,4 @@ NEXT_PUBLIC_GRAPHIQL_TRANSACTION=none NEXT_PUBLIC_API_SPEC_URL=none -NEXT_PUBLIC_VIEWS_CONTRACT_EXTRA_VERIFICATION_METHODS=none \ No newline at end of file +NEXT_PUBLIC_VIEWS_CONTRACT_EXTRA_VERIFICATION_METHODS=none +NEXT_PUBLIC_HOMEPAGE_STATS=[] \ No newline at end of file diff --git a/deploy/tools/envs-validator/test/.env.base b/deploy/tools/envs-validator/test/.env.base index 064bb48199..fc628aeefd 100644 --- a/deploy/tools/envs-validator/test/.env.base +++ b/deploy/tools/envs-validator/test/.env.base @@ -35,10 +35,10 @@ NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c18099 NEXT_PUBLIC_HIDE_INDEXING_ALERT_BLOCKS=false NEXT_PUBLIC_HIDE_INDEXING_ALERT_INT_TXS=false NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs'] +NEXT_PUBLIC_HOMEPAGE_STATS=['total_blocks','average_block_time','total_txs','wallet_addresses','gas_tracker','current_epoch'] NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR='#fff' NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND='rgb(255, 145, 0)' NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['lightpink'],'text_color':['deepskyblue','white'],'border':['3px solid black']} -NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME=true NEXT_PUBLIC_GAS_TRACKER_ENABLED=true NEXT_PUBLIC_GAS_TRACKER_UNITS=['gwei'] NEXT_PUBLIC_IS_TESTNET=true diff --git a/docs/DEPRECATED_ENVS.md b/docs/DEPRECATED_ENVS.md index 0cf27ae106..e00aea9307 100644 --- a/docs/DEPRECATED_ENVS.md +++ b/docs/DEPRECATED_ENVS.md @@ -10,3 +10,4 @@ | NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER | `boolean` | Set to false if network doesn't have gas tracker | - | `true` | `false` | - | v1.25.0 | Replaced by NEXT_PUBLIC_GAS_TRACKER_ENABLED | | NEXT_PUBLIC_NETWORK_GOVERNANCE_TOKEN_SYMBOL | `string` | Network governance token symbol | - | - | `GNO` | v1.12.0 | v1.29.0 | Replaced by NEXT_PUBLIC_NETWORK_SECONDARY_COIN_SYMBOL | | NEXT_PUBLIC_SWAP_BUTTON_URL | `string` | Application ID in the marketplace or website URL | - | - | `uniswap` | v1.24.0 | v1.31.0 | Replaced by NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS | +| NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME | `boolean` | Set to false if average block time is useless for the network | - | `true` | `false` | v1.0.x+ | v1.35.0 | Replaces by NEXT_PUBLIC_HOMEPAGE_STATS \ No newline at end of file diff --git a/docs/ENVS.md b/docs/ENVS.md index cf63f0475e..fa32d893e6 100644 --- a/docs/ENVS.md +++ b/docs/ENVS.md @@ -118,9 +118,9 @@ Please be aware that all environment variables prefixed with `NEXT_PUBLIC_` will | Variable | Type| Description | Compulsoriness | Default value | Example value | Version | | --- | --- | --- | --- | --- | --- | --- | | NEXT_PUBLIC_HOMEPAGE_CHARTS | `Array<'daily_txs' \| 'coin_price' \| 'secondary_coin_price' \| 'market_cap' \| 'tvl'>` | List of charts displayed on the home page | - | - | `['daily_txs','coin_price','market_cap']` | v1.0.x+ | +| NEXT_PUBLIC_HOMEPAGE_STATS | `Array<'latest_batch' \| 'total_blocks' \| 'average_block_time' \| 'total_txs' \| 'latest_l1_state_batch' \| 'wallet_addresses' \| 'gas_tracker' \| 'btc_locked' \| 'current_epoch'>` | List of stats widgets displayed on the home page | - | For zkSync, zkEvm and Arbitrum rollups: `['latest_batch','average_block_time','total_txs','wallet_addresses','gas_tracker']`, for other cases: `['total_blocks','average_block_time','total_txs','wallet_addresses','gas_tracker']` | `['total_blocks','total_txs','wallet_addresses']` | v1.35.x+ | | NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR | `string` | Text color of the hero plate on the homepage (escape "#" symbol if you use HEX color codes or use rgba-value instead). **DEPRECATED** _Use `NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG` instead_ | - | `white` | `\#DCFE76` | v1.0.x+ | | NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND | `string` | Background css value for hero plate on the homepage (escape "#" symbol if you use HEX color codes or use rgba-value instead). **DEPRECATED** _Use `NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG` instead_ | - | `radial-gradient(103.03% 103.03% at 0% 0%, rgba(183, 148, 244, 0.8) 0%, rgba(0, 163, 196, 0.8) 100%), var(--chakra-colors-blue-400)` | `radial-gradient(at 15% 86%, hsla(350,65%,70%,1) 0px, transparent 50%)` \| `no-repeat bottom 20% right 0px/100% url(https://placekitten/1400/200)` | v1.1.0+ | -| NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME | `boolean` | Set to false if average block time is useless for the network | - | `true` | `false` | v1.0.x+ | | NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG | `HeroBannerConfig`, see details [below](#hero-banner-configuration-properties) | Configuration of hero banner appearance. | - | - | See [below](#hero-banner-configuration-properties) | v1.35.0+ | #### Hero banner configuration properties diff --git a/types/homepage.ts b/types/homepage.ts index 6bc73ee8d3..d8d06647c9 100644 --- a/types/homepage.ts +++ b/types/homepage.ts @@ -1,6 +1,19 @@ export const CHAIN_INDICATOR_IDS = [ 'daily_txs', 'coin_price', 'secondary_coin_price', 'market_cap', 'tvl' ] as const; export type ChainIndicatorId = typeof CHAIN_INDICATOR_IDS[number]; +export const HOME_STATS_WIDGET_IDS = [ + 'latest_batch', + 'total_blocks', + 'average_block_time', + 'total_txs', + 'latest_l1_state_batch', + 'wallet_addresses', + 'gas_tracker', + 'btc_locked', + 'current_epoch', +] as const; +export type HomeStatsWidgetId = typeof HOME_STATS_WIDGET_IDS[number]; + export interface HeroBannerButtonState { background?: Array; text_color?: Array; diff --git a/ui/home/Stats.pw.tsx b/ui/home/Stats.pw.tsx index eeaa89dc2c..9add012cba 100644 --- a/ui/home/Stats.pw.tsx +++ b/ui/home/Stats.pw.tsx @@ -9,7 +9,10 @@ import Stats from './Stats'; test.describe('all items', () => { let component: Locator; - test.beforeEach(async({ render, mockApiResponse }) => { + test.beforeEach(async({ render, mockApiResponse, mockEnvs }) => { + await mockEnvs([ + [ 'NEXT_PUBLIC_HOMEPAGE_STATS', '["total_blocks","average_block_time","total_txs","wallet_addresses","gas_tracker","btc_locked"]' ], + ]); await mockApiResponse('stats', statsMock.withBtcLocked); component = await render(); }); @@ -28,7 +31,7 @@ test('no gas info', async({ render, mockApiResponse }) => { test('4 items default view +@mobile -@default', async({ render, mockApiResponse, mockEnvs }) => { await mockEnvs([ - [ 'NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME', 'false' ], + [ 'NEXT_PUBLIC_HOMEPAGE_STATS', '["total_txs","gas_tracker","wallet_addresses","total_blocks"]' ], ]); await mockApiResponse('stats', statsMock.base); const component = await render(); @@ -37,8 +40,7 @@ test('4 items default view +@mobile -@default', async({ render, mockApiResponse, test('3 items default view +@mobile -@default', async({ render, mockApiResponse, mockEnvs }) => { await mockEnvs([ - [ 'NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME', 'false' ], - [ 'NEXT_PUBLIC_GAS_TRACKER_ENABLED', 'false' ], + [ 'NEXT_PUBLIC_HOMEPAGE_STATS', '["total_txs","wallet_addresses","total_blocks"]' ], ]); await mockApiResponse('stats', statsMock.base); const component = await render(); diff --git a/ui/home/Stats.tsx b/ui/home/Stats.tsx index 29c2c3b96d..ab00e80cf1 100644 --- a/ui/home/Stats.tsx +++ b/ui/home/Stats.tsx @@ -2,6 +2,8 @@ import { Grid } from '@chakra-ui/react'; import BigNumber from 'bignumber.js'; import React from 'react'; +import type { HomeStatsWidgetId } from 'types/homepage'; + import config from 'configs/app'; import useApiQuery from 'lib/api/useApiQuery'; import { WEI } from 'lib/consts'; @@ -12,7 +14,6 @@ import IconSvg from 'ui/shared/IconSvg'; import type { Props as StatsWidgetProps } from 'ui/shared/stats/StatsWidget'; import StatsWidget from 'ui/shared/stats/StatsWidget'; -const hasAvgBlockTime = config.UI.homepage.showAvgBlockTime; const rollupFeature = config.features.rollup; const Stats = () => { @@ -35,37 +36,54 @@ const Stats = () => { const zkEvmLatestBatchQuery = useApiQuery('homepage_zkevm_latest_batch', { queryOptions: { placeholderData: 12345, - enabled: rollupFeature.isEnabled && rollupFeature.type === 'zkEvm', + enabled: rollupFeature.isEnabled && rollupFeature.type === 'zkEvm' && config.UI.homepage.stats.includes('latest_batch'), }, }); const zkSyncLatestBatchQuery = useApiQuery('homepage_zksync_latest_batch', { queryOptions: { placeholderData: 12345, - enabled: rollupFeature.isEnabled && rollupFeature.type === 'zkSync', + enabled: rollupFeature.isEnabled && rollupFeature.type === 'zkSync' && config.UI.homepage.stats.includes('latest_batch'), }, }); const arbitrumLatestBatchQuery = useApiQuery('homepage_arbitrum_latest_batch', { queryOptions: { placeholderData: 12345, - enabled: rollupFeature.isEnabled && rollupFeature.type === 'arbitrum', + enabled: rollupFeature.isEnabled && rollupFeature.type === 'arbitrum' && config.UI.homepage.stats.includes('latest_batch'), }, }); - if (isError || zkEvmLatestBatchQuery.isError || zkSyncLatestBatchQuery.isError || arbitrumLatestBatchQuery.isError) { + const latestBatchQuery = (() => { + if (!rollupFeature.isEnabled || !config.UI.homepage.stats.includes('latest_batch')) { + return; + } + + switch (rollupFeature.type) { + case 'zkEvm': + return zkEvmLatestBatchQuery; + case 'zkSync': + return zkSyncLatestBatchQuery; + case 'arbitrum': + return arbitrumLatestBatchQuery; + } + })(); + + if (isError || latestBatchQuery?.isError) { return null; } - const isLoading = isPlaceholderData || - (rollupFeature.isEnabled && rollupFeature.type === 'zkEvm' && zkEvmLatestBatchQuery.isPlaceholderData) || - (rollupFeature.isEnabled && rollupFeature.type === 'zkSync' && zkSyncLatestBatchQuery.isPlaceholderData) || - (rollupFeature.isEnabled && rollupFeature.type === 'arbitrum' && arbitrumLatestBatchQuery.isPlaceholderData); + const isLoading = isPlaceholderData || latestBatchQuery?.isPlaceholderData; + + interface Item extends StatsWidgetProps { + id: HomeStatsWidgetId; + } - const content = (() => { + const items: Array = (() => { if (!data) { - return null; + return []; } + const gasInfoTooltip = hasGasTracker && data.gas_prices && data.gas_prices.average ? ( { ) : null; - const hasBatches = rollupFeature.isEnabled && (rollupFeature.type === 'zkEvm' || rollupFeature.type === 'zkSync' || rollupFeature.type === 'arbitrum'); - const latestBatch = - (hasBatches && rollupFeature.type === 'zkEvm' ? zkEvmLatestBatchQuery.data : null) || - (hasBatches && rollupFeature.type === 'zkSync' ? zkSyncLatestBatchQuery.data : null) || - (hasBatches && rollupFeature.type === 'arbitrum' ? arbitrumLatestBatchQuery.data : null) || 0; - - const items: Array = [ - hasBatches && { + return [ + latestBatchQuery?.data !== undefined && { + id: 'latest_batch' as const, icon: 'txn_batches_slim' as const, label: 'Latest batch', - value: latestBatch.toLocaleString(), + value: latestBatchQuery.data.toLocaleString(), href: { pathname: '/batches' as const }, isLoading, }, - !hasBatches && { + { + id: 'total_blocks' as const, icon: 'block_slim' as const, label: 'Total blocks', value: Number(data.total_blocks).toLocaleString(), href: { pathname: '/blocks' as const }, isLoading, }, - hasAvgBlockTime && { + { + id: 'average_block_time' as const, icon: 'clock-light' as const, label: 'Average block time', value: `${ (data.average_block_time / 1000).toFixed(1) }s`, isLoading, }, { + id: 'total_txs' as const, icon: 'transactions_slim' as const, label: 'Total transactions', value: Number(data.total_transactions).toLocaleString(), href: { pathname: '/txs' as const }, isLoading, }, - rollupFeature.isEnabled && data.last_output_root_size && { + data.last_output_root_size && { + id: 'latest_l1_state_batch' as const, icon: 'txn_batches_slim' as const, label: 'Latest L1 state batch', value: data.last_output_root_size, @@ -122,12 +139,14 @@ const Stats = () => { isLoading, }, { + id: 'wallet_addresses' as const, icon: 'wallet' as const, label: 'Wallet addresses', value: Number(data.total_addresses).toLocaleString(), isLoading, }, hasGasTracker && data.gas_prices && { + id: 'gas_tracker' as const, icon: 'gas' as const, label: 'Gas tracker', value: data.gas_prices.average ? : 'N/A', @@ -135,33 +154,39 @@ const Stats = () => { isLoading, }, data.rootstock_locked_btc && { + id: 'btc_locked' as const, icon: 'coins/bitcoin' as const, label: 'BTC Locked in 2WP', value: `${ BigNumber(data.rootstock_locked_btc).div(WEI).dp(0).toFormat() } RBTC`, isLoading, }, data.celo && { + id: 'current_epoch' as const, icon: 'hourglass' as const, label: 'Current epoch', value: `#${ data.celo.epoch_number }`, isLoading, }, - ].filter(Boolean); - - return ( - <> - { items.map((item, index) => ( - - ), - ) } - - ); + ] + .filter(Boolean) + .filter(({ id }) => config.UI.homepage.stats.includes(id)) + .sort((a, b) => { + const indexA = config.UI.homepage.stats.indexOf(a.id); + const indexB = config.UI.homepage.stats.indexOf(b.id); + if (indexA > indexB) { + return 1; + } + if (indexA < indexB) { + return -1; + } + return 0; + }); })(); + if (items.length === 0) { + return null; + } + return ( { flexBasis="50%" flexGrow={ 1 } > - { content } + { items.map((item, index) => ( + + ), + ) } ); diff --git a/ui/home/__screenshots__/Stats.pw.tsx_mobile_3-items-default-view-mobile---default-1.png b/ui/home/__screenshots__/Stats.pw.tsx_mobile_3-items-default-view-mobile---default-1.png index f53d6e247f3135060bcebbefdbb76ffc07d073c1..e9e8730a82bcd8b306883772f3e0f3ab9b25fd62 100644 GIT binary patch literal 8546 zcmbW71yoc~yY~-*0+I@XG)T8fcSuNg$A}<0)F3c)i6BUKBO#3gBF)gLLrb@GcMf@v z?|0W-@4esm-tVrv=BzWb*Qvet?EO6d-+!Oan(B%K_bKlK06?JhQcfEHFg}65199$v zdnz+30`TkJYZXN~;P&q)tFa&s0O$cFIT>B|^qpBZQlWC5ss#0U2P;JGXD>zXJT<`tTw-Osf=pR`G9!DpK#V>`BEMkV<=$Y%AmuX#0 zOxT8MJx9I=iiZn)&O}5>Ju8t}P|6$G;mYtFc1m5m2ii|?0+?Dtm~a9HO(@!NH}VD2 zao*HcqS!@(vOhkyhzWcaHll^mj{B^DQr$0~sVF>WA3|Y66iYv$FjevJ6NwG)8{rsW zkfR%r-BB2FDM|m$)$J%tlZDS3n-867RiI%kcvrO~_gKBKopeDC_0(UJwUC(}pLK-7 zDU{_s9Toi3)vx_lN7)R9f)5?UvKiS2T{|9XSl8r({D>`Q(?DX+uBXflf%rK2Oo7oD zt?_}x&*_t6iDmC$={%JE>HkVu7KegZfqlcee!sn}#^?N`ny6{&qIGUFqsZyV8 zmFzP|$@FG%c{w^vz-wxBIWwR7+M;hMLF$Ul-rmQYZ{vxtC>(9GNz=JR2Hgstw`-2! z(G|CMa6m63u~JM+$K)skjh7Vlx?gWhY;ZQu_FHI&+&~pnIphQHf*VH5&DXU%-m{)T zI4-(mtE6amQL!l#zDzmnRB?IK5O*J%w`nlR-tNjYe+Yi=E;|1UMK>sf1%&p{5(7b< zkFMJSfUNJj%d4;7cD#ny9<5QS6dpa!%dOUxcu1$xplzgQ32mk0%V|zRE)_YC!|;y4 zEvT+jCr9zVb6CGwlO8Mddqq|HQx;TLahf%2v07JDq;d20yECBd80k^L(rn6Ds%JYl zG11_AIrLLfM#$j}MoSMPBj&X@@F(iqRXl``GBs7glqRQ}(3*&IoEa;v!RM70zH`Fp@h6cN3;fsEgRxjBbKvJl9w|aw6~BXkOoK- zLcGP(QvwODssuRcLhZkCcSTbFS$tPQ=8H--7W?MDzizmgpg3CPJ6GD(<#)sIj*O!k z`JBawDO-^3T^L5+!@fxy`*V%v^G{_<>`LldNFruM`O|e0N=-x4roHt^H*3Wx3fjqu ziS4D08BRHRd;3Ng3CpW>HiNgwEvQ=@Pp(=dZT4i8OAMD%-HA#r$fNRku3i zw;d1k-LjL&9#6VU+5Sy73Hi0pY#L>n29sG>hR9sNfJ#HOu_4#tq2ma(F;9UjoieRp zp~1ke@7eu5R%%t#rdP33>!OJYu}pE<;FY3Rv91rS#T|s2iVA;B{c6qsp6fkR_~CBn zN&=BBwH@NV3aUGNJ=1;R)7g0}iVgEek$+KmqmT3Oj0zclU1HK{It@BR*u zA+{HI8)Ib{0s!8PrfjJWc6KaE4}oIZP^kY<`;#l5*~)5ejz{n7wg-28vHUZWRC>b= zehQY3O^y9d#-CjnuTVKSbYbTzdgl-$S!(a-`u*V4=^sUhA_VN%5&r6-VCS1Bc+Tc! z#26UFO#7A9{Jf2jqAF{X)>r*Pdi><)wW1;um3lZF&x+uheUAsZEGG8p-1BaIM4OUy z!NFWzsVP}i{-dx2ri+jsa&b~Nwsw7xIk0l13bjr`JbnI}ou^}3-&t_lu$&vCB}5*@ zUPlon_I_qiWt@*NQ}uy6GJ=-O;&t1Q9cK~j`=)g%_0Is<*j(N-im7n2L{ zYYiNwn%8e~CYL6=y3XW@qS9YN4Q_XAc=lZ%xg!N@UPfg!#X1SJcMr=~aLqG6ARkkT+aRq5hLpn)_`jks|QB40}ur!>6G)e};4d2YJH{X|% zirEI}?XXzl7~!bk`;#S6A|XXYkm|kBzxDeNMb-YvGwCRE{6NUzi$kQE8aEio@-gm* z_Bi9A0`AfRE!I?Fw4raFivWO{4(aU3h!gt4p2kdKNbXU^Y7T0X&Xv~I#>Rq*D#dXk z%UvvgXl%Hzyv`^!F-8q@c{!P#;20(G&r9xS@KfiA`^ix7A}1@csMX$S@}nURw^CVh3Wru{|~0(KvIH1 zf68;g=2~y~6$3cjo99005p~+b^X#6(+vYQ4&pnV&?RMY6X#Q+9Sx-Lz9Nntv1o+c! z!J$&}e1U4V7ajLiku8!L8d(a5qCU>o2k%aVP2NR&3XhKpaLg-Ty4Q|`FbgJMkcqszii-rY*SSg&iWy+rcP5(SR@b~9&QMRX<9L#jS+O(&0ML( zN1thq5wXIrxQg8ORO?u5z?R*RlpQq_4lyN2?1^Og36U%{YcSe4j82To7fS5oG2<{` z2C(BYSV{kXvtYDqdZXF=;P*Gvr5(d>Ipv=4@tHS=>`w$adp9)3Kiag}8Y_*G^5R+1 zf>&iAc7AH{cJycV39Z$PX3t$%b~Pnt#1)KfHo7fYH%UY+#K&7Xp~n!oRDuo(%6W=J zdpnaAVn@(QH?t628WTBf)=A>#9lOII>;%2U#Kadl_qfdY$NT$B5vAJ0zl9v8Jl7&M z)qh=IU*~IN@L%M`sB&1nU5lg;(z4Agw#aW0$A3-6qoyoL1k`BjaB*{sHI$Zq-k6+5 zAP`HCv?rvi!V}ZMfmnJWaw#d3`S~+1q*$=-U10j>Hr=K8+Nl;Q5khq6*umbK_d?%hIMT}u~>HtGE5 z{d3VlYCuo5NiI z>)w4F`X4`>mz``TV<+mIt=AEn+Qt`imzl-zWQeA&nc2|-cF$buY5tFBkH@C$po)KV+U55yhX;!~$Q<$qnMO=pM)6!aTrxnEpgaI4d{R#+wq z@~fof{+PPxVuy7Kdtkw4(zB{wG@j6f+JfgQhJW7OkB^s<{NRJt`asN;?i_Ng%Nq5E z3QEyiFf<2;x6&EkZD$d!{&`3w>2`?oMUu0+x=Bmx$KhoJczf7D#PD`O&S7?zm)zNR znHoN4Qf6>>6>w31`AJ__(n?!qr{JQTsdijiL&ose_5D$&PZpXwCi8ABFK=mMz&n6j z@rz1ZGc$DXMtN>ADj0a`@{@iSlH@`mbjl2{k$)!Dz`Gx2Z}-h|bwJy6_hX;6M&>CC zV0C?xsTnbMvGRxrXc_IyYuC{ZrR1ka_m(TczoLHrmHJP z!88P$QSGb9VC3bbGdWYNXBA2+Q!0U$$9kR--t|{WDpOAr{oK9)wET)w z0*D_RtRai_IHe41wN16}0D{$m#$qET5M7=-Kx+P4f0WAYb#;2q#R&nV$u1k2M%B*F ze*OIhSv{8LM!91~{#v%13~HZ%;eQZkkev?&#l!B*qtmGE5@X+!3pL>JLxER)^=i#m zvFH0kjDCL26L+1l3Bs)mW%PVrv{z?%fpNq6ZFAl!CyPb2TiL7b{zit`kLH=eH-j;j z8Ab*MT`s)rOibt3Zu50%DFQaffq6ZW>HO%OvZia_{XZCCWc@?N%}v=1zDMe0Vd+nO zx#DgFwvr5V0cq_+bWTp}oJDpb*=%g=K;v@@Ww1vg)ru^K*O%)xy-qer?gJ3NBMEt} z&{#7sUoLj;yZ)P-lvSv^Xn7_j--DIn3|z0qh8eF@{5qe@-SCuWtQr{>hBBkOvzK&X zbj=4{w$-lH^{hn{_xRQPjt|I5<$Z28f{n}YCQ9M(H#_GYec&t`YR%62URYU)5A?c= zOF$Ayrb8P9CA6#VV0G?H=VgRD!hbla5#gKlk_bPkj1vSq|qemxL*J>DAl`( zdLzlqa;%PQ+>)i)SDy)hl+B5|EE{(1NZq-Eg}xgU6x4}%p=jFZs-s>+Csvm5k}b5J zvsdz@hoN)#C@8+id6nnpe7H;z3bSMTws$uPqDMuKHM4~ z&SAZR-CP-YdO4Id<>jqpeTWJ5#sZj>nwnpK{*1fU*4e|aR%5HIx}M?cH6A3|HQI?@ zv%KsMr`0TrQuLzXN1+_VKxXbB=^D zmCY25&$x}l@Am37-_{C?Axw_cJU8>EHw@ey<{y(TXC}E30p8vtXQ~JU7e))@Pl56J z!tOmlV3CsL5h<8$TzBSRHmHoR&g4air{{-Td$x4rO*M-&vu{hDLBPJ{XV%l#$M6pe ztN0N}k3(+23e-Yw)>>&&Oqb9RH(7mxc$LD9$#i+;;CLFy~+s{T_xP>*{Okiv6xAA3nqfJkT0f*r>)N zB7l(aRF#9xZn{qKNm1r=G@O%D<=qPt3;HCTZa+y}Kqbj%eP>+f;A_bAoKJ8##icR! z*l5DD>#h5{v^W6Lbdneb?Lpduut$&S0RXJAu!B4}(JWqImzf+1gyrSEO)=$3 z(m{25ZVtPE2ln*KbWB$>@;6}mrBDY43IV6u#W>4G9c?Nt&c@+aKX{Hw>+0&PtgZbj zoYX8WNdSI+K_0I&%M?>d_~Cqk5vR~r;K35`YNhxjNWL=^vNLsLX|u_#h#frmMIu=j z@b6yi_By5hlaku+=~cX``uG#4jI@tB>khO?JAk;LY{VXh$pwN`KuS*ACFG=@KPt=v{<$z=`I*nAij5-IM zsK0>S9Z9i;**e64T49{Euh!Y%9Td8;vhu~POj?_DW1QD}JW@?TK_RQ$Nb2%xde)05 zIoYx8GH^7c6a2^R1iiY)=;A$OU_r2ElNz{5+m#1jQXw_24Xn0U%bQ&JWZNDL3-?ta zVJ*_P!>mNz-Fvl%TM@a-NBQEzKYbU5^P5D3i<@&~Wh}B6WfZz-MnCndtA}E*tPlb8 z^qMW-C6jEOUfuRbq*Z5#IPXqX>Dq$x1Ey|DEoM*`@sIW(j{mme*yX)&x{p^4V*Wex zvxDsnF+AEcZkTtlyw2zvQapR&-->!qM1!$jw^=I}DGP`9 zHCRce!JH@wC3s)}sb-WPH4b5Fdw){~?~_?XL$zeEW8Soc9Kf z0%{WFGJ?RJ#slBni2s*qqN?;?v}MtI5!b*enH|p?(5>Oa37~(*n%)0OfVDp;D7%Yo#JCteQ zrI_&xa%{V&7y!aaS$${#uD=fXC~q^MsQg$xL}b+QLX7#t;#?XjcY#b5F#~e|y&=}q z8G<%P*?K4e>z($y3|7MXx=R1q`&s@>RXxbh{q^1bD8(m%Hy&6r(O8dT0yj78-5&z7 z>mtKW5B+r&v})gi_L2I_fLBy8S;C1U9Npev`3s1=2|9o@NB>)|xg!}IINT{TADS9( zAqhH3_eA95&Jzh3tmv2dqmyGmn<*e4Dz5kNf1GCNkMhkieFLL2DB^btFQ_jlq&w;8#6=tFps-$R94mP>=W## z-F~BfoBmlTwj|{lw>rySw)p6Ivc2n8w(r~4+OdMi!j7y@^(9rN zLY4D%o9ughCfCLblfP+lpfP_gyPi3A&_3On_k@IGX@3y7(=y#|^k*kE#U$7GgS{Q~ z(O5}ozbgTOnnIUCR7aJlCl%??$96%%rT4*v>u^?1$Qhe_-V>fAnyJ|+VE@SJbIL*J zp@Jqw%9(F-oRCM`OGYw0;AJe9e{t|@%2&tVae5VTC~713n8EJ-#?2kCVgHS5bCXJs zQk*2rpSTK-ZN3~5y&r6EH`;f#SMAN$`LQd1m9aTj zSY*O+!mmke$w`Eyn*g-3miB*)iYyXbl|Is-us!)VSw+ zb*tJM11{0>XXJgfQf`~Ig+IU4dzCy;AtfsAgs)!x<57RTgdYQXoJ9p}_W?sDwAKti zBbmpB@u$O@JFxLdoi3h?Gf&$Ru9eOC6)+Ht9K9gI&70&RPEI1o{jMdL1{KfPKwF`&?{{Um9VI<$ zGr!~l7BLp!C~U`*bacVlUONAfEFlz-)-}3r@3#c+0@?y3gjC5hLX-^0S1wl(RAKV! z8N!>O@7Qr9#Layk*G;sRb^y>n7e8+qI(oB`;G7@c$IAnu@e8rHn<;a9HTt4Fa?Ug8 z95Ltpk|jp>{8?)9uo$(d6>7H*3p9@bfw3d%pQE z`S5QemB(PNnyX`s*Kq=AVnc^D!WU|VWP$uE{&(RbX6T?EuBc%TO?}3E2xvKM%*!W4uA0pUsr#6zdf;PYe|G!eSZIYadEIn-5Gc$(f0HL@BZi%;=ku_ z41dk!qutBfq>PM`!m`9z*-LyIsKe)Q??u}uWoqtkI`*?uEt&rnOg~Ncwzb_lAJ4}L z5+OW2Wnhqb^hC?ry1Iz{Y%mJR&`F z&NI#e0~k2J`tnht1tO+~epjIJOZH@2*p94=_Y1&sW5 z$m9tqqrF!ra)okmBX|#z48#GzfSjD==oZ}p{hTXleZwU$c?bBAsqs7IYk>yss*@Up zdQgOQa8(bOUk6$k^Tlz-kD_xN`D{DpLyoIhN|IX2&1ybK``{(A=ZB4Z5aDaEI zU&N$JH9Dfr7qp(?B_+fs+916DiIHEJKPH)BeBIVjbhi7*)60WnH@wa2u+b~{PD@^o zfr+s(DKo1E3x>2Dmia3nyWs0AIjfSS*TVK>7&<5j6pPo4m%gXJE>Vzw&_(bx36lHE zmtA20j|_8M{}vVHqR^gI`A^)X?oEWLxfTYX^lQzhq0uuqXm#Zg6LTgqCe?LuBC3?9 z-zEX?FzjXQ)nbpHkoIuf<*}3N`+AR~8VWwkv2QnSL*v3s6)r&%-lZJtowKOyu&B5~?p$VCnCdLYG*Fp>| zrQGqC(=MxdTcj(>%Tg-KWc)+;)33LNyp6&$qoYAgzc8*D0soxBC@J)2OKWD6S>0*y z$$XJs=|2&!n~)Gt8|~!LKhsI)cX1N3@Ir)|u>IHce=dgh^|Le{;!W^H;Y;DK5mCvn|Ld-^_AmqYIg)f=uj?4qMnVdK-Oa|220b_i2t zF?o!gr{I9Ul3ZZmkw(WejwAb#VsK z*Z=a}>vj$DO_$bC>2l|+Bew!e=6L%-4x0z}#Urw?nR-h%^<4@1UtMa`p(@I4ZJx!x z`7CigD^AL2_xCfQApW#}A~dgAwIwT&@UrL6i1)rhj&7xXNly^uYF1BSa+V+qZNoAz!}N<##Y$X5*c+X7bpt~2xz49o3ZtlS5@KOKjh^C zO)73@Cl_&Fm&}NWswrt;e{yYpch0M&Bamc{^_v1$e{ZjK#iUsEO_n&?WN*3RhZBoh z3VX~5o_FIlmhbEGbL&m+6xC`bhgJ|Jr*9V-14o`+cl1q7ZFZDjn^f;9t2fb;t~v^D z@9%$ShpAHwI3?RufmZtL?Ce9=ou0nNw>CBxzrz^GcvB0+(Zm3%hYpaI{*!r03OZ4t z*c23Qx|i==oqmfk^NcUI++KTzDehlO*x zE9K62lE^;bQbs-d3w&Jw@9(<+=ieF1@m33cAIR-3V`5%wWQtSMH7}vcgg_@R?NF8R zGDsusB7gCiIZ$&=VoNNZ`W6k&7rLD(3MohF=G!h%(iE&4LDJ=tGrIW%cBp7iGbwNw zj!7l9{v8{Ew7#1Gd=QI5_s3%Y@}NP29JrwV--(`otiA`1)S^IOlAr_8D>?2jC&>d) zxz~SJ1yodD`|l4WLkTJ+ozf*KDJdY`DWHf*4V}^@-6^Hy2tzv3Eg&(#5CXygGIYa8 z*PY+H-h0>oz5lz`{jYP@iFMXKYoEQJ@3Wup=fvn}y&xf^Ap`(`L`_vm4*;;DFxL?v zY|N3?l9mK>y7&6!3nk$0pRK69JPiQoN7R($4Se(VkUkcVeC~k5F-uj2hf&0D4-!7= zkiRgTa+r45Lz6?HUehhy{0xqJlU6&EHd!#Q14)D#tokd6KabNO){upXw(le80XD9J z``H!Bi6$-C0$}GWJd2Y{1$Ug$`!LEjTk!kfYEB+<d5|;LMNhY7jasV$Z|aZIgh+zaY{gpxa;R4xsFwgn{Yb0iAr1%@ zW`y12ssR1`#s1-0ovvd=!F@(zjwu>$8dYNEDH=(}h2M@$n}s1|?-iF&ED_@#QCtMf zwkm?`%n>7?GPa21$KB}>WKUVMQ^^$UaP=Q5{ERoLg?REQez-Q^7UcMR?MEMahFaXU zeFHT&%`>-M8tm^Iln3jdoRG*l{l0U%W`p;PbuJyrFPLX$e(0ShcI;-Uu$10$ecJZ3 zp=`hX%l6S};X|qsx?z<2{9CqQ{VF}ZgNo|*;uh?#g79)hY-uYH=~ErkJpI)J)UQ`q zp(9HT_sdTco_ig5i~VAKwHjPom{@ZVqUOf zp1>$yfrNLqMC0b)$Q{x87XJLb{`gq8ZwFHr`i*GyRJ{oBW|EfGb%iB82m8rZu|f0^TTd=E^zQCE!r`eQa!jDQ2K{Q5N0J>8o-**=*E4!3JNK8G#>MYO{Ht-nYVpo>XQ zEVn3E%6%MmTZ4jVyQIHKvqLx?Hab?bJCFe?QRI|ad$PXUa>D(IG`|}=I=Ytz_973N zl=UYsrbcE{gcw{b^(MjW`I?1-r)%qGt@^G$f2!OxHHY|Glji2$8v!?6do#B=3m=SWcW?Kc7`g)yqhG9WADZ) z;466Q@BN!QPlO6m1FnETJv?h~*n;%Z^!zq|_#yk=dYxcn1s^RO`9+?c(#ufMEwk5v z$73H`fvJ$yhTQ7nAeg_nplB-FoF@{i7q-R)X)<{IelQ`C7z>aCH!{g3RV}dCMdx*+ z+);~u^uYG^Dy2o-iwOrDD9I)=e++f(x6pm_s)>12znrbTUE;UTLy&I@5*v$Yd`8A) zyK_)ZAU!81mj zu@UGBQ~b)Ak)c{dA&k)q^6gugmw$Nj&D89_$8Yery1_}4%FSP0Ls)rhnq6dDSipty z+4|VWHMiz7HVXX2GHQFMI`<<2JV1vFT31I&v)_kl137wP%2x@aB)|$$Ol5=@HhJ6) zqK%*8p9F;ZiT)g8{W(_rS=VjzM_>AI4r}!3`=fM3!z8AA!zF#N*ZoTamOiHK@)cS_ zPc-4rXXphj%!6K~CY8roES}FNIMEapHSsnsyO<=41BbpAYLNyI11w-%L>b}khl-q{ zjWU1Pd>l~x1@is-?Lz5Nui_2K*$QfFV!TLoY@`g!{rIK0lN=!~7Vtq>IM2{) z44EMDNM?uDh6CjKmb9l4x^1Pc_M&;@uYE{(lm$wYmZ*=YfVA zh*|h`&)mFv=~J7tF?>=+9&YaSV~jFd;Xz>kF@_Yg=|pm~Te5pFj4}B`SBgR7>8-DeOg{1{z zMI(Bdu$w1kMsn-pcKywVV`qI;IbyYXTxQz6x$L;JE#^Fz z;=3{x81rLDeX88&Z(FnQ&CLfA4YIAbo|-fy#C$3{va zsj2sFS^QS8I@s1CbO$vsZMxzV#v}$d5w+I|_JWBzibE~hL&rAGViWz(YgstN$NGQS z9qdE9<+1!fWlaC-V37J;TQNH}GcY`?_(7_??b;@!b4dW-+cZWAV4~dMz1<9+n`_nx zgu)r;Jf6Q%e6!S{o$qtkpB>yO?OE$$6~mzoPr4%m6cocjOfK&>Dh#H+M568Bc|-1p znwpw*U=8v(kG%Z6p5E5QEY7NJQTG~56Yf;`Bm(9)b46&V&1R>>>G*cV zt3$IzB#HGmrXLJasEY+hC$TsCN4JaFz4lY4(67H67cxGm{meR0v2)EldU8lay1yvS z!;!>w5j3rWd1CyALu6)`v{D??2>vmkvs#|nn6uJxhoj@s#y0(T7nFBdSg`$AQSG9+ z&;HHKtXlP=jq#-L^std?rDc2XD+bX_`1wJWF|OARlFy+lp^C0-RmDildgj$Dtdz51 z9+UgGU4Kv`>J?wB->Mtc+##l=oF=B8@fxG#j+1_Mxj!g&oUpgHzj+J=iXy*8Z zq37HUKCt{}f7I^!MPfnnpaaTIo0RZ_droN4^ShEXd~LdU0Wy&3{aYJ9Jb;)%3;W)MAak0enyiwsvtaJ?^|pmb&;h=}-b(%Ji>Uf`R0>`Qf^tFD0+?YXyo zkV~6dqJa&FXpZI57am=aP$-{lQQUNYX?|7UUrplw?1Tm&j@@c}J$-2vtXbvzmlGq9 z#XM7-%d@v~=L|9|Sj*Ru!)Y7|8|Vwbb=Tw}@OK~iAh-@mqcT&1=o)|htpj0i)9FU? zqXc1-Em?E_=W1LUTcKpY_EhtAPfu0VF4fiP<@IFJlt4z794-JJD_{Kh;X@m++#T*N zmN4^c+IhAqp_h5!N1~Wn^X_dRpsFs5I@p+JM%LhGB zOMTgC5hThd)3QP2vR^$@eIw>&wh(*J>F+fK$_ytZCB3pg3O1^q6a286UGa1Oj6L<+ z-}q3RD|n$)8hkf77veZk(lu_rWdBV%F2T`r784|_g3s9BB1fMc?+^gB-@g+Q6I=7U z!7HFpR#2E5uqn zq`Z?Ji(|SZC}3(DW1pKjT-YK;fu3r);CUpRuD-V5$5>KUmPC)PnQJI-cpQ_Tj|{mD z%mLv5scdqWuAfWU?{=GsM4*8-cJ~LdLi{}JDtxA_Xvil!tqOCubK~RXOzz8aU3gyi zB&{At6+R3a8CCC0PCZ|VYZnL4-7ei-#lu5VXs$%xJ6MYtV}|qFUcad1E+y^AJmAqQmLng9@w2xTXLOt1^JB4+Q&OY78CP zC}s&<=^fxrpZxCd&|X+LYpAcEW=`!x7pL1C_Eu6Q83t3|otK(7 z;!207@Qo&duVjR_$mPi%AbWFC#rtnR^)ictkvVCf2GXm{J4>5N*toeB&^uzK>ZN+R z+XF-^avJKg!nTK9hCChXt{QXFBKheb)>{vZMMXrg0nN!JUUS6wxWtE9o%MNBcw+yL zj(fmxW(_|tx1GB8?j;xBUQ1kqhpmziMngN4gn*RyzAovX)4jY(5gjqpAUbe-<*4Gn#*LzShcXPU(*VTA@wCplsg5m#)k ztn*MbBd?CJdAl9zt0*lWFK>$%5j4m`-^8HG3;S)*C zCf)b;^c>#?0kU^1^O#xYeNNV&#o1JX6so)1+d5@mQOxo7}E&@8c zik?FZ{4w9I2eH7!>S@5FhSkL#+5cG_%kHKAv9}RsLw=k{z+`1>#zT6_dGG=q-EI=Y z?}n`b`oY0>eJgabg;ezPqDOmfz0o9yDlzaruYkZ9MxYz(>jaTK#wu-X*0%xMX{1<1 zRl8U~M1-v0JQpXgErYGy;*`?>e0q8_85euFJ>WakymM`JaMHNC8-s`A%S{}gpW4=DrNL>23^0^K2CK}+QQ7+FN{);+75Kw&wtjP$(`E{d?&fN zl9>-!muXDYXBO1*cQITY5kc+5V;YR*3$y_tABufXWp5s7+t*7qlun zJ4l-0fN}DH1JzjY)oUdgMqfv@DYJhLQHN5h|1UTGUy8!8e_40ce4boZTWsjdl{XTf ze=&i=e&j`%g`+*stueRDWY5i#sTC{MB($wUi7}YqUNoCp7?T9GN`!w!GcS$rAO*0n1C`!S*LV5eO$mY2X{uh`%ezm*^Cls7J50h4Vo0 zD#X(g^^YELY-<^1 ziC5z>ah=GYHu@jQE@^EtQm+FS2wxruC&eAeG695fh0=Vy8NMw(b<3`1(%5cVDJ9ps zaa1orH)$r+HQ37sd#8@a6uD&tVVu0pOHyBVNZe#eo&)3=s@LtvAI-|;0v0tX(_ULn z;&uk{#ep2{d(t1+Wb%CL+7z}ot)=`;TTy0^^)Ub;lqJX-H|<)mr>Jl47-#opWJpv{}R-=t149L1Lr93prO(cNx$&MX!I-s z$IqhLC1&6Lgnzc>B#F$Qu(F+vC#5J2mVDuBXrlK^W@O2XjkBiWb%B4=vwUrMJpJPa z+dt`t)=MP~TmH1VkP6GIv;Y;{;Cfeejlz$X_^A|{L%NDrDxN2d!rUstj9j_7p0ozs zhOMU@XM2c~;JC#YLehsDjCh5AE%haka+D7Rd`l36K6F%@N|7Am0f} z6vy7e?*F3F9O}ix$Xt@J_s7|a@vJBHiXD zm&&#o`+Hu{QSj60ETWs1ot{tEygHy5uT*GcoA6_l)W zA;{bLOw41X7h2lHFRWCqCgzJ^85P@Z2`yS{C>pRfRePk9B*`%vbd0vQH=vVr6Iyd$ z|M@xan|j!_j48jprzD8^bT-Hpg>J&k)8pXPr(7`uu+3fTD-4DSl63(v)v@k3i$!1N z6BQ3W-vG&(Uqiw!>k|MequR`Y#KQPE2#{tl)?+s0E|g7pUM>$NeV3zgdj+?kSzg}@ z!(YpQQ_$=g=)G$8o@Z`uOBsOGuA)PjJYSmd|8(DDjxc%MnuQBsExL$`o}A`8WtZPB z?i=dm6z4+~IX+#l)E|iNqTHGT{Uc*&QsE|5)0Ka{KJZd?CtwO{E!ZW zO#o>@v$>J1p))2!UcX@pyQH7rp3e`H_{1HVLlf3I0b3=3gN7M?^zo2KV$je14{C zzDkGl{=W9dkDFydYDTQ)4K~A&)dtcb#@};uBp5egeOtwE*&;GyVCLW7a`FkhNM6Zl z=<2$hu7-Ni@ibmDa(8z@wak(dYn3Y= z5Cuzs?bo|`ENQFD;s7&~dYHw~Oj;m9ho??c?X}zJO44msetzXussVRk;BE<~6427J zygb|SICGinz=0r)$k;R8DEtCX zIU~c6F0Oo?r4pJD_(so0x2~{8`z~2_W&YXxcXo@G?91U$OCy#PJ2-knK=`5}1FZmp zG0Zcjd&X_{GCyPF%?;i?AN;!%G_&yXa_ODb!D7R~+UIa%=y}ut3acv@_Q|MvQSkNo zIIOaB(%}Vn#(kP&?xca2v(3*q#~A_lgVjzU7x!WXx07QoDJiL9if=SkHCY41L8aBz zx7TxTa<2qv#at|JdvkSJqifD@c~aRZ2>bGy<3`IY&O1q|wDKi&Ej9VU)Iv|cn?0$7 zREL(IrE26-DO70I%4CuY7g-$-Dx#KXUT$7r->mfU0EcT-g@SjDfS}K)23Vj*zkF=S z7G{=_L?^?XHrx*P1!WKBH2)`zD?hH6VRRFx-wUyEvI5eR0N zQ_uAlM`;G|&}t*r^68|MzvD0GmVg>3MDTi4WaKxySD?>g-D2!e%bWbPwA(kFnwsjs zvTPuQLvEQN_x3tpozdDbWCpO-(deY8{6*^j-oWH+@lC(x&@j(m^ob2WvGupGvfnK& zeDmI>X2V(U&_!@FPHOk@pEAT1EY!CsZxG;=8fzTK0BA|O|wR$M9fo9 zelOED7Raz-E$@JXia2Ar=IVCJQz!I*imIxKuNKKxN~x<80$Jesg5{kZiU$vZQ2kKI z08)P^U=j(6y>9ec~jY|6)N$m&UTV7Vd`s>^#nSw8&6? zl>){4CmLhKW?vq=`bfFkk6}OuqwH7dEO!K=+h$2y3gf)7x_dX z1o)fvKjDhF$2B-PDZ|5a_316o_RbohV{FxFfAp|aUG#mARkJI{ z&3SRNog_alHVHu%mb{yPqG)*45u8+b=wjv{wGK&5NJs!D7W$(zXGcdzXJ&S^UWHbv z{3_S}n+V;(SSnz-Luo?J?niPrj<~Z00ZQS)gmE_uj}zENNiA#Sbbe zKn*?I^QjaA&&gi3zb6t+#C?BqytT2!wtM>+U}5bQ1*h$8ZZ`R^HMXGt%~EsA)oJoE z83YdN?xZXnTgtC}dy=ae6I1T8NZ#5c(JA$|XXNog#T|Hfhyi%6YEOpt9OQ^oR0w-` zdi?=ou5{SwByGnr(Wa;vK21VXtz&8m3m6+SVnKZKdE#(iu`(;HheI4SI?@I)g~O*| z(Dg_%2ahq-efH=ix`4ZIZEvUf@y;dTwg)Km79R6o4Vk34w2uu3A0rfyg~PY>0rDUj z{V`Sy!x@T=*($#+on307iWnD;Y|K=`(C4=QVI5sEI(_p%p(2nBSN^pY23r%{$11^# z`NyD8O0cOt#O>~`iXd|U)1@+jn6N^IyOY5GRP_&WvlOub`AHG|sgf@S;$*dx81W3#ch;DOD?2hy5=L Cb~4uh diff --git a/ui/home/__screenshots__/Stats.pw.tsx_mobile_4-items-default-view-mobile---default-1.png b/ui/home/__screenshots__/Stats.pw.tsx_mobile_4-items-default-view-mobile---default-1.png index c8348e42c7964159ac709750ab18f3bccedecdf1..d64b78d81c1476f709c6361285a7af2bf4c332ba 100644 GIT binary patch literal 10439 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 G_`d*4nmC03 literal 9511 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 fQzV(6_C%haqk<|Y*DncM`2