mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
Merge branch 'main' of github.com:blockscout/frontend into tabs
This commit is contained in:
+1
-1
@@ -10,4 +10,4 @@ NEXT_PUBLIC_FOOTER_GITHUB_LINK=https://github.com/blockscout/blockscout
|
||||
NEXT_PUBLIC_FOOTER_TWITTER_LINK=https://www.twitter.com/blockscoutcom
|
||||
NEXT_PUBLIC_FOOTER_TELEGRAM_LINK=https://t.me/poa_network
|
||||
NEXT_PUBLIC_FOOTER_STAKING_LINK=https://duneanalytics.com/maxaleks/xdai-staking
|
||||
NEXT_PUBLIC_SUPPORTED_NETWORKS=[{"name":"Gnosis Chain","type":"xdai","subType":"mainnet","group":"mainnets","isAccountSupported":true},{"name":"Optimism on Gnosis Chain","shortName":"OoG","type":"xdai","subType":"optimism","group":"mainnets","icon":"https://www.fillmurray.com/60/60"},{"name":"Arbitrum on xDai","type":"xdai","subType":"aox","group":"mainnets"},{"name":"Ethereum","shortName":"ETH","type":"eth","subType":"mainnet","group":"mainnets"},{"name":"Ethereum Classic","shortName":"ETC","type":"etc","subType":"mainnet","group":"mainnets"},{"name":"POA","shortName":"POA","type":"poa","subType":"core","group":"mainnets","isAccountSupported":true},{"name":"RSK","shortName":"RBTC","type":"rsk","subType":"mainnet","group":"mainnets"},{"name":"Gnosis Chain Testnet","type":"xdai","subType":"testnet","group":"testnets"},{"name":"POA Sokol","shortName":"POA","type":"poa","subType":"sokol","group":"testnets"},{"name":"ARTIS Σ1","type":"artis","subType":"sigma1","group":"other"},{"name":"LUKSO L14","shortName":"POA","type":"lukso","subType":"l14","group":"other"}]
|
||||
NEXT_PUBLIC_SUPPORTED_NETWORKS=[{"name":"Gnosis Chain","type":"xdai","subType":"mainnet","group":"mainnets","isAccountSupported":true, "chainId": 100},{"name":"Optimism on Gnosis Chain","shortName":"OoG","type":"xdai","subType":"optimism","group":"mainnets","icon":"https://www.fillmurray.com/60/60", "chainId": 300},{"name":"Arbitrum on xDai","type":"xdai","subType":"aox","group":"mainnets", "chainId": 200},{"name":"Ethereum","shortName":"ETH","type":"eth","subType":"mainnet","group":"mainnets", "chainId": 1},{"name":"Ethereum Classic","shortName":"ETC","type":"etc","subType":"mainnet","group":"mainnets", "chainId": 61},{"name":"POA","shortName":"POA","type":"poa","subType":"core","group":"mainnets","isAccountSupported":true, "chainId": 99},{"name":"RSK","shortName":"RBTC","type":"rsk","subType":"mainnet","group":"mainnets", "chainId": 30},{"name":"Gnosis Chain Testnet","type":"xdai","subType":"testnet","group":"testnets"},{"name":"POA Sokol","shortName":"POA","type":"poa","subType":"sokol","group":"testnets", "chainId": 77},{"name":"ARTIS Σ1","type":"artis","subType":"sigma1","group":"other", "chainId": 246529},{"name":"LUKSO L14","shortName":"POA","type":"lukso","subType":"l14","group":"other", "chainId": 22}]
|
||||
|
||||
@@ -27,18 +27,19 @@ The app instance could be customized by passing following variables to NodeJS en
|
||||
|
||||
| Variable | Type | Description | Default value
|
||||
| --- | --- | --- | --- |
|
||||
| NEXT_PUBLIC_BLOCKSCOUT_VERSION | `string` | Current running version of Blockscout (used to display link to release in the footer) |
|
||||
| NEXT_PUBLIC_BLOCKSCOUT_VERSION | `string` | Current running version of Blockscout (used to display link to release in the footer) |
|
||||
| NEXT_PUBLIC_FOOTER_GITHUB_LINK | `string` | Link to Github in the footer | `https://github.com/blockscout/blockscout` |
|
||||
| NEXT_PUBLIC_FOOTER_TWITTER_LINK | `string` | Link to Twitter in the footer | `https://www.twitter.com/blockscoutcom` |
|
||||
| NEXT_PUBLIC_FOOTER_TELEGRAM_LINK | `string` | Link to Telegram in the footer | `https://t.me/poa_network` |
|
||||
| NEXT_PUBLIC_FOOTER_STAKING_LINK | `string` | Link to staking dashboard in the footer | `https://duneanalytics.com/maxaleks/xdai-staking` |
|
||||
| NEXT_PUBLIC_SUPPORTED_NETWORKS | `Array<Network>` where `Network` can have following [properties](#network-configuration-properties) | Configuration of supported networks | `[{"name":"Gnosis Chain","type":"xdai","subType":"mainnet","group":"mainnets","isAccountSupported":true},{"name":"Optimism on Gnosis Chain","type":"xdai","subType":"optimism","group":"mainnets"},{"name":"Arbitrum on xDai","type":"xdai","subType":"aox","group":"mainnets"},{"name":"Ethereum","type":"eth","subType":"mainnet","group":"mainnets"},{"name":"Ethereum Classic","type":"etc","subType":"mainnet","group":"mainnets"},{"name":"POA","type":"poa","subType":"core","group":"mainnets"},{"name":"RSK","type":"rsk","subType":"mainnet","group":"mainnets"},{"name":"Gnosis Chain Testnet","type":"xdai","subType":"testnet","group":"testnets","isAccountSupported":true},{"name":"POA Sokol","type":"poa","subType":"sokol","group":"testnets"},{"name":"ARTIS Σ1","type":"artis","subType":"sigma1","group":"other"},{"name":"LUKSO L14","type":"lukso","subType":"l14","group":"other"}]` |
|
||||
| NEXT_PUBLIC_SUPPORTED_NETWORKS | `Array<Network>` where `Network` can have following [properties](#network-configuration-properties) | Configuration of supported networks | `[{"name":"Gnosis Chain","type":"xdai","subType":"mainnet","group":"mainnets","isAccountSupported":true, "chainId": 100},{"name":"Optimism on Gnosis Chain","shortName":"OoG","type":"xdai","subType":"optimism","group":"mainnets","icon":"https://www.fillmurray.com/60/60", "chainId": 300},{"name":"Arbitrum on xDai","type":"xdai","subType":"aox","group":"mainnets", "chainId": 200},{"name":"Ethereum","shortName":"ETH","type":"eth","subType":"mainnet","group":"mainnets", "chainId": 1},{"name":"Ethereum Classic","shortName":"ETC","type":"etc","subType":"mainnet","group":"mainnets", "chainId": 61},{"name":"POA","shortName":"POA","type":"poa","subType":"core","group":"mainnets","isAccountSupported":true, "chainId": 99},{"name":"RSK","shortName":"RBTC","type":"rsk","subType":"mainnet","group":"mainnets", "chainId": 30},{"name":"Gnosis Chain Testnet","type":"xdai","subType":"testnet","group":"testnets"},{"name":"POA Sokol","shortName":"POA","type":"poa","subType":"sokol","group":"testnets", "chainId": 77},{"name":"ARTIS Σ1","type":"artis","subType":"sigma1","group":"other", "chainId": 246529},{"name":"LUKSO L14","shortName":"POA","type":"lukso","subType":"l14","group":"other", "chainId": 22}]` |
|
||||
|
||||
### Network configuration properties
|
||||
|
||||
| Property | Type | Description | Example value
|
||||
| --- | --- | --- | --- |
|
||||
| name | `string` | Displayed name of the network | `"Gnosis Chain"` |
|
||||
| chainId | `number` | Id of the network. Could be seen there – [https://chainlist.org/](https://chainlist.org/) | `1` |
|
||||
| type | `string` | Network type (used as first part of the base path) | `"xdai"` |
|
||||
| subType | `string` | Network subtype (used as second part of the base path) | `"mainnet"` |
|
||||
| group | `mainnets \| testnets \| other` | Indicates in which tab network appears in the menu | `"mainnets"` |
|
||||
@@ -46,4 +47,4 @@ The app instance could be customized by passing following variables to NodeJS en
|
||||
| icon | `string` *(optional)* | Network icon; if not provided, will fallback to icon predefined in the project; if the project doesn't have icon for such network then the common placeholder will be shown; *Note* that icon size should be 30px by 30px | `"https://www.fillmurray.com/60/60"` |
|
||||
| logo | `string` *(optional)* | Network logo; if not provided, will fallback to logo predefined in the project; if the project doesn't have logo for such network then the common placeholder will be shown; *Note* that logo height should be 20px and width less than 120px | `"https://www.fillmurray.com/240/40"` |
|
||||
|
||||
*Note* the base path for the network is built up from its `type` and `subType` like so `https://blockscout.com/<type>/<subType>`
|
||||
*Note* the base path for the network is built up from its `type` and `subType` like so `https://blockscout.com/<type>/<subType>`
|
||||
|
||||
@@ -33,7 +33,7 @@ environment: {}
|
||||
NEXT_PUBLIC_FOOTER_STAKING_LINK:
|
||||
_default: https://duneanalytics.com/maxaleks/xdai-staking
|
||||
NEXT_PUBLIC_SUPPORTED_NETWORKS:
|
||||
_default: [{"name":"Gnosis Chain","type":"xdai","subType":"mainnet","group":"mainnets","isAccountSupported":true},{"name":"Optimism on Gnosis Chain","type":"xdai","subType":"optimism","group":"mainnets"},{"name":"Arbitrum on xDai","type":"xdai","subType":"aox","group":"mainnets"},{"name":"Ethereum","type":"eth","subType":"mainnet","group":"mainnets"},{"name":"Ethereum Classic","type":"etc","subType":"mainnet","group":"mainnets"},{"name":"POA","type":"poa","subType":"core","group":"mainnets"},{"name":"RSK","type":"rsk","subType":"mainnet","group":"mainnets"},{"name":"Gnosis Chain Testnet","type":"xdai","subType":"testnet","group":"testnets","isAccountSupported":true},{"name":"POA Sokol","type":"poa","subType":"sokol","group":"testnets"},{"name":"ARTIS Σ1","type":"artis","subType":"sigma1","group":"other"},{"name":"LUKSO L14","type":"lukso","subType":"l14","group":"other"}]
|
||||
_default: [{"name":"Gnosis Chain","type":"xdai","subType":"mainnet","group":"mainnets","isAccountSupported":true, "chainId": 100},{"name":"Optimism on Gnosis Chain","shortName":"OoG","type":"xdai","subType":"optimism","group":"mainnets","icon":"https://www.fillmurray.com/60/60", "chainId": 300},{"name":"Arbitrum on xDai","type":"xdai","subType":"aox","group":"mainnets", "chainId": 200},{"name":"Ethereum","shortName":"ETH","type":"eth","subType":"mainnet","group":"mainnets", "chainId": 1},{"name":"Ethereum Classic","shortName":"ETC","type":"etc","subType":"mainnet","group":"mainnets", "chainId": 61},{"name":"POA","shortName":"POA","type":"poa","subType":"core","group":"mainnets","isAccountSupported":true, "chainId": 99},{"name":"RSK","shortName":"RBTC","type":"rsk","subType":"mainnet","group":"mainnets", "chainId": 30},{"name":"Gnosis Chain Testnet","type":"xdai","subType":"testnet","group":"testnets"},{"name":"POA Sokol","shortName":"POA","type":"poa","subType":"sokol","group":"testnets", "chainId": 77},{"name":"ARTIS Σ1","type":"artis","subType":"sigma1","group":"other", "chainId": 246529},{"name":"LUKSO L14","shortName":"POA","type":"lukso","subType":"l14","group":"other", "chainId": 22}]
|
||||
|
||||
global:
|
||||
env: test
|
||||
|
||||
+300
@@ -0,0 +1,300 @@
|
||||
import type { AppItemOverview } from 'types/client/apps';
|
||||
|
||||
import { APP_CATEGORIES } from 'ui/apps/constants';
|
||||
|
||||
export const TEMPORARY_DEMO_APPS: Array<AppItemOverview> = [
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'easy-staking',
|
||||
title: 'Easy Staking',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[0], APP_CATEGORIES[1] ],
|
||||
shortDescription: 'Accessible DeFi staking platform for STAKE holders on Ethereum',
|
||||
site: 'https://easy-staking.xdaichain.com/',
|
||||
// eslint-disable-next-line max-len
|
||||
description: 'Easy Staking allows users to place STAKE into a contract and receive STAKE emissions on Ethereum. It provides an accessible staking mechanism for users and increases STAKE utility and DeFi composability. EasyStaking also:\n\n- Incentivizes liquidity providers on decentralized exchanges through unique reward mechanisms\n- Creates staking opportunities via hardware wallets and other Ethereum applications\n- Provides staking opportunities with no minimum STAKE requirements to participate\n- Limits total circulating supply',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'curve',
|
||||
title: 'Curve',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[1], APP_CATEGORIES[2] ],
|
||||
// eslint-disable-next-line max-len
|
||||
shortDescription: 'Curve is an exchange liquidity pool on Ethereum designed for: extremely efficient stablecoin trading, low risk, supplemental fee income for liquidity providers, without an opportunity cost.',
|
||||
site: 'https://xdai.curve.fi/',
|
||||
// eslint-disable-next-line max-len
|
||||
description: 'Curve is an exchange liquidity pool on Ethereum designed for: extremely efficient stablecoin trading, low risk, supplemental fee income for liquidity providers, without an opportunity cost.',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'honwyswap',
|
||||
title: 'HonwySwap',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[1], APP_CATEGORIES[2] ],
|
||||
// eslint-disable-next-line max-len
|
||||
shortDescription: 'Honeyswap is a decentralized exchange built on the Gnosis Chain, this enables users to experience fast and secure transactions with incredibly low fees. Multiple tokens are available with which you can swap and add liquidity.',
|
||||
site: 'https://honeyswap.org/',
|
||||
// eslint-disable-next-line max-len
|
||||
description: 'Honeyswap is a decentralized exchange built on the Gnosis Chain, this enables users to experience fast and secure transactions with incredibly low fees. Multiple tokens are available with which you can swap and add liquidity.',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'sushi',
|
||||
title: 'Sushi',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[0], APP_CATEGORIES[1] ],
|
||||
shortDescription: 'Swap, yield, lend, borrow, leverage, limit, launch all on one community-driven ecosystem',
|
||||
site: 'https://app.sushi.com/',
|
||||
description: 'Swap, yield, lend, borrow, leverage, limit, launch all on one community-driven ecosystem',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'bao-finance',
|
||||
title: 'Bao Finance',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[0], APP_CATEGORIES[1] ],
|
||||
shortDescription: 'Yield Farming for Synthetic Assets from LP tokens',
|
||||
site: 'https://farms.baoswap.xyz/',
|
||||
description: 'Yield Farming for Synthetic Assets from LP tokens',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'component',
|
||||
title: 'Component',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[1], APP_CATEGORIES[2] ],
|
||||
// eslint-disable-next-line max-len
|
||||
shortDescription: 'During the Unit protocol development, we faced difficulty finding a reliable, flexible protocol for stablecoin swap without interface censorship.',
|
||||
site: 'https://xdai.component.finance',
|
||||
// eslint-disable-next-line max-len
|
||||
description: 'During the Unit protocol development, we faced difficulty finding a reliable, flexible protocol for stablecoin swap without interface censorship.',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'pooltogether',
|
||||
title: 'PoolTogether',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[1], APP_CATEGORIES[2] ],
|
||||
shortDescription: 'View, deposit and withdraw for all V3 Pools',
|
||||
site: 'https://app.pooltogether.com/',
|
||||
description: 'View, deposit and withdraw for all V3 Pools',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'swapr',
|
||||
title: 'Swapr',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[0], APP_CATEGORIES[1] ],
|
||||
shortDescription: 'A governance-enabled automated market maker with adjustable fees.',
|
||||
site: 'https://swapr.eth.limo',
|
||||
description: 'A governance-enabled automated market maker with adjustable fees.',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'levinswap',
|
||||
title: 'Levinswap',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[0], APP_CATEGORIES[1] ],
|
||||
// eslint-disable-next-line max-len
|
||||
shortDescription: 'AMM DEX on the xDai chain. Its uniqueness comes from the ability to trade securities tokens, specifically, tokenized real estate tokens.',
|
||||
site: 'https://app.levinswap.org/',
|
||||
description: 'AMM DEX on the xDai chain. Its uniqueness comes from the ability to trade securities tokens, specifically, tokenized real estate tokens.',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'omen',
|
||||
title: 'Omen',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[1], APP_CATEGORIES[2] ],
|
||||
shortDescription: 'Decentralized prediction markets on Ethereum',
|
||||
site: 'https://xdai.omen.eth.link/',
|
||||
description: 'Decentralized prediction markets on Ethereum',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'nifty-ink',
|
||||
title: 'Nifty Ink',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[1], APP_CATEGORIES[2] ],
|
||||
shortDescription: 'NFT artwork created and sold on xDAI using meta transactions, burner wallets, and bridged to Ethereum',
|
||||
site: 'https://nifty.ink/explore',
|
||||
description: 'NFT artwork created and sold on xDAI using meta transactions, burner wallets, and bridged to Ethereum',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'treasure-chess',
|
||||
title: 'Treasure Chess',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[0], APP_CATEGORIES[1] ],
|
||||
shortDescription: 'Every chess game is one-of-a-kind. Make yours a collectible.',
|
||||
site: 'https://treasure.chess.com/',
|
||||
description: 'Every chess game is one-of-a-kind. Make yours a collectible.',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'unique-one',
|
||||
title: 'Unique.One',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[0], APP_CATEGORIES[1] ],
|
||||
// eslint-disable-next-line max-len
|
||||
shortDescription: 'A truly decentralised non-profit platform owned and managed by the Digital Arts community, bringing together Artists, Creators and Collectors as One.',
|
||||
site: 'https://www.unique.one/',
|
||||
// eslint-disable-next-line max-len
|
||||
description: 'A truly decentralised non-profit platform owned and managed by the Digital Arts community, bringing together Artists, Creators and Collectors as One.',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'cold-truth-culture',
|
||||
title: 'Cold Truth Culture',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[1], APP_CATEGORIES[2] ],
|
||||
shortDescription: 'A Community That Empowers NFT Artists',
|
||||
site: 'https://www.coldtruthculture.io/',
|
||||
description: 'A Community That Empowers NFT Artists',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'xdai-bridge',
|
||||
title: 'xDai Bridge',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[1], APP_CATEGORIES[2] ],
|
||||
shortDescription: 'Token bridge between the Gnosis Chain and the Ethereum network',
|
||||
site: 'https://bridge.gnosischain.com/',
|
||||
description: 'Token bridge between the Gnosis Chain and the Ethereum network',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'omni-bridge',
|
||||
title: 'OmniBridge',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[0], APP_CATEGORIES[1] ],
|
||||
shortDescription: 'The OmniBridge multi-token extension is the simplest way to transfer ANY ERC20/ ERC677 /ERC827 token to and from the xDai chain.',
|
||||
site: 'https://omni.gnosischain.com/bridge',
|
||||
description: 'The OmniBridge multi-token extension is the simplest way to transfer ANY ERC20/ ERC677 /ERC827 token to and from the xDai chain.',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'gnosis-safe',
|
||||
title: 'Gnosis Safe',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[0], APP_CATEGORIES[1] ],
|
||||
shortDescription: 'Gnosis Safe is the most trusted platform to manage digital assets on Ethereum',
|
||||
site: 'https://gnosis-safe.io/',
|
||||
description: 'Gnosis Safe is the most trusted platform to manage digital assets on Ethereum',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'multisender',
|
||||
title: 'Multisender',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[1], APP_CATEGORIES[2] ],
|
||||
// eslint-disable-next-line max-len
|
||||
shortDescription: 'Send ERC20 token or ETH. Batch sender. Bulk Sender. Token Multisender allows you to airdrop tokens in a few transactions in trustless way. Batch sending ERC20, Ethereum tokens.',
|
||||
site: 'https://multisender.app/',
|
||||
// eslint-disable-next-line max-len
|
||||
description: 'Send ERC20 token or ETH. Batch sender. Bulk Sender. Token Multisender allows you to airdrop tokens in a few transactions in trustless way. Batch sending ERC20, Ethereum tokens.',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'disperse',
|
||||
title: 'Disperse',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[1], APP_CATEGORIES[2] ],
|
||||
shortDescription: 'Distribute ether or tokens to multiple addresses',
|
||||
site: 'https://disperse.app/',
|
||||
description: 'Distribute ether or tokens to multiple addresses',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
{
|
||||
author: 'xDaichain',
|
||||
id: 'symmetric',
|
||||
title: 'Symmetric',
|
||||
logo: 'https://www.fillmurray.com/144/144',
|
||||
categories: [ APP_CATEGORIES[1], APP_CATEGORIES[2] ],
|
||||
// eslint-disable-next-line max-len
|
||||
shortDescription: 'DEX or Decentralized Exchange, also called an Automated Market Maker (AMM) in Decentralized Finance (DeFi). Symmetric is live on gnosis chain (xDai) and Celo.',
|
||||
site: 'https://symmetric.finance/',
|
||||
// eslint-disable-next-line max-len
|
||||
description: 'DEX or Decentralized Exchange, also called an Automated Market Maker (AMM) in Decentralized Finance (DeFi). Symmetric is live on gnosis chain (xDai) and Celo.',
|
||||
url: 'https://blockscout-allowance-mainnet-stage.vercel.app/',
|
||||
twitter: 'https://twitter.com/EasyStaking',
|
||||
telegram: 'https://t.me/easystaking',
|
||||
github: 'https://github.com/mikhin',
|
||||
},
|
||||
];
|
||||
+5
-3
@@ -1,7 +1,9 @@
|
||||
import type { TxInternalsType } from 'types/api/tx';
|
||||
|
||||
export const data = [
|
||||
{
|
||||
id: 1,
|
||||
type: 'call',
|
||||
type: 'call' as TxInternalsType,
|
||||
status: 'success' as const,
|
||||
from: '0x12E80C27BfFBB76b4A8d26FF2bfd3C9f310FFA01',
|
||||
to: '0xF7A558692dFB5F456e291791da7FAE8Dd046574e',
|
||||
@@ -10,7 +12,7 @@ export const data = [
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: 'delegate call',
|
||||
type: 'delegate_call' as TxInternalsType,
|
||||
status: 'error' as const,
|
||||
from: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45',
|
||||
to: '0x12E80C27BfFBB76b4A8d26FF2bfd3C9f310FFA01',
|
||||
@@ -19,7 +21,7 @@ export const data = [
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
type: 'static call',
|
||||
type: 'static_call' as TxInternalsType,
|
||||
status: 'success' as const,
|
||||
from: '0x97Aa2EfcF35c0f4c9AaDDCa8c2330fa7A9533830',
|
||||
to: '0x35317007D203b8a86CA727ad44E473E40450E378',
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<svg viewBox="0 0 240 192" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M82.667 4H56a4 4 0 0 0-4 4v26.667a4 4 0 0 0 4 4h26.667a4 4 0 0 0 4-4V8a4 4 0 0 0-4-4ZM56 0a8 8 0 0 0-8 8v26.667a8 8 0 0 0 8 8h26.667a8 8 0 0 0 8-8V8a8 8 0 0 0-8-8H56Zm122.667 4H152a4 4 0 0 0-4 4v26.667a4 4 0 0 0 4 4h26.667a4 4 0 0 0 4-4V8a4 4 0 0 0-4-4ZM152 0a8 8 0 0 0-8 8v26.667a8 8 0 0 0 8 8h26.667a8 8 0 0 0 8-8V8a8 8 0 0 0-8-8H152ZM56 52h26.667a4 4 0 0 1 4 4v26.667a4 4 0 0 1-4 4H56a4 4 0 0 1-4-4V56a4 4 0 0 1 4-4Zm-8 4a8 8 0 0 1 8-8h26.667a8 8 0 0 1 8 8v26.667a8 8 0 0 1-8 8H56a8 8 0 0 1-8-8V56Zm34.667 44H56a4 4 0 0 0-4 4v26.667a4 4 0 0 0 4 4h26.667a4 4 0 0 0 4-4V104a4 4 0 0 0-4-4ZM56 96a8 8 0 0 0-8 8v26.667a8 8 0 0 0 8 8h26.667a8 8 0 0 0 8-8V104a8 8 0 0 0-8-8H56Zm0 52h26.667a4 4 0 0 1 4 4v26.667a4 4 0 0 1-4 4H56a4 4 0 0 1-4-4V152a4 4 0 0 1 4-4Zm-8 4a8 8 0 0 1 8-8h26.667a8 8 0 0 1 8 8v26.667a8 8 0 0 1-8 8H56a8 8 0 0 1-8-8V152ZM178.667 52H152a4 4 0 0 0-4 4v26.667a4 4 0 0 0 4 4h26.667a4 4 0 0 0 4-4V56a4 4 0 0 0-4-4ZM152 48a8 8 0 0 0-8 8v26.667a8 8 0 0 0 8 8h26.667a8 8 0 0 0 8-8V56a8 8 0 0 0-8-8H152Zm0 52h26.667a4 4 0 0 1 4 4v26.667a4 4 0 0 1-4 4H152a4 4 0 0 1-4-4V104a4 4 0 0 1 4-4Zm-8 4a8 8 0 0 1 8-8h26.667a8 8 0 0 1 8 8v26.667a8 8 0 0 1-8 8H152a8 8 0 0 1-8-8V104Zm34.667 44H152a4 4 0 0 0-4 4v26.667a4 4 0 0 0 4 4h26.667a4 4 0 0 0 4-4V152a4 4 0 0 0-4-4ZM152 144a8 8 0 0 0-8 8v26.667a8 8 0 0 0 8 8h26.667a8 8 0 0 0 8-8V152a8 8 0 0 0-8-8H152ZM8 28h26.667a4 4 0 0 1 4 4v26.667a4 4 0 0 1-4 4H8a4 4 0 0 1-4-4V32a4 4 0 0 1 4-4Zm-8 4a8 8 0 0 1 8-8h26.667a8 8 0 0 1 8 8v26.667a8 8 0 0 1-8 8H8a8 8 0 0 1-8-8V32Zm104-4h26.667a4 4 0 0 1 4 4v26.667a4 4 0 0 1-4 4H104a4 4 0 0 1-4-4V32a4 4 0 0 1 4-4Zm-8 4a8 8 0 0 1 8-8h26.667a8 8 0 0 1 8 8v26.667a8 8 0 0 1-8 8H104a8 8 0 0 1-8-8V32Zm130.667-4H200a4 4 0 0 0-4 4v26.667a4 4 0 0 0 4 4h26.667a4 4 0 0 0 4-4V32a4 4 0 0 0-4-4ZM200 24a8 8 0 0 0-8 8v26.667a8 8 0 0 0 8 8h26.667a8 8 0 0 0 8-8V32a8 8 0 0 0-8-8H200Zm-96 52h26.667a4 4 0 0 1 4 4v26.667a4 4 0 0 1-4 4H104a4 4 0 0 1-4-4V80a4 4 0 0 1 4-4Zm-8 4a8 8 0 0 1 8-8h26.667a8 8 0 0 1 8 8v26.667a8 8 0 0 1-8 8H104a8 8 0 0 1-8-8V80Zm34.667 44H104a4 4 0 0 0-4 4v26.667a4 4 0 0 0 4 4h26.667a4 4 0 0 0 4-4V128a4 4 0 0 0-4-4ZM104 120a8 8 0 0 0-8 8v26.667a8 8 0 0 0 8 8h26.667a8 8 0 0 0 8-8V128a8 8 0 0 0-8-8H104Zm96-44h26.667a4 4 0 0 1 4 4v26.667a4 4 0 0 1-4 4H200a4 4 0 0 1-4-4V80a4 4 0 0 1 4-4Zm-8 4a8 8 0 0 1 8-8h26.667a8 8 0 0 1 8 8v26.667a8 8 0 0 1-8 8H200a8 8 0 0 1-8-8V80Zm34.667 44H200a4 4 0 0 0-4 4v26.667a4 4 0 0 0 4 4h26.667a4 4 0 0 0 4-4V128a4 4 0 0 0-4-4ZM200 120a8 8 0 0 0-8 8v26.667a8 8 0 0 0 8 8h26.667a8 8 0 0 0 8-8V128a8 8 0 0 0-8-8H200ZM8 76h26.667a4 4 0 0 1 4 4v26.667a4 4 0 0 1-4 4H8a4 4 0 0 1-4-4V80a4 4 0 0 1 4-4Zm-8 4a8 8 0 0 1 8-8h26.667a8 8 0 0 1 8 8v26.667a8 8 0 0 1-8 8H8a8 8 0 0 1-8-8V80Zm34.667 44H8a4 4 0 0 0-4 4v26.667a4 4 0 0 0 4 4h26.667a4 4 0 0 0 4-4V128a4 4 0 0 0-4-4ZM8 120a8 8 0 0 0-8 8v26.667a8 8 0 0 0 8 8h26.667a8 8 0 0 0 8-8V128a8 8 0 0 0-8-8H8Z" fill="url(#empty_search_result_svg__a)"/>
|
||||
<path d="m135.337 94.376 11.182 11.242-3.694 3.715-11.18-11.245a23.31 23.31 0 0 1-14.666 5.17c-12.971 0-23.498-10.586-23.498-23.629C93.48 66.586 104.008 56 116.979 56c12.971 0 23.499 10.586 23.499 23.629a23.614 23.614 0 0 1-5.141 14.747Zm-5.238-1.948a18.372 18.372 0 0 0 5.157-12.799c0-10.155-8.18-18.378-18.277-18.378-10.099 0-18.276 8.223-18.276 18.378 0 10.153 8.177 18.378 18.276 18.378a18.166 18.166 0 0 0 12.729-5.185l.391-.394Z" fill="#A0AEC0"/>
|
||||
<defs>
|
||||
<radialGradient id="empty_search_result_svg__a" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="rotate(103.716 25.035 85.404) scale(58.3301 137.703)">
|
||||
<stop offset=".081" stop-color="#CBD5E0" stop-opacity="0"/>
|
||||
<stop offset=".563" stop-color="#CBD5E0" stop-opacity=".54"/>
|
||||
<stop offset="1" stop-color="#CBD5E0" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 18 18" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.76 17.333a.604.604 0 0 1-.294-.075l.293.075Zm.004 0a.625.625 0 0 0 .477-.234.671.671 0 0 0 .14-.538l-.853-5.21 3.615-3.689a.69.69 0 0 0 .16-.677.663.663 0 0 0-.194-.301.617.617 0 0 0-.316-.149l-4.884-.743a.208.208 0 0 1-.157-.117l-2.186-4.64a.65.65 0 0 0-.233-.269.61.61 0 0 0-.666 0 .65.65 0 0 0-.232.269l-2.186 4.64a.208.208 0 0 1-.158.117l-4.884.743a.618.618 0 0 0-.316.149.663.663 0 0 0-.193.3.69.69 0 0 0 .16.678l3.54 3.614a.208.208 0 0 1 .058.18l-.837 5.105a.69.69 0 0 0 .038.36.657.657 0 0 0 .213.286.613.613 0 0 0 .663.05L8.9 14.854a.208.208 0 0 1 .2 0l4.366 2.405m-7.795-2.915c-.028.172.154.3.307.216L8.9 12.95a.208.208 0 0 1 .2 0l2.923 1.61a.208.208 0 0 0 .306-.216l-.566-3.452a.208.208 0 0 1 .057-.18l2.486-2.536a.208.208 0 0 0-.118-.351l-3.408-.519a.208.208 0 0 1-.157-.117L9.189 4.145a.208.208 0 0 0-.377 0L7.378 7.19a.208.208 0 0 1-.158.117l-3.408.519a.208.208 0 0 0-.117.351l2.485 2.537a.208.208 0 0 1 .057.18l-.566 3.45Zm8.093 2.99h-.003.003Z" fill="#4A5568"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -18,3 +18,4 @@ export const disk = String.fromCharCode(8226); // диск •
|
||||
export const minus = String.fromCharCode(8722); // минус −
|
||||
export const leftLineArrow = String.fromCharCode(8592); // стрелка ←
|
||||
export const rightLineArrow = String.fromCharCode(8594); // стрелка →
|
||||
export const apos = String.fromCharCode(39); // апостроф '
|
||||
|
||||
@@ -60,6 +60,7 @@ export default NETWORKS;
|
||||
// subType: 'mainnet',
|
||||
// group: 'mainnets',
|
||||
// isAccountSupported: true,
|
||||
// chainId: 100
|
||||
// },
|
||||
// {
|
||||
// name: 'Optimism on Gnosis Chain',
|
||||
@@ -68,12 +69,14 @@ export default NETWORKS;
|
||||
// subType: 'optimism',
|
||||
// group: 'mainnets',
|
||||
// icon: 'https://www.fillmurray.com/60/60'
|
||||
// chainId: 300
|
||||
// },
|
||||
// {
|
||||
// name: 'Arbitrum on xDai',
|
||||
// type: 'xdai',
|
||||
// subType: 'aox',
|
||||
// group: 'mainnets',
|
||||
// chainId: 200
|
||||
// },
|
||||
// {
|
||||
// name: 'Ethereum',
|
||||
@@ -81,6 +84,7 @@ export default NETWORKS;
|
||||
// type: 'eth',
|
||||
// subType: 'mainnet',
|
||||
// group: 'mainnets',
|
||||
// chainId: 1
|
||||
// },
|
||||
// {
|
||||
// name: 'Ethereum Classic',
|
||||
@@ -88,6 +92,7 @@ export default NETWORKS;
|
||||
// type: 'etc',
|
||||
// subType: 'mainnet',
|
||||
// group: 'mainnets',
|
||||
// chainId: 61
|
||||
// },
|
||||
// {
|
||||
// name: 'POA',
|
||||
@@ -95,6 +100,7 @@ export default NETWORKS;
|
||||
// type: 'poa',
|
||||
// subType: 'core',
|
||||
// group: 'mainnets',
|
||||
// chainId: 99
|
||||
// },
|
||||
// {
|
||||
// name: 'RSK',
|
||||
@@ -102,6 +108,7 @@ export default NETWORKS;
|
||||
// type: 'rsk',
|
||||
// subType: 'mainnet',
|
||||
// group: 'mainnets',
|
||||
// chainId: 30
|
||||
// },
|
||||
// {
|
||||
// name: 'Gnosis Chain Testnet',
|
||||
@@ -116,12 +123,14 @@ export default NETWORKS;
|
||||
// type: 'poa',
|
||||
// subType: 'sokol',
|
||||
// group: 'testnets',
|
||||
// chainId: 77
|
||||
// },
|
||||
// {
|
||||
// name: 'ARTIS Σ1',
|
||||
// type: 'artis',
|
||||
// subType: 'sigma1',
|
||||
// group: 'other',
|
||||
// chainId: 246529
|
||||
// },
|
||||
// {
|
||||
// name: 'LUKSO L14',
|
||||
@@ -129,5 +138,6 @@ export default NETWORKS;
|
||||
// type: 'lukso',
|
||||
// subType: 'l14',
|
||||
// group: 'other',
|
||||
// chainId: 22
|
||||
// },
|
||||
// ];
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import Head from 'next/head';
|
||||
import React from 'react';
|
||||
|
||||
import Apps from 'ui/pages/Apps';
|
||||
import Page from 'ui/shared/Page';
|
||||
import PageHeader from 'ui/shared/PageHeader';
|
||||
|
||||
const AppsPage = () => {
|
||||
return (
|
||||
<Page>
|
||||
<PageHeader text="Apps"/>
|
||||
<Head><title>Apps</title></Head>
|
||||
|
||||
<Apps/>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppsPage;
|
||||
@@ -23,6 +23,7 @@ const sizes = {
|
||||
minH: 6,
|
||||
minW: 6,
|
||||
fontSize: 'sm',
|
||||
lineHeight: 'sm',
|
||||
px: 2,
|
||||
py: '2px',
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const breakpoints = {
|
||||
// maybe we need them in future
|
||||
// sm: '320px',
|
||||
// md: '768px',
|
||||
sm: '414px',
|
||||
// md: '768px',
|
||||
lg: '1000px',
|
||||
xl: '1440px',
|
||||
// these breakpoint are needed just to make others work
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"~/*": ["./*"]
|
||||
},
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "additional.d.ts", "decs.d.ts"],
|
||||
"exclude": ["node_modules"],
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export type TxInternalsType = 'call' | 'delegate_call' | 'static_call' | 'create' | 'create2' | 'self_destruct' | 'reward'
|
||||
@@ -0,0 +1,22 @@
|
||||
export type AppCategory = {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export type AppItemPreview = {
|
||||
id: string;
|
||||
title: string;
|
||||
logo: string;
|
||||
shortDescription: string;
|
||||
categories: Array<AppCategory>;
|
||||
}
|
||||
|
||||
export type AppItemOverview = AppItemPreview & {
|
||||
author: string;
|
||||
url: string;
|
||||
description: string;
|
||||
site?: string;
|
||||
twitter?: string;
|
||||
telegram?: string;
|
||||
github?: string;
|
||||
}
|
||||
@@ -4,6 +4,8 @@ export type NetworkGroup = 'mainnets' | 'testnets' | 'other';
|
||||
|
||||
export interface Network {
|
||||
name: string;
|
||||
// https://chainlist.org/
|
||||
chainId?: number;
|
||||
shortName?: string;
|
||||
// basePath = /<type>/<subType>, e.g. /xdai/mainnet
|
||||
type: string;
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { Box, Heading, Image, Text, useColorModeValue } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import type { AppItemPreview } from 'types/client/apps';
|
||||
|
||||
const AppCard = ({ title, logo, shortDescription, categories }: AppItemPreview) => {
|
||||
const categoriesLabel = categories.map(c => c.name).join(', ');
|
||||
|
||||
return (
|
||||
<Box
|
||||
borderRadius={{ base: 'none', sm: 'md' }}
|
||||
height="100%"
|
||||
padding={{ base: '16px', sm: '20px' }}
|
||||
boxShadow={ `0 0 0 1px ${ useColorModeValue('var(--chakra-colors-gray-200)', 'var(--chakra-colors-gray-600)') }` }
|
||||
>
|
||||
<Box overflow="hidden" height="100%">
|
||||
<Box
|
||||
marginBottom={ 4 }
|
||||
w={{ base: '64px', sm: '96px' }}
|
||||
h={{ base: '64px', sm: '96px' }}
|
||||
>
|
||||
<Image
|
||||
src={ logo }
|
||||
alt={ `${ title } app icon` }
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Heading
|
||||
as="h3"
|
||||
marginBottom={ 2 }
|
||||
fontSize={{ base: 'sm', sm: 'lg' }}
|
||||
fontWeight="semibold"
|
||||
>
|
||||
{ title }
|
||||
</Heading>
|
||||
|
||||
<Text
|
||||
marginBottom={ 2 }
|
||||
variant="secondary"
|
||||
fontSize="xs"
|
||||
>
|
||||
{ categoriesLabel }
|
||||
</Text>
|
||||
|
||||
<Text
|
||||
fontSize={{ base: 'xs', sm: 'sm' }}
|
||||
lineHeight="20px"
|
||||
noOfLines={ 4 }
|
||||
>
|
||||
{ shortDescription }
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppCard;
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Grid, GridItem, VisuallyHidden, Heading } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import type { AppItemPreview } from 'types/client/apps';
|
||||
|
||||
import { apos } from 'lib/html-entities';
|
||||
import AppCard from 'ui/apps/AppCard';
|
||||
import EmptySearchResult from 'ui/apps/EmptySearchResult';
|
||||
|
||||
type Props = {
|
||||
apps: Array<AppItemPreview>;
|
||||
}
|
||||
|
||||
const AppList = ({ apps }: Props) => {
|
||||
return (
|
||||
<>
|
||||
<VisuallyHidden>
|
||||
<Heading as="h2">App list</Heading>
|
||||
</VisuallyHidden>
|
||||
|
||||
{ apps.length > 0 ? (
|
||||
<Grid
|
||||
templateColumns={{
|
||||
base: 'repeat(auto-fill, minmax(160px, 1fr))',
|
||||
sm: 'repeat(auto-fill, minmax(200px, 1fr))',
|
||||
lg: 'repeat(auto-fill, minmax(260px, 1fr))',
|
||||
}}
|
||||
autoRows="1fr"
|
||||
gap={{ base: '1px', sm: '24px' }}
|
||||
>
|
||||
{ apps.map((app) => (
|
||||
<GridItem
|
||||
key={ app.id }
|
||||
>
|
||||
<AppCard
|
||||
id={ app.id }
|
||||
title={ app.title }
|
||||
logo={ app.logo }
|
||||
shortDescription={ app.shortDescription }
|
||||
categories={ app.categories }
|
||||
/>
|
||||
</GridItem>
|
||||
)) }
|
||||
</Grid>
|
||||
) : (
|
||||
<EmptySearchResult text={ `Couldn${ apos }t find an app that matches your filter query.` }/>
|
||||
) }
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppList;
|
||||
@@ -0,0 +1,245 @@
|
||||
import { LinkIcon, StarIcon } from '@chakra-ui/icons';
|
||||
import {
|
||||
Box, Button, Heading, Icon, IconButton, Image, Link, List, Modal, ModalBody,
|
||||
ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, Tag, Text,
|
||||
} from '@chakra-ui/react';
|
||||
import type { FunctionComponent } from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import type { AppCategory, AppItemOverview } from 'types/client/apps';
|
||||
|
||||
import { TEMPORARY_DEMO_APPS } from 'data/apps';
|
||||
import ghIcon from 'icons/social/git.svg';
|
||||
import tgIcon from 'icons/social/telega.svg';
|
||||
import twIcon from 'icons/social/tweet.svg';
|
||||
import starOutlineIcon from 'icons/star_outline.svg';
|
||||
import { nbsp } from 'lib/html-entities';
|
||||
|
||||
type Props = {
|
||||
id: string | null;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const AppModal = ({
|
||||
id,
|
||||
onClose,
|
||||
}: Props) => {
|
||||
const handleFavorite = useCallback(() => {
|
||||
// TODO: implement
|
||||
}, []);
|
||||
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
author,
|
||||
description,
|
||||
url,
|
||||
site,
|
||||
github,
|
||||
telegram,
|
||||
twitter,
|
||||
logo,
|
||||
categories,
|
||||
} = TEMPORARY_DEMO_APPS.find(app => app.id === id) as AppItemOverview;
|
||||
|
||||
const isFavorite = false;
|
||||
|
||||
const socialLinks = [
|
||||
Boolean(telegram) && {
|
||||
icon: tgIcon,
|
||||
url: telegram,
|
||||
},
|
||||
Boolean(twitter) && {
|
||||
icon: twIcon,
|
||||
url: twitter,
|
||||
},
|
||||
Boolean(github) && {
|
||||
icon: ghIcon,
|
||||
url: github,
|
||||
},
|
||||
].filter(Boolean) as Array<{ icon: FunctionComponent; url: string }>;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={ Boolean(id) }
|
||||
onClose={ onClose }
|
||||
size={{ base: 'full', lg: 'md' }}
|
||||
isCentered
|
||||
>
|
||||
<ModalOverlay/>
|
||||
|
||||
<ModalContent>
|
||||
<ModalHeader
|
||||
display="grid"
|
||||
gridTemplateColumns={{ base: 'auto 1fr' }}
|
||||
paddingRight={{ sm: 12 }}
|
||||
>
|
||||
<Box
|
||||
w={{ base: '72px', sm: '144px' }}
|
||||
h={{ base: '72px', sm: '144px' }}
|
||||
marginRight={{ base: 6, sm: 8 }}
|
||||
gridRow={{ base: '1 / 3', sm: '1 / 4' }}
|
||||
>
|
||||
<Image
|
||||
src={ logo }
|
||||
alt={ `${ title } app icon` }
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Heading
|
||||
as="h2"
|
||||
gridColumn={ 2 }
|
||||
fontSize={{ base: '2xl', sm: '3xl' }}
|
||||
fontWeight="medium"
|
||||
lineHeight={ 1 }
|
||||
color="blue.600"
|
||||
whiteSpace="nowrap"
|
||||
overflow="hidden"
|
||||
textOverflow="ellipsis"
|
||||
>
|
||||
{ title }
|
||||
</Heading>
|
||||
|
||||
<Text
|
||||
variant="secondary"
|
||||
gridColumn={ 2 }
|
||||
fontSize="sm"
|
||||
fontWeight="normal"
|
||||
lineHeight={ 1 }
|
||||
>
|
||||
By{ nbsp }{ author }
|
||||
</Text>
|
||||
|
||||
<Box
|
||||
gridColumn={{ base: '1 / 3', sm: 2 }}
|
||||
marginTop={{ base: 6, sm: 0 }}
|
||||
>
|
||||
<Box display="flex">
|
||||
<Button
|
||||
href={ url }
|
||||
as="a"
|
||||
size="sm"
|
||||
marginRight={ 2 }
|
||||
width={{ base: '100%', sm: 'auto' }}
|
||||
>
|
||||
Launch app
|
||||
</Button>
|
||||
|
||||
<IconButton
|
||||
aria-label="Mark as favorite"
|
||||
title="Mark as favorite"
|
||||
variant="outline"
|
||||
colorScheme="gray"
|
||||
w={ 9 }
|
||||
h={ 8 }
|
||||
onClick={ handleFavorite }
|
||||
icon={ isFavorite ?
|
||||
<Icon as={ StarIcon } w={ 4 } h={ 4 } color="yellow.400"/> :
|
||||
<Icon as={ starOutlineIcon } w={ 4 } h={ 4 }/> }
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</ModalHeader>
|
||||
|
||||
<ModalCloseButton/>
|
||||
|
||||
<ModalBody>
|
||||
<Heading
|
||||
as="h3"
|
||||
fontSize="2xl"
|
||||
marginBottom={ 4 }
|
||||
>
|
||||
Overview
|
||||
</Heading>
|
||||
|
||||
<Box marginBottom={ 2 }>
|
||||
{ categories.map((category: AppCategory) => (
|
||||
<Tag
|
||||
colorScheme="blue"
|
||||
marginRight={ 2 }
|
||||
marginBottom={ 2 }
|
||||
key={ category.id }
|
||||
>
|
||||
{ category.name }
|
||||
</Tag>
|
||||
)) }
|
||||
</Box>
|
||||
|
||||
<Text>{ description }</Text>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter
|
||||
display="flex"
|
||||
flexDirection={{ base: 'column', sm: 'row' }}
|
||||
alignItems={{ base: 'flex-start', sm: 'center' }}
|
||||
>
|
||||
{ site && (
|
||||
<Link
|
||||
isExternal
|
||||
href={ site }
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
paddingRight={{ sm: 2 }}
|
||||
marginBottom={{ base: 3, sm: 0 }}
|
||||
maxW="100%"
|
||||
overflow="hidden"
|
||||
>
|
||||
<Icon
|
||||
as={ LinkIcon }
|
||||
display="inline"
|
||||
verticalAlign="baseline"
|
||||
boxSize={ 3 }
|
||||
marginRight={ 2 }
|
||||
/>
|
||||
|
||||
<Text
|
||||
color="inherit"
|
||||
whiteSpace="nowrap"
|
||||
overflow="hidden"
|
||||
textOverflow="ellipsis"
|
||||
>
|
||||
{ site }
|
||||
</Text>
|
||||
</Link>
|
||||
) }
|
||||
|
||||
{ socialLinks.length && (
|
||||
<List
|
||||
marginLeft={{ sm: 'auto' }}
|
||||
display="grid"
|
||||
gridAutoFlow="column"
|
||||
columnGap={ 2 }
|
||||
>
|
||||
{ socialLinks.map(({ icon, url }) => (
|
||||
<Link
|
||||
aria-label={ `Link to ${ url }` }
|
||||
title={ url }
|
||||
key={ url }
|
||||
href={ url }
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
isExternal
|
||||
w={ 10 }
|
||||
h={ 10 }
|
||||
>
|
||||
<Icon
|
||||
as={ icon }
|
||||
w="20px"
|
||||
h="20px"
|
||||
display="block"
|
||||
/>
|
||||
</Link>
|
||||
)) }
|
||||
</List>
|
||||
) }
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppModal;
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Box, Heading, Icon, Text } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import emptyIcon from 'icons/empty_search_result.svg';
|
||||
|
||||
interface Props {
|
||||
text: string;
|
||||
}
|
||||
|
||||
const EmptySearchResult = ({ text }: Props) => {
|
||||
return (
|
||||
<Box
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
alignItems="center"
|
||||
>
|
||||
<Icon
|
||||
as={ emptyIcon }
|
||||
boxSize={ 60 }
|
||||
display="block"
|
||||
/>
|
||||
|
||||
<Heading
|
||||
as="h3"
|
||||
marginBottom={ 2 }
|
||||
fontSize={{ base: '2xl', sm: '3xl' }}
|
||||
fontWeight="semibold"
|
||||
>
|
||||
No results
|
||||
</Heading>
|
||||
|
||||
<Text
|
||||
fontSize={{ base: 'sm' }}
|
||||
variant="secondary"
|
||||
align="center"
|
||||
>
|
||||
{ text }
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmptySearchResult;
|
||||
@@ -0,0 +1,44 @@
|
||||
import type { AppCategory } from 'types/client/apps';
|
||||
|
||||
export const APP_CATEGORIES: Array<AppCategory> = [
|
||||
{
|
||||
id: 'defi',
|
||||
name: 'DeFi',
|
||||
},
|
||||
{
|
||||
id: 'exchanges',
|
||||
name: 'Exchanges',
|
||||
},
|
||||
{
|
||||
id: 'finance',
|
||||
name: 'Finance',
|
||||
},
|
||||
{
|
||||
id: 'games',
|
||||
name: 'Games',
|
||||
},
|
||||
{
|
||||
id: 'marketplaces',
|
||||
name: 'Marketplaces',
|
||||
},
|
||||
{
|
||||
id: 'nft',
|
||||
name: 'NFT',
|
||||
},
|
||||
{
|
||||
id: 'security',
|
||||
name: 'Security',
|
||||
},
|
||||
{
|
||||
id: 'social',
|
||||
name: 'Social',
|
||||
},
|
||||
{
|
||||
id: 'tools',
|
||||
name: 'Tools',
|
||||
},
|
||||
{
|
||||
id: 'Yield-farming',
|
||||
name: 'yield-farming',
|
||||
},
|
||||
];
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Link, Icon, Text, HStack, Tooltip } from '@chakra-ui/react';
|
||||
import { Link, Icon, Text, HStack, Tooltip, Box } from '@chakra-ui/react';
|
||||
import NextLink from 'next/link';
|
||||
import React from 'react';
|
||||
|
||||
@@ -28,36 +28,37 @@ const NavLink = ({ text, url, icon, isCollapsed, isActive, px }: Props) => {
|
||||
})();
|
||||
|
||||
return (
|
||||
<NextLink href={ url } passHref>
|
||||
<Link
|
||||
as="li"
|
||||
listStyleType="none"
|
||||
w={ width }
|
||||
px={ px || (isCollapsed ? '15px' : 3) }
|
||||
py={ 2.5 }
|
||||
color={ isActive ? colors.text.active : colors.text.default }
|
||||
bgColor={ isActive ? colors.bg.active : colors.bg.default }
|
||||
_hover={{ color: isActive ? colors.text.active : colors.text.hover }}
|
||||
borderRadius="base"
|
||||
whiteSpace="nowrap"
|
||||
{ ...getDefaultTransitionProps({ transitionProperty: 'width, padding' }) }
|
||||
>
|
||||
<Tooltip
|
||||
label={ text }
|
||||
hasArrow={ false }
|
||||
isDisabled={ !isCollapsed }
|
||||
placement="right"
|
||||
variant="nav"
|
||||
gutter={ 15 }
|
||||
color={ isActive ? colors.text.active : colors.text.hover }
|
||||
<Box as="li" listStyleType="none" w="100%">
|
||||
<NextLink href={ url } passHref>
|
||||
<Link
|
||||
w={ width }
|
||||
px={ px || (isCollapsed ? '15px' : 3) }
|
||||
py={ 2.5 }
|
||||
display="flex"
|
||||
color={ isActive ? colors.text.active : colors.text.default }
|
||||
bgColor={ isActive ? colors.bg.active : colors.bg.default }
|
||||
_hover={{ color: isActive ? colors.text.active : colors.text.hover }}
|
||||
borderRadius="base"
|
||||
whiteSpace="nowrap"
|
||||
{ ...getDefaultTransitionProps({ transitionProperty: 'width, padding' }) }
|
||||
>
|
||||
<HStack spacing={ 3 }>
|
||||
<Icon as={ icon } boxSize="30px"/>
|
||||
{ !isCollapsed && <Text variant="inherit" fontSize="sm" lineHeight="20px">{ text }</Text> }
|
||||
</HStack>
|
||||
</Tooltip>
|
||||
</Link>
|
||||
</NextLink>
|
||||
<Tooltip
|
||||
label={ text }
|
||||
hasArrow={ false }
|
||||
isDisabled={ !isCollapsed }
|
||||
placement="right"
|
||||
variant="nav"
|
||||
gutter={ 15 }
|
||||
color={ isActive ? colors.text.active : colors.text.hover }
|
||||
>
|
||||
<HStack spacing={ 3 }>
|
||||
<Icon as={ icon } boxSize="30px"/>
|
||||
{ !isCollapsed && <Text variant="inherit" fontSize="sm" lineHeight="20px">{ text }</Text> }
|
||||
</HStack>
|
||||
</Tooltip>
|
||||
</Link>
|
||||
</NextLink>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import debounce from 'lodash/debounce';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
|
||||
import type { AppItemOverview } from 'types/client/apps';
|
||||
|
||||
import { TEMPORARY_DEMO_APPS } from 'data/apps';
|
||||
import AppList from 'ui/apps/AppList';
|
||||
import FilterInput from 'ui/shared/FilterInput';
|
||||
import AppModal from 'ui/apps/AppModal';
|
||||
|
||||
const defaultDisplayedApps = [ ...TEMPORARY_DEMO_APPS ]
|
||||
.sort((a, b) => a.title.localeCompare(b.title));
|
||||
|
||||
const Apps = () => {
|
||||
const [ displayedApps, setDisplayedApps ] = useState<Array<AppItemOverview>>(defaultDisplayedApps);
|
||||
const [ displayedAppId, setDisplayedAppId ] = useState<string | null>('component');
|
||||
|
||||
const filterApps = (q: string) => {
|
||||
const apps = displayedApps
|
||||
.filter(app => app.title.toLowerCase().includes(q.toLowerCase()));
|
||||
|
||||
setDisplayedApps(apps);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const debounceFilterApps = useCallback(debounce(q => filterApps(q), 500), []);
|
||||
|
||||
const clearDisplayedAppId = useCallback(() => setDisplayedAppId(null), []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<FilterInput onChange={ debounceFilterApps } marginBottom={{ base: '4', lg: '6' }} placeholder="Find app"/>
|
||||
<AppList apps={ displayedApps }/>
|
||||
<AppModal
|
||||
id={ displayedAppId }
|
||||
onClose={ clearDisplayedAppId }
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Apps;
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Button, Circle, Icon, useColorModeValue } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import filterIcon from 'icons/filter.svg';
|
||||
|
||||
const FilterIcon = <Icon as={ filterIcon } boxSize={ 5 }/>;
|
||||
|
||||
interface Props {
|
||||
isActive: boolean;
|
||||
isCollapsed?: boolean;
|
||||
appliedFiltersNum?: number;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
const FilterButton = ({ isActive, appliedFiltersNum, onClick, isCollapsed }: Props, ref: React.ForwardedRef<HTMLButtonElement>) => {
|
||||
const badgeColor = useColorModeValue('white', 'black');
|
||||
const badgeBgColor = useColorModeValue('blue.700', 'gray.50');
|
||||
|
||||
return (
|
||||
<Button
|
||||
ref={ ref }
|
||||
leftIcon={ isCollapsed ? undefined : FilterIcon }
|
||||
rightIcon={ appliedFiltersNum ? <Circle bg={ badgeBgColor } size={ 5 } color={ badgeColor }>{ appliedFiltersNum }</Circle> : undefined }
|
||||
size="sm"
|
||||
variant="outline"
|
||||
colorScheme="gray-dark"
|
||||
onClick={ onClick }
|
||||
isActive={ isActive }
|
||||
px={ 1.5 }
|
||||
>
|
||||
{ isCollapsed ? FilterIcon : 'Filter' }
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.forwardRef(FilterButton);
|
||||
@@ -0,0 +1,44 @@
|
||||
import { SearchIcon } from '@chakra-ui/icons';
|
||||
import { Input, InputGroup, InputLeftElement, useColorModeValue, chakra } from '@chakra-ui/react';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
|
||||
type Props = {
|
||||
onChange: (searchTerm: string) => void;
|
||||
className?: string;
|
||||
size?: 'xs' | 'sm' | 'md' | 'lg';
|
||||
placeholder: string;
|
||||
}
|
||||
|
||||
const FilterInput = ({ onChange, className, size = 'sm', placeholder }: Props) => {
|
||||
const [ filterQuery, setFilterQuery ] = useState('');
|
||||
|
||||
const handleFilterQueryChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
|
||||
const { value } = event.target;
|
||||
|
||||
setFilterQuery(value);
|
||||
onChange(value);
|
||||
}, [ onChange ]);
|
||||
|
||||
return (
|
||||
<InputGroup
|
||||
size={ size }
|
||||
className={ className }
|
||||
>
|
||||
<InputLeftElement
|
||||
pointerEvents="none"
|
||||
>
|
||||
<SearchIcon color={ useColorModeValue('blackAlpha.600', 'whiteAlpha.600') }/>
|
||||
</InputLeftElement>
|
||||
|
||||
<Input
|
||||
size={ size }
|
||||
value={ filterQuery }
|
||||
onChange={ handleFilterQueryChange }
|
||||
placeholder={ placeholder }
|
||||
/>
|
||||
</InputGroup>
|
||||
);
|
||||
};
|
||||
|
||||
export default chakra(FilterInput);
|
||||
@@ -1,3 +1,7 @@
|
||||
// DEPRECATED
|
||||
// migrate to separate components
|
||||
// ui/shared/FilterButton.tsx + custom filter
|
||||
// ui/shared/FilterInput.tsx
|
||||
import { SearchIcon } from '@chakra-ui/icons';
|
||||
import { Flex, Icon, Button, Circle, InputGroup, InputLeftElement, Input, useColorModeValue } from '@chakra-ui/react';
|
||||
import type { ChangeEvent } from 'react';
|
||||
|
||||
@@ -43,9 +43,7 @@ const Page = ({ children }: Props) => {
|
||||
<Header/>
|
||||
<Box
|
||||
as="main"
|
||||
borderRadius="base"
|
||||
w="100%"
|
||||
overflow="hidden"
|
||||
paddingTop={ isMobile ? '138px' : '52px' }
|
||||
>
|
||||
{ children }
|
||||
|
||||
+44
-12
@@ -1,15 +1,42 @@
|
||||
import { Box, Table, Thead, Tbody, Tr, Th, TableContainer } from '@chakra-ui/react';
|
||||
import { Box, Flex, Table, Thead, Tbody, Tr, Th, TableContainer } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import type { TxInternalsType } from 'types/api/tx';
|
||||
import type ArrayElement from 'types/utils/ArrayElement';
|
||||
|
||||
import { data } from 'data/txInternal';
|
||||
import Filters from 'ui/shared/Filters';
|
||||
import { apos } from 'lib/html-entities';
|
||||
import EmptySearchResult from 'ui/apps/EmptySearchResult';
|
||||
import FilterInput from 'ui/shared/FilterInput';
|
||||
import TxInternalsFilter from 'ui/tx/internals/TxInternalsFilter';
|
||||
import TxInternalsTableItem from 'ui/tx/internals/TxInternalsTableItem';
|
||||
|
||||
const searchFn = (searchTerm: string) => (item: ArrayElement<typeof data>): boolean => {
|
||||
const formattedSearchTerm = searchTerm.toLowerCase();
|
||||
return item.type.toLowerCase().includes(formattedSearchTerm) ||
|
||||
item.from.toLowerCase().includes(formattedSearchTerm) ||
|
||||
item.to.toLowerCase().includes(formattedSearchTerm);
|
||||
};
|
||||
|
||||
const TxInternals = () => {
|
||||
return (
|
||||
<Box>
|
||||
<Filters/>
|
||||
<TableContainer width="100%" mt={ 6 }>
|
||||
const [ filters, setFilters ] = React.useState<Array<TxInternalsType>>([]);
|
||||
const [ searchTerm, setSearchTerm ] = React.useState<string>('');
|
||||
|
||||
const handleFilterChange = React.useCallback((nextValue: Array<TxInternalsType>) => {
|
||||
setFilters(nextValue);
|
||||
}, []);
|
||||
|
||||
const content = (() => {
|
||||
const filteredData = data
|
||||
.filter(({ type }) => filters.length > 0 ? filters.includes(type) : true)
|
||||
.filter(searchFn(searchTerm));
|
||||
|
||||
if (filteredData.length === 0) {
|
||||
return <EmptySearchResult text={ `Couldn${ apos }t find any transaction that matches your query.` }/>;
|
||||
}
|
||||
|
||||
return (
|
||||
<TableContainer width="100%">
|
||||
<Table variant="simple" minWidth="950px" size="sm">
|
||||
<Thead>
|
||||
<Tr>
|
||||
@@ -21,15 +48,20 @@ const TxInternals = () => {
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{ data.map((item) => (
|
||||
<TxInternalsTableItem
|
||||
key={ item.id }
|
||||
{ ...item }
|
||||
/>
|
||||
)) }
|
||||
{ filteredData.map((item) => <TxInternalsTableItem key={ item.id } { ...item }/>) }
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
);
|
||||
})();
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Flex mb={ 6 }>
|
||||
<TxInternalsFilter onFilterChange={ handleFilterChange } defaultFilters={ filters } appliedFiltersNum={ filters.length }/>
|
||||
<FilterInput onChange={ setSearchTerm } maxW="360px" ml={ 3 } size="xs" placeholder="Search by addresses, hash, method..."/>
|
||||
</Flex>
|
||||
{ content }
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { Popover, PopoverTrigger, PopoverContent, PopoverBody, CheckboxGroup, Checkbox, Text, useDisclosure } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import type { TxInternalsType } from 'types/api/tx';
|
||||
|
||||
import useIsMobile from 'lib/hooks/useIsMobile';
|
||||
import FilterButton from 'ui/shared/FilterButton';
|
||||
import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
|
||||
|
||||
interface Props {
|
||||
appliedFiltersNum?: number;
|
||||
defaultFilters: Array<TxInternalsType>;
|
||||
onFilterChange: (nextValue: Array<TxInternalsType>) => void;
|
||||
}
|
||||
|
||||
const TxInternalsFilter = ({ onFilterChange, defaultFilters, appliedFiltersNum }: Props) => {
|
||||
const { isOpen, onToggle, onClose } = useDisclosure();
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
return (
|
||||
<Popover isOpen={ isOpen } onClose={ onClose } placement="bottom-start" isLazy>
|
||||
<PopoverTrigger>
|
||||
<FilterButton
|
||||
isActive={ isOpen || Number(appliedFiltersNum) > 0 }
|
||||
isCollapsed={ isMobile }
|
||||
onClick={ onToggle }
|
||||
appliedFiltersNum={ appliedFiltersNum }
|
||||
/>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent w={{ md: '100%', lg: '438px' }}>
|
||||
<PopoverBody px={ 4 } py={ 6 } display="grid" gridTemplateColumns="1fr 1fr" rowGap={ 5 }>
|
||||
<CheckboxGroup size="lg" onChange={ onFilterChange } defaultValue={ defaultFilters }>
|
||||
{ TX_INTERNALS_ITEMS.map(({ title, id }) => <Checkbox key={ id } value={ id }><Text fontSize="md">{ title }</Text></Checkbox>) }
|
||||
</CheckboxGroup>
|
||||
</PopoverBody>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(TxInternalsFilter);
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Tr, Td, Tag, Icon } from '@chakra-ui/react';
|
||||
import capitalize from 'lodash/capitalize';
|
||||
import React from 'react';
|
||||
|
||||
import rightArrowIcon from 'icons/arrows/right.svg';
|
||||
import Address from 'ui/shared/address/Address';
|
||||
import AddressIcon from 'ui/shared/address/AddressIcon';
|
||||
import AddressLink from 'ui/shared/address/AddressLink';
|
||||
import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
|
||||
import TxStatus from 'ui/tx/TxStatus';
|
||||
|
||||
interface Props {
|
||||
@@ -18,10 +18,12 @@ interface Props {
|
||||
}
|
||||
|
||||
const TxInternalTableItem = ({ type, status, from, to, value, gasLimit }: Props) => {
|
||||
const typeTitle = TX_INTERNALS_ITEMS.find(({ id }) => id === type)?.title;
|
||||
|
||||
return (
|
||||
<Tr alignItems="top">
|
||||
<Td>
|
||||
<Tag colorScheme="cyan" mr={ 2 }>{ capitalize(type) }</Tag>
|
||||
{ typeTitle && <Tag colorScheme="cyan" mr={ 2 }>{ typeTitle }</Tag> }
|
||||
<TxStatus status={ status }/>
|
||||
</Td>
|
||||
<Td pr="0">
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import type { TxInternalsType } from 'types/api/tx';
|
||||
|
||||
interface TxInternalsTypeItem {
|
||||
title: string;
|
||||
id: TxInternalsType;
|
||||
}
|
||||
|
||||
export const TX_INTERNALS_ITEMS: Array<TxInternalsTypeItem> = [
|
||||
{ title: 'Call', id: 'call' },
|
||||
{ title: 'Delegate call', id: 'delegate_call' },
|
||||
{ title: 'Static call', id: 'static_call' },
|
||||
{ title: 'Create', id: 'create' },
|
||||
{ title: 'Create2', id: 'create2' },
|
||||
{ title: 'Self-destruct', id: 'self_destruct' },
|
||||
{ title: 'Reward', id: 'reward' },
|
||||
];
|
||||
Reference in New Issue
Block a user