Commit 6cb80c92 authored by tom's avatar tom

Merge branch 'tabs' of github.com:blockscout/frontend into tx-mobile-view

parents 1170ca50 7f6aa995
......@@ -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"}]
\ No newline at end of file
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>`
\ No newline at end of file
*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
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',
},
];
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: 'success' as const,
from: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45',
to: '0x12E80C27BfFBB76b4A8d26FF2bfd3C9f310FFA01',
......@@ -19,7 +21,7 @@ export const data = [
},
{
id: 3,
type: 'static call',
type: 'static_call' as TxInternalsType,
status: 'error' as const,
from: '0x97Aa2EfcF35c0f4c9AaDDCa8c2330fa7A9533830',
to: '0x35317007D203b8a86CA727ad44E473E40450E378',
......
<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>
<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>
......@@ -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
// },
// ];
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;
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"],
......
export type TxInternalsType = 'call' | 'delegate_call' | 'static_call' | 'create' | 'create2' | 'self_destruct' | 'reward'
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;
......
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;
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;
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;
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;
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',
},
];
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>
);
};
......
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 AppModal from 'ui/apps/AppModal';
import FilterInput from 'ui/shared/FilterInput';
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;
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);
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);
// 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';
......
......@@ -50,9 +50,7 @@ const Page = ({ children }: Props) => {
<Header/>
<Box
as="main"
borderRadius="base"
w="100%"
// overflow="hidden"
paddingTop={ isMobile ? '138px' : '52px' }
>
{ children }
......
import { Box } from '@chakra-ui/react';
import { Box, Flex } 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 useIsMobile from 'lib/hooks/useIsMobile';
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 TxInternalsList from 'ui/tx/internals/TxInternalsList';
import TxInternalsTable from 'ui/tx/internals/TxInternalsTable';
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 = () => {
const [ filters, setFilters ] = React.useState<Array<TxInternalsType>>([]);
const [ searchTerm, setSearchTerm ] = React.useState<string>('');
const isMobile = useIsMobile();
const list = isMobile ? <TxInternalsList/> : <TxInternalsTable/>;
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 isMobile ? <TxInternalsList data={ filteredData }/> : <TxInternalsTable data={ filteredData }/>;
})();
return (
<Box>
<Filters/>
{ list }
<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>
);
};
......
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);
import { Box } from '@chakra-ui/react';
import React from 'react';
import { data } from 'data/txInternal';
import type { data as txData } from 'data/txInternal';
import TxInternalsListItem from 'ui/tx/internals/TxInternalsListItem';
const TxInternalsList = () => {
const TxInternalsList = ({ data }: { data: typeof txData}) => {
return (
<Box mt={ 6 }>
{ data.map((item) => <TxInternalsListItem key={ item.id } { ...item }/>) }
......
import { Table, Thead, Tbody, Tr, Th, TableContainer } from '@chakra-ui/react';
import React from 'react';
import { data } from 'data/txInternal';
import type { data as txData } from 'data/txInternal';
import TxInternalsTableItem from 'ui/tx/internals/TxInternalsTableItem';
const TxInternalsTable = () => {
const TxInternalsTable = ({ data }: { data: typeof txData}) => {
return (
<TableContainer width="100%" mt={ 6 }>
<Table variant="simple" size="sm">
......
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>
......
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' },
];
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