Feat/1501 improve party details (#1785)

* feat(explorer): change styling party details page

* feat(explorer): use panel component in txs-stats-info.tsx

* feat(explorer): change order for party details sections
This commit is contained in:
Elmar 2022-10-20 16:11:37 +01:00 committed by GitHub
parent 70eeeeb1e2
commit 1964d42e5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 105 additions and 56 deletions

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useMemo } from 'react';
import type { ReactNode } from 'react';
import { Panel } from '../panel';
import {
@ -8,6 +8,8 @@ import {
Lozenge,
Tooltip,
} from '@vegaprotocol/ui-toolkit';
import { TruncateInline } from '../truncate/truncate';
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
interface InfoPanelProps {
children?: ReactNode | ReactNode[];
@ -24,32 +26,56 @@ export const InfoPanel = ({
type,
copy = true,
}: InfoPanelProps) => {
const { screenSize } = useScreenDimensions();
const isTruncated = useMemo(
() => ['xs', 'sm', 'md', 'lg'].includes(screenSize),
[screenSize]
);
const isDesktop = useMemo(() => ['lg'].includes(screenSize), [screenSize]);
const visibleChars = useMemo(() => (isDesktop ? 20 : 10), [isDesktop]);
return (
<Panel>
<section className="flex gap-3 mb-1 items-center">
<h3 className="text-lg font-bold">{title}</h3>
<p title={id} className="truncate ...">
{id}
</p>
{type && (
<Lozenge
className="text-xs leading-relaxed cursor-auto"
variant={Intent.None}
>
<Tooltip side="top" description={type} align="center">
<span>{type}</span>
</Tooltip>
</Lozenge>
)}
<section className="flex justify-between items-center items-center">
<div>
<div className="flex gap-3 items-center">
<h3 className="text-lg font-medium">{title}</h3>
{isTruncated ? (
<TruncateInline
text={id}
startChars={visibleChars}
endChars={visibleChars}
className="text-black dark:text-zinc-200"
/>
) : (
<p
title={id}
className="text-black dark:text-zinc-200 truncate ..."
>
{id}
</p>
)}
{type && (
<Lozenge
className="text-xs leading-relaxed cursor-auto"
variant={Intent.None}
>
<Tooltip side="top" description={type} align="center">
<span>{type}</span>
</Tooltip>
</Lozenge>
)}
</div>
<div>{children}</div>
</div>
{copy && (
<CopyWithTooltip text={id}>
<button className="underline">
<Icon name="duplicate" className="ml-2" />
<button className="bg-zinc-100 dark:bg-zinc-900 rounded-sm py-2 px-3">
<Icon name="duplicate" />
</button>
</CopyWithTooltip>
)}
</section>
{children}
</Panel>
);
};

View File

@ -6,5 +6,12 @@ interface PanelProps {
className?: string;
}
export const Panel = ({ children, className }: PanelProps) => (
<div className={classNames('border p-5 mb-5', className)}>{children}</div>
<div
className={classNames(
'border border-zinc-200 dark:border-zinc-800 rounded-md p-5 mb-5',
className
)}
>
{children}
</div>
);

View File

@ -2,8 +2,8 @@ import { gql, useQuery } from '@apollo/client';
import { t } from '@vegaprotocol/react-helpers';
import { useEffect } from 'react';
import { InfoBlock } from '../../components/info-block';
import { Panel } from '../../components/panel';
import type { TxsStats, TxsStats_statistics } from './__generated__/TxsStats';
import classNames from 'classnames';
const STATS_QUERY = gql`
query TxsStats {
@ -63,17 +63,18 @@ export const TxsStatsInfo = ({ className }: TxsStatsInfoProps) => {
const gridStyles =
'grid grid-rows-2 gap-4 grid-cols-2 xl:gap-8 xl:grid-rows-1 xl:grid-cols-4';
const containerStyles = 'p-5 border rounded-lg border-zinc-500';
return (
<aside className={classNames(gridStyles, containerStyles, className)}>
{TXS_STATS_MAP.map((field) => (
<InfoBlock
subtitle={field.label}
tooltipInfo={field.info}
title={data?.statistics[field.field] || ''}
/>
))}
</aside>
<Panel className={className}>
<section className={gridStyles}>
{TXS_STATS_MAP.map((field) => (
<InfoBlock
subtitle={field.label}
tooltipInfo={field.info}
title={data?.statistics[field.field] || ''}
/>
))}
</section>
</Panel>
);
};

View File

@ -4,16 +4,21 @@ import {
t,
useFetch,
addDecimalsFormatNumber,
useScreenDimensions,
} from '@vegaprotocol/react-helpers';
import { AccountTypeMapping } from '@vegaprotocol/types';
import React from 'react';
import React, { useMemo } from 'react';
import { useParams } from 'react-router-dom';
import { RouteTitle } from '../../../components/route-title';
import { SubHeading } from '../../../components/sub-heading';
import { AsyncRenderer, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import {
CopyWithTooltip,
Icon,
SyntaxHighlighter,
AsyncRenderer,
} from '@vegaprotocol/ui-toolkit';
import { Panel } from '../../../components/panel';
import { InfoPanel } from '../../../components/info-panel';
import { toNonHex } from '../../../components/search/detect-search';
import { TruncateInline } from '../../../components/truncate/truncate';
import { DATA_SOURCES } from '../../../config';
import type {
PartyAssetsQuery,
@ -61,6 +66,8 @@ const PARTY_ASSETS_QUERY = gql`
const Party = () => {
const { party } = useParams<{ party: string }>();
const partyId = party ? toNonHex(party) : '';
const { isMobile } = useScreenDimensions();
const visibleChars = useMemo(() => (isMobile ? 10 : 14), [isMobile]);
const filters = `filters[tx.submitter]=${partyId}`;
const { hasMoreTxs, loadTxs, error, txsData, loading } = useTxsData({
limit: 10,
@ -84,11 +91,19 @@ const Party = () => {
);
const header = data?.party?.id ? (
<InfoPanel
title={t('Address')}
id={data.party.id}
type={data.party.__typename}
/>
<header className="flex items-center gap-x-4">
<TruncateInline
text={data.party.id}
startChars={visibleChars}
endChars={visibleChars}
className="text-4xl xl:text-5xl uppercase font-alpha"
/>
<CopyWithTooltip text={data.party.id}>
<button className="bg-zinc-100 dark:bg-zinc-900 rounded-sm py-2 px-3">
<Icon name="duplicate" className="" />
</button>
</CopyWithTooltip>
</header>
) : (
<Panel>
<p>No party found for key {party}</p>
@ -100,17 +115,13 @@ const Party = () => {
{data?.party?.accounts?.length ? (
data.party.accounts.map((account) => {
return (
<InfoPanel
title={account.asset.name}
id={account.asset.id}
type={`Account Type - ${AccountTypeMapping[account.type]}`}
>
<InfoPanel title={account.asset.name} id={account.asset.id}>
<section>
<dl className="flex gap-2 font-mono">
<dt className="font-bold">
<dl className="flex gap-2">
<dt className="text-zinc-500 dark:text-zinc-400 text-md">
{t('Balance')} ({account.asset.symbol})
</dt>
<dd>
<dd className="text-md">
{addDecimalsFormatNumber(
account.balance,
account.asset.decimals
@ -135,7 +146,6 @@ const Party = () => {
<InfoPanel
title={t('Current Stake Available')}
id={data?.party?.stake?.currentStakeAvailable}
type={data?.party?.stake.__typename}
copy={false}
/>
) : (
@ -148,7 +158,12 @@ const Party = () => {
return (
<section>
<RouteTitle data-testid="parties-header">{t('Party')}</RouteTitle>
<h1
className="font-alpha uppercase font-xl mb-4 text-zinc-800 dark:text-zinc-200"
data-testid="parties-header"
>
{t('Party')}
</h1>
{data ? (
<>
{header}
@ -156,12 +171,16 @@ const Party = () => {
{accounts}
<SubHeading>{t('Staking')}</SubHeading>
{staking}
<SubHeading>{t('Transactions')}</SubHeading>
<SubHeading>{t('JSON')}</SubHeading>
<section data-testid="parties-json">
<SyntaxHighlighter data={data} />
</section>
<AsyncRenderer
loading={loading as boolean}
error={error}
data={txsData}
>
<SubHeading>{t('Transactions')}</SubHeading>
<TxsInfiniteList
hasMoreTxs={hasMoreTxs}
areTxsLoading={loading}
@ -171,10 +190,6 @@ const Party = () => {
className="mb-28"
/>
</AsyncRenderer>
<SubHeading>{t('JSON')}</SubHeading>
<section data-testid="parties-json">
<SyntaxHighlighter data={data} />
</section>
</>
) : null}

View File

@ -13,7 +13,7 @@ export const TxsList = () => {
<section className="md:p-2 lg:p-4 xl:p-6">
<RouteTitle>{t('Transactions')}</RouteTitle>
<BlocksRefetch refetch={refreshTxs} />
<TxsStatsInfo className="my-8 py-8" />
<TxsStatsInfo className="!my-12 py-8" />
<TxsInfiniteList
hasMoreTxs={hasMoreTxs}
areTxsLoading={loading}