Commit 25114bae authored by tom's avatar tom

Merge branch 'main' of github.com:tom2drum/block-scout into custom-abi

parents 3d4b227f 8bfb04b2
<svg width="30" height="30" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#a)"><path d="M10.176 10.291a1.253 1.253 0 0 0-1.76.159L5.29 14.2a1.247 1.247 0 0 0 0 1.6l3.125 3.75a1.25 1.25 0 1 0 1.919-1.6L7.876 15l2.459-2.949a1.25 1.25 0 0 0-.159-1.76ZM16.494 7.525a1.261 1.261 0 0 0-1.47.981l-2.5 12.5a1.246 1.246 0 0 0 1.229 1.494 1.249 1.249 0 0 0 1.223-1.006l2.5-12.5a1.246 1.246 0 0 0-.982-1.469ZM24.709 14.2l-3.125-3.75a1.251 1.251 0 0 0-2.209.687 1.25 1.25 0 0 0 .29.914l2.459 2.95-2.459 2.948a1.248 1.248 0 0 0 .584 2 1.25 1.25 0 0 0 1.335-.398l3.125-3.75a1.247 1.247 0 0 0 0-1.601Z"/></g><defs><clipPath id="a"><path fill="#fff" transform="translate(5 5)" d="M0 0h20v20H0z"/></clipPath></defs></svg> <svg width="30" height="30" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
\ No newline at end of file <g clip-path="url(#abi-a)">
<path d="M10.176 10.291a1.253 1.253 0 0 0-1.76.159L5.29 14.2a1.247 1.247 0 0 0 0 1.6l3.125 3.75a1.25 1.25 0 1 0 1.919-1.6L7.876 15l2.459-2.949a1.25 1.25 0 0 0-.159-1.76Zm6.318-2.766a1.261 1.261 0 0 0-1.47.981l-2.5 12.5a1.246 1.246 0 0 0 1.229 1.494 1.249 1.249 0 0 0 1.223-1.006l2.5-12.5a1.246 1.246 0 0 0-.982-1.469Zm8.215 6.675-3.125-3.75a1.251 1.251 0 0 0-2.209.687 1.25 1.25 0 0 0 .29.914l2.459 2.95-2.459 2.948a1.248 1.248 0 0 0 .584 2 1.25 1.25 0 0 0 1.335-.398l3.125-3.75a1.247 1.247 0 0 0 0-1.601Z"/>
</g>
<defs>
<clipPath id="abi-a">
<path fill="#fff" transform="translate(5 5)" d="M0 0h20v20H0z"/>
</clipPath>
</defs>
</svg>
\ No newline at end of file
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.293 14.465a1 1 0 0 0 1.414 0l7.778-7.78A1 1 0 0 1 19.899 8.1l-9.192 9.193a1 1 0 0 1-1.414 0l-4.95-4.95a1 1 0 0 1 1.414-1.414l3.536 3.536Z" fill="currentColor"/>
</svg>
\ No newline at end of file
<svg width="30" height="30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.77 1H1v6.588h10.77V1ZM29 1H18.23v6.588H29V1Zm0 15.922h-6.462v5.49h-4.307V29H29V16.922Zm-21.538 0H1V29h10.77v-6.588H7.461v-5.49Z" fill="#48A9A6"/>
</svg>
\ No newline at end of file
<svg width="30" height="30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 16.736 10 8.5m-9 8.236L11 23M1 16.736 6.283 3.528M1 16.736 8.925 27.83M10 8.5 20.547 3M10 8.5 6.283 3.528M20.547 3l2.642 11M20.547 3 29 13.566M20.547 3l-14.264.528M23.189 14v12.774m0-12.774L29 13.566m-5.811 13.208L11 23m12.189 3.774L8.925 27.83m14.264-1.056L29 13.566M11 23l-2.075 4.83m9.509-16.905h-6.868l4.226 4.226-4.226 4.755h6.868" stroke="#129C6B" stroke-width="1.4" stroke-linejoin="round"/>
</svg>
\ No newline at end of file
<svg width="30" height="30" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="30" height="30" rx="15" fill="#328332"/>
<path opacity=".6" d="M8.625 15.958c2.337 1.241 4.776 2.54 6.66 3.546l6.604-3.546c-2.391 3.553-4.384 6.51-6.605 9.784-2.224-3.266-4.681-6.87-6.659-9.784Zm.254-.98 6.413-3.422 6.329 3.397-6.326 3.426-6.416-3.401Zm6.405-4.518-6.659 3.506 6.63-9.708 6.634 9.73-6.605-3.528Z" fill="#fff"/>
<path opacity=".7" d="m15.284 19.504 6.605-3.546a7441.882 7441.882 0 0 1-6.605 9.784v-6.238Zm.008-7.948 6.329 3.397-6.326 3.426-.003-6.823Zm-.008-1.096-.029-6.202 6.634 9.73-6.605-3.528Z" fill="#fff"/>
<path opacity=".7" d="m8.88 14.978 6.412.526 6.33-.548-6.326 3.426-6.417-3.404Z" fill="#fff"/>
<path d="m15.292 15.504 6.33-.548-6.326 3.426-.004-2.878Z" fill="#fff"/>
</svg>
\ No newline at end of file
<svg width="30" height="30" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="30" height="30" rx="15" fill="#627EEA"/>
<path d="M15.305 12.153V4.088c-.013 0-.02.006-.03.012-.013.01-.028.022-.066.022-.254.497-.524.975-.799 1.462-.108.192-.218.385-.327.582-.515.9-1.03 1.834-1.544 2.768a141.5 141.5 0 0 1-.844 1.52c-.28.497-.558.994-.83 1.491-.257.468-.522.935-.787 1.402-.266.468-.531.935-.788 1.403-.048.085-.096.161-.143.238a5.99 5.99 0 0 0-.147.246h.032c.02.021.028.016.038.01.007-.005.014-.01.027-.01.112-.052.233-.112.353-.173.121-.06.242-.121.354-.173.307-.165.584-.298.86-.43l.041-.02 1.062-.52.868-.415 1.062-.519c.225-.135.47-.249.704-.358.067-.03.133-.061.197-.092.116-.053.223-.107.331-.16.101-.05.203-.101.312-.152.032 0 .064-.034.064-.069ZM15.277 25.997a.08.08 0 0 0 .029.003v-5.435c0-.035 0-.07-.033-.07a7.196 7.196 0 0 0-.257-.155c-.088-.052-.177-.104-.257-.156a93.415 93.415 0 0 0-1.499-.96 91.637 91.637 0 0 1-1.525-.979 187.64 187.64 0 0 0-1.32-.83c-.442-.277-.884-.554-1.318-.83-.017 0-.025-.01-.033-.018-.008-.009-.016-.017-.032-.017 0 .017.008.026.016.034.008.009.016.017.016.034l.483.727c.389.618.79 1.22 1.19 1.818.227.342.454.681.676 1.021l1.93 2.908c.311.469.615.93.918 1.39.324.492.648.983.98 1.483.019.02.027.029.036.032Z" fill="#fff"/>
<path d="M15.3 4v11.307h6.3L15.3 4ZM9 15.175l6.3-3.024v7.1L9 15.175ZM15.3 20.566v5.39l6.177-9.203-6.177 3.813Z" fill="#C0CBF6"/>
<path d="M15.3 19.251v-7.1l6.3 3.156-6.3 3.944Z" fill="#8197EE"/>
</svg>
\ No newline at end of file
<svg width="30" height="30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.467 7.495c.046.041.084.073.12.107.377.365.75.734 1.133 1.095.085.081.086.137.024.23-.8 1.21-1.09 2.537-.824 3.943.358 1.886 1.456 3.26 3.248 4.089 1.06.489 2.183.614 3.338.443a5.646 5.646 0 0 0 2.166-.788c.11-.068.17-.06.26.028.974.958 1.955 1.91 2.928 2.87.108.105.163.117.28.004 1.112-1.087 2.234-2.166 3.347-3.254.122-.12.199-.14.36-.047.973.568 2.033.795 3.167.744 2.25-.102 4.305-1.625 5.003-3.716.528-1.583.332-3.086-.529-4.515-.056-.093-.06-.15.025-.231.314-.293.619-.594.928-.891.028-.028.06-.052.092-.079 3.297 4.694 3.762 12.244-1.543 17.803-5.495 5.758-14.563 6.206-20.618 1.264-6.149-5.02-6.88-13.26-2.905-19.1Z" fill="#276749"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M25.318 5.632C19.417-.21 9.822.285 4.703 5.4c.03.033.059.067.09.098 3.383 3.283 6.766 6.564 10.145 9.848.096.093.15.082.236-.004.437-.429.878-.853 1.319-1.277 2.852-2.745 5.705-5.49 8.559-8.232.076-.073.17-.13.266-.2Zm-10.27 11.786L2.685 5.4c.03-.038.054-.075.083-.107 1.488-1.598 3.215-2.89 5.23-3.81A16.24 16.24 0 0 1 11.432.358a16.717 16.717 0 0 1 4.154-.341c2.04.088 3.992.54 5.858 1.347 2.243.97 4.137 2.386 5.745 4.176.093.103.04.15-.032.219-2 1.925-3.998 3.85-5.996 5.776l-5.982 5.767c-.036.035-.074.068-.13.117ZM9.733 14.608c-.837.742-2.699.914-3.931-.278-1.237-1.197-1.067-2.966-.255-3.886l4.186 4.164ZM20.563 14.32l4.193-4.072c.59.64.863 2.272-.158 3.476-1.136 1.338-3.01 1.33-4.035.596Z" fill="#276749"/>
</svg>
\ No newline at end of file
<svg width="30" height="30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.467 7.495c.046.041.084.073.12.107.377.365.75.734 1.133 1.095.085.081.086.137.024.23-.8 1.21-1.09 2.537-.824 3.943.358 1.886 1.456 3.26 3.248 4.089 1.06.489 2.183.614 3.338.443a5.646 5.646 0 0 0 2.166-.788c.11-.068.17-.06.26.028.974.958 1.955 1.91 2.928 2.87.108.105.163.117.28.004 1.112-1.087 2.234-2.166 3.347-3.254.122-.12.199-.14.36-.047.973.568 2.033.795 3.167.744 2.25-.102 4.305-1.625 5.003-3.716.528-1.583.332-3.086-.529-4.515-.056-.093-.06-.15.025-.231.314-.293.619-.594.928-.891.028-.028.06-.052.092-.079 3.297 4.694 3.762 12.244-1.543 17.803-5.495 5.758-14.563 6.206-20.618 1.264-6.149-5.02-6.88-13.26-2.905-19.1Z" fill="#DD6B20"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M25.318 5.632C19.417-.21 9.822.285 4.703 5.4c.03.033.059.067.09.098 3.383 3.283 6.766 6.564 10.145 9.848.096.093.15.082.236-.004.437-.429.878-.853 1.319-1.277 2.852-2.745 5.705-5.49 8.559-8.232.076-.073.17-.13.266-.2Zm-10.27 11.786L2.685 5.4c.03-.038.054-.075.083-.107 1.488-1.598 3.215-2.89 5.23-3.81A16.24 16.24 0 0 1 11.432.358a16.717 16.717 0 0 1 4.154-.341c2.04.088 3.992.54 5.858 1.347 2.243.97 4.137 2.386 5.745 4.176.093.103.04.15-.032.219-2 1.925-3.998 3.85-5.996 5.776l-5.982 5.767c-.036.035-.074.068-.13.117ZM9.733 14.608c-.837.742-2.699.914-3.931-.278-1.237-1.197-1.067-2.966-.255-3.886l4.186 4.164ZM20.563 14.32l4.193-4.072c.59.64.863 2.272-.158 3.476-1.136 1.338-3.01 1.33-4.035.596Z" fill="#DD6B20"/>
</svg>
\ No newline at end of file
<svg width="30" height="30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.285 3.6a1.6 1.6 0 0 0-1.6-1.6H8.298a1.6 1.6 0 0 0-1.6 1.6v2.217a1.6 1.6 0 0 1-1.6 1.6H3.6a1.6 1.6 0 0 0-1.6 1.6V26.4A1.6 1.6 0 0 0 3.6 28h2.387a1.6 1.6 0 0 0 1.6-1.6V9.017a1.6 1.6 0 0 1 1.6-1.6h1.498a1.6 1.6 0 0 0 1.6-1.6V3.6Zm11.212 0a1.6 1.6 0 0 0-1.6-1.6H19.51a1.6 1.6 0 0 0-1.6 1.6v2.217a1.6 1.6 0 0 0 1.6 1.6h1.303a1.6 1.6 0 0 1 1.6 1.6V26.4a1.6 1.6 0 0 0 1.6 1.6H26.4a1.6 1.6 0 0 0 1.6-1.6V9.017a1.6 1.6 0 0 0-1.6-1.6h-1.303a1.6 1.6 0 0 1-1.6-1.6V3.6Zm-5.665 10.37a1.6 1.6 0 0 0-1.6-1.6h-2.387a1.6 1.6 0 0 0-1.6 1.6v7.323a1.6 1.6 0 0 0 1.6 1.6h2.387a1.6 1.6 0 0 0 1.6-1.6v-7.324Z" fill="currentColor"/>
</svg>
\ No newline at end of file
<svg width="30" height="30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 11a2 2 0 0 1 2-2h22.753a2 2 0 0 1 1.92 1.436L30 21.75H14.25l-1.125-5.25H0V11Zm0 8.75V18h12l.75 3.75H2a2 2 0 0 1-2-2Zm6-9.25H2.25l1.5 4.5H7.5L6 10.5Zm6 0H8.25l1.5 4.5h3.75L12 10.5Zm8.25 7.5h1.821l.429 1.5h-1.821L20.25 18Zm7.071 0H25.5l.429 1.5h1.821l-.429-1.5ZM17.25 10.5h7.5L27 17.25h-7.5l-2.25-6.75Z" fill="#38B2AC"/>
</svg>
\ No newline at end of file
<svg width="30" height="30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.247 3h1.616a5 5 0 0 1 0 10h-1.116v1.5a.5.5 0 0 1-.5.5h-5.116a.5.5 0 0 1-.5-.5V3.06a.06.06 0 0 1 .06-.06h5.556ZM7.678 14.678a.5.5 0 0 1 .848 0l6.601 10.557a.5.5 0 0 1-.424.765H1.501a.5.5 0 0 1-.424-.765l6.601-10.557ZM22.373 27c3.66 0 6.625-2.91 6.625-6.5S26.032 14 22.373 14c-3.66 0-6.626 2.91-6.626 6.5s2.966 6.5 6.626 6.5Z" fill="#5B2DA4"/>
</svg>
\ No newline at end of file
<svg width="30" height="30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.85 5.28c1.174 0 2.057-.905 2.057-1.94S16.024 1.4 14.85 1.4s-2.058.905-2.058 1.94c0 .247.05.486.143.707l.119.198-.018.01c.341.6 1.01 1.025 1.814 1.025Zm-3.058-1.92v-.02c0-1.624 1.37-2.94 3.058-2.94 1.688 0 3.057 1.316 3.057 2.94v.006l6 3.33.006-.002c1.462-.812 3.332-.33 4.177 1.076.844 1.406.343 3.204-1.12 4.016a3.129 3.129 0 0 1-.705.286v6.096c.241.065.479.16.706.286 1.462.812 1.963 2.61 1.12 4.016-.844 1.403-2.708 1.886-4.169 1.081l-6.015 3.341c-.006 1.618-1.373 2.928-3.057 2.928-1.689 0-3.058-1.316-3.058-2.94v-.005l-6-3.331-.005.002c-1.462.812-3.332.33-4.177-1.076-.844-1.406-.343-3.204 1.12-4.016.227-.126.464-.221.705-.286v-6.096a3.136 3.136 0 0 1-.705-.286C1.267 10.954.766 9.156 1.61 7.75c.845-1.406 2.715-1.888 4.177-1.076l.02.011 5.985-3.324ZM6.865 7.683l5.296-2.941a3.046 3.046 0 0 0 1.874 1.433v4.927c-.795.245-1.473.861-1.911 1.693L7.19 10.055c.25-.807.12-1.672-.326-2.373Zm4.79 6.55-5.251-2.916a3.1 3.1 0 0 1-1.542.786v5.996a3.092 3.092 0 0 1 1.615.858l5.23-2.903a4.98 4.98 0 0 1-.052-1.822Zm.602 3.213-5.038 2.797a2.85 2.85 0 0 1-.363 2.289l5.298 2.94c.39-.7 1.068-1.23 1.881-1.445v-5.123c-.718-.221-1.341-.746-1.778-1.458ZM15.564 24a3.049 3.049 0 0 1 1.989 1.484l5.298-2.943a2.85 2.85 0 0 1-.37-2.3l-5.103-2.834c-.44.736-1.078 1.277-1.814 1.5V24Zm2.351-7.992 5.308 2.947a3.092 3.092 0 0 1 1.615-.858v-5.996a3.1 3.1 0 0 1-1.541-.786l-5.332 2.96a5.037 5.037 0 0 1-.05 1.733Zm-.406-3.177 5-2.777a2.849 2.849 0 0 1 .334-2.385l-5.298-2.941a3.05 3.05 0 0 1-1.981 1.47v4.898c.813.246 1.505.879 1.945 1.735Zm-.832 13.139-.002.001.029.049c.13.257.203.543.203.839 0 1.035-.883 1.94-2.057 1.94s-2.058-.905-2.058-1.94c0-.253.053-.499.15-.725l.102-.17-.014-.007a2.064 2.064 0 0 1 1.82-1.038c.815 0 1.491.437 1.827 1.05Zm7.069-17.8-.015-.008a1.893 1.893 0 0 0-.153 1.873l.197.328c.593.795 1.745 1.064 2.68.545.997-.553 1.31-1.757.76-2.674s-1.791-1.257-2.787-.704a2.04 2.04 0 0 0-.597.498l-.085.142ZM6.12 10.038c.422-.891.088-1.987-.849-2.507-.995-.553-2.237-.212-2.787.704-.55.917-.236 2.121.76 2.674.936.52 2.09.25 2.681-.547l.195-.324ZM23.58 20.16l.194-.323c.591-.797 1.745-1.067 2.682-.547.996.553 1.31 1.757.76 2.674s-1.792 1.257-2.788.704c-.937-.52-1.27-1.616-.848-2.508Zm-20.336-.87c.937-.52 2.09-.25 2.683.547l.194.324c.422.891.088 1.987-.849 2.507-.996.553-2.237.213-2.787-.704-.55-.917-.237-2.121.76-2.674Zm10.791-4.19v2.716c-.768-.404-1.44-1.395-1.44-2.815 0-1.888 1.188-3.018 2.211-3.018s2.21 1.13 2.21 3.018c0 1.428-.678 2.422-1.452 2.822V15.1h-1.529Z" fill="#27AA8B"/>
</svg>
\ No newline at end of file
export default function delay(time: number) {
return new Promise((resolve) => window.setTimeout(resolve, time));
}
import { useRouter } from 'next/router';
export default function useBasePath() {
const router = useRouter();
return `/${ router.query.network_type }/${ router.query.network_sub_type }`;
}
import type { Network } from 'types/networks';
import arbitrumIcon from 'icons/networks/arbitrum.svg';
import artisIcon from 'icons/networks/artis.svg';
import ethereumClassicIcon from 'icons/networks/ethereum-classic.svg';
import ethereumIcon from 'icons/networks/ethereum.svg';
import gnosisIcon from 'icons/networks/gnosis.svg';
import optimismIcon from 'icons/networks/optimism.svg';
import poaSokolIcon from 'icons/networks/poa-sokol.svg';
import poaIcon from 'icons/networks/poa.svg';
import rskIcon from 'icons/networks/rsk.svg';
export const NETWORKS: Array<Network> = [
{
name: 'Gnosis Chain',
type: 'xdai',
subType: 'mainnet',
icon: gnosisIcon,
group: 'mainnets',
isAccountSupported: true,
isNewUiSupported: true,
},
{
name: 'Optimism on Gnosis Chain',
type: 'xdai',
subType: 'optimism',
icon: optimismIcon,
group: 'mainnets',
},
{
name: 'Arbitrum on xDai',
type: 'xdai',
subType: 'aox',
icon: arbitrumIcon,
group: 'mainnets',
},
{
name: 'Ethereum',
type: 'eth',
subType: 'mainnet',
icon: ethereumIcon,
group: 'mainnets',
},
{
name: 'Ethereum Classic',
type: 'etc',
subType: 'mainnet',
icon: ethereumClassicIcon,
group: 'mainnets',
},
{
name: 'POA',
type: 'poa',
subType: 'core',
icon: poaIcon,
group: 'mainnets',
},
{
name: 'RSK',
type: 'rsk',
subType: 'mainnet',
icon: rskIcon,
group: 'mainnets',
},
{
name: 'Gnosis Chain Testnet',
type: 'xdai',
subType: 'testnet',
icon: arbitrumIcon,
group: 'testnets',
isAccountSupported: true,
isNewUiSupported: true,
},
{
name: 'POA Sokol',
type: 'poa',
subType: 'sokol',
icon: poaSokolIcon,
group: 'testnets',
},
{
name: 'ARTIS Σ1',
type: 'artis',
subType: 'sigma1',
icon: artisIcon,
group: 'other',
},
{
name: 'LUKSO L14',
type: 'lukso',
subType: 'l14',
group: 'other',
},
];
export const ACCOUNT_ROUTES = [ '/watchlist', '/private-tags', '/public-tags', '/api-keys', '/custom-abi' ];
export function isAccountRoute(route: string) {
return ACCOUNT_ROUTES.includes(route);
}
...@@ -7,4 +7,13 @@ module.exports = withReactSvg({ ...@@ -7,4 +7,13 @@ module.exports = withReactSvg({
webpack(config) { webpack(config) {
return config; return config;
}, },
async redirects() {
return [
{
source: '/',
destination: '/xdai/mainnet',
permanent: true,
},
];
},
}); });
import { Center } from '@chakra-ui/react';
import type { NextPage } from 'next';
import { useRouter } from 'next/router';
import React from 'react';
import Page from 'ui/shared/Page/Page';
const Home: NextPage = () => {
const router = useRouter();
return (
<Page>
<Center h="100%">
home page for { router.query.network_type } { router.query.network_sub_type } network
</Center>
</Page>
);
};
export default Home;
import { Center } from '@chakra-ui/react';
import type { NextPage } from 'next'; import type { NextPage } from 'next';
import React from 'react';
import Page from 'ui/shared/Page/Page';
const Home: NextPage = () => { const Home: NextPage = () => {
return ( return null;
<Page>
<Center h="100%">
Home Page
</Center>
</Page>
);
}; };
export default Home; export default Home;
import { popoverAnatomy as parts } from '@chakra-ui/anatomy';
import type { PartsStyleFunction, SystemStyleFunction, SystemStyleObject } from '@chakra-ui/theme-tools';
import { cssVar, mode } from '@chakra-ui/theme-tools';
const $popperBg = cssVar('popper-bg');
const $arrowBg = cssVar('popper-arrow-bg');
const $arrowShadowColor = cssVar('popper-arrow-shadow-color');
const baseStylePopper: SystemStyleObject = {
zIndex: 10,
};
const baseStyleContent: SystemStyleFunction = (props) => {
const bg = mode('white', 'gray.900')(props);
const shadowColor = mode('gray.200', 'whiteAlpha.300')(props);
return {
[$popperBg.variable]: `colors.${ bg }`,
bg: $popperBg.reference,
[$arrowBg.variable]: $popperBg.reference,
[$arrowShadowColor.variable]: `colors.${ shadowColor }`,
width: 'xs',
border: 'none',
borderColor: 'inherit',
borderRadius: 'md',
boxShadow: '2xl',
zIndex: 'inherit',
_focusVisible: {
outline: 0,
boxShadow: '2xl',
},
};
};
const baseStyleHeader: SystemStyleObject = {
px: 3,
py: 2,
borderBottomWidth: '1px',
};
const baseStyleBody: SystemStyleObject = {
px: 4,
py: 4,
};
const baseStyleFooter: SystemStyleObject = {
px: 3,
py: 2,
borderTopWidth: '1px',
};
const baseStyleCloseButton: SystemStyleObject = {
position: 'absolute',
borderRadius: 'md',
top: 1,
insetEnd: 2,
padding: 2,
};
const baseStyle: PartsStyleFunction<typeof parts> = (props) => ({
popper: baseStylePopper,
content: baseStyleContent(props),
header: baseStyleHeader,
body: baseStyleBody,
footer: baseStyleFooter,
arrow: {},
closeButton: baseStyleCloseButton,
});
const Popover = {
parts: parts.keys,
baseStyle,
};
export default Popover;
import { Skeleton as SkeletonComponent } from '@chakra-ui/react';
import { keyframes } from '@chakra-ui/system';
import type { SystemStyleFunction } from '@chakra-ui/theme-tools';
import { getColor, mode } from '@chakra-ui/theme-tools';
const shine = () =>
keyframes({
to: { backgroundPositionX: '-200%' },
});
const baseStyle: SystemStyleFunction = (props) => {
const defaultStartColor = mode('blackAlpha.50', 'whiteAlpha.50')(props);
const defaultEndColor = mode('blackAlpha.100', 'whiteAlpha.100')(props);
const {
startColor = defaultStartColor,
endColor = defaultEndColor,
speed,
theme,
} = props;
const start = getColor(theme, startColor);
const end = getColor(theme, endColor);
return {
opacity: 1,
borderRadius: 'base',
borderColor: start,
background: `linear-gradient(90deg, ${ start } 8%, ${ end } 18%, ${ start } 33%)`,
backgroundSize: '200% 100%',
animation: `${ speed }s linear infinite ${ shine() }`,
};
};
const Skeleton = {
baseStyle,
};
export default Skeleton;
SkeletonComponent.defaultProps = {
...SkeletonComponent.defaultProps,
speed: 1,
};
...@@ -5,7 +5,9 @@ import Heading from './Heading'; ...@@ -5,7 +5,9 @@ import Heading from './Heading';
import Input from './Input'; import Input from './Input';
import Link from './Link'; import Link from './Link';
import Modal from './Modal'; import Modal from './Modal';
import Popover from './Popover';
import Radio from './Radio'; import Radio from './Radio';
import Skeleton from './Skeleton';
import Table from './Table'; import Table from './Table';
import Tabs from './Tabs'; import Tabs from './Tabs';
import Tag from './Tag'; import Tag from './Tag';
...@@ -21,7 +23,9 @@ const components = { ...@@ -21,7 +23,9 @@ const components = {
Form, Form,
Link, Link,
Modal, Modal,
Popover,
Radio, Radio,
Skeleton,
Tabs, Tabs,
Table, Table,
Tag, Tag,
......
import type { FunctionComponent, SVGAttributes } from 'react';
export type NetworkGroup = 'mainnets' | 'testnets' | 'other';
export interface Network {
name: string;
// basePath = /<type>/<subType>, e.g. /xdai/mainnet
type: string;
subType: string;
group: 'mainnets' | 'testnets' | 'other';
icon?: FunctionComponent<SVGAttributes<SVGElement>>;
isAccountSupported?: boolean;
isNewUiSupported?: boolean;
}
...@@ -18,7 +18,7 @@ interface Props { ...@@ -18,7 +18,7 @@ interface Props {
onDeleteClick: (item: ApiKey) => void; onDeleteClick: (item: ApiKey) => void;
} }
const WatchlistTableItem = ({ item, onEditClick, onDeleteClick }: Props) => { const ApiKeyTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
const onItemEditClick = useCallback(() => { const onItemEditClick = useCallback(() => {
return onEditClick(item); return onEditClick(item);
...@@ -47,4 +47,4 @@ const WatchlistTableItem = ({ item, onEditClick, onDeleteClick }: Props) => { ...@@ -47,4 +47,4 @@ const WatchlistTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
); );
}; };
export default WatchlistTableItem; export default ApiKeyTableItem;
...@@ -22,8 +22,7 @@ import styles from './ColorModeToggler.module.css'; ...@@ -22,8 +22,7 @@ import styles from './ColorModeToggler.module.css';
export interface ColorModeTogglerProps export interface ColorModeTogglerProps
extends Omit<UseCheckboxProps, 'isIndeterminate'>, extends Omit<UseCheckboxProps, 'isIndeterminate'>,
Omit<HTMLChakraProps<'label'>, keyof UseCheckboxProps>, Omit<HTMLChakraProps<'label'>, keyof UseCheckboxProps>,
ThemingProps<'Switch'> { ThemingProps<'Switch'> {}
}
const ColorModeToggler = forwardRef<ColorModeTogglerProps, 'input'>((props, ref) => { const ColorModeToggler = forwardRef<ColorModeTogglerProps, 'input'>((props, ref) => {
const ownProps = omitThemingProps(props); const ownProps = omitThemingProps(props);
......
...@@ -3,8 +3,11 @@ import { InputGroup, Input, InputLeftAddon, InputLeftElement, useColorModeValue ...@@ -3,8 +3,11 @@ import { InputGroup, Input, InputLeftAddon, InputLeftElement, useColorModeValue
import type { ChangeEvent, FormEvent } from 'react'; import type { ChangeEvent, FormEvent } from 'react';
import React from 'react'; import React from 'react';
import useBasePath from 'lib/hooks/useBasePath';
const SearchBar = () => { const SearchBar = () => {
const [ value, setValue ] = React.useState(''); const [ value, setValue ] = React.useState('');
const basePath = useBasePath();
const handleChange = React.useCallback((event: ChangeEvent<HTMLInputElement>) => { const handleChange = React.useCallback((event: ChangeEvent<HTMLInputElement>) => {
setValue(event.target.value); setValue(event.target.value);
...@@ -12,8 +15,8 @@ const SearchBar = () => { ...@@ -12,8 +15,8 @@ const SearchBar = () => {
const handleSubmit = React.useCallback((event: FormEvent<HTMLFormElement>) => { const handleSubmit = React.useCallback((event: FormEvent<HTMLFormElement>) => {
event.preventDefault(); event.preventDefault();
window.location.assign(`https://blockscout.com/xdai/mainnet/search-results?q=${ value }`); window.location.assign(`https://blockscout.com${ basePath }/search-results?q=${ value }`);
}, [ value ]); }, [ value, basePath ]);
return ( return (
<form noValidate onSubmit={ handleSubmit }> <form noValidate onSubmit={ handleSubmit }>
......
import { Link, Icon, Text, HStack, Tooltip } from '@chakra-ui/react'; import { Link, Icon, Text, HStack, Tooltip } from '@chakra-ui/react';
import NextLink from 'next/link'; import NextLink from 'next/link';
import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import getDefaultTransitionProps from 'theme/utils/getDefaultTransitionProps'; import getDefaultTransitionProps from 'theme/utils/getDefaultTransitionProps';
...@@ -9,20 +8,17 @@ import useColors from './useColors'; ...@@ -9,20 +8,17 @@ import useColors from './useColors';
interface Props { interface Props {
isCollapsed: boolean; isCollapsed: boolean;
isActive: boolean;
pathname: string; pathname: string;
text: string; text: string;
icon: React.FunctionComponent<React.SVGAttributes<SVGElement>>; icon: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
} }
const NavLink = ({ text, pathname, icon, isCollapsed }: Props) => { const NavLink = ({ text, pathname, icon, isCollapsed, isActive }: Props) => {
const router = useRouter();
const isActive = router.pathname === pathname;
const colors = useColors(); const colors = useColors();
return ( return (
<NextLink href={ pathname } passHref> <NextLink href={ pathname } passHref>
<Link <Link
as="li" as="li"
listStyleType="none" listStyleType="none"
......
import { ChevronLeftIcon } from '@chakra-ui/icons'; import { ChevronLeftIcon } from '@chakra-ui/icons';
import { Flex, Icon, Box, VStack, useColorModeValue } from '@chakra-ui/react'; import { Flex, Icon, Box, VStack, useColorModeValue } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import abiIcon from 'icons/ABI.svg'; import abiIcon from 'icons/ABI.svg';
...@@ -8,35 +9,39 @@ import appsIcon from 'icons/apps.svg'; ...@@ -8,35 +9,39 @@ import appsIcon from 'icons/apps.svg';
import blocksIcon from 'icons/block.svg'; import blocksIcon from 'icons/block.svg';
import gearIcon from 'icons/gear.svg'; import gearIcon from 'icons/gear.svg';
import logoIcon from 'icons/logo.svg'; import logoIcon from 'icons/logo.svg';
import networksIcon from 'icons/networks.svg';
import privateTagIcon from 'icons/privattags.svg'; import privateTagIcon from 'icons/privattags.svg';
import publicTagIcon from 'icons/publictags.svg'; import publicTagIcon from 'icons/publictags.svg';
import tokensIcon from 'icons/token.svg'; import tokensIcon from 'icons/token.svg';
import transactionsIcon from 'icons/transactions.svg'; import transactionsIcon from 'icons/transactions.svg';
import watchlistIcon from 'icons/watchlist.svg'; import watchlistIcon from 'icons/watchlist.svg';
import * as cookies from 'lib/cookies'; import * as cookies from 'lib/cookies';
import useBasePath from 'lib/hooks/useBasePath';
import getDefaultTransitionProps from 'theme/utils/getDefaultTransitionProps'; import getDefaultTransitionProps from 'theme/utils/getDefaultTransitionProps';
import NavFooter from './NavFooter'; import NavFooter from './NavFooter';
import NavLink from './NavLink'; import NavLink from './NavLink';
import NetworkMenu from './networkMenu/NetworkMenu';
const mainNavItems = [ const Navigation = () => {
{ text: 'Blocks', pathname: '/blocks', icon: blocksIcon }, const router = useRouter();
{ text: 'Transactions', pathname: '/transactions', icon: transactionsIcon }, const basePath = useBasePath();
{ text: 'Tokens', pathname: '/tokens', icon: tokensIcon },
{ text: 'Apps', pathname: '/apps', icon: appsIcon },
{ text: 'Other', pathname: '/other', icon: gearIcon },
];
const accountNavItems = [ const mainNavItems = [
{ text: 'Watchlist', pathname: '/watchlist', icon: watchlistIcon }, { text: 'Blocks', pathname: basePath + '/blocks', icon: blocksIcon },
{ text: 'Private tags', pathname: '/private-tags', icon: privateTagIcon }, { text: 'Transactions', pathname: basePath + '/transactions', icon: transactionsIcon },
{ text: 'Public tags', pathname: '/public-tags', icon: publicTagIcon }, { text: 'Tokens', pathname: basePath + '/tokens', icon: tokensIcon },
{ text: 'API keys', pathname: '/api-keys', icon: apiKeysIcon }, { text: 'Apps', pathname: basePath + '/apps', icon: appsIcon },
{ text: 'Custom ABI', pathname: '/custom-abi', icon: abiIcon }, { text: 'Other', pathname: basePath + '/other', icon: gearIcon },
]; ];
const accountNavItems = [
{ text: 'Watchlist', pathname: basePath + '/watchlist', icon: watchlistIcon },
{ text: 'Private tags', pathname: basePath + '/private-tags', icon: privateTagIcon },
{ text: 'Public tags', pathname: basePath + '/public-tags', icon: publicTagIcon },
{ text: 'API keys', pathname: basePath + '/api-keys', icon: apiKeysIcon },
{ text: 'Custom ABI', pathname: basePath + '/custom-abi', icon: abiIcon },
];
const Navigation = () => {
const [ isCollapsed, setCollapsedState ] = React.useState(cookies.get(cookies.NAMES.NAV_BAR_COLLAPSED) === 'true'); const [ isCollapsed, setCollapsedState ] = React.useState(cookies.get(cookies.NAMES.NAV_BAR_COLLAPSED) === 'true');
const handleTogglerClick = React.useCallback(() => { const handleTogglerClick = React.useCallback(() => {
...@@ -82,23 +87,16 @@ const Navigation = () => { ...@@ -82,23 +87,16 @@ const Navigation = () => {
{ ...getDefaultTransitionProps() } { ...getDefaultTransitionProps() }
/> />
</Box> </Box>
<Icon <NetworkMenu isCollapsed={ isCollapsed }/>
as={ networksIcon }
width="16px"
height="16px"
color={ useColorModeValue('gray.500', 'white') }
marginLeft={ isCollapsed ? '0px' : '27px' }
{ ...getDefaultTransitionProps({ transitionProperty: 'margin' }) }
/>
</Box> </Box>
<Box as="nav" mt={ 14 }> <Box as="nav" mt={ 14 }>
<VStack as="ul" spacing="2" alignItems="flex-start" overflow="hidden"> <VStack as="ul" spacing="2" alignItems="flex-start" overflow="hidden">
{ mainNavItems.map((item) => <NavLink key={ item.text } { ...item } isCollapsed={ isCollapsed }/>) } { mainNavItems.map((item) => <NavLink key={ item.text } { ...item } isCollapsed={ isCollapsed } isActive={ router.asPath === item.pathname }/>) }
</VStack> </VStack>
</Box> </Box>
<Box as="nav" mt={ 12 }> <Box as="nav" mt={ 12 }>
<VStack as="ul" spacing="2" alignItems="flex-start" overflow="hidden"> <VStack as="ul" spacing="2" alignItems="flex-start" overflow="hidden">
{ accountNavItems.map((item) => <NavLink key={ item.text } { ...item } isCollapsed={ isCollapsed }/>) } { accountNavItems.map((item) => <NavLink key={ item.text } { ...item } isCollapsed={ isCollapsed } isActive={ router.asPath === item.pathname }/>) }
</VStack> </VStack>
</Box> </Box>
<NavFooter isCollapsed={ isCollapsed }/> <NavFooter isCollapsed={ isCollapsed }/>
......
import { Popover, PopoverTrigger, Icon, useColorModeValue, Button } from '@chakra-ui/react';
import React from 'react';
import networksIcon from 'icons/networks.svg';
import getDefaultTransitionProps from 'theme/utils/getDefaultTransitionProps';
import NetworkMenuPopup from './NetworkMenuPopup';
interface Props {
isCollapsed: boolean;
}
const NetworkMenu = ({ isCollapsed }: Props) => {
return (
<Popover openDelay={ 300 } placement="right-start" gutter={ 22 } isLazy>
<PopoverTrigger>
<Button variant="unstyled" display="inline-flex" alignSelf="stretch" alignItems="center">
<Icon
as={ networksIcon }
width="16px"
height="16px"
color={ useColorModeValue('gray.500', 'white') }
_hover={{ color: 'blue.400' }}
marginLeft={ isCollapsed ? '0px' : '27px' }
cursor="pointer"
{ ...getDefaultTransitionProps({ transitionProperty: 'margin' }) }
/>
</Button>
</PopoverTrigger>
<NetworkMenuPopup/>
</Popover>
);
};
export default React.memo(NetworkMenu);
import { Box, Flex, Icon, Text } from '@chakra-ui/react';
import NextLink from 'next/link';
import React from 'react';
import type { Network } from 'types/networks';
import checkIcon from 'icons/check.svg';
import placeholderIcon from 'icons/networks/placeholder.svg';
import { isAccountRoute } from 'lib/networks';
import useColors from './useColors';
interface Props extends Network {
isActive: boolean;
routeName: string;
}
const NetworkMenuLink = ({ name, type, subType, icon, isActive, routeName, isAccountSupported, isNewUiSupported }: Props) => {
const isAccount = isAccountRoute(routeName);
const localPath = (() => {
if (isAccount && isAccountSupported) {
return routeName;
}
if (isAccount && !isAccountSupported) {
return '';
}
// will change when blocks&transaction is implemented
return routeName;
})();
const pathName = `/${ type }/${ subType }${ localPath }`;
// will fix later after we agree on CI/CD workflow
const href = isNewUiSupported ? pathName : 'https://blockscout.com' + pathName;
const hasIcon = Boolean(icon);
const colors = useColors({ hasIcon });
return (
<Box as="li" listStyleType="none">
<NextLink href={ href } passHref>
<Flex
as="a"
px={ 4 }
py={ 3 }
alignItems="center"
cursor="pointer"
pointerEvents={ isActive ? 'none' : 'initial' }
borderRadius="base"
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 }}
>
<Icon
as={ hasIcon ? icon : placeholderIcon }
boxSize="30px"
color={ isActive ? colors.icon.active : colors.icon.default }
/>
<Text
marginLeft={ 3 }
fontWeight="500"
color="inherit"
>
{ name }
</Text>
{ isActive && (
<Icon
as={ checkIcon }
boxSize="24px"
marginLeft="auto"
/>
) }
</Flex>
</NextLink>
</Box>
);
};
export default React.memo(NetworkMenuLink);
import { PopoverContent, PopoverBody, Text, Tabs, TabList, TabPanels, TabPanel, Tab, VStack } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react';
import type { NetworkGroup } from 'types/networks';
import { NETWORKS } from 'lib/networks';
import NetworkMenuLink from './NetworkMenuLink';
const TABS: Array<NetworkGroup> = [ 'mainnets', 'testnets', 'other' ];
const NetworkMenuPopup = () => {
const router = useRouter();
const routeName = router.pathname.replace('/[network_type]/[network_sub_type]', '');
const selectedNetwork = NETWORKS.find((network) => router.query.network_type === network.type && router.query.network_sub_type === network.subType);
const selectedTab = TABS.findIndex((tab) => selectedNetwork?.group === tab);
return (
<PopoverContent w="382px">
<PopoverBody>
<Text as="h4" fontSize="18px" lineHeight="30px" fontWeight="500">Networks</Text>
<Tabs variant="soft-rounded" mt={ 4 } isLazy defaultIndex={ selectedTab !== -1 ? selectedTab : undefined }>
<TabList>
{ TABS.map((tab) => <Tab key={ tab } textTransform="capitalize">{ tab }</Tab>) }
</TabList>
<TabPanels mt={ 8 }>
{ TABS.map((tab) => (
<TabPanel key={ tab } p={ 0 }>
<VStack as="ul" spacing={ 2 } alignItems="stretch" mt={ 4 }>
{ NETWORKS
.filter((network) => network.group === tab)
.map((network) => (
<NetworkMenuLink
key={ network.name }
{ ...network }
isActive={ network.name === selectedNetwork?.name }
routeName={ routeName }
/>
)) }
</VStack>
</TabPanel>
)) }
</TabPanels>
</Tabs>
</PopoverBody>
</PopoverContent>
);
};
export default NetworkMenuPopup;
import type { FunctionComponent, SVGAttributes } from 'react';
export interface NetworkLink {
pathname: string;
name: string;
icon?: FunctionComponent<SVGAttributes<SVGElement>>;
isNewUi?: boolean;
}
import { useColorModeValue } from '@chakra-ui/react';
export default function useColors({ hasIcon }: {hasIcon: boolean}) {
const iconDefaultColor = useColorModeValue('blackAlpha.600', 'whiteAlpha.600');
const iconPlaceholderDefaultColor = useColorModeValue('blackAlpha.100', 'whiteAlpha.100');
return {
text: {
'default': useColorModeValue('gray.600', 'gray.400'),
active: useColorModeValue('gray.700', 'whiteAlpha.900'),
hover: useColorModeValue('blue.600', 'blue.400'),
},
icon: {
'default': hasIcon ? iconDefaultColor : iconPlaceholderDefaultColor,
active: useColorModeValue('blackAlpha.900', 'whiteAlpha.900'),
},
bg: {
'default': 'transparent',
active: useColorModeValue('blue.50', 'gray.800'),
},
border: {
'default': useColorModeValue('gray.200', 'whiteAlpha.200'),
active: useColorModeValue('blue.50', 'gray.800'),
},
};
}
...@@ -11,5 +11,9 @@ export default function useColors() { ...@@ -11,5 +11,9 @@ export default function useColors() {
'default': 'transparent', 'default': 'transparent',
active: useColorModeValue('blue.50', 'gray.800'), active: useColorModeValue('blue.50', 'gray.800'),
}, },
border: {
'default': useColorModeValue('gray.200', 'whiteAlpha.200'),
active: useColorModeValue('blue.50', 'gray.800'),
},
}; };
} }
import { Box, Button, HStack, Link, Text, Spinner, useDisclosure } from '@chakra-ui/react'; import { Box, Button, HStack, Link, Text, Skeleton, useDisclosure } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
...@@ -10,6 +10,7 @@ import ApiKeyTable from 'ui/apiKey/ApiKeyTable/ApiKeyTable'; ...@@ -10,6 +10,7 @@ import ApiKeyTable from 'ui/apiKey/ApiKeyTable/ApiKeyTable';
import DeleteApiKeyModal from 'ui/apiKey/DeleteApiKeyModal'; import DeleteApiKeyModal from 'ui/apiKey/DeleteApiKeyModal';
import AccountPageHeader from 'ui/shared/AccountPageHeader'; import AccountPageHeader from 'ui/shared/AccountPageHeader';
import Page from 'ui/shared/Page/Page'; import Page from 'ui/shared/Page/Page';
import SkeletonTable from 'ui/shared/SkeletonTable';
const DATA_LIMIT = 3; const DATA_LIMIT = 3;
...@@ -50,20 +51,23 @@ const ApiKeysPage: React.FC = () => { ...@@ -50,20 +51,23 @@ const ApiKeysPage: React.FC = () => {
const content = (() => { const content = (() => {
if (isLoading || isError) { if (isLoading || isError) {
return <Spinner/>; return (
<>
<SkeletonTable columns={ [ '100%', '108px' ] }/>
<Skeleton height="44px" width="156px" marginTop={ 8 }/>
</>
);
} }
const canAdd = data.length < DATA_LIMIT; const canAdd = data.length < DATA_LIMIT;
return ( return (
<> <>
{ data.length > 0 && ( <ApiKeyTable
<ApiKeyTable data={ data }
data={ data } onDeleteClick={ onDeleteClick }
onDeleteClick={ onDeleteClick } onEditClick={ onEditClick }
onEditClick={ onEditClick } limit={ DATA_LIMIT }
limit={ DATA_LIMIT } />
/>
) }
<HStack marginTop={ 8 } spacing={ 5 }> <HStack marginTop={ 8 } spacing={ 5 }>
<Button <Button
variant="primary" variant="primary"
......
import { Box, Button, Spinner, Text, useDisclosure } from '@chakra-ui/react'; import { Box, Button, Text, Skeleton, useDisclosure } from '@chakra-ui/react';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import type { AddressTags, AddressTag } from 'types/api/account'; import type { AddressTags, AddressTag } from 'types/api/account';
import SkeletonTable from 'ui/shared/SkeletonTable';
import AddressModal from './AddressModal/AddressModal'; import AddressModal from './AddressModal/AddressModal';
import AddressTagTable from './AddressTagTable/AddressTagTable'; import AddressTagTable from './AddressTagTable/AddressTagTable';
import DeletePrivateTagModal from './DeletePrivateTagModal'; import DeletePrivateTagModal from './DeletePrivateTagModal';
type Props = { type Props = {
addressTags: AddressTags; addressTags?: AddressTags;
} }
const PrivateAddressTags = ({ addressTags }: Props) => { const PrivateAddressTags = ({ addressTags }: Props) => {
...@@ -38,13 +40,26 @@ const PrivateAddressTags = ({ addressTags }: Props) => { ...@@ -38,13 +40,26 @@ const PrivateAddressTags = ({ addressTags }: Props) => {
deleteModalProps.onClose(); deleteModalProps.onClose();
}, [ deleteModalProps ]); }, [ deleteModalProps ]);
return ( const description = (
<> <Text marginBottom={ 12 }>
<Text marginBottom={ 12 }>
Use private transaction tags to label any transactions of interest. Use private transaction tags to label any transactions of interest.
Private tags are saved in your account and are only visible when you are logged in. Private tags are saved in your account and are only visible when you are logged in.
</Text> </Text>
{ !addressTags && <Spinner/> } );
if (!addressTags) {
return (
<>
{ description }
<SkeletonTable columns={ [ '60%', '40%', '108px' ] }/>
<Skeleton height="44px" width="156px" marginTop={ 8 }/>
</>
);
}
return (
<>
{ description }
{ Boolean(addressTags?.length) && ( { Boolean(addressTags?.length) && (
<AddressTagTable <AddressTagTable
data={ addressTags } data={ addressTags }
......
import { Box, Button, Text, useDisclosure } from '@chakra-ui/react'; import { Box, Button, Skeleton, Text, useDisclosure } from '@chakra-ui/react';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import type { TransactionTags, TransactionTag } from 'types/api/account'; import type { TransactionTags, TransactionTag } from 'types/api/account';
import SkeletonTable from 'ui/shared/SkeletonTable';
import DeletePrivateTagModal from './DeletePrivateTagModal'; import DeletePrivateTagModal from './DeletePrivateTagModal';
import TransactionModal from './TransactionModal/TransactionModal'; import TransactionModal from './TransactionModal/TransactionModal';
import TransactionTagTable from './TransactionTagTable/TransactionTagTable'; import TransactionTagTable from './TransactionTagTable/TransactionTagTable';
type Props = { type Props = {
transactionTags: TransactionTags; transactionTags?: TransactionTags;
} }
const PrivateTransactionTags = ({ transactionTags }: Props) => { const PrivateTransactionTags = ({ transactionTags }: Props) => {
...@@ -38,12 +40,26 @@ const PrivateTransactionTags = ({ transactionTags }: Props) => { ...@@ -38,12 +40,26 @@ const PrivateTransactionTags = ({ transactionTags }: Props) => {
deleteModalProps.onClose(); deleteModalProps.onClose();
}, [ deleteModalProps ]); }, [ deleteModalProps ]);
return ( const description = (
<> <Text marginBottom={ 12 }>
<Text marginBottom={ 12 }>
Use private transaction tags to label any transactions of interest. Use private transaction tags to label any transactions of interest.
Private tags are saved in your account and are only visible when you are logged in. Private tags are saved in your account and are only visible when you are logged in.
</Text> </Text>
);
if (!transactionTags) {
return (
<>
{ description }
<SkeletonTable columns={ [ '75%', '25%', '108px' ] }/>
<Skeleton height="44px" width="156px" marginTop={ 8 }/>
</>
);
}
return (
<>
{ description }
{ Boolean(transactionTags.length) && ( { Boolean(transactionTags.length) && (
<TransactionTagTable <TransactionTagTable
data={ transactionTags } data={ transactionTags }
......
import { Box, Text } from '@chakra-ui/react';
import { keyframes } from '@chakra-ui/system';
import React from 'react';
const runnerAnimation = keyframes`
0% { left: 0%; transform: translateX(-1%); }
100% { left: '100%'; transform: translateX(-99%); }
`;
const ContentLoader = () => {
return (
<Box display="inline-block">
<Box
width="100%"
height="6px"
position="relative"
_after={{
content: `" "`,
position: 'absolute',
width: '60px',
height: '6px',
animation: `${ runnerAnimation } 700ms ease-in-out infinite alternate`,
left: '100%',
top: 0,
backgroundColor: 'blue.300',
borderRadius: 'full',
}}
/>
<Text mt={ 6 } variant="secondary">Loading data, please wait... </Text>
</Box>
);
};
export default ContentLoader;
import { HStack, Skeleton } from '@chakra-ui/react';
import React from 'react';
interface Props {
columns: Array<string>;
}
const SkeletonTable = ({ columns }: Props) => {
return (
<div>
<Skeleton height={ 10 } width="100%" borderBottomLeftRadius="none" borderBottomRightRadius="none"/>
{ Array.from(Array(3)).map((item, index) => (
<HStack key={ index } spacing={ 6 } marginTop={ 8 }>
{ columns.map((width, index) => (
<Skeleton
key={ index }
height={ 5 }
width={ width }
flexShrink={ width.includes('%') ? 'initial' : 0 }
borderRadius="full"
/>
)) }
</HStack>
)) }
</div>
);
};
export default React.memo(SkeletonTable);
...@@ -18,7 +18,7 @@ const WatchListAddressItem = ({ item }: {item: TWatchlistItem}) => { ...@@ -18,7 +18,7 @@ const WatchListAddressItem = ({ item }: {item: TWatchlistItem}) => {
<AddressLinkWithTooltip address={ item.address }/> <AddressLinkWithTooltip address={ item.address }/>
{ item.tokenBalance && ( { item.tokenBalance && (
<HStack spacing={ 0 } fontSize="sm" h={ 6 }> <HStack spacing={ 0 } fontSize="sm" h={ 6 }>
<Image src="./xdai.png" alt="chain-logo" marginRight="10px" w="16px" h="16px"/> <Image src="/xdai.png" alt="chain-logo" marginRight="10px" w="16px" h="16px"/>
<Text color={ mainTextColor }>{ `xDAI balance:${ nbsp }` + item.tokenBalance }</Text> <Text color={ mainTextColor }>{ `xDAI balance:${ nbsp }` + item.tokenBalance }</Text>
<Text variant="secondary">{ `${ nbsp }($${ item.tokenBalanceUSD } USD)` }</Text> <Text variant="secondary">{ `${ nbsp }($${ item.tokenBalanceUSD } USD)` }</Text>
</HStack> </HStack>
......
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