Commit c07bff1b authored by tom goriunov's avatar tom goriunov Committed by GitHub

Merge pull request #2654 from blockscout/chakra-v3

Update Chakra UI to v3
parents 32a9f92b 3c72a7d8

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

......@@ -362,6 +362,7 @@
"arbitrum",
"arbitrum_sepolia",
"base",
"blackfort_testnet",
"celo_alfajores",
"garnet",
"gnosis",
......@@ -371,12 +372,15 @@
"eth_sepolia",
"filecoin",
"mekong",
"neon_devnet",
"optimism",
"optimism_celestia",
"optimism_interop_0",
"optimism_sepolia",
"polygon",
"rari_testnet",
"rootstock_testnet",
"scroll_sepolia",
"shibarium",
"stability_testnet",
"zkevm",
......
......@@ -9,7 +9,12 @@ RUN ln -sf /usr/bin/python3 /usr/bin/python
### APP
# Install dependencies
WORKDIR /app
COPY package.json yarn.lock ./
COPY package.json yarn.lock tsconfig.json ./
COPY types ./types
COPY lib ./lib
COPY configs/app ./configs/app
COPY toolkit/theme ./toolkit/theme
COPY ui/shared/forms/validators/url.ts ./ui/shared/forms/validators/url.ts
RUN apk add git
RUN yarn --frozen-lockfile --network-timeout 100000
......
......@@ -10,10 +10,12 @@ const baseUrl = [
appPort && ':' + appPort,
].filter(Boolean).join('');
const isDev = getEnvValue('NEXT_PUBLIC_APP_ENV') === 'development';
const isPw = getEnvValue('NEXT_PUBLIC_APP_INSTANCE') === 'pw';
const spriteHash = getEnvValue('NEXT_PUBLIC_ICON_SPRITE_HASH');
const app = Object.freeze({
isDev,
isPw,
protocol: appSchema,
host: appHost,
port: appPort,
......
......@@ -10,37 +10,41 @@ NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws
# Instance ENVs
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP={ "id": "728301", "width": "728", "height": "90" }
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE={ "id": "728302", "width": "320", "height": "100" }
NEXT_PUBLIC_AD_BANNER_ADDITIONAL_PROVIDER=adbutler
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com
NEXT_PUBLIC_API_BASE_PATH=/
NEXT_PUBLIC_API_HOST=base.blockscout.com
NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
NEXT_PUBLIC_CONTRACT_CODE_IDES=[{'title':'Remix IDE','url':'https://remix.ethereum.org/?address={hash}&blockscout={domain}','icon_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/ide-icons/remix.png'}]
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swap','icon':'swap','dappId':'aerodrome'},{'text':'Payment link','icon':'payment_link','dappId':'peanut-protocol'},{'text':'Get gas','icon':'gas','dappId':'smol-refuel'}]
NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swap','icon':'swap','dappId':'rubic'},{'text':'Disperse','icon':'txn_batches_slim','dappId':'smol'},{'text':'Payment link','icon':'payment_link','dappId':'peanut-protocol'},{'text':'Get gas','icon':'gas','dappId':'smol-refuel'}]
NEXT_PUBLIC_DEX_POOLS_ENABLED=true
NEXT_PUBLIC_FAULT_PROOF_ENABLED=true
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/base-mainnet.json
NEXT_PUBLIC_FOOTER_LINKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/footer-links/base-mainnet.json
NEXT_PUBLIC_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/sherblockHolmesBadge
NEXT_PUBLIC_GAS_REFUEL_PROVIDER_CONFIG={'name': 'Need gas?', 'url_template': 'https://smolrefuel.com/?outboundChain={chainId}&partner=blockscout&utm_source=blockscout&disableBridges=true', 'dapp_id': 'smol-refuel', 'logo': 'https://blockscout-content.s3.amazonaws.com/smolrefuel-logo-action-button.png'}
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xfd5c5dae7b69fe29e61d19b9943e688aa0f1be1e983c4fba8fe985f90ff69d5f
NEXT_PUBLIC_HAS_CONTRACT_AUDIT_REPORTS=true
NEXT_PUBLIC_HAS_USER_OPS=true
NEXT_PUBLIC_HIDE_INDEXING_ALERT_INT_TXS=true
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND=linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)
NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)']}
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_LOGOUT_URL=https://basechain.us.auth0.com/v2/logout
NEXT_PUBLIC_MARKETPLACE_BANNER_CONTENT_URL=https://gist.githubusercontent.com/maxaleks/0d18fc309ff499075127b364cc69306d/raw/2a51f961a8c1b9f884f2ab7eed79d4b69330e1ae/peanut_protocol_banner.html
NEXT_PUBLIC_MARKETPLACE_BANNER_LINK_URL=https://base.blockscout.com/apps/peanut-protocol
NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE=<p>Joined recent campaigns? Mint your Merit Badge <a href="https://badges.blockscout.com?utm_source=instance&utm_medium=base">here</a></p>
NEXT_PUBLIC_MARKETPLACE_BANNER_CONTENT_URL=https://gist.githubusercontent.com/maikReal/974c47f86a3158c1a86b092ae2f044b3/raw/abcc7e02150cd85d4974503a0357162c0a2c35a9/merits-banner.html
NEXT_PUBLIC_MARKETPLACE_BANNER_LINK_URL=https://swap.blockscout.com?utm_source=blockscout&utm_medium=base
NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-categories/default.json
NEXT_PUBLIC_MARKETPLACE_ENABLED=true
NEXT_PUBLIC_MARKETPLACE_RATING_AIRTABLE_BASE_ID=appGkvtmKI7fXE4Vs
NEXT_PUBLIC_MARKETPLACE_SECURITY_REPORTS_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-security-reports/default.json
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6uMGPKjj1DK7NL
NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form
NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com
NEXT_PUBLIC_METASUITES_ENABLED=true
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}]
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'},{'name': 'zapper', 'url_template': 'https://zapper.xyz/account/{address}', 'logo': 'https://blockscout-content.s3.amazonaws.com/zapper-icon.png'}]
NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps']
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/pools']
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
......@@ -59,8 +63,10 @@ NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth.blockscout.com/
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://bridge.base.org/withdraw
NEXT_PUBLIC_ROLLUP_TYPE=optimistic
NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-base.safe.global
NEXT_PUBLIC_STATS_API_HOST=https://stats-l2-base-mainnet.k8s-prod-1.blockscout.com
NEXT_PUBLIC_STATS_API_HOST=https://stats-l2-base-mainnet.k8s-prod-2.blockscout.com
NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout
NEXT_PUBLIC_VIEWS_ADDRESS_IDENTICON_TYPE=gradient_avatar
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_VIEWS_NFT_MARKETPLACES=[{'name':'OpenSea','collection_url':'https://opensea.io/assets/base/{hash}','instance_url':'https://opensea.io/assets/base/{hash}/{id}','logo_url':'https://opensea.io/static/images/logos/opensea-logo.svg'}]
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
NEXT_PUBLIC_XSTAR_SCORE_URL=https://docs.xname.app/the-solution-adaptive-proof-of-humanity-on-blockchain/xhs-scoring-algorithm?utm_source=blockscout&utm_medium=address
\ No newline at end of file
......@@ -9,18 +9,21 @@ NEXT_PUBLIC_APP_PORT=3000
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws
NEXT_PUBLIC_CELO_ENABLED=true
NEXT_PUBLIC_CELO_L2_UPGRADE_BLOCK=26369280
# Instance ENVs
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com
NEXT_PUBLIC_API_BASE_PATH=/
NEXT_PUBLIC_API_HOST=celo-alfajores.blockscout.com
NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
NEXT_PUBLIC_CELO_ENABLED=true
NEXT_PUBLIC_CELO_L2_UPGRADE_BLOCK=26369280
NEXT_PUBLIC_CONTRACT_CODE_IDES=[{'title':'Remix IDE','url':'https://remix.ethereum.org/?address={hash}&blockscout={domain}','icon_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/ide-icons/remix.png'}]
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/celo-alfajores-testnet.json
NEXT_PUBLIC_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/sherblockHolmesBadge
NEXT_PUBLIC_GAS_TRACKER_ENABLED=false
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0x9767ce30754afad2a3279b9df2d13257f467c3dad4e0e601271e66d16dfd1641
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND=rgba(252, 255, 82, 1)
NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR=rgba(0, 0, 0, 1)
NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['rgba(252, 255, 82, 1)'],'text_color':['rgba(0, 0, 0, 1)']}
NEXT_PUBLIC_IS_TESTNET=true
NEXT_PUBLIC_MARKETPLACE_ENABLED=false
NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com
......@@ -32,12 +35,14 @@ NEXT_PUBLIC_NETWORK_ICON_DARK=https://raw.githubusercontent.com/blockscout/front
NEXT_PUBLIC_NETWORK_ID=44787
NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-logos/celo-logo-light.svg
NEXT_PUBLIC_NETWORK_LOGO_DARK=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-logos/celo-logo-dark.svg
NEXT_PUBLIC_NETWORK_MULTIPLE_GAS_CURRENCIES=true
NEXT_PUBLIC_NETWORK_NAME=Celo Alfajores
NEXT_PUBLIC_NETWORK_RPC_URL=https://alfajores-forno.celo-testnet.org
NEXT_PUBLIC_NETWORK_SHORT_NAME=Alfajores
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_STATS_API_HOST=https://stats-alfajores-testnet.k8s-prod-1.blockscout.com
NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout
NEXT_PUBLIC_VIEWS_BLOCK_HIDDEN_FIELDS=['burnt_fees']
NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true
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
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
\ No newline at end of file
......@@ -9,6 +9,8 @@ NEXT_PUBLIC_APP_PORT=3000
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws
NEXT_PUBLIC_COLOR_THEME_DEFAULT=dim
# Instance ENVs
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com
NEXT_PUBLIC_API_BASE_PATH=/
......
......@@ -9,45 +9,49 @@ NEXT_PUBLIC_APP_PORT=3000
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws
NEXT_PUBLIC_ROLLUP_OUTPUT_ROOTS_ENABLED=true
# Instance ENVs
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP={ "id": "749780", "width": "728", "height": "90" }
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE={ "id": "749779", "width": "320", "height": "100" }
NEXT_PUBLIC_AD_BANNER_ADDITIONAL_PROVIDER=adbutler
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com
NEXT_PUBLIC_API_BASE_PATH=/
NEXT_PUBLIC_API_HOST=optimism.blockscout.com
NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
NEXT_PUBLIC_CONTRACT_CODE_IDES=[{'title':'Remix IDE','url':'https://remix.ethereum.org/?address={hash}&blockscout={domain}','icon_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/ide-icons/remix.png'}]
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swap','icon':'swap','dappId':'velodrome'},{'text':'Payment link','icon':'payment_link','dappId':'peanut-protocol'},{'text':'Get gas','icon':'gas','dappId':'smol-refuel'}]
NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swap','icon':'swap','dappId':'rubic'},{'text':'Disperse','icon':'txn_batches_slim','dappId':'smol'},{'text':'Payment link','icon':'payment_link','dappId':'peanut-protocol'},{'text':'Get gas','icon':'gas','dappId':'smol-refuel'}]
NEXT_PUBLIC_DEX_POOLS_ENABLED=true
NEXT_PUBLIC_FAULT_PROOF_ENABLED=true
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/optimism-mainnet.json
NEXT_PUBLIC_FOOTER_LINKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/footer-links/optimism.json
NEXT_PUBLIC_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/sherblockHolmesBadge
NEXT_PUBLIC_GAS_REFUEL_PROVIDER_CONFIG={'name': 'Need gas?', 'url_template': 'https://smolrefuel.com/?outboundChain={chainId}&partner=blockscout&utm_source=blockscout&disableBridges=true', 'dapp_id': 'smol-refuel', 'logo': 'https://blockscout-content.s3.amazonaws.com/smolrefuel-logo-action-button.png'}
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0x97f34a4cf685e365460dd38dbe16e092d8e4cc4b6ac779e3abcf4c18df6b1329
NEXT_PUBLIC_HAS_CONTRACT_AUDIT_REPORTS=true
NEXT_PUBLIC_HAS_USER_OPS=true
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs', 'coin_price', 'market_cap', 'secondary_coin_price']
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND=linear-gradient(90deg, rgb(232, 52, 53) 0%, rgb(139, 28, 232) 100%)
NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR=rgb(255, 255, 255)
NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['linear-gradient(90deg, rgb(232, 52, 53) 0%, rgb(139, 28, 232) 100%)'],'text_color':['rgb(255, 255, 255)']}
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_LOGOUT_URL=https://optimism-goerli.us.auth0.com/v2/logout
NEXT_PUBLIC_MARKETPLACE_BANNER_CONTENT_URL=https://gist.githubusercontent.com/maxaleks/0d18fc309ff499075127b364cc69306d/raw/2a51f961a8c1b9f884f2ab7eed79d4b69330e1ae/peanut_protocol_banner.html
NEXT_PUBLIC_MARKETPLACE_BANNER_LINK_URL=https://optimism.blockscout.com/apps/peanut-protocol
NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE=<p>Joined recent campaigns? Mint your Merit Badge <a href="https://badges.blockscout.com?utm_source=instance&utm_medium=optimism">here</a></p>
NEXT_PUBLIC_MARKETPLACE_BANNER_CONTENT_URL=https://gist.githubusercontent.com/maikReal/974c47f86a3158c1a86b092ae2f044b3/raw/abcc7e02150cd85d4974503a0357162c0a2c35a9/merits-banner.html
NEXT_PUBLIC_MARKETPLACE_BANNER_LINK_URL=https://swap.blockscout.com?utm_source=blockscout&utm_medium=optimism
NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-categories/default.json
NEXT_PUBLIC_MARKETPLACE_ENABLED=true
NEXT_PUBLIC_MARKETPLACE_RATING_AIRTABLE_BASE_ID=appGkvtmKI7fXE4Vs
NEXT_PUBLIC_MARKETPLACE_SECURITY_REPORTS_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-security-reports/default.json
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6uMGPKjj1DK7NL
NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form
NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com
NEXT_PUBLIC_METASUITES_ENABLED=true
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}]
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}]
NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps']
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/pools']
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'GeckoTerminal','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/geckoterminal.png','baseUrl':'https://www.geckoterminal.com/','paths':{'token':'/optimism/pools'}}, {'title':'Tenderly','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/tenderly.png','baseUrl':'https://dashboard.tenderly.co','paths':{'tx':'/tx/optimistic'}},{'title':'3xpl','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/3xpl.png','baseUrl':'https://3xpl.com/','paths':{'tx':'/optimism/transaction','address':'/optimism/address'}}]
NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/optimism.svg
NEXT_PUBLIC_NETWORK_ICON_DARK=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/optimism.svg
NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/optimism-mainnet-light.svg
NEXT_PUBLIC_NETWORK_ICON_DARK=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/optimism-mainnet-dark.svg
NEXT_PUBLIC_NETWORK_ID=10
NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-logos/optimism.svg
NEXT_PUBLIC_NETWORK_LOGO_DARK=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-logos/optimism.svg
......@@ -66,4 +70,5 @@ NEXT_PUBLIC_STATS_API_HOST=https://stats-optimism-mainnet.k8s-prod-1.blockscout.
NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout
NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
NEXT_PUBLIC_WEB3_WALLETS=['token_pocket', 'metamask']
\ No newline at end of file
NEXT_PUBLIC_WEB3_WALLETS=['token_pocket', 'metamask']
NEXT_PUBLIC_XSTAR_SCORE_URL=https://docs.xname.app/the-solution-adaptive-proof-of-humanity-on-blockchain/xhs-scoring-algorithm?utm_source=blockscout&utm_medium=address
\ No newline at end of file
# Set of ENVs for OP Interop Alpha 0 network explorer
# https://optimism-interop-alpha-0.blockscout.com
# This is an auto-generated file. To update all values, run "yarn dev:preset:sync --name=optimism_interop_0"
# Local ENVs
NEXT_PUBLIC_APP_PROTOCOL=http
NEXT_PUBLIC_APP_HOST=localhost
NEXT_PUBLIC_APP_PORT=3000
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws
# Instance ENVs
NEXT_PUBLIC_AD_BANNER_PROVIDER=none
NEXT_PUBLIC_AD_TEXT_PROVIDER=none
NEXT_PUBLIC_API_BASE_PATH=/
NEXT_PUBLIC_API_HOST=optimism-interop-alpha-0.blockscout.com
NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
NEXT_PUBLIC_CONTRACT_CODE_IDES=[{'title':'Remix IDE','url':'https://remix.ethereum.org/?address={hash}&blockscout={domain}','icon_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/ide-icons/remix.png'}]
NEXT_PUBLIC_FAULT_PROOF_ENABLED=true
NEXT_PUBLIC_FOOTER_LINKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/footer-links/optimism.json
NEXT_PUBLIC_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/sherblockHolmesBadge
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['linear-gradient(90deg, rgb(232, 52, 53) 0%, rgb(139, 28, 232) 100%)'],'text_color':['rgb(255, 255, 255)']}
NEXT_PUBLIC_INTEROP_ENABLED=true
NEXT_PUBLIC_IS_TESTNET=true
NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/optimism.svg
NEXT_PUBLIC_NETWORK_ICON_DARK=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/optimism.svg
NEXT_PUBLIC_NETWORK_ID=420120000
NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-logos/optimism.svg
NEXT_PUBLIC_NETWORK_LOGO_DARK=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-logos/optimism.svg
NEXT_PUBLIC_NETWORK_NAME=OP Interop Alpha 0
NEXT_PUBLIC_NETWORK_RPC_URL=https://interop-alpha-0.optimism.io
NEXT_PUBLIC_NETWORK_SHORT_NAME=OP Interop Alpha 0
NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth-sepolia.blockscout.com/
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://bridge.interop-alpha-0.optimism.io
NEXT_PUBLIC_ROLLUP_OUTPUT_ROOTS_ENABLED=false
NEXT_PUBLIC_ROLLUP_TYPE=optimistic
NEXT_PUBLIC_STATS_API_HOST=https://stats-optimism-interop-devnet-0.k8s-prod-1.blockscout.com
NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout
NEXT_PUBLIC_VIEWS_TOKEN_SCAM_TOGGLE_ENABLED=true
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
NEXT_PUBLIC_WEB3_WALLETS=['token_pocket', 'metamask']
\ No newline at end of file
......@@ -14,7 +14,9 @@ NEXT_PUBLIC_API_BASE_PATH=/
NEXT_PUBLIC_API_HOST=scroll-sepolia.blockscout.com
NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
NEXT_PUBLIC_CONTRACT_CODE_IDES=[{'title':'Remix IDE','url':'https://remix.ethereum.org/?address={hash}&blockscout={domain}','icon_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/ide-icons/remix.png'}]
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/scroll-testnet.json
NEXT_PUBLIC_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/sherblockHolmesBadge
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xa0d22caf6217a488b1e97b646c5ed88e8a3020a607bcd1f3fe8d4c430bb19ad5
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['rgba(255, 238, 218, 1)'],'text_color':['rgba(25, 6, 2, 1)']}
......@@ -33,9 +35,8 @@ NEXT_PUBLIC_NETWORK_RPC_URL=https://sepolia-rpc.scroll.io
NEXT_PUBLIC_NETWORK_SHORT_NAME=Scroll Sepolia Testnet
NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/scroll-testnet.png
NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY=6Ld0iT8aAAAAAJdju0CmAwGjW7JTDvIw-Q5pwt5T
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth-sepolia.blockscout.com
NEXT_PUBLIC_ROLLUP_TYPE=scroll
NEXT_PUBLIC_STATS_API_HOST=https://stats-scroll-sepolia.k8s-prod-2.blockscout.com
NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
NEXT_PUBLIC_ROLLUP_TYPE=scroll
NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth-sepolia.blockscout.com/
\ No newline at end of file
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
\ No newline at end of file
declare module 'react-identicons'
declare module 'react-identicons';
declare module 'use-font-face-observer';
......@@ -71,4 +71,4 @@ node --no-warnings ./og_image_generator.js
node ./feature-reporter.js
echo "Starting Next.js application"
exec "$@"
\ No newline at end of file
exec "$@"
......@@ -4,6 +4,7 @@
"noEmit": false,
"target": "es2016",
"module": "CommonJS",
"moduleResolution": "node",
"paths": {
"nextjs-routes": ["./nextjs/nextjs-routes.d.ts"],
}
......
......@@ -3,6 +3,7 @@
"compilerOptions": {
"noEmit": false,
"module": "CommonJS",
"moduleResolution": "node",
"outDir": "./build",
"paths": {
"nextjs-routes": ["./nextjs/nextjs-routes.d.ts"],
......
......@@ -59,7 +59,7 @@ module.exports = {
{
userAgent: '*',
allow: '/',
disallow: ['/auth/*', '/login', '/sprite', '/account/*', '/api/*', '/node-api/*'],
disallow: ['/auth/*', '/login', '/chakra', '/sprite', '/account/*', '/api/*', '/node-api/*'],
},
],
},
......@@ -70,6 +70,7 @@ module.exports = {
'/auth/*',
'/login',
'/sprite',
'/chakra',
],
transform: async(config, path) => {
switch (path) {
......
......@@ -27,13 +27,24 @@ const RESTRICTED_MODULES = {
{ name: 'playwright/TestApp', message: 'Please use render() fixture from test() function of playwright/lib module' },
{
name: '@chakra-ui/react',
importNames: [ 'Popover', 'Menu', 'PinInput', 'useToast', 'Skeleton' ],
message: 'Please use corresponding component or hook from ui/shared/chakra component instead',
importNames: [
'Menu', 'useToast', 'useDisclosure', 'useClipboard', 'Tooltip', 'Skeleton', 'IconButton', 'Button', 'ButtonGroup', 'Link', 'LinkBox', 'LinkOverlay',
'Dialog', 'DialogRoot', 'DialogContent', 'DialogHeader', 'DialogCloseTrigger',
'Tag', 'Switch', 'Image', 'Popover', 'PopoverTrigger', 'PopoverContent', 'PopoverBody', 'PopoverFooter',
'DrawerRoot', 'DrawerBody', 'DrawerContent', 'DrawerOverlay', 'DrawerBackdrop', 'DrawerTrigger', 'Drawer',
'Alert', 'AlertIcon', 'AlertTitle', 'AlertDescription',
'Select', 'SelectRoot', 'SelectControl', 'SelectContent', 'SelectItem', 'SelectValueText',
'Heading', 'Badge', 'Tabs', 'Show', 'Hide', 'Checkbox', 'CheckboxGroup',
'Table', 'TableRoot', 'TableBody', 'TableHeader', 'TableRow', 'TableCell',
'Menu', 'MenuRoot', 'MenuTrigger', 'MenuContent', 'MenuItem', 'MenuTriggerItem', 'MenuRadioItemGroup', 'MenuContextTrigger',
'Rating', 'RatingGroup',
],
message: 'Please use corresponding component or hook from "toolkit" instead',
},
{
name: 'next/link',
importNames: [ 'default' ],
message: 'Please use ui/shared/NextLink component instead',
message: 'Please use toolkit/chakra/link component instead',
},
],
patterns: [
......@@ -294,6 +305,7 @@ export default tseslint.config(
'/^playwright/',
'/^stubs/',
'/^theme/',
'/^toolkit/',
'/^ui/',
],
[ 'parent', 'sibling', 'index' ],
......@@ -440,4 +452,13 @@ export default tseslint.config(
'no-restricted-properties': 'off',
},
},
{
files: [
'toolkit/chakra/**',
],
rules: {
// for toolkit components allow to import @chakra-ui/react directly
'no-restricted-imports': 'off',
},
},
);
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.44 8.035a.791.791 0 0 0 1.12 0l3.802-3.803a.791.791 0 0 1 1.119 0l.287.287a.79.79 0 0 1 0 1.119L11.965 9.44a.79.79 0 0 0 0 1.118l3.803 3.803a.791.791 0 0 1 0 1.119l-.287.287a.791.791 0 0 1-1.119 0l-3.803-3.803a.79.79 0 0 0-1.118 0l-3.803 3.803a.79.79 0 0 1-1.119 0l-.287-.287a.791.791 0 0 1 0-1.119l3.803-3.803a.791.791 0 0 0 0-1.118L4.232 5.638a.791.791 0 0 1 0-1.119l.287-.287a.791.791 0 0 1 1.119 0L9.44 8.035Z" fill="currentColor"/>
</svg>
<svg viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="m6 5.293 2.475-2.475.707.707L6.707 6l2.475 2.475-.707.707L6 6.707 3.525 9.182l-.707-.707L5.293 6 2.818 3.525l.707-.707L6 5.293Z" fill="currentColor"/>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.2929 9.87888C11.6834 10.2694 12.3166 10.2694 12.7071 9.87888L16.243 6.34299C16.6335 5.95252 17.2665 5.95252 17.657 6.34299C18.0475 6.73345 18.0475 7.36652 17.657 7.75699L14.1211 11.2929C13.7306 11.6834 13.7306 12.3166 14.1211 12.7071L17.657 16.243C18.0475 16.6335 18.0475 17.2665 17.657 17.657C17.2665 18.0475 16.6335 18.0475 16.243 17.657L12.7071 14.1211C12.3166 13.7306 11.6834 13.7306 11.2929 14.1211L7.75699 17.657C7.36652 18.0475 6.73345 18.0475 6.34299 17.657C5.95252 17.2665 5.95252 16.6335 6.34299 16.243L9.87888 12.7071C10.2694 12.3166 10.2694 11.6834 9.87888 11.2929L6.34299 7.75699C5.95252 7.36652 5.95252 6.73345 6.34299 6.34299C6.73345 5.95252 7.36652 5.95252 7.75699 6.34299L11.2929 9.87888Z" fill="currentColor"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="none">
<path d="m10 3.557-.555-.577c-.947-.946-2.205-.989-3.508-.97a4.876 4.876 0 0 0-3.469 1.547A5.443 5.443 0 0 0 1.001 7.22a5.46 5.46 0 0 0 1.363 3.709L10 18.5l7.636-7.58a5.46 5.46 0 0 0 1.363-3.709 5.443 5.443 0 0 0-1.467-3.664 4.876 4.876 0 0 0-3.47-1.546c-1.302-.02-2.56.023-3.507.969L10 3.557Z" fill="currentColor"/>
<svg viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="m10 4.34-.555-.578c-.947-.946-2.205-.988-3.508-.97A4.876 4.876 0 0 0 2.468 4.34a5.443 5.443 0 0 0-1.467 3.664 5.46 5.46 0 0 0 1.363 3.71L10 19.282l7.636-7.58a5.46 5.46 0 0 0 1.363-3.71 5.443 5.443 0 0 0-1.467-3.663 4.876 4.876 0 0 0-3.47-1.547c-1.302-.019-2.56.023-3.507.97L10 4.338Z" fill="currentColor"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21 20" fill="none">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.671 3.458a5.332 5.332 0 0 1 7.542 7.532l-.007.008-7.54 7.548-7.539-7.54-.007-.008a5.332 5.332 0 0 1 7.542-7.532l.002-.001.008-.007Zm1.017 1.06-1.017 1.018L9.647 4.53A3.862 3.862 0 0 0 4.18 9.983l6.485 6.484 6.485-6.493a3.863 3.863 0 0 0-5.463-5.455Z" fill="currentColor" stroke="currentColor" stroke-width=".4"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.671 3.458a5.332 5.332 0 0 1 7.542 7.532l-.007.008-7.54 7.548-7.539-7.54-.007-.008a5.332 5.332 0 0 1 7.542-7.532l.002-.001.008-.007Zm1.017 1.06-1.017 1.018L9.647 4.53A3.862 3.862 0 0 0 4.18 9.983l6.485 6.484 6.485-6.493a3.863 3.863 0 0 0-5.463-5.455Z" fill="currentColor"/>
<svg viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.005 4.24a5.332 5.332 0 0 1 7.542 7.532l-.007.008L10 19.328l-7.54-7.54-.007-.007a5.332 5.332 0 0 1 7.542-7.532l.003-.002.007-.007Zm1.017 1.061L10.004 6.32 8.98 5.312a3.862 3.862 0 0 0-5.465 5.453L10 17.25l6.485-6.493A3.862 3.862 0 0 0 11.022 5.3Z" fill="currentColor" stroke="currentColor" stroke-width=".4"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.005 4.24a5.332 5.332 0 0 1 7.542 7.532l-.007.008L10 19.328l-7.54-7.54-.007-.007a5.332 5.332 0 0 1 7.542-7.532l.003-.002.007-.007Zm1.017 1.061L10.004 6.32 8.98 5.312a3.862 3.862 0 0 0-5.465 5.453L10 17.25l6.485-6.493A3.863 3.863 0 0 0 11.022 5.3Z" fill="currentColor"/>
</svg>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.99984 18.3334C5.39734 18.3334 1.6665 14.6026 1.6665 10.0001C1.6665 5.39758 5.39734 1.66675 9.99984 1.66675C14.6023 1.66675 18.3332 5.39758 18.3332 10.0001C18.3332 14.6026 14.6023 18.3334 9.99984 18.3334ZM9.1665 9.16675V14.1667H10.8332V9.16675H9.1665ZM9.1665 5.83342V7.50008H10.8332V5.83342H9.1665Z" fill="currentColor"/>
</svg>
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="m15.026 13.848 2.98 2.978a.834.834 0 1 1-1.18 1.18l-2.978-2.98a7.467 7.467 0 0 1-4.681 1.64c-4.14 0-7.5-3.36-7.5-7.5 0-4.14 3.36-7.5 7.5-7.5 4.14 0 7.5 3.36 7.5 7.5a7.466 7.466 0 0 1-1.641 4.681Zm-1.672-.619A5.814 5.814 0 0 0 15 9.167a5.832 5.832 0 0 0-5.833-5.834 5.831 5.831 0 0 0-5.834 5.834A5.832 5.832 0 0 0 9.167 15a5.814 5.814 0 0 0 4.062-1.646l.125-.125Z" fill="currentColor"/>
<path d="m14.048 13.074 2.464 2.463a.69.69 0 1 1-.975.975l-2.463-2.464A6.205 6.205 0 0 1 3 9.202 6.205 6.205 0 0 1 9.203 3a6.205 6.205 0 0 1 4.845 10.074Zm-1.382-.512a4.823 4.823 0 0 0-3.463-8.184 4.822 4.822 0 0 0-4.825 4.825 4.823 4.823 0 0 0 8.184 3.463l.104-.104Z" fill="currentColor"/>
</svg>
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.004 2.61 13.2 8.432l1.443-3.434 6.36-2.386Z" fill="#E2761B"/>
<path d="m2.988 2.61 7.741 5.876-1.372-3.489-6.369-2.386Zm15.208 13.492L16.117 19.3l4.447 1.229 1.279-4.356-3.647-.07Zm-16.032.071 1.271 4.356L7.882 19.3l-2.078-3.198-3.64.071Z" fill="#E4761B"/>
<path d="m7.631 10.7-1.24 1.882 4.417.197-.157-4.765L7.63 10.7Zm8.73 0L13.3 7.959l-.101 4.82 4.408-.197-1.248-1.883Zm-8.479 8.6 2.651-1.3-2.29-1.795-.36 3.095ZM13.46 18l2.658 1.3-.368-3.095L13.459 18Z" fill="#E4761B"/>
<path d="M16.117 19.3 13.458 18l.212 1.741-.023.733 2.47-1.174Zm-8.235 0 2.47 1.174-.015-.733.196-1.74-2.65 1.299Z" fill="#D7C1B3"/>
<path d="M10.392 15.055 8.18 14.4l1.561-.717.65 1.37Zm3.208 0 .65-1.37 1.57.716-2.22.654Z" fill="#233447"/>
<path d="m7.882 19.3.377-3.198-2.455.071L7.882 19.3Zm7.859-3.198.376 3.198 2.079-3.127-2.455-.07Zm1.867-3.52-4.408.197.408 2.276.65-1.37 1.57.716 1.78-1.82Zm-9.428 1.82 1.569-.718.643 1.37.416-2.275-4.416-.197 1.788 1.82Z" fill="#CD6116"/>
<path d="m6.392 12.582 1.85 3.623L8.18 14.4l-1.788-1.82Zm9.435 1.82-.078 1.803 1.859-3.623-1.78 1.82Zm-5.02-1.623-.415 2.276.518 2.686.117-3.537-.22-1.425Zm2.393 0-.212 1.417.094 3.545.526-2.686-.408-2.276Z" fill="#E4751F"/>
<path d="m13.608 15.055-.526 2.686.377.26 2.29-1.796.078-1.804-2.22.654ZM8.18 14.4l.063 1.804L10.533 18l.377-.26-.518-2.685L8.18 14.4Z" fill="#F6851B"/>
<path d="m13.647 20.474.023-.733-.196-.173h-2.957l-.18.173.016.733-2.47-1.174.862.709 1.749 1.22h3.004l1.757-1.22.862-.709-2.47 1.174Z" fill="#C0AD9E"/>
<path d="m13.459 18-.377-.26H10.91l-.377.26-.196 1.741.18-.173h2.957l.196.173-.211-1.74Z" fill="#161616"/>
<path d="M21.333 8.81 22 5.595l-.996-2.985-7.545 5.623L16.36 10.7l4.102 1.206.91-1.064-.392-.283.628-.575-.487-.378.628-.48-.416-.316ZM2 5.595l.666 3.213-.423.315.627.48-.478.379.627.575-.392.283.902 1.064 4.102-1.206 2.902-2.465L2.988 2.61 2 5.596Z" fill="#763D16"/>
<path d="M20.462 11.904 16.361 10.7l1.247 1.883-1.86 3.623 2.448-.032h3.647l-1.38-4.269ZM7.632 10.7l-4.103 1.205-1.365 4.27h3.64l2.439.03-1.851-3.622 1.24-1.883Zm5.568 2.08.259-4.545 1.192-3.237H9.357l1.176 3.237.275 4.545.094 1.433.008 3.529h2.172l.016-3.529.102-1.433Z" fill="#F6851B"/>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
<g clip-path="url(#a)">
<path fill="#FF5C16" d="m17.763 17.7-3.864-1.15-2.914 1.742H8.952L6.037 16.55 2.175 17.7 1 13.736l1.175-4.402L1 5.613 2.175 1l6.034 3.605h3.519L17.763 1l1.175 4.612-1.175 3.721 1.175 4.402-1.175 3.966Z"/>
<path fill="#FF5C16" d="M2.176 1 8.21 4.608l-.24 2.476L2.176 1Zm3.862 12.737 2.655 2.022-2.655.791v-2.813Zm2.443-3.344-.51-3.307-3.267 2.249-.002-.001v.001l.01 2.315 1.325-1.257H8.48ZM17.763 1l-6.035 3.608.24 2.476L17.762 1ZM13.9 13.737l-2.656 2.022 2.656.791v-2.813Zm1.335-4.402v-.002l-.001.001-3.267-2.248-.51 3.307H13.9l1.325 1.257.01-2.315Z"/>
<path fill="#E34807" d="M6.037 16.55 2.175 17.7 1 13.737h5.037v2.814Zm2.443-6.159.738 4.781-1.023-2.658-3.485-.865 1.326-1.257H8.48Zm5.42 6.159 3.863 1.15 1.175-3.964H13.9v2.814Zm-2.442-6.159-.738 4.781 1.022-2.658 3.485-.865-1.326-1.257h-2.443Z"/>
<path fill="#FF8D5D" d="m1 13.735 1.175-4.402H4.7l.01 2.316 3.484.864 1.023 2.658-.526.586-2.655-2.023H1Zm17.938 0-1.175-4.402h-2.527l-.009 2.316-3.485.864-1.022 2.658.525.586 2.656-2.023h5.037Zm-7.21-9.13H8.209l-.238 2.476 1.247 8.088h1.502l1.248-8.088-.24-2.476Z"/>
<path fill="#661800" d="M2.175 1 1 5.612l1.175 3.721H4.7l3.27-2.249L2.175 1ZM7.75 11.352H6.605l-.623.61 2.214.55-.446-1.16ZM17.763 1l1.175 4.612-1.175 3.721h-2.527l-3.268-2.249L17.763 1Zm-5.574 10.352h1.147l.623.611-2.217.55.447-1.162Zm-1.205 5.363.261-.957-.525-.585H9.217l-.526.585.261.957"/>
<path fill="#C0C4CD" d="M10.984 16.714v1.579H8.952v-1.579h2.032Z"/>
<path fill="#E7EBF6" d="m6.038 16.548 2.916 1.744v-1.579l-.261-.956-2.655.791Zm7.863 0-2.917 1.744v-1.579l.262-.956 2.655.791Z"/>
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M1 1h18v17.366H1z"/>
</clipPath>
</defs>
</svg>
import { ChakraProvider } from '@chakra-ui/react';
import { GrowthBookProvider } from '@growthbook/growthbook-react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import type { RenderOptions } from '@testing-library/react';
......@@ -8,7 +7,7 @@ import React from 'react';
import { AppContextProvider } from 'lib/contexts/app';
import { ScrollDirectionProvider } from 'lib/contexts/scrollDirection';
import { SocketProvider } from 'lib/socket/context';
import theme from 'theme/theme';
import { Provider as ChakraProvider } from 'toolkit/chakra/provider';
import 'lib/setLocale';
......@@ -32,7 +31,7 @@ const TestApp = ({ children }: { children: React.ReactNode }) => {
}));
return (
<ChakraProvider theme={ theme }>
<ChakraProvider>
<QueryClientProvider client={ queryClient }>
<AppContextProvider pageProps={ PAGE_PROPS }>
<ScrollDirectionProvider>
......
......@@ -41,3 +41,15 @@ global.console = {
consoleError(...args);
},
};
// Polyfill for structuredClone
if (typeof structuredClone === 'undefined') {
global.structuredClone = <T>(obj: T): T => {
try {
return JSON.parse(JSON.stringify(obj)) as T;
} catch (error) {
// Fallback for circular references and other special cases
return obj;
}
};
}
import {
ChakraProvider as ChakraProviderDefault,
cookieStorageManagerSSR,
localStorageManager,
} from '@chakra-ui/react';
import type { ChakraProviderProps } from '@chakra-ui/react';
import React from 'react';
import { get, NAMES } from 'lib/cookies';
import theme from 'theme/theme';
interface Props extends ChakraProviderProps {
cookies?: string;
}
export function ChakraProvider({ cookies, children }: Props) {
// When a cookie header is present, cookieStorageManagerSSR looks for a "chakra-ui-color-mode" cookie.
// If it doesn’t find one, it doesn’t consider theme’s initialColorMode. Instead, it is defaulting to light mode
// So we need to use localStorageManager instead of cookieStorageManagerSSR to get the correct default color mode
const colorModeManager =
typeof cookies === 'string' && get(NAMES.COLOR_MODE, cookies) ?
cookieStorageManagerSSR(typeof document !== 'undefined' ? document.cookie : cookies) :
localStorageManager;
return (
<ChakraProviderDefault colorModeManager={ colorModeManager } theme={ theme }>
{ children }
</ChakraProviderDefault>
);
}
import { useBoolean } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query';
import { useQueryClient } from '@tanstack/react-query';
import { useToggle } from '@uidotdev/usehooks';
import { useRouter } from 'next/router';
import React, { createContext, useContext, useEffect, useMemo, useCallback } from 'react';
import { useSignMessage } from 'wagmi';
......@@ -22,10 +22,10 @@ import * as cookies from 'lib/cookies';
import decodeJWT from 'lib/decodeJWT';
import getErrorMessage from 'lib/errors/getErrorMessage';
import getErrorObjPayload from 'lib/errors/getErrorObjPayload';
import useToast from 'lib/hooks/useToast';
import getQueryParamString from 'lib/router/getQueryParamString';
import removeQueryParam from 'lib/router/removeQueryParam';
import useAccount from 'lib/web3/useAccount';
import { toaster } from 'toolkit/chakra/toaster';
import useProfileQuery from 'ui/snippets/auth/useProfileQuery';
const feature = config.features.rewards;
......@@ -116,13 +116,12 @@ export function RewardsContextProvider({ children }: Props) {
const router = useRouter();
const queryClient = useQueryClient();
const apiFetch = useApiFetch();
const toast = useToast();
const { address } = useAccount();
const { signMessageAsync } = useSignMessage();
const profileQuery = useProfileQuery();
const [ isLoginModalOpen, setIsLoginModalOpen ] = useBoolean(false);
const [ isInitialized, setIsInitialized ] = useBoolean(false);
const [ isLoginModalOpen, setIsLoginModalOpen ] = useToggle(false);
const [ isInitialized, setIsInitialized ] = useToggle(false);
const [ apiToken, setApiToken ] = React.useState<string | undefined>();
// Initialize state with the API token from cookies
......@@ -133,7 +132,7 @@ export function RewardsContextProvider({ children }: Props) {
if (registeredAddress === profileQuery.data?.address_hash) {
setApiToken(token);
}
setIsInitialized.on();
setIsInitialized(true);
}
}, [ setIsInitialized, profileQuery ]);
......@@ -189,22 +188,18 @@ export function RewardsContextProvider({ children }: Props) {
cookies.set(cookies.NAMES.REWARDS_REFERRAL_CODE, refCode);
removeQueryParam(router, 'ref');
if (!apiToken) {
setIsLoginModalOpen.on();
setIsLoginModalOpen(true);
}
}
}, [ router, apiToken, isInitialized, setIsLoginModalOpen ]);
const errorToast = useCallback((error: unknown) => {
const apiError = getErrorObjPayload<{ message: string }>(error);
toast({
position: 'top-right',
toaster.error({
title: 'Error',
description: apiError?.message || getErrorMessage(error) || 'Something went wrong. Try again later.',
status: 'error',
variant: 'subtle',
isClosable: true,
});
}, [ toast ]);
}, [ ]);
// Login to the rewards program
const login = useCallback(async(refCode: string) => {
......@@ -263,6 +258,14 @@ export function RewardsContextProvider({ children }: Props) {
}
}, [ apiFetch, errorToast, fetchParams ]);
const openLoginModal = React.useCallback(() => {
setIsLoginModalOpen(true);
}, [ setIsLoginModalOpen ]);
const closeLoginModal = React.useCallback(() => {
setIsLoginModalOpen(false);
}, [ setIsLoginModalOpen ]);
const value = useMemo(() => {
if (!feature.isEnabled) {
return initialState;
......@@ -277,14 +280,15 @@ export function RewardsContextProvider({ children }: Props) {
saveApiToken,
isInitialized,
isLoginModalOpen,
openLoginModal: setIsLoginModalOpen.on,
closeLoginModal: setIsLoginModalOpen.off,
openLoginModal,
closeLoginModal,
login,
claim,
};
}, [
isLoginModalOpen, setIsLoginModalOpen, balancesQuery, dailyRewardQuery, checkUserQuery,
balancesQuery, dailyRewardQuery, checkUserQuery,
apiToken, login, claim, referralsQuery, rewardsConfigQuery, isInitialized, saveApiToken,
isLoginModalOpen, openLoginModal, closeLoginModal,
]);
return (
......
......@@ -9,7 +9,7 @@ const feature = config.features.marketplace;
export default function useGraphLinks() {
const fetch = useFetch();
return useQuery<unknown, ResourceError<unknown>, Record<string, Array<{ text: string; url: string }>>>({
return useQuery<unknown, ResourceError<unknown>, Record<string, Array<{ title: string; url: string }>>>({
queryKey: [ 'graph-links' ],
queryFn: async() => fetch((feature.isEnabled && feature.graphLinksUrl) ? feature.graphLinksUrl : '', undefined, { resource: 'graph-links' }),
enabled: feature.isEnabled && Boolean(feature.graphLinksUrl),
......
import React from 'react';
type Id = string | number;
export interface Params<T> {
data: Array<T>;
idFn: (item: T) => Id;
enabled: boolean;
}
export default function useInitialList<T>({ data, idFn, enabled }: Params<T>) {
const [ list, setList ] = React.useState<Array<Id>>([]);
React.useEffect(() => {
if (enabled) {
setList(data.map(idFn));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ enabled ]);
const isNew = React.useCallback((data: T) => {
return !list.includes(idFn(data));
}, [ list, idFn ]);
const getAnimationProp = React.useCallback((data: T) => {
return isNew(data) ? 'fade-in 500ms linear' : undefined;
}, [ isNew ]);
return React.useMemo(() => {
return {
list,
isNew,
getAnimationProp,
};
}, [ list, isNew, getAnimationProp ]);
}
import type { UseToastOptions, ToastProps } from '@chakra-ui/react';
import { createToastFn, useChakra } from '@chakra-ui/react';
import React from 'react';
import Toast from 'ui/shared/chakra/Toast';
// there is no toastComponent prop in UseToastOptions type
// but these options will be passed to createRenderToast under the hood
// and it accepts custom toastComponent
const defaultOptions: UseToastOptions & { toastComponent?: React.FC<ToastProps> } = {
toastComponent: Toast,
position: 'top-right',
isClosable: true,
containerStyle: {
margin: 3,
marginBottom: 0,
},
variant: 'subtle',
};
export default function useToastModified() {
const { theme } = useChakra();
return React.useMemo(
() => createToastFn(theme.direction, defaultOptions),
[ theme.direction ],
);
}
......@@ -65,6 +65,7 @@ const OG_TYPE_DICT: Record<Route['pathname'], OGPageType> = {
// service routes, added only to make typescript happy
'/login': 'Regular page',
'/sprite': 'Regular page',
'/chakra': 'Regular page',
'/api/metrics': 'Regular page',
'/api/monitoring/invalid-api-schema': 'Regular page',
'/api/log': 'Regular page',
......
......@@ -68,6 +68,7 @@ const TEMPLATE_MAP: Record<Route['pathname'], string> = {
// service routes, added only to make typescript happy
'/login': DEFAULT_TEMPLATE,
'/sprite': DEFAULT_TEMPLATE,
'/chakra': DEFAULT_TEMPLATE,
'/api/metrics': DEFAULT_TEMPLATE,
'/api/monitoring/invalid-api-schema': DEFAULT_TEMPLATE,
'/api/log': DEFAULT_TEMPLATE,
......
......@@ -65,6 +65,7 @@ const TEMPLATE_MAP: Record<Route['pathname'], string> = {
// service routes, added only to make typescript happy
'/login': '%network_name% login',
'/sprite': '%network_name% SVG sprite',
'/chakra': '%network_name% Chakra UI showcase',
'/api/metrics': '%network_name% node API prometheus metrics',
'/api/monitoring/invalid-api-schema': '%network_name% node API prometheus metrics',
'/api/log': '%network_name% node API request log',
......
......@@ -63,6 +63,7 @@ export const PAGE_TYPE_DICT: Record<Route['pathname'], string> = {
// service routes, added only to make typescript happy
'/login': 'Login',
'/sprite': 'Sprite',
'/chakra': 'Chakra UI showcase',
'/api/metrics': 'Node API: Prometheus metrics',
'/api/monitoring/invalid-api-schema': 'Node API: Prometheus metrics',
'/api/log': 'Node API: Request log',
......
import type { ColorMode } from '@chakra-ui/react';
import { useColorMode } from '@chakra-ui/react';
import { usePathname } from 'next/navigation';
import { useRouter } from 'next/router';
import React from 'react';
......@@ -8,6 +6,8 @@ import config from 'configs/app';
import * as cookies from 'lib/cookies';
import getQueryParamString from 'lib/router/getQueryParamString';
import { COLOR_THEMES } from 'lib/settings/colorTheme';
import { useColorMode } from 'toolkit/chakra/color-mode';
import type { ColorMode } from 'toolkit/chakra/color-mode';
import getPageType from './getPageType';
import getTabName from './getTabName';
......
import type { ColorMode } from '@chakra-ui/react';
import type { ColorThemeId } from 'types/settings';
import type { ColorMode } from 'toolkit/chakra/color-mode';
interface ColorTheme {
id: ColorThemeId;
label: string;
......
......@@ -71,8 +71,7 @@ export function app(): CspDev.DirectiveDescriptor {
config.app.isDev ? KEY_WORDS.UNSAFE_EVAL : '',
// hash of ColorModeScript: system + dark
'\'sha256-e7MRMmTzLsLQvIy1iizO1lXf7VWYoQ6ysj5fuUzvRwE=\'',
'\'sha256-9A7qFFHmxdWjZMQmfzYD2XWaNHLu1ZmQB0Ds4Go764k=\'',
'\'sha256-yYJq8IP5/WhJj6zxyTmujEqBFs/MufRufp2QKJFU76M=\'',
// CapybaraRunner
'\'sha256-5+YTmTcBwCYdJ8Jetbr6kyjGp0Ry/H7ptpoun6CrSwQ=\'',
......
......@@ -38,6 +38,7 @@ declare module "nextjs-routes" {
| DynamicRoute<"/block/countdown/[height]", { "height": string }>
| StaticRoute<"/block/countdown">
| StaticRoute<"/blocks">
| StaticRoute<"/chakra">
| StaticRoute<"/contract-verification">
| StaticRoute<"/csv-export">
| StaticRoute<"/deposits">
......
......@@ -17,6 +17,8 @@
"start": "next start",
"start:docker:local": "docker run -p 3000:3000 --env-file .env.local blockscout-frontend:local",
"start:docker:preset": "./tools/scripts/docker.preset.sh",
"chakra:snippets:add": "chakra snippet add --outdir ./toolkit/chakra",
"chakra:typegen": "chakra typegen ./toolkit/theme/theme.ts",
"lint:eslint": "eslint .",
"lint:eslint:fix": "eslint . --fix",
"lint:tsc": "tsc -p ./tsconfig.json",
......@@ -36,17 +38,16 @@
"og-image:generate:dev": "./tools/scripts/og-image-generator.dev.sh",
"sitemap:generate:dev": "./tools/scripts/sitemap-generator.dev.sh",
"monitoring:prometheus:local": "docker run --name blockscout_prometheus -d -p 127.0.0.1:9090:9090 -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus",
"monitoring:grafana:local": "docker run -d -p 4000:3000 --name=blockscout_grafana --user $(id -u) --volume $(pwd)/grafana:/var/lib/grafana grafana/grafana-enterprise"
"monitoring:grafana:local": "docker run -d -p 4000:3000 --name=blockscout_grafana --user $(id -u) --volume $(pwd)/grafana:/var/lib/grafana grafana/grafana-enterprise",
"postinstall": "chakra typegen ./toolkit/theme/theme.ts"
},
"dependencies": {
"@blockscout/bens-types": "1.4.1",
"@blockscout/stats-types": "2.5.0-alpha",
"@blockscout/visualizer-types": "0.2.0",
"@chakra-ui/react": "2.7.1",
"@chakra-ui/theme-tools": "^2.0.18",
"@chakra-ui/react": "3.15.0",
"@cloudnouns/kit": "1.1.6",
"@emotion/react": "^11.10.4",
"@emotion/styled": "^11.10.4",
"@emotion/react": "11.14.0",
"@growthbook/growthbook-react": "0.21.0",
"@helia/verified-fetch": "2.0.1",
"@hypelab/sdk-react": "^1.0.0",
......@@ -71,6 +72,7 @@
"@tanstack/react-query-devtools": "5.55.4",
"@types/papaparse": "^5.3.5",
"@types/react-scroll": "^1.8.4",
"@uidotdev/usehooks": "2.4.1",
"airtable": "^0.12.2",
"bignumber.js": "^9.1.0",
"blo": "^1.1.1",
......@@ -82,7 +84,6 @@
"dom-to-image": "^2.6.0",
"es-toolkit": "1.31.0",
"focus-visible": "^5.2.0",
"framer-motion": "^6.5.1",
"getit-sdk": "^1.0.4",
"gradient-avatar": "git+https://github.com/blockscout/gradient-avatar.git",
"graphiql": "^2.2.0",
......@@ -93,6 +94,7 @@
"mixpanel-browser": "^2.47.0",
"monaco-editor": "^0.34.1",
"next": "15.2.3",
"next-themes": "0.4.4",
"nextjs-routes": "^1.0.8",
"node-fetch": "^3.2.9",
"papaparse": "^5.3.2",
......@@ -107,6 +109,7 @@
"react-dom": "18.3.1",
"react-google-recaptcha": "3.1.0",
"react-hook-form": "7.52.1",
"react-icons": "5.4.0",
"react-identicons": "^1.2.5",
"react-intersection-observer": "^9.5.2",
"react-jazzicon": "^1.0.4",
......@@ -121,6 +124,7 @@
"xss": "^1.0.14"
},
"devDependencies": {
"@chakra-ui/cli": "3.15.0",
"@eslint/compat": "1.2.2",
"@eslint/js": "9.14.0",
"@next/eslint-plugin-next": "15.0.3",
......
import { type ChakraProps } from '@chakra-ui/react';
import type { HTMLChakraProps } from '@chakra-ui/react';
import { GrowthBookProvider } from '@growthbook/growthbook-react';
import { QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
......@@ -10,7 +10,6 @@ import type { NextPageWithLayout } from 'nextjs/types';
import config from 'configs/app';
import useQueryClientConfig from 'lib/api/useQueryClientConfig';
import { AppContextProvider } from 'lib/contexts/app';
import { ChakraProvider } from 'lib/contexts/chakra';
import { MarketplaceContextProvider } from 'lib/contexts/marketplace';
import { RewardsContextProvider } from 'lib/contexts/rewards';
import { ScrollDirectionProvider } from 'lib/contexts/scrollDirection';
......@@ -20,6 +19,8 @@ import useLoadFeatures from 'lib/growthbook/useLoadFeatures';
import useNotifyOnNavigation from 'lib/hooks/useNotifyOnNavigation';
import { clientConfig as rollbarConfig, Provider as RollbarProvider } from 'lib/rollbar';
import { SocketProvider } from 'lib/socket/context';
import { Provider as ChakraProvider } from 'toolkit/chakra/provider';
import { Toaster } from 'toolkit/chakra/toaster';
import RewardsLoginModal from 'ui/rewards/login/RewardsLoginModal';
import AppErrorBoundary from 'ui/shared/AppError/AppErrorBoundary';
import AppErrorGlobalContainer from 'ui/shared/AppError/AppErrorGlobalContainer';
......@@ -34,7 +35,7 @@ type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout;
};
const ERROR_SCREEN_STYLES: ChakraProps = {
const ERROR_SCREEN_STYLES: HTMLChakraProps<'div'> = {
h: '100vh',
display: 'flex',
flexDirection: 'column',
......@@ -47,16 +48,29 @@ const ERROR_SCREEN_STYLES: ChakraProps = {
};
function MyApp({ Component, pageProps }: AppPropsWithLayout) {
// to avoid hydration mismatch between server and client
// we have to render the app only on client (when it is mounted)
// https://github.com/pacocoursey/next-themes?tab=readme-ov-file#avoid-hydration-mismatch
const [ mounted, setMounted ] = React.useState(false);
React.useEffect(() => {
setMounted(true);
}, []);
useLoadFeatures(pageProps.uuid);
useNotifyOnNavigation();
const growthBook = initGrowthBook(pageProps.uuid);
const queryClient = useQueryClientConfig();
if (!mounted) {
return null;
}
const getLayout = Component.getLayout ?? ((page) => <Layout>{ page }</Layout>);
return (
<ChakraProvider cookies={ pageProps.cookies }>
<ChakraProvider>
<RollbarProvider config={ rollbarConfig }>
<AppErrorBoundary
{ ...ERROR_SCREEN_STYLES }
......@@ -72,6 +86,7 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
<MarketplaceContextProvider>
<SettingsContextProvider>
{ getLayout(<Component { ...pageProps }/>) }
<Toaster/>
{ config.features.rewards.isEnabled && <RewardsLoginModal/> }
</SettingsContextProvider>
</MarketplaceContextProvider>
......
import { ColorModeScript } from '@chakra-ui/react';
import type { DocumentContext } from 'next/document';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import React from 'react';
......@@ -7,7 +6,6 @@ import logRequestFromBot from 'nextjs/utils/logRequestFromBot';
import * as serverTiming from 'nextjs/utils/serverTiming';
import config from 'configs/app';
import theme from 'theme/theme';
import * as svgSprite from 'ui/shared/IconSvg';
class MyDocument extends Document {
......@@ -57,7 +55,6 @@ class MyDocument extends Document {
<link rel="preload" as="image" href={ svgSprite.href }/>
</Head>
<body>
<ColorModeScript initialColorMode={ theme.config.initialColorMode }/>
<Main/>
<NextScript/>
</body>
......
import type { NextPage } from 'next';
import React from 'react';
import PageNextJs from 'nextjs/PageNextJs';
import Chakra from 'ui/pages/Chakra';
const Page: NextPage = () => {
return (
<PageNextJs pathname="/chakra">
<Chakra/>
</PageNextJs>
);
};
export default Page;
export { base as getServerSideProps } from 'nextjs/getServerSideProps';
import { ChakraProvider } from '@chakra-ui/react';
import { GrowthBookProvider } from '@growthbook/growthbook-react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import React from 'react';
......@@ -15,7 +14,7 @@ import { RewardsContextProvider } from 'lib/contexts/rewards';
import { SettingsContextProvider } from 'lib/contexts/settings';
import { SocketProvider } from 'lib/socket/context';
import { currentChain } from 'lib/web3/chains';
import theme from 'theme/theme';
import { Provider as ChakraProvider } from 'toolkit/chakra/provider';
import { port as socketPort } from './utils/socket';
......@@ -73,7 +72,7 @@ const TestApp = ({ children, withSocket, appContext = defaultAppContext, marketp
}));
return (
<ChakraProvider theme={ theme }>
<ChakraProvider>
<QueryClientProvider client={ queryClient }>
<SocketProvider url={ withSocket ? `ws://${ config.app.host }:${ socketPort }` : undefined }>
<AppContextProvider { ...appContext }>
......
......@@ -35,6 +35,7 @@
| "checkered_flag"
| "clock-light"
| "clock"
| "close"
| "coins/bitcoin"
| "collection"
| "columns"
......@@ -80,6 +81,7 @@
| "heart_filled"
| "heart_outline"
| "hourglass"
| "info_filled"
| "info"
| "integration/full"
| "integration/partial"
......
......@@ -11,5 +11,5 @@
<path fill-rule="evenodd" clip-rule="evenodd" d="M137.981 51.029a4.626 4.626 0 0 1-4.411-3.228l-3.136-9.883h-1.927a4.629 4.629 0 0 1-4.412-3.228l-1.863-5.872h6.988l-3.686-5.553h34.921l-3.686 5.553h6.988l-1.863 5.872a4.628 4.628 0 0 1-4.411 3.228h-1.928l-3.135 9.883a4.629 4.629 0 0 1-4.412 3.228h-10.027Zm-2.368-15.81c0 1.49 1.113 2.7 2.486 2.7 1.373 0 2.486-1.21 2.486-2.7 0-1.49-1.113-2.7-2.486-2.7-1.373 0-2.486 1.21-2.486 2.7Zm14.764 0c0 1.49-1.113 2.7-2.486 2.7-1.374 0-2.487-1.21-2.487-2.7 0-1.49 1.113-2.7 2.487-2.7 1.373 0 2.486 1.21 2.486 2.7Z" fill="#004293"/>
<path d="M77.313 78.287h31.623c11.672 0 21.144-9.357 21.144-20.914V26.1c0-11.557-9.472-20.914-21.144-20.914H77.313c-11.672 0-21.144 9.357-21.144 20.914v31.272c0 11.557 9.472 20.914 21.144 20.914Z" fill="#CFE3FF" stroke="#7E94CE" stroke-width="1.125" stroke-linejoin="round"/>
<path d="M75.064 74.538h31.623c11.672 0 21.144-9.357 21.144-20.914V22.352c0-11.557-9.472-20.914-21.144-20.914H75.064c-11.672 0-21.144 9.357-21.144 20.914v31.272c0 11.557 9.472 20.914 21.144 20.914Z" fill="#fff" stroke="#7E94CE" stroke-width="1.125" stroke-linejoin="round"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M109.285 48.52h.013v2.028a5.795 5.795 0 0 1-5.795 5.796h-3.333v-.01H81.7a1.77 1.77 0 0 1-1.768-1.774v-1.486c.007-.066.011-.134.011-.202 0-1.043-.908-1.889-2.028-1.889-1.08 0-1.964.787-2.025 1.78l-.005.002v1.672a1.833 1.833 0 1 1-3.665 0v-7.123a2.324 2.324 0 0 1-.016-.238v-4.203c0-.98.792-1.774 1.769-1.774H85.56a1.687 1.687 0 1 1 0 3.374h-1.792c-1.032.014-1.865.917-1.865 2.029 0 1.12.846 2.028 1.889 2.028h.003c.123.033 9.006.045 15.868.05v-.009h.028c1.025 0 1.862-.799 1.924-1.808l.004-.003v-4.316c0-.8.649-1.449 1.449-1.449h4.767c.8 0 1.449.65 1.449 1.45v6.075ZM97.713 26.796c-.042 0-.084.002-.126.004-1.258-.038-12.012-.044-15.724-.044l-.05-.001c-1.025 0-1.862.8-1.924 1.809l-.003.002v4.316c0 .8-.649 1.449-1.449 1.449H73.67c-.8 0-1.449-.649-1.449-1.45v-6.085h-.016v-2.029a5.796 5.796 0 0 1 5.796-5.796h3.333v.033h18.469c.976 0 1.768.794 1.768 1.774v1.498a1.734 1.734 0 0 0 0 .36c.003.078.015.149.036.213.195.854 1.009 1.493 1.984 1.493 1.077 0 1.957-.78 2.024-1.768l.003-.001v-.05l.001-.07v-.025l-.001-.043v-1.496a1.832 1.832 0 1 1 3.665 0v7.139c.011.094.016.173.016.234v4.203c0 .98-.792 1.773-1.769 1.773h-4.191c-.068 0-.135-.004-.202-.011h-7.195a1.687 1.687 0 1 1 0-3.374h1.771c1.043 0 1.889-.908 1.889-2.028s-.846-2.029-1.89-2.029Z" fill="#5353D3"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M109.285 48.52h.013v2.028a5.795 5.795 0 0 1-5.795 5.796h-3.333v-.01H81.7a1.77 1.77 0 0 1-1.768-1.774v-1.486c.007-.066.011-.134.011-.202 0-1.043-.908-1.889-2.028-1.889-1.08 0-1.964.787-2.025 1.78l-.005.002v1.672a1.833 1.833 0 1 1-3.665 0v-7.123a2.324 2.324 0 0 1-.016-.238v-4.203c0-.98.792-1.774 1.769-1.774H85.56a1.687 1.687 0 1 1 0 3.374h-1.792c-1.032.014-1.865.917-1.865 2.029 0 1.12.846 2.028 1.889 2.028h.003c.123.033 9.006.045 15.868.05v-.009h.028a1.927 1.927 0 0 0 1.924-1.808l.004-.003v-4.316c0-.8.649-1.449 1.449-1.449h4.767c.8 0 1.449.65 1.449 1.45v6.075ZM97.713 26.796a2.65 2.65 0 0 0-.126.004c-1.258-.038-12.012-.044-15.724-.044l-.05-.001c-1.025 0-1.862.8-1.924 1.809l-.003.002v4.316c0 .8-.649 1.449-1.449 1.449H73.67a1.45 1.45 0 0 1-1.449-1.45v-6.085h-.016v-2.029a5.796 5.796 0 0 1 5.796-5.796h3.333v.033h18.469c.976 0 1.768.794 1.768 1.774v1.498a1.734 1.734 0 0 0 0 .36.777.777 0 0 0 .036.213c.195.854 1.009 1.493 1.984 1.493 1.077 0 1.957-.78 2.024-1.768l.003-.001v-.05l.001-.07v-.025l-.001-.043v-1.496a1.832 1.832 0 1 1 3.665 0v7.139c.011.094.016.173.016.234v4.203a1.77 1.77 0 0 1-1.769 1.773h-4.191c-.068 0-.135-.004-.202-.011h-7.195a1.687 1.687 0 1 1 0-3.374h1.771c1.043 0 1.889-.908 1.889-2.028s-.846-2.029-1.89-2.029Z" fill="#5353D3"/>
</svg>
This diff is collapsed.
/node_modules
/dist
\ No newline at end of file
import type { AlertProps } from '@chakra-ui/react';
import { Alert, AlertIcon, AlertTitle } from '@chakra-ui/react';
import React from 'react';
import { test, expect } from 'playwright/lib';
test.use({ viewport: { width: 400, height: 720 } });
const TEST_CASES: Array<AlertProps> = [
{
status: 'info',
},
{
status: 'warning',
},
{
status: 'success',
},
{
status: 'error',
},
{
status: 'info',
colorScheme: 'gray',
},
];
TEST_CASES.forEach((props) => {
const testName = Object.entries(props).map(([ key, value ]) => `${ key }=${ value }`).join(', ');
test(`${ testName } +@dark-mode`, async({ render }) => {
const component = await render(
<Alert { ...props }>
<AlertIcon/>
<AlertTitle>
This is alert text
</AlertTitle>
</Alert>,
);
await expect(component).toHaveScreenshot();
});
});
import { alertAnatomy as parts } from '@chakra-ui/anatomy';
import type { StyleFunctionProps } from '@chakra-ui/styled-system';
import { createMultiStyleConfigHelpers, cssVar } from '@chakra-ui/styled-system';
import { transparentize } from '@chakra-ui/theme-tools';
const { definePartsStyle, defineMultiStyleConfig } =
createMultiStyleConfigHelpers(parts.keys);
const $fg = cssVar('alert-fg');
const $bg = cssVar('alert-bg');
function getBg(props: StyleFunctionProps) {
const { theme, colorScheme: c } = props;
const darkBg = transparentize(`${ c }.200`, 0.16)(theme);
return {
light: `colors.${ c }.100`,
dark: darkBg,
};
}
const baseStyle = definePartsStyle({
container: {
bg: $bg.reference,
borderRadius: 'md',
px: 6,
py: 3,
},
title: {
fontWeight: 'bold',
lineHeight: '6',
marginEnd: '2',
},
description: {
lineHeight: '6',
},
icon: {
color: $fg.reference,
flexShrink: 0,
marginEnd: '3',
w: '5',
h: '6',
},
spinner: {
color: $fg.reference,
flexShrink: 0,
marginEnd: '3',
w: '5',
h: '5',
},
});
const variantSubtle = definePartsStyle((props) => {
const { colorScheme } = props;
const bg = getBg(props);
return {
container: {
[$fg.variable]: colorScheme === 'gray' ? 'colors.blackAlpha.800' : `colors.${ colorScheme }.500`,
[$bg.variable]: colorScheme === 'gray' ? 'colors.blackAlpha.100' : bg.light,
_dark: {
[$fg.variable]: colorScheme === 'gray' ? 'colors.whiteAlpha.800' : `colors.${ colorScheme }.200`,
[$bg.variable]: colorScheme === 'gray' ? 'colors.whiteAlpha.200' : bg.dark,
},
},
};
});
const variantSolid = definePartsStyle((props) => {
const { colorScheme: c } = props;
return {
container: {
[$fg.variable]: `colors.white`,
[$bg.variable]: `colors.${ c }.500`,
_dark: {
[$fg.variable]: `colors.gray.900`,
[$bg.variable]: `colors.${ c }.200`,
},
color: $fg.reference,
},
};
});
const variants = {
subtle: variantSubtle,
solid: variantSolid,
};
const Alert = defineMultiStyleConfig({
baseStyle,
variants,
defaultProps: {
variant: 'subtle',
colorScheme: 'blue',
},
});
export default Alert;
import { defineStyle, defineStyleConfig } from '@chakra-ui/styled-system';
import { mode } from '@chakra-ui/theme-tools';
const baseStyle = defineStyle({
fontSize: 'xs',
borderRadius: 'sm',
fontWeight: 'bold',
});
const variantSubtle = defineStyle((props) => {
const { colorScheme: c } = props;
if (c === 'gray') {
return {
bg: mode('blackAlpha.50', 'whiteAlpha.100')(props),
color: mode('blackAlpha.800', 'whiteAlpha.800')(props),
};
}
if (c === 'gray-blue') {
return {
bg: mode('gray.100', 'gray.800')(props),
color: mode('blackAlpha.800', 'whiteAlpha.800')(props),
_hover: {
opacity: 0.76,
},
};
}
if (c === 'black-blue') {
return {
bg: mode('blue.50', 'blue.800')(props),
color: mode('blackAlpha.800', 'whiteAlpha.800')(props),
};
}
if (c === 'black-purple') {
return {
bg: mode('purple.100', 'purple.800')(props),
color: mode('blackAlpha.800', 'whiteAlpha.800')(props),
};
}
return {
bg: mode(`${ c }.50`, `${ c }.800`)(props),
color: mode(`${ c }.500`, `${ c }.100`)(props),
};
});
const variants = {
subtle: variantSubtle,
};
const Badge = defineStyleConfig({
baseStyle,
variants,
defaultProps: {
variant: 'subtle',
colorScheme: 'gray',
},
});
export default Badge;
import { Box, Button, Flex } from '@chakra-ui/react';
import React from 'react';
import { test, expect } from 'playwright/lib';
test.use({ viewport: { width: 150, height: 350 } });
[
{ variant: 'solid', states: [ 'default', 'disabled', 'hovered', 'active' ] },
{ variant: 'outline', colorScheme: 'gray', withDarkMode: true, states: [ 'default', 'disabled', 'hovered', 'active', 'selected' ] },
{ variant: 'outline', colorScheme: 'blue', withDarkMode: true, states: [ 'default', 'disabled', 'hovered', 'active', 'selected' ] },
{ variant: 'simple', withDarkMode: true, states: [ 'default', 'hovered' ] },
{ variant: 'ghost', withDarkMode: true, states: [ 'default', 'hovered', 'active' ] },
{ variant: 'subtle', states: [ 'default', 'hovered' ] },
{ variant: 'subtle', colorScheme: 'gray', states: [ 'default', 'hovered' ], withDarkMode: true },
{ variant: 'hero', states: [ 'default', 'hovered' ], withDarkMode: true },
{ variant: 'header', states: [ 'default', 'hovered', 'selected' ], withDarkMode: true },
{ variant: 'radio_group', states: [ 'default', 'hovered', 'selected' ], withDarkMode: true },
].forEach(({ variant, colorScheme, withDarkMode, states }) => {
test.describe(`variant ${ variant }${ colorScheme ? ` with ${ colorScheme } color scheme` : '' }${ withDarkMode ? ' +@dark-mode' : '' }`, () => {
test('base view', async({ render }) => {
const component = await render(
<Flex p={ 2 } flexDir="column" rowGap={ 3 }>
{ states?.map((state) => {
switch (state) {
case 'default': {
return (
<Box>
<Box color="text_secondary" fontSize="sm">Default:</Box>
<Button variant={ variant } colorScheme={ colorScheme }>Click me</Button>
</Box>
);
}
case 'disabled': {
return (
<Box>
<Box color="text_secondary" fontSize="sm">Disabled:</Box>
<Button variant={ variant } colorScheme={ colorScheme } isDisabled>Click me</Button>
</Box>
);
}
case 'active': {
return (
<Box>
<Box color="text_secondary" fontSize="sm">Active:</Box>
<Button variant={ variant } colorScheme={ colorScheme } isActive>Click me</Button>
</Box>
);
}
case 'hovered': {
return (
<Box>
<Box color="text_secondary" fontSize="sm">Hovered:</Box>
<Button variant={ variant } colorScheme={ colorScheme }>Hover me</Button>
</Box>
);
}
case 'selected': {
return (
<Box>
<Box color="text_secondary" fontSize="sm">Selected:</Box>
<Button variant={ variant } colorScheme={ colorScheme } data-selected="true">Click me</Button>
</Box>
);
}
default: {
return null;
}
}
}) }
</Flex>,
);
await component.getByText('Hover me').hover();
await expect(component).toHaveScreenshot();
});
});
});
import { defineStyle, defineStyleConfig } from '@chakra-ui/styled-system';
import { mode } from '@chakra-ui/theme-tools';
import { runIfFn } from '@chakra-ui/utils';
import config from 'configs/app';
const variantSolid = defineStyle((props) => {
const { colorScheme: c } = props;
const bg = `${ c }.600`;
const color = 'white';
const hoverBg = `${ c }.400`;
const activeBg = hoverBg;
return {
bg,
color,
_hover: {
bg: hoverBg,
_disabled: {
bg,
},
},
_disabled: {
opacity: 0.2,
},
// According to design there is no "active" or "pressed" state
// It is simply should be the same as the "hover" state
_active: { bg: activeBg },
fontWeight: 600,
};
});
const variantOutline = defineStyle((props) => {
const { colorScheme: c } = props;
const isGrayTheme = c === 'gray';
const bg = 'transparent';
const color = isGrayTheme ? mode('blackAlpha.800', 'whiteAlpha.800')(props) : mode(`${ c }.600`, `${ c }.300`)(props);
const borderColor = isGrayTheme ? mode('gray.200', 'gray.600')(props) : mode(`${ c }.600`, `${ c }.300`)(props);
const selectedBg = isGrayTheme ? mode('blue.50', 'gray.600')(props) : mode(`${ c }.50`, 'gray.600')(props);
const selectedColor = mode('blue.600', 'gray.50')(props);
return {
color,
fontWeight: props.fontWeight || 600,
borderWidth: props.borderWidth || '2px',
borderStyle: 'solid',
borderColor,
bg,
_hover: {
color: 'link_hovered',
borderColor: 'link_hovered',
bg,
span: {
color: 'link_hovered',
},
_disabled: {
color,
borderColor,
},
},
_disabled: {
opacity: 0.2,
},
// According to design there is no "active" or "pressed" state
// It is simply should be the same as the "hover" state
_active: {
color: 'link_hovered',
borderColor: 'link_hovered',
bg,
span: {
color: 'link_hovered',
},
_disabled: {
color: 'link_hovered',
borderColor: 'link_hovered',
},
},
// We have a special state for this button variant that serves as a popover trigger.
// When any items (filters) are selected in the popover, the button should change its background and text color.
// The last CSS selector is for redefining styles for the TabList component.
[`
&[data-selected=true],
&[data-selected=true][aria-selected=true]
`]: {
bg: selectedBg,
color: selectedColor,
borderColor: selectedBg,
},
};
});
const variantRadioGroup = defineStyle((props) => {
const outline = runIfFn(variantOutline, props);
const bgColor = mode('blue.50', 'gray.800')(props);
const selectedTextColor = mode('blue.700', 'gray.50')(props);
return {
...outline,
fontWeight: 500,
cursor: 'pointer',
bgColor: 'none',
borderColor: bgColor,
_hover: {
borderColor: bgColor,
color: 'link_hovered',
},
_active: {
bgColor: 'none',
},
_notFirst: {
borderLeftWidth: 0,
},
// We have a special state for this button variant that serves as a popover trigger.
// When any items (filters) are selected in the popover, the button should change its background and text color.
// The last CSS selector is for redefining styles for the TabList component.
[`
&[data-selected=true],
&[data-selected=true][aria-selected=true]
`]: {
cursor: 'initial',
bgColor,
borderColor: bgColor,
color: selectedTextColor,
_hover: {
color: selectedTextColor,
},
},
};
});
const variantSimple = defineStyle((props) => {
const outline = runIfFn(variantOutline, props);
return {
color: outline.color,
_hover: {
color: outline._hover.color,
},
};
});
const variantGhost = defineStyle((props) => {
const { colorScheme: c } = props;
const activeBg = mode(`${ c }.50`, 'gray.800')(props);
return {
bg: 'transparent',
color: mode(`${ c }.700`, 'gray.400')(props),
_active: {
color: mode(`${ c }.700`, 'gray.50')(props),
bg: mode(`${ c }.50`, 'gray.800')(props),
},
_hover: {
color: `${ c }.400`,
_active: {
bg: props.isActive ? activeBg : 'transparent',
color: mode(`${ c }.700`, 'gray.50')(props),
},
},
};
});
const variantSubtle = defineStyle((props) => {
const { colorScheme: c } = props;
if (c === 'gray') {
return {
bg: mode('blackAlpha.200', 'whiteAlpha.200')(props),
color: mode('blackAlpha.800', 'whiteAlpha.800')(props),
_hover: {
color: 'link_hovered',
_disabled: {
color: mode('blackAlpha.800', 'whiteAlpha.800')(props),
bg: mode('blackAlpha.200', 'whiteAlpha.200')(props),
},
},
};
}
return {
bg: `${ c }.100`,
color: `${ c }.600`,
_hover: {
color: 'link_hovered',
},
};
});
// for buttons in the hero banner
const variantHero = defineStyle((props) => {
const buttonConfig = config.UI.homepage.heroBanner?.button;
return {
bg: mode(
buttonConfig?._default?.background?.[0] || 'blue.600',
buttonConfig?._default?.background?.[1] || buttonConfig?._default?.background?.[0] || 'blue.600',
)(props),
color: mode(
buttonConfig?._default?.text_color?.[0] || 'white',
buttonConfig?._default?.text_color?.[1] || buttonConfig?._default?.text_color?.[0] || 'white',
)(props),
_hover: {
bg: mode(
buttonConfig?._hover?.background?.[0] || 'blue.400',
buttonConfig?._hover?.background?.[1] || buttonConfig?._hover?.background?.[0] || 'blue.400',
)(props),
color: mode(
buttonConfig?._hover?.text_color?.[0] || 'white',
buttonConfig?._hover?.text_color?.[1] || buttonConfig?._hover?.text_color?.[0] || 'white',
)(props),
},
'&[data-selected=true]': {
bg: mode(
buttonConfig?._selected?.background?.[0] || 'blue.50',
buttonConfig?._selected?.background?.[1] || buttonConfig?._selected?.background?.[0] || 'blue.50',
)(props),
color: mode(
buttonConfig?._selected?.text_color?.[0] || 'blackAlpha.800',
buttonConfig?._selected?.text_color?.[1] || buttonConfig?._selected?.text_color?.[0] || 'blackAlpha.800',
)(props),
},
};
});
// for buttons in the page header
const variantHeader = defineStyle((props) => {
return {
bgColor: 'transparent',
color: mode('blackAlpha.800', 'gray.400')(props),
borderColor: mode('gray.300', 'gray.600')(props),
borderWidth: props.borderWidth || '2px',
borderStyle: 'solid',
_hover: {
color: 'link_hovered',
borderColor: 'link_hovered',
},
'&[data-selected=true]': {
bgColor: mode('blackAlpha.50', 'whiteAlpha.100')(props),
color: mode('blackAlpha.800', 'whiteAlpha.800')(props),
borderColor: 'transparent',
borderWidth: props.borderWidth || '0px',
},
'&[data-selected=true][data-warning=true]': {
bgColor: mode('orange.100', 'orange.900')(props),
color: mode('blackAlpha.800', 'whiteAlpha.800')(props),
borderColor: 'transparent',
borderWidth: props.borderWidth || '0px',
},
};
});
const variants = {
solid: variantSolid,
outline: variantOutline,
simple: variantSimple,
ghost: variantGhost,
subtle: variantSubtle,
hero: variantHero,
header: variantHeader,
radio_group: variantRadioGroup,
};
const baseStyle = defineStyle({
fontWeight: 600,
borderRadius: 'base',
overflow: 'hidden',
_focusVisible: {
boxShadow: { base: 'none', lg: 'outline' },
},
});
const sizes = {
lg: defineStyle({
h: 12,
minW: 'unset',
fontSize: 'lg',
px: 6,
}),
md: defineStyle({
h: 10,
minW: 'unset',
fontSize: 'md',
px: 4,
}),
sm: defineStyle({
h: 8,
minW: 'unset',
fontSize: 'sm',
px: 3,
}),
xs: defineStyle({
h: 6,
minW: 'unset',
fontSize: 'xs',
px: 2,
}),
};
const Button = defineStyleConfig({
baseStyle,
variants,
sizes,
defaultProps: {
variant: 'solid',
size: 'md',
colorScheme: 'blue',
},
});
export default Button;
import { checkboxAnatomy as parts } from '@chakra-ui/anatomy';
import {
createMultiStyleConfigHelpers,
defineStyle,
cssVar,
} from '@chakra-ui/styled-system';
import { mode } from '@chakra-ui/theme-tools';
import { runIfFn } from '@chakra-ui/utils';
const { definePartsStyle, defineMultiStyleConfig } =
createMultiStyleConfigHelpers(parts.keys);
const $size = cssVar('checkbox-size');
const baseStyleControl = defineStyle((props) => {
const { colorScheme: c } = props;
return {
_checked: {
bg: mode(`${ c }.500`, `${ c }.300`)(props),
borderColor: mode(`${ c }.500`, `${ c }.300`)(props),
_hover: {
bg: mode(`${ c }.600`, `${ c }.400`)(props),
borderColor: mode(`${ c }.600`, `${ c }.400`)(props),
},
},
_indeterminate: {
bg: mode(`${ c }.500`, `${ c }.300`)(props),
borderColor: mode(`${ c }.500`, `${ c }.300`)(props),
},
};
});
const sizes = {
sm: definePartsStyle({
control: { [$size.variable]: 'sizes.3' },
label: { fontSize: 'sm' },
icon: { fontSize: '3xs' },
}),
md: definePartsStyle({
control: { [$size.variable]: 'sizes.4' },
label: { fontSize: 'md' },
icon: { fontSize: '2xs' },
}),
lg: definePartsStyle({
control: { [$size.variable]: 'sizes.5' },
label: { fontSize: 'md' },
icon: { fontSize: '2xs' },
}),
};
const baseStyleLabel = defineStyle({
_disabled: { opacity: 0.2 },
});
const baseStyle = definePartsStyle((props) => ({
label: baseStyleLabel,
control: runIfFn(baseStyleControl, props),
}));
const Checkbox = defineMultiStyleConfig({
baseStyle,
sizes,
});
export default Checkbox;
import { drawerAnatomy as parts } from '@chakra-ui/anatomy';
import {
createMultiStyleConfigHelpers,
defineStyle,
} from '@chakra-ui/styled-system';
import { mode } from '@chakra-ui/theme-tools';
import { runIfFn } from '@chakra-ui/utils';
const { definePartsStyle, defineMultiStyleConfig } =
createMultiStyleConfigHelpers(parts.keys);
import getDefaultTransitionProps from '../utils/getDefaultTransitionProps';
const transitionProps = getDefaultTransitionProps();
const baseStyleOverlay = defineStyle({
...transitionProps,
bg: 'blackAlpha.800',
zIndex: 'overlay',
});
const baseStyleDialog = defineStyle((props) => {
const { isFullHeight } = props;
return {
...(isFullHeight && { height: '100vh' }),
...transitionProps,
zIndex: 'modal',
maxH: '100vh',
bg: mode('white', 'gray.900')(props),
color: 'inherit',
boxShadow: mode('lg', 'dark-lg')(props),
};
});
const baseStyle = definePartsStyle((props) => ({
overlay: baseStyleOverlay,
dialog: runIfFn(baseStyleDialog, props),
}));
const Drawer = defineMultiStyleConfig({
baseStyle,
});
export default Drawer;
const sizes = {
sm: {
field: {
px: '0',
height: '36px',
},
},
md: {
field: {
px: '0',
height: '56px',
},
},
lg: {
field: {
px: '0',
height: '76px',
},
},
};
const FancySelect = {
sizes,
};
export default FancySelect;
import { formAnatomy as parts } from '@chakra-ui/anatomy';
import { createMultiStyleConfigHelpers } from '@chakra-ui/styled-system';
import type { StyleFunctionProps } from '@chakra-ui/theme-tools';
import getFormStyles from '../utils/getFormStyles';
import FancySelect from './FancySelect';
import FormLabel from './FormLabel';
import Input from './Input';
import Textarea from './Textarea';
const { definePartsStyle, defineMultiStyleConfig } =
createMultiStyleConfigHelpers(parts.keys);
function getFloatingVariantStylesForSize(size: 'md' | 'lg', props: StyleFunctionProps) {
const formStyles = getFormStyles(props);
const activeLabelStyles = {
...FormLabel.variants?.floating?.(props)._focusWithin,
...FormLabel.sizes?.[size](props)._focusWithin,
};
const activeInputStyles = (() => {
switch (size) {
case 'md': {
return {
paddingTop: '26px',
paddingBottom: '10px',
};
}
case 'lg': {
return {
paddingTop: '38px',
paddingBottom: '18px',
};
}
}
})();
const inputPx = (() => {
switch (size) {
case 'md': {
return '16px';
}
case 'lg': {
return '24px';
}
}
})();
return {
container: {
// active styles
_focusWithin: {
label: activeLabelStyles,
'input, textarea': activeInputStyles,
},
'&[data-active=true] label': activeLabelStyles,
// label styles
label: FormLabel.sizes?.[size](props) || {},
'input:not(:placeholder-shown) + label, textarea:not(:placeholder-shown) + label': activeLabelStyles,
'textarea:not(:placeholder-shown) + label': {
bgColor: formStyles.input.filled.bgColor,
},
[`
input[readonly] + label,
textarea[readonly] + label,
&[aria-readonly=true] label
`]: {
bgColor: formStyles.input.readOnly.bgColor,
},
[`
input[aria-invalid=true] + label,
textarea[aria-invalid=true] + label,
&[aria-invalid=true] label
`]: {
color: formStyles.placeholder.error.color,
},
[`
input[disabled] + label,
textarea[disabled] + label,
&[aria-disabled=true] label
`]: {
color: formStyles.placeholder.disabled.color,
},
// input styles
input: Input.sizes?.[size].field,
'input[aria-autocomplete=list]': FancySelect.sizes[size].field,
textarea: Textarea.sizes?.[size],
'input, textarea': {
padding: inputPx,
},
'input:not(:placeholder-shown), textarea:not(:placeholder-shown)': activeInputStyles,
// indicator styles
'input:not(:placeholder-shown) + label .chakra-form__required-indicator, textarea:not(:placeholder-shown) + label .chakra-form__required-indicator': {
color: formStyles.placeholder.default.color,
},
[`
input[aria-invalid=true] + label .chakra-form__required-indicator,
textarea[aria-invalid=true] + label .chakra-form__required-indicator,
&[aria-invalid=true] .chakra-form__required-indicator
`]: {
color: formStyles.placeholder.error.color,
},
[`
input[disabled] + label .chakra-form__required-indicator,
textarea[disabled] + label .chakra-form__required-indicator,
&[aria-disabled=true] .chakra-form__required-indicator
`]: {
color: formStyles.placeholder.disabled.color,
},
},
};
}
const baseStyle = definePartsStyle(() => {
return {
requiredIndicator: {
marginStart: 0,
color: 'gray.500',
},
};
});
const variantFloating = definePartsStyle((props) => {
return {
container: {
label: FormLabel.variants?.floating(props) || {},
},
};
});
const sizes = {
lg: definePartsStyle((props) => {
if (props.variant === 'floating') {
return getFloatingVariantStylesForSize('lg', props);
}
return {};
}),
md: definePartsStyle((props) => {
if (props.variant === 'floating') {
return getFloatingVariantStylesForSize('md', props);
}
return {};
}),
};
const variants = {
floating: variantFloating,
};
const Form = defineMultiStyleConfig({
baseStyle,
variants,
sizes,
defaultProps: {
size: 'md',
},
});
export default Form;
import { FormControl, Input, FormLabel } from '@chakra-ui/react';
import React from 'react';
import { test, expect } from 'playwright/lib';
test.use({ viewport: { width: 500, height: 300 } });
test.describe('floating label size md +@dark-mode', () => {
test('empty', async({ render }) => {
const component = await render(
<FormControl variant="floating" id="name" isRequired size="md">
<Input required value=""/>
<FormLabel>Smart contract / Address (0x...)</FormLabel>
</FormControl>,
);
await expect(component).toHaveScreenshot();
await component.locator('input').focus();
await expect(component).toHaveScreenshot();
});
test('empty error', async({ render }) => {
const component = await render(
<FormControl variant="floating" id="name" isRequired size="md">
<Input required value="" isInvalid/>
<FormLabel>Smart contract / Address (0x...)</FormLabel>
</FormControl>,
);
await expect(component).toHaveScreenshot();
await component.locator('input').focus();
await expect(component).toHaveScreenshot();
});
test('filled', async({ render }) => {
const component = await render(
<FormControl variant="floating" id="name" isRequired size="md">
<Input required value="foo"/>
<FormLabel>Smart contract / Address (0x...)</FormLabel>
</FormControl>,
);
await expect(component).toHaveScreenshot();
});
test('filled disabled', async({ render }) => {
const component = await render(
<FormControl variant="floating" id="name" isRequired size="md">
<Input required value="foo" isDisabled/>
<FormLabel>Smart contract / Address (0x...)</FormLabel>
</FormControl>,
);
await expect(component).toHaveScreenshot();
});
test('filled read-only', async({ render }) => {
const component = await render(
<FormControl variant="floating" id="name" isRequired size="md">
<Input required value="foo" isReadOnly/>
<FormLabel>Smart contract / Address (0x...)</FormLabel>
</FormControl>,
);
await expect(component).toHaveScreenshot();
});
test('filled error', async({ render }) => {
const component = await render(
<FormControl variant="floating" id="name" isRequired size="md">
<Input required value="foo" isInvalid/>
<FormLabel>Smart contract / Address (0x...)</FormLabel>
</FormControl>,
);
await expect(component).toHaveScreenshot();
});
});
test.describe('floating label size lg +@dark-mode', () => {
test('empty', async({ render }) => {
const component = await render(
<FormControl variant="floating" id="name" isRequired size="lg">
<Input required value=""/>
<FormLabel>Smart contract / Address (0x...)</FormLabel>
</FormControl>,
);
await expect(component).toHaveScreenshot();
await component.locator('input').focus();
await expect(component).toHaveScreenshot();
});
test('filled', async({ render }) => {
const component = await render(
<FormControl variant="floating" id="name" isRequired size="lg">
<Input required value="foo"/>
<FormLabel>Smart contract / Address (0x...)</FormLabel>
</FormControl>,
);
await expect(component).toHaveScreenshot();
await component.locator('input').focus();
await expect(component).toHaveScreenshot();
});
});
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.
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.
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.
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.
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.
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.
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