Skip to content

Commit

Permalink
[explorer] Tweak visual presentation of node map (MystenLabs#7328)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jordan-Mysten authored Jan 12, 2023
1 parent 87c2e4b commit 16028ba
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function MapFeature({ path, feature, onMouseOver, onMouseOut }: Props) {
d={path}
fill="white"
strokeWidth={0.2}
stroke="var(--steel)"
stroke="var(--steel-dark)"
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@
import { useQuery } from '@tanstack/react-query';
import { ParentSizeModern } from '@visx/responsive';
import { TooltipWithBounds, useTooltip } from '@visx/tooltip';
import React, { useCallback, useMemo } from 'react';
import React, { type ReactNode, useCallback, useMemo } from 'react';

import { WorldMap } from './WorldMap';
import { type NodeLocation } from './types';

import styles from './ValidatorMap.module.css';

import { Card } from '~/ui/Card';
import { DateFilter, useDateFilterState } from '~/ui/DateFilter';
import { Heading } from '~/ui/Heading';
import { Placeholder } from '~/ui/Placeholder';
import { Text } from '~/ui/Text';

const HOST = 'https://imgmod.sui.io';

Expand All @@ -28,11 +29,25 @@ const DATE_FILTER_TO_WINDOW = {
ALL: 'all',
};

export default function ValidatorMap() {
function NodeStat({ title, children }: { title: string; children: ReactNode }) {
return (
<div className="space-y-1.5">
<Heading variant="heading2/semibold" color="steel-darker">
{children}
</Heading>
<Text variant="caption/semibold" color="steel-dark">
{title}
</Text>
</div>
);
}

// NOTE: This component is lazy imported, so it needs to be default exported:
export default function NodeMap() {
const [dateFilter, setDateFilter] = useDateFilterState('D');

const { data, isLoading, isSuccess } = useQuery(
['validator-map', dateFilter],
['node-map', dateFilter],
async () => {
const res = await fetch(
`${HOST}/location?${new URLSearchParams({
Expand All @@ -45,7 +60,7 @@ export default function ValidatorMap() {
);

if (!res.ok) {
throw new Error('Failed to fetch validator map data');
throw new Error('Failed to fetch node map data');
}

return res.json() as Promise<NodeLocation[]>;
Expand Down Expand Up @@ -110,79 +125,81 @@ export default function ValidatorMap() {
);

return (
<div data-testid="fullnode-map" className={styles.card}>
<div className={styles.container}>
<div className={styles.contents}>
<div>
<div className={styles.stat}>
<Card spacing="none">
<div
data-testid="node-map"
className="relative flex min-h-[320px] flex-col justify-end"
>
<div className="pointer-events-none relative z-10 flex flex-1 flex-col justify-between gap-8 p-6">
<Heading variant="heading4/semibold" color="steel-darker">
Sui Nodes
</Heading>

<div className="flex flex-col gap-8">
<NodeStat title="Countries">
{isLoading && (
<Placeholder width="59px" height="32px" />
<Placeholder width="60px" height="0.8em" />
)}
{isSuccess &&
countryCount &&
numberFormatter.format(countryCount)}
</div>
<div className={styles.title}>Countries</div>
</div>
<div>
<div className={styles.stat}>
</NodeStat>

<NodeStat title="Nodes on Devnet and Testnet">
{isLoading && (
<Placeholder width="59px" height="32px" />
<Placeholder width="60px" height="0.8em" />
)}
{
// Fetch received response with no errors and the value was not null
isSuccess &&
totalCount &&
numberFormatter.format(totalCount)
}
</div>
<div className={styles.title}>
Nodes on Devnet and Testnet
</div>
</NodeStat>
</div>
</div>
</div>

<div className="absolute top-5 right-5 z-10">
<DateFilter value={dateFilter} onChange={setDateFilter} />
</div>

<div className={styles.mapcontainer}>
<div className={styles.map}>
<ParentSizeModern>
{(parent) => (
<WorldMap
nodes={data}
width={parent.width}
height={parent.height}
onMouseOver={handleMouseOver}
onMouseOut={hideTooltip}
/>
)}
</ParentSizeModern>
<div className="absolute top-5 right-5 z-10">
<DateFilter value={dateFilter} onChange={setDateFilter} />
</div>
</div>

{tooltipOpen && tooltipData && (
<TooltipWithBounds
top={tooltipTop}
left={tooltipLeft}
className={styles.tooltip}
// NOTE: Tooltip will un-style itself if we provide a style object:
style={{}}
>
<div className={styles.tipitem}>
<div>Nodes</div>
<div>{countryNodes[tooltipData].count}</div>
</div>
<div className={styles.tipdivider} />
<div>
{regionNamesInEnglish.of(
countryNodes[tooltipData].country
) || countryNodes[tooltipData].country}
<div className="absolute inset-0 z-0 overflow-hidden">
<div className="pointer-events-none absolute inset-0 md:pointer-events-auto">
<ParentSizeModern>
{(parent) => (
<WorldMap
nodes={data}
width={parent.width}
height={parent.height}
onMouseOver={handleMouseOver}
onMouseOut={hideTooltip}
/>
)}
</ParentSizeModern>
</div>
</TooltipWithBounds>
)}
</div>
</div>

{tooltipOpen && tooltipData && (
<TooltipWithBounds
top={tooltipTop}
left={tooltipLeft}
className="absolute z-40 hidden min-w-[100px] rounded-md bg-gray-100 p-2 font-sans text-xs text-white md:block"
// NOTE: Tooltip will un-style itself if we provide a style object:
style={{}}
>
<div className="flex items-center justify-between font-semibold uppercase">
<div>Nodes</div>
<div>{countryNodes[tooltipData].count}</div>
</div>
<div className="my-1 h-px bg-gray-90" />
<div>
{regionNamesInEnglish.of(
countryNodes[tooltipData].country
) || countryNodes[tooltipData].country}
</div>
</TooltipWithBounds>
)}
</div>
</Card>
);
}
47 changes: 0 additions & 47 deletions apps/explorer/src/components/validator-map/ValidatorMap.module.css

This file was deleted.

1 change: 1 addition & 0 deletions apps/explorer/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
--issue-light: theme('colors.issue.light');
--issue-dark: theme('colors.issue.dark');
--steel: theme('colors.steel.DEFAULT');
--steel-dark: theme('colors.steel.dark');
}

body {
Expand Down
6 changes: 2 additions & 4 deletions apps/explorer/src/pages/home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ import styles from './Home.module.css';

import { Tab, TabGroup, TabList, TabPanel, TabPanels } from '~/ui/Tabs';

const ValidatorMap = lazy(
() => import('../../components/validator-map/ValidatorMap')
);
const NodeMap = lazy(() => import('../../components/node-map'));

const TXN_PER_PAGE = 25;

Expand Down Expand Up @@ -50,7 +48,7 @@ function Home() {
</div>
<ErrorBoundary>
<Suspense fallback={null}>
<ValidatorMap />
<NodeMap />
</Suspense>
</ErrorBoundary>
<div>
Expand Down
16 changes: 11 additions & 5 deletions apps/explorer/src/ui/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,27 @@ import { type ReactNode } from 'react';

const cardStyles = cva('bg-gray-40', {
variants: {
rounded: {
lg: 'rounded-lg',
xl: 'rounded-xl',
},
spacing: {
sm: 'px-5 py-4 rounded-lg',
md: 'p-5 rounded-xl',
lg: 'p-8 rounded-xl',
none: '',
sm: 'px-5 py-4',
md: 'p-5',
lg: 'p-8',
},
},
defaultVariants: {
spacing: 'md',
rounded: 'lg',
},
});

export interface CardProps extends VariantProps<typeof cardStyles> {
children: ReactNode;
}

export function Card({ spacing, children }: CardProps) {
return <div className={cardStyles({ spacing })}>{children}</div>;
export function Card({ spacing, rounded, children }: CardProps) {
return <div className={cardStyles({ spacing, rounded })}>{children}</div>;
}
9 changes: 6 additions & 3 deletions apps/explorer/src/ui/Placeholder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import clsx from 'clsx';
import styles from './utils/customStyles.module.css';

export interface PlaceholderProps {
width: string;
height: string;
width?: string;
height?: string;
}

export function Placeholder({ width, height }: PlaceholderProps) {
export function Placeholder({
width = '100%',
height = '1em',
}: PlaceholderProps) {
return (
<div
className={clsx(
Expand Down
4 changes: 2 additions & 2 deletions apps/explorer/tests/home.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ test('displays the validator table', async ({ page }) => {
await expect(page.getByTestId('validators-table')).toBeVisible();
});

test('displays the fullnode map', async ({ page }) => {
test('displays the node map', async ({ page }) => {
await page.goto('/');
await expect(page.getByTestId('fullnode-map')).toBeVisible();
await expect(page.getByTestId('node-map')).toBeVisible();
});

0 comments on commit 16028ba

Please sign in to comment.