mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
fix(explore/ui): readable detail labels, real validator metrics, stat contrast (v1.1.9)
Three UI-correctness fixes surfaced by visual inspection of explore.lux.network: - DetailedInfo (block/tx/address detail pages): every field label + value rendered white-on-white because the grid inherited the @luxfi/ui Tamagui `t_dark` theme color while the page is in light mode. The two most-used drill-downs were unreadable. Anchor the container to --color-text-primary and labels to --color-text-secondary so text follows the app color mode instead of the stray Tamagui theme. - StatsWidget (home metric cards): the value had no explicit color and inherited the same Tamagui white -> near-invisible "Total blocks / transactions / addresses". Anchor to --color-text-primary. - Validators dashboard + Network Overview: dropped the "Connected" (0/5) and "Avg Uptime" (0.0%) widgets/columns. platform.getCurrentValidators reports connected=null and uptime=0 for every validator on the public RPC (the API node does not track peer uptime), so those numbers were fabricated-looking zeros. Only chain-verifiable metrics (count, stake, delegation fee, delegators) remain -- real data, no fake numbers. Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@luxfi/explore",
|
||||
"version": "1.1.8",
|
||||
"version": "1.1.9",
|
||||
"private": false,
|
||||
"homepage": "https://github.com/luxfi/explore#readme",
|
||||
"engines": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Skeleton } from '@luxfi/ui/skeleton';
|
||||
import React from 'react';
|
||||
|
||||
import { cn } from 'lib/utils/cn';
|
||||
import { Skeleton } from '@luxfi/ui/skeleton';
|
||||
import { Hint } from 'toolkit/components/Hint/Hint';
|
||||
import * as ContainerWithScrollY from 'ui/shared/ContainerWithScrollY';
|
||||
|
||||
@@ -16,7 +16,11 @@ interface ContainerProps {
|
||||
|
||||
export const Container = ({ children, className }: ContainerProps) => {
|
||||
return (
|
||||
<div className={ cn('grid gap-x-8 gap-y-0 lg:gap-y-3 grid-cols-1 lg:grid-cols-[max-content_minmax(728px,auto)] text-sm lg:text-base', className) }>
|
||||
<div className={ cn(
|
||||
'grid gap-x-8 gap-y-0 lg:gap-y-3 grid-cols-1 lg:grid-cols-[max-content_minmax(728px,auto)]',
|
||||
'text-sm lg:text-base text-[var(--color-text-primary)]',
|
||||
className,
|
||||
) }>
|
||||
{ children }
|
||||
</div>
|
||||
);
|
||||
@@ -41,7 +45,7 @@ export const ItemLabel = ({ hint, children, isLoading, id, hasScroll, className
|
||||
return (
|
||||
<div
|
||||
id={ id }
|
||||
className={ cn('min-h-[30px] lg:min-h-[32px] [&:not(:first-child)]:mt-3 lg:[&:not(:first-child)]:mt-0', className) }
|
||||
className={ cn('min-h-[30px] lg:min-h-[32px] text-[var(--color-text-secondary)] [&:not(:first-child)]:mt-3 lg:[&:not(:first-child)]:mt-0', className) }
|
||||
>
|
||||
<div className="flex gap-x-1 lg:gap-x-2 items-start w-full">
|
||||
{ hint && <Hint label={ hint } isLoading={ isLoading } className="my-[5px] lg:my-[6px]"/> }
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Skeleton } from '@luxfi/ui/skeleton';
|
||||
import React from 'react';
|
||||
|
||||
import type { Route } from 'nextjs-routes';
|
||||
import { route } from 'nextjs-routes';
|
||||
|
||||
import { cn } from 'lib/utils/cn';
|
||||
import { Link } from 'toolkit/next/link';
|
||||
import { Skeleton } from '@luxfi/ui/skeleton';
|
||||
import { Hint } from 'toolkit/components/Hint/Hint';
|
||||
import { TruncatedText } from 'toolkit/components/truncation/TruncatedText';
|
||||
import { Link } from 'toolkit/next/link';
|
||||
import IconSvg, { type IconName } from 'ui/shared/IconSvg';
|
||||
|
||||
export type Props = {
|
||||
@@ -83,7 +83,7 @@ const StatsWidget = ({
|
||||
<Skeleton
|
||||
loading={ isLoading }
|
||||
className={ cn(
|
||||
'flex items-baseline font-medium text-lg',
|
||||
'flex items-baseline font-medium text-lg text-[var(--color-text-primary)]',
|
||||
isFallback && !isLoading && 'opacity-[var(--opacity-control-disabled)]',
|
||||
) }
|
||||
>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// Network-level stats: validators, chains, stake, uptime.
|
||||
// Displayed above the standard Explorer chain stats on the stats page.
|
||||
|
||||
import { Skeleton } from '@luxfi/ui/skeleton';
|
||||
import React from 'react';
|
||||
|
||||
import config from 'configs/app';
|
||||
import { useBlockchains, useCurrentValidators } from 'lib/api/pchain';
|
||||
import { Skeleton } from '@luxfi/ui/skeleton';
|
||||
|
||||
// ── Constants ──
|
||||
|
||||
@@ -13,8 +13,6 @@ const PRIMARY_NETWORK_ID = '11111111111111111111111111111111LpoYY';
|
||||
const PRIMARY_CHAIN_COUNT = 14;
|
||||
const LUX_DECIMALS = 6;
|
||||
|
||||
const STAT_BG = { _light: 'gray.50', _dark: 'whiteAlpha.50' };
|
||||
|
||||
// ── Helpers ──
|
||||
|
||||
function formatStake(nanoLux: bigint): string {
|
||||
@@ -35,8 +33,7 @@ interface StatCardProps {
|
||||
|
||||
const StatCard = ({ label, value, isLoading }: StatCardProps) => (
|
||||
<div
|
||||
|
||||
|
||||
|
||||
>
|
||||
<span className="text-[var(--color-text-secondary)]">
|
||||
{ label }
|
||||
@@ -71,7 +68,7 @@ const NetworkStats = () => {
|
||||
Network Overview
|
||||
</span>
|
||||
<div
|
||||
|
||||
|
||||
>
|
||||
<StatCard
|
||||
label="Total Chains"
|
||||
@@ -83,21 +80,16 @@ const NetworkStats = () => {
|
||||
value={ hasValidatorData ? String(stats.validatorCount) : '\u2014' }
|
||||
isLoading={ isLoading }
|
||||
/>
|
||||
<StatCard
|
||||
label="Connected"
|
||||
value={ hasValidatorData ? `${ stats.connectedCount }/${ stats.validatorCount }` : '\u2014' }
|
||||
isLoading={ isLoading }
|
||||
/>
|
||||
<StatCard
|
||||
label="Total Stake"
|
||||
value={ hasValidatorData ? `${ formatStake(stats.totalStake) } ${ config.chain.currency.symbol || 'LUX' }` : '\u2014' }
|
||||
isLoading={ isLoading }
|
||||
/>
|
||||
<StatCard
|
||||
label="Avg Uptime"
|
||||
value={ hasValidatorData ? `${ stats.averageUptime.toFixed(1) }%` : '\u2014' }
|
||||
isLoading={ isLoading }
|
||||
/>
|
||||
{ /*
|
||||
Connected / Avg Uptime intentionally omitted: platform.getCurrentValidators
|
||||
reports connected=null and uptime=0 on the public RPC, so any value would be
|
||||
fabricated. Only chain-verifiable metrics are shown.
|
||||
*/ }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@ import React from 'react';
|
||||
import config from 'configs/app';
|
||||
import type { PChainValidator, ValidatorStats } from 'lib/api/pchain';
|
||||
|
||||
import { formatStake, formatUptime, truncateNodeId } from './utils';
|
||||
import { formatStake, truncateNodeId } from './utils';
|
||||
|
||||
const CURRENCY = config.chain.currency.symbol || 'LUX';
|
||||
|
||||
@@ -117,12 +117,6 @@ const ActiveValidatorsTable = ({ validators, isLoading }: ActiveValidatorsTableP
|
||||
<div className="font-semibold flex-1 text-right">
|
||||
Delegation Fee
|
||||
</div>
|
||||
<div className="font-semibold flex-1 text-center">
|
||||
Connected
|
||||
</div>
|
||||
<div className="font-semibold flex-1 text-right">
|
||||
Uptime
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{ /* Rows */ }
|
||||
@@ -148,12 +142,6 @@ const ActiveValidatorsTable = ({ validators, isLoading }: ActiveValidatorsTableP
|
||||
<div className="flex-1 text-right">
|
||||
{ v.delegationFee }%
|
||||
</div>
|
||||
<div className="flex-1 flex justify-center">
|
||||
<div/>
|
||||
</div>
|
||||
<div className="flex-1 text-right">
|
||||
{ formatUptime(v.uptime) }
|
||||
</div>
|
||||
</div>
|
||||
)) }
|
||||
</div>
|
||||
@@ -174,30 +162,26 @@ const ValidatorsDashboard = ({ validators, stats, isLoading }: ValidatorsDashboa
|
||||
return (
|
||||
<div className="flex flex-col gap-6 text-[var(--color-text-primary)]">
|
||||
{ /* Stat cards */ }
|
||||
{ /*
|
||||
Connected / Avg Uptime intentionally omitted: platform.getCurrentValidators
|
||||
reports connected=null and uptime=0 for every validator on the public RPC
|
||||
(the API node does not track peer uptime), so any value here would be
|
||||
fabricated. Only chain-sourced, verifiable metrics are shown.
|
||||
*/ }
|
||||
<div
|
||||
className="grid gap-4"
|
||||
style={{ gridTemplateColumns: 'repeat(4, 1fr)' }}
|
||||
style={{ gridTemplateColumns: 'repeat(2, 1fr)' }}
|
||||
>
|
||||
<StatCard
|
||||
label="Validators"
|
||||
value={ stats.validatorCount.toLocaleString() }
|
||||
isLoading={ isLoading }
|
||||
/>
|
||||
<StatCard
|
||||
label="Connected"
|
||||
value={ `${ stats.connectedCount }/${ stats.validatorCount }` }
|
||||
isLoading={ isLoading }
|
||||
/>
|
||||
<StatCard
|
||||
label="Delegators"
|
||||
value={ stats.delegatorCount.toLocaleString() }
|
||||
isLoading={ isLoading }
|
||||
/>
|
||||
<StatCard
|
||||
label="Avg Uptime"
|
||||
value={ `${ stats.averageUptime.toFixed(1) }%` }
|
||||
isLoading={ isLoading }
|
||||
/>
|
||||
</div>
|
||||
|
||||
{ /* Stake breakdown */ }
|
||||
|
||||
Reference in New Issue
Block a user