From 16028bab0fbbe32f01972902f3e84e42d43b5e21 Mon Sep 17 00:00:00 2001 From: Jordan Gensler Date: Thu, 12 Jan 2023 10:28:59 -0800 Subject: [PATCH] [explorer] Tweak visual presentation of node map (#7328) --- .../MapFeature.tsx | 2 +- .../NodesLocation.tsx | 0 .../{validator-map => node-map}/WorldMap.tsx | 0 .../ValidatorMap.tsx => node-map/index.tsx} | 139 ++++++++++-------- .../{validator-map => node-map}/topology.json | 0 .../{validator-map => node-map}/types.ts | 0 .../validator-map/ValidatorMap.module.css | 47 ------ apps/explorer/src/index.css | 1 + apps/explorer/src/pages/home/Home.tsx | 6 +- apps/explorer/src/ui/Card.tsx | 16 +- apps/explorer/src/ui/Placeholder.tsx | 9 +- apps/explorer/tests/home.spec.ts | 4 +- 12 files changed, 101 insertions(+), 123 deletions(-) rename apps/explorer/src/components/{validator-map => node-map}/MapFeature.tsx (95%) rename apps/explorer/src/components/{validator-map => node-map}/NodesLocation.tsx (100%) rename apps/explorer/src/components/{validator-map => node-map}/WorldMap.tsx (100%) rename apps/explorer/src/components/{validator-map/ValidatorMap.tsx => node-map/index.tsx} (52%) rename apps/explorer/src/components/{validator-map => node-map}/topology.json (100%) rename apps/explorer/src/components/{validator-map => node-map}/types.ts (100%) delete mode 100644 apps/explorer/src/components/validator-map/ValidatorMap.module.css diff --git a/apps/explorer/src/components/validator-map/MapFeature.tsx b/apps/explorer/src/components/node-map/MapFeature.tsx similarity index 95% rename from apps/explorer/src/components/validator-map/MapFeature.tsx rename to apps/explorer/src/components/node-map/MapFeature.tsx index a418f92efeb1b..b190ce28f8836 100644 --- a/apps/explorer/src/components/validator-map/MapFeature.tsx +++ b/apps/explorer/src/components/node-map/MapFeature.tsx @@ -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)" /> ); } diff --git a/apps/explorer/src/components/validator-map/NodesLocation.tsx b/apps/explorer/src/components/node-map/NodesLocation.tsx similarity index 100% rename from apps/explorer/src/components/validator-map/NodesLocation.tsx rename to apps/explorer/src/components/node-map/NodesLocation.tsx diff --git a/apps/explorer/src/components/validator-map/WorldMap.tsx b/apps/explorer/src/components/node-map/WorldMap.tsx similarity index 100% rename from apps/explorer/src/components/validator-map/WorldMap.tsx rename to apps/explorer/src/components/node-map/WorldMap.tsx diff --git a/apps/explorer/src/components/validator-map/ValidatorMap.tsx b/apps/explorer/src/components/node-map/index.tsx similarity index 52% rename from apps/explorer/src/components/validator-map/ValidatorMap.tsx rename to apps/explorer/src/components/node-map/index.tsx index 08edd97e3f8ee..c3c88b40b0114 100644 --- a/apps/explorer/src/components/validator-map/ValidatorMap.tsx +++ b/apps/explorer/src/components/node-map/index.tsx @@ -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'; @@ -28,11 +29,25 @@ const DATE_FILTER_TO_WINDOW = { ALL: 'all', }; -export default function ValidatorMap() { +function NodeStat({ title, children }: { title: string; children: ReactNode }) { + return ( +
+ + {children} + + + {title} + +
+ ); +} + +// 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({ @@ -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; @@ -110,24 +125,29 @@ export default function ValidatorMap() { ); return ( -
-
-
-
-
+ +
+
+ + Sui Nodes + + +
+ {isLoading && ( - + )} {isSuccess && countryCount && numberFormatter.format(countryCount)} -
-
Countries
-
-
-
+ + + {isLoading && ( - + )} { // Fetch received response with no errors and the value was not null @@ -135,54 +155,51 @@ export default function ValidatorMap() { totalCount && numberFormatter.format(totalCount) } -
-
- Nodes on Devnet and Testnet -
+
-
-
- -
- -
-
- - {(parent) => ( - - )} - +
+
-
- {tooltipOpen && tooltipData && ( - -
-
Nodes
-
{countryNodes[tooltipData].count}
-
-
-
- {regionNamesInEnglish.of( - countryNodes[tooltipData].country - ) || countryNodes[tooltipData].country} +
+
+ + {(parent) => ( + + )} +
- - )} -
+
+ + {tooltipOpen && tooltipData && ( + +
+
Nodes
+
{countryNodes[tooltipData].count}
+
+
+
+ {regionNamesInEnglish.of( + countryNodes[tooltipData].country + ) || countryNodes[tooltipData].country} +
+ + )} +
+ ); } diff --git a/apps/explorer/src/components/validator-map/topology.json b/apps/explorer/src/components/node-map/topology.json similarity index 100% rename from apps/explorer/src/components/validator-map/topology.json rename to apps/explorer/src/components/node-map/topology.json diff --git a/apps/explorer/src/components/validator-map/types.ts b/apps/explorer/src/components/node-map/types.ts similarity index 100% rename from apps/explorer/src/components/validator-map/types.ts rename to apps/explorer/src/components/node-map/types.ts diff --git a/apps/explorer/src/components/validator-map/ValidatorMap.module.css b/apps/explorer/src/components/validator-map/ValidatorMap.module.css deleted file mode 100644 index ad5c7f5d55649..0000000000000 --- a/apps/explorer/src/components/validator-map/ValidatorMap.module.css +++ /dev/null @@ -1,47 +0,0 @@ -.card { - @apply relative flex min-h-[320px] flex-col justify-end rounded-lg bg-gray-45 antialiased; -} - -.container { - @apply pointer-events-none relative z-10 flex flex-col items-start justify-between gap-8 p-6 sm:flex-row sm:items-end md:flex-col md:items-start; -} - -.contents { - @apply flex flex-col gap-8; -} - -.title { - @apply text-xs font-semibold uppercase text-gray-65; -} - -.stat { - @apply text-2xl font-semibold text-gray-90; -} - -.button { - @apply pointer-events-auto inline-flex items-center gap-2 whitespace-nowrap rounded-md border border-solid border-gray-55 p-2 text-sm font-semibold text-gray-80 no-underline; -} - -.mapcontainer { - @apply absolute inset-0 z-0 overflow-hidden; -} - -.map { - @apply pointer-events-none absolute inset-0 md:pointer-events-auto; -} - -.map svg { - @apply overflow-visible; -} - -.tooltip { - @apply absolute z-20 z-40 hidden min-w-[100px] rounded-md bg-gray-100 p-2 font-sans text-xs text-white md:block; -} - -.tipitem { - @apply flex items-center justify-between font-semibold uppercase; -} - -.tipdivider { - @apply my-1 h-px bg-gray-90; -} diff --git a/apps/explorer/src/index.css b/apps/explorer/src/index.css index 6fbaaec9a3002..8e342e8b33e93 100644 --- a/apps/explorer/src/index.css +++ b/apps/explorer/src/index.css @@ -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 { diff --git a/apps/explorer/src/pages/home/Home.tsx b/apps/explorer/src/pages/home/Home.tsx index 1d2edcf5133fc..9cdbf20a614bd 100644 --- a/apps/explorer/src/pages/home/Home.tsx +++ b/apps/explorer/src/pages/home/Home.tsx @@ -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; @@ -50,7 +48,7 @@ function Home() {
- +
diff --git a/apps/explorer/src/ui/Card.tsx b/apps/explorer/src/ui/Card.tsx index d21b77ce77ebb..c57b25fc5af51 100644 --- a/apps/explorer/src/ui/Card.tsx +++ b/apps/explorer/src/ui/Card.tsx @@ -6,14 +6,20 @@ 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', }, }); @@ -21,6 +27,6 @@ export interface CardProps extends VariantProps { children: ReactNode; } -export function Card({ spacing, children }: CardProps) { - return
{children}
; +export function Card({ spacing, rounded, children }: CardProps) { + return
{children}
; } diff --git a/apps/explorer/src/ui/Placeholder.tsx b/apps/explorer/src/ui/Placeholder.tsx index 851bd40f7aa28..2415baaf457a2 100644 --- a/apps/explorer/src/ui/Placeholder.tsx +++ b/apps/explorer/src/ui/Placeholder.tsx @@ -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 (
{ 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(); });